LaTeX说到底还是一个排版系统,字体是排版关注的核心内容之一,但是由于历史原因,字体系统在设计和使用中混乱不堪, 深究起来就是巨坑,这里简单整理一下LaTeX在中文排版时的字体配置相关知识。
由于版权等原因,Tex Live 虽然已经打包了很多内容,但是并不会包括一些常见的中文字体,需要用户自行配置处理。 由于本文中的命令需要直接或间接依赖 fontspec 宏包,它是一个基于 XeLaTeX 和 LuaLaTeX 的字体配置宏包,因此不支持 pdfLaTeX,这个宏包可能会影响数学字体,在使用时可以传入no-math选项。 本文只考虑ctex宏包,在Windows/Linux系统的中文字体排版,并且只使用XeLaTeX 。
本文主要参考ctex用户文档,以及LaTeX 中文字体配置基础指南
中文字体常识 与书法字体不同,中文印刷/显示字体主要有以下几种:
楷体:源自实际书写中的楷体得到的字体
宋体:从唐宋直到明清,印刷行业对字体从楷体进行的简化,典型的特点是横平竖直,并且有尖角等辅助结构。(与宋朝没什么特别关系,主要定型于明朝,在清朝被改称宋体,在日本被称为明体)
仿宋:因为宋体不美观,在民国时期参考宋朝古籍重新设计的字体,相当于在宋体的基础上向楷体进行的复古潮,例如横平竖直不再是严格的,而是略微倾斜等
黑体:计算机时代,适合显示屏呈现的字体,特点是横竖笔画粗细均匀,并且没有多余的笔画
时至今日,宋体仍然是公文报刊和书籍等的正文部分的主流字体,有很多原因:历史习惯;长时间阅读时,宋体字相对不易疲劳;在字体风格上,宋体代表着文化和传统。 计算机和手机上显示的默认都是黑体:Windows使用的是著名的微软雅黑(版权是方正的,不可以用来商用),安卓使用的是开源的思源黑体,这也有很多原因:早期显示器分辨率差,宋体等的细节无法呈现,而黑体的可读性更高;在字体风格上,黑体体现着现代和科技感。
在英文字体中,通常会按照衬线和无衬线来分类,区别是核心笔画之外是否含有装饰性的笔画,将概念迁移到中文字体中,宋体就是典型的衬线字体,而黑体是典型的无衬线字体。 英文字体中还有等宽字体的概念,等宽字体保证每一个字母都显示相同的显示宽度,这在代码编写和表格排版等情景中很常见,将概念迁移到中文字体中,通常对应为所谓的等线字体。
在Windows系统中,默认会安装并使用如下字体:
黑体:SimHei
宋体(中易宋体):SimSun
新宋体:NSimSun
仿宋:FangSong
楷体:KaiTi
仿宋GB2312:FangSongGB2312
楷体GB2312:KaiTiGB2312
微软雅黑:Microsoft YaHei
在安装了office之后还会多出一些字体,例如
隶书:LiSu
幼圆:YouYuan
华文系列:华文细黑:STXihei,华文楷体:STKaiti,华文宋体:STSong,华文中宋:STZhongsong,华文仿宋:STFangsong,华文行楷:STXingkai,等等。
方正舒体:FZShuTi,方正姚体:FZYaoti
PDF中使用到的部分字体通常会直接嵌入到PDF中,即使接收方没有安装对应的字体,PDF的内容也可以正常显示。
ctex 字体配置常识 ctex是一个统一的中文排版宏包,涉及到默认中文字体,中文标点,中文间空格的处理等排版细节, 它针对不同编译器自动选择不同的底层中文支持方案(CJK,xeCJK,luatexja等), 针对不同平台会自动选择不同的默认字体,如下图所示(表格取自ctex宏包手册)
其中对于系统的判定比较简单:它可以判断出是否是Windows或macOS系统,对于其它情形全部视作Linux系统。 对于编译器只关注XeLaTeX。
关于中易字库:中易宋体(SimSun.ttc)(属于宋体,衬线体)是中易公司开发的一套字体,在微软雅黑(微软委托方正公司开发)出现之前是Windows默认中文字体,但是目前的Windows默认字体为微软雅黑(msyh.ttf)(属于黑体,无衬线体)。由于历史原因,Windows最新系统中仍然会附带中易宋体,并且在Windows简体中文环境下会直接显示为“宋体”,这很容易导致歧义。
关于fandol字库 :这是一套由马起园等人开发的开源中文字体。由于开发字体的公司已经破产,因此字体的商用版权存在争议。在Linux系统被默认使用,但是fandol字体的效果和完整性并不好,例如它缺少浛,祎这些不太生僻的姓名常用字,在编译后的PDF中会显示为方框,并给出警告。
查看当前texlive可以识别的所有中文字体(在Linux和Windows均可以使用)
1 fc-list -f "%{family}\n" :lang=zh > zhfont.txt
可用如下命令刷新texlive的字体缓存(在Linux和Windows均可以使用,可能需要sudo)
ctex在内部定义了一系列字体配置文件,位于TexLive安装根目录中的texmf-dist/tex/latex/ctex/fontset子目录,其下有八个字体定义文件,对应了不同的字体预设方案:
ctex-fontset-adobe.def (adobe字体方案)
ctex-fontset-fandol.def
ctex-fontset-founder.def (方正founder字体方案)
ctex-fontset-mac.def
ctex-fontset-macnew.def
ctex-fontset-macold.def
ctex-fontset-ubuntu.def
ctex-fontset-windows.def
在导入ctex宏包或者ctexart文档类时可以使用选项fontset=windows来指定选择其中一种预设方案,例如
1 2 3 4 5 6 7 \documentclass [fontset=windows]{ctexart}... \documentclass {article}\usepackage [fontset=windows]{ctex}...
其中:
如果fontset选项缺省,ctex就会根据当前的系统来判断,通常会默认选择windows或fandol方案。
如果拒绝使用这些默认方案,可以指定fontset=none,然后自行配置中文字体方案,具体命令见下文。
即使采用了这些默认方案,仍然可以用下面的自定义命令来改变使用的字体。
ctex 默认配置解析 对几个默认方案进行解析,移除了注释后的源文件全文如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 \GetIdInfo $ Id: ctex.dtx 13a2256 2022-07-14 18:54:09 +0800 Qing Lee <sobenlee@gmail.com> $ {Windows fonts definition (CTEX)} \ProvidesExplFile {ctex-fontset-windows.def} {\ExplFileDate }{2.5.10}{\ExplFileDescription } \file_if_exist:nTF { \c_dollar_str WINDIR/Fonts/msyh.ttc } { \tl_const:Nn \c__ctex_msyh_suffix_tl { ttc } } { \file_if_exist:nTF { msyh.ttc } { \tl_const:Nn \c__ctex_msyh_suffix_tl { ttc } } { \tl_const:Nn \c__ctex_msyh_suffix_tl { ttf } } } \ctex_fontset_case:nnn { \ctex_zhmap_case:nnn { \ctex_punct_set:n { windows } \setCJKmainfont { simsun.ttc } [ BoldFont = simhei.ttf, ItalicFont = simkai.ttf ] \setCJKsansfont { msyh.\c__ctex_msyh_suffix_tl } [ BoldFont = msyhbd.\c__ctex_msyh_suffix_tl ] \setCJKmonofont { simfang.ttf } \setCJKfamilyfont { zhsong } { simsun.ttc } \setCJKfamilyfont { zhhei } { simhei.ttf } \setCJKfamilyfont { zhfs } { simfang.ttf } \setCJKfamilyfont { zhkai } { simkai.ttf } \setCJKfamilyfont { zhyahei } { msyh.\c__ctex_msyh_suffix_tl } [ BoldFont = msyhbd.\c__ctex_msyh_suffix_tl ] \setCJKfamilyfont { zhli } { simli.ttf } \setCJKfamilyfont { zhyou } { simyou.ttf } \ctex_punct_map_family:nn { \CJKrmdefault } { zhsong } \ctex_punct_map_bfseries:nn { \CJKrmdefault } { zhhei } \ctex_punct_map_itshape:nn { \CJKrmdefault } { zhkai } \ctex_punct_map_family:nn { \CJKsfdefault } { zhyahei } \ctex_punct_map_bfseries:nn { \CJKsfdefault , zhyahei } { zhyaheib } \ctex_punct_map_family:nn { \CJKttdefault } { zhfs } } { \ctex_load_zhmap:nnnn { rm } { zhhei } { zhfs } { windows } \ctex_punct_set:n { windows } \ctex_punct_map_family:nn { \CJKrmdefault } { zhsong } \ctex_punct_map_bfseries:nn { \CJKrmdefault } { zhhei } \ctex_punct_map_itshape:nn { \CJKrmdefault } { zhkai } } { } } { \ctex_set_upfonts:nnnnnn { simsun.ttc } { simhei.ttf } { simkai.ttf } { msyh.\c__ctex_msyh_suffix_tl } { msyhbd.\c__ctex_msyh_suffix_tl } { simfang.ttf } \ctex_set_upfamily:nnn { zhsong } { upzhserif } {} \ctex_set_upfamily:nnn { zhhei } { upzhserifb } {} \ctex_set_upfamily:nnn { zhfs } { upzhmono } {} \ctex_set_upfamily:nnn { zhkai } { upzhserifit } {} \ctex_set_upfamily:nnn { zhyahei } { upzhsans } { upzhsansb } \ctex_set_upfamily:nnn { zhli } { upschrm } {} \ctex_set_upfamily:nnn { zhyou } { upschgt } {} \ctex_set_upmap:nnn { upstsl } { simli.ttf } {} \ctex_set_upmap:nnn { upstht } { simyou.ttf } {} } { \setCJKmainfont { SimSun } [ BoldFont = SimHei , ItalicFont = KaiTi ] \setCJKsansfont { Microsoft~YaHei } [ BoldFont = *~Bold ] \setCJKmonofont { FangSong } \setCJKfamilyfont { zhsong } { SimSun } \setCJKfamilyfont { zhhei } { SimHei } \setCJKfamilyfont { zhfs } { FangSong } \setCJKfamilyfont { zhkai } { KaiTi } \setCJKfamilyfont { zhyahei } { Microsoft~YaHei } [ BoldFont = *~Bold ] \setCJKfamilyfont { zhli } { LiSu } \setCJKfamilyfont { zhyou } { YouYuan } } \NewDocumentCommand \songti { } { \CJKfamily { zhsong } }\NewDocumentCommand \heiti { } { \CJKfamily { zhhei } }\NewDocumentCommand \fangsong { } { \CJKfamily { zhfs } }\NewDocumentCommand \kaishu { } { \CJKfamily { zhkai } }\NewDocumentCommand \lishu { } { \CJKfamily { zhli } }\NewDocumentCommand \youyuan { } { \CJKfamily { zhyou } }\NewDocumentCommand \yahei { } { \CJKfamily { zhyahei } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 \GetIdInfo $ Id: ctex.dtx 13a2256 2022-07-14 18:54:09 +0800 Qing Lee <sobenlee@gmail.com> $ {Fandol fonts definition (CTEX)} \ProvidesExplFile {ctex-fontset-fandol.def} {\ExplFileDate }{2.5.10}{\ExplFileDescription } \ctex_fontset_case:nnnn { \ctex_fontset_error:n { fandol } } { \ctex_zhmap_case:nnn { \setCJKmainfont { FandolSong-Regular.otf } [ cmap = UniGB-UTF16-H, BoldFont = FandolSong-Bold.otf, ItalicFont = FandolKai-Regular.otf ] \setCJKsansfont { FandolHei-Regular.otf } [ cmap = UniGB-UTF16-H, BoldFont = FandolHei-Bold.otf ] \setCJKmonofont { FandolFang-Regular.otf } [ cmap = UniGB-UTF16-H ] \setCJKfamilyfont { zhsong } { FandolSong-Regular.otf } [ cmap = UniGB-UTF16-H, BoldFont = FandolSong-Bold.otf ] \setCJKfamilyfont { zhhei } { FandolHei-Regular.otf } [ cmap = UniGB-UTF16-H, BoldFont = FandolHei-Bold.otf ] \setCJKfamilyfont { zhfs } { FandolFang-Regular.otf } [ cmap = UniGB-UTF16-H ] \setCJKfamilyfont { zhkai } { FandolKai-Regular.otf } [ cmap = UniGB-UTF16-H ] \ctex_punct_set:n { fandol } \ctex_punct_map_family:nn { \CJKrmdefault } { zhsong } \ctex_punct_map_family:nn { \CJKsfdefault } { zhhei } \ctex_punct_map_family:nn { \CJKttdefault } { zhfs } \ctex_punct_map_bfseries:nn { \CJKrmdefault , zhsong } { zhsongb } \ctex_punct_map_bfseries:nn { \CJKsfdefault , zhhei } { zhheib } \ctex_punct_map_itshape:nn { \CJKrmdefault } { zhkai } } { \ctex_load_zhmap:nnnn { rm } { zhhei } { zhfs } { fandol } \ctex_punct_set:n { fandol } \ctex_punct_map_family:nn { \CJKrmdefault } { zhsong } \ctex_punct_map_bfseries:nn { \CJKrmdefault } { zhhei } \ctex_punct_map_itshape:nn { \CJKrmdefault } { zhkai } } { \ctex_fontset_error:n { fandol } } } { \ctex_set_upfonts:nnnnnn { FandolSong-Regular.otf } { FandolSong-Bold.otf } { FandolKai-Regular.otf } { FandolHei-Regular.otf } { FandolHei-Bold.otf } { FandolFang-Regular.otf } \ctex_set_upfamily:nnn { zhsong } { upzhserif } { upzhserifb } \ctex_set_upfamily:nnn { zhhei } { upzhsans } { upzhsansb } \ctex_set_upfamily:nnn { zhfs } { upzhmono } {} \ctex_set_upfamily:nnn { zhkai } { upzhserifit } {} } { \setCJKmainfont { FandolSong-Regular } [ Extension = .otf, BoldFont = FandolSong-Bold, ItalicFont = FandolKai-Regular ] \setCJKsansfont { FandolHei-Regular } [ Extension = .otf, BoldFont = FandolHei-Bold ] \setCJKmonofont { FandolFang-Regular } [ Extension = .otf ] \setCJKfamilyfont { zhsong } { FandolSong-Regular } [ Extension = .otf, BoldFont = FandolSong-Bold ] \setCJKfamilyfont { zhhei } { FandolHei-Regular } [ Extension = .otf, BoldFont = FandolHei-Bold ] \setCJKfamilyfont { zhfs } { FandolFang-Regular } [ Extension = .otf ] \setCJKfamilyfont { zhkai } { FandolKai-Regular } [ Extension = .otf ] } \NewDocumentCommand \songti { } { \CJKfamily { zhsong } }\NewDocumentCommand \heiti { } { \CJKfamily { zhhei } }\NewDocumentCommand \fangsong { } { \CJKfamily { zhfs } }\NewDocumentCommand \kaishu { } { \CJKfamily { zhkai } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 \GetIdInfo $ Id: ctex.dtx 13a2256 2022-07-14 18:54:09 +0800 Qing Lee <sobenlee@gmail.com> $ {Founder fonts definition (CTEX)} \ProvidesExplFile {ctex-fontset-founder.def} {\ExplFileDate }{2.5.10}{\ExplFileDescription } \ctex_fontset_case:nnn { \ctex_zhmap_case:nnn { \setCJKmainfont { FZSSK.TTF } [ BoldFont = FZXBSK.TTF, ItalicFont = FZKTK.TTF ] \setCJKsansfont { FZXH1K.TTF } [ BoldFont = FZHTK.TTF ] \setCJKmonofont { FZFSK.TTF } \setCJKfamilyfont { zhsong } { FZSSK.TTF } [ BoldFont = FZXBSK.TTF ] \setCJKfamilyfont { zhhei } { FZHTK.TTF } \setCJKfamilyfont { zhkai } { FZKTK.TTF } \setCJKfamilyfont { zhfs } { FZFSK.TTF } \setCJKfamilyfont { zhli } { FZLSK.TTF } \setCJKfamilyfont { zhyou } { FZY1K.TTF } [ BoldFont = FZY3K.TTF ] \ctex_punct_set:n { founder } \ctex_punct_map_family:nn { \CJKrmdefault } { zhsong } \ctex_punct_map_family:nn { \CJKsfdefault } { zhheil } \ctex_punct_map_family:nn { \CJKttdefault } { zhfs } \ctex_punct_map_itshape:nn { \CJKrmdefault } { zhkai } \ctex_punct_map_bfseries:nn { \CJKrmdefault , zhsong } { zhsongb } \ctex_punct_map_bfseries:nn { \CJKsfdefault } { zhhei } \ctex_punct_map_bfseries:nn { zhyou } { zhyoub } } { \ctex_load_zhmap:nnnn { rm } { zhhei } { zhfs } { founder } \ctex_punct_set:n { founder } \ctex_punct_map_family:nn { \CJKrmdefault } { zhsong } \ctex_punct_map_bfseries:nn { \CJKrmdefault } { zhhei } \ctex_punct_map_itshape:nn { \CJKrmdefault } { zhkai } } { \ctex_fontset_error:n { founder } } } { \ctex_set_upfonts:nnnnnn { FZSSK.TTF } { FZXBSK.TTF } { FZKTK.TTF } { FZXH1K.TTF } { FZHTK.TTF } { FZFSK.TTF } \ctex_set_upfamily:nnn { zhsong } { upzhserif } { upzhserifb } \ctex_set_upfamily:nnn { zhhei } { upzhsans } { upzhsansb } \ctex_set_upfamily:nnn { zhfs } { upzhmono } {} \ctex_set_upfamily:nnn { zhkai } { upzhserifit } {} \ctex_set_upfamily:nnn { zhli } { upschrm } {} \ctex_set_upfamily:nnn { zhyou } { upschgt } {} \ctex_set_upmap:nnn { upstsl } { FZLSK.TTF } {} \ctex_set_upmap:nnn { upstht } { FZY1K.TTF } {} } { \setCJKmainfont { FZShuSong-Z01 } [ BoldFont = FZXiaoBiaoSong-B05, ItalicFont = FZKai-Z03 ] \setCJKsansfont { FZXiHeiI-Z08 } [ BoldFont = FZHei-B01 ] \setCJKmonofont { FZFangSong-Z02 } \setCJKfamilyfont { zhsong } { FZShuSong-Z01 } [ BoldFont = FZXiaoBiaoSong-B05 ] \setCJKfamilyfont { zhhei } { FZHei-B01 } \setCJKfamilyfont { zhkai } { FZKai-Z03 } \setCJKfamilyfont { zhfs } { FZFangSong-Z02 } \setCJKfamilyfont { zhli } { FZLiShu-S01 } \setCJKfamilyfont { zhyou } { FZXiYuan-M01 } [ BoldFont = FZZhunYuan-M02 ] } \NewDocumentCommand \songti { } { \CJKfamily { zhsong } }\NewDocumentCommand \heiti { } { \CJKfamily { zhhei } }\NewDocumentCommand \fangsong { } { \CJKfamily { zhfs } }\NewDocumentCommand \kaishu { } { \CJKfamily { zhkai } }\NewDocumentCommand \lishu { } { \CJKfamily { zhli } }\NewDocumentCommand \youyuan { } { \CJKfamily { zhyou } }
这些默认配置方案的核心部分其实只有三行代码(剩下的内容是处理标点等排版细节,并且定义了一些字体族和命令,例如\songti等,便于调整局部的字体)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 \setCJKmainfont { simsun.ttc }[ BoldFont = simhei.ttf, ItalicFont = simkai.ttf ]\setCJKsansfont { msyh.\c__ctex_msyh_suffix_tl }[ BoldFont = msyhbd.\c__ctex_msyh_suffix_tl ]\setCJKmonofont { simfang.ttf }\setCJKmainfont { FandolSong-Regular.otf }[ cmap = UniGB-UTF16-H,BoldFont = FandolSong-Bold.otf,ItalicFont = FandolKai-Regular.otf ]\setCJKsansfont { FandolHei-Regular.otf }[ cmap = UniGB-UTF16-H, BoldFont = FandolHei-Bold.otf ]\setCJKmonofont { FandolFang-Regular.otf }[ cmap = UniGB-UTF16-H ]\setCJKmainfont { FZShuSong-Z01 }[ BoldFont = FZXiaoBiaoSong-B05, ItalicFont = FZKai-Z03 ]\setCJKsansfont { FZXiHeiI-Z08 } [ BoldFont = FZHei-B01 ]\setCJKmonofont { FZFangSong-Z02 }
值得注意的是:
中文字体通常不会附带自身的粗体或斜体变式,因此在windows字体方案中,采用黑体作为宋体的粗体,这是比较奇怪的行为,因为宋体加粗后应该是“加粗的宋体”才合适,就像fandol字体方案一样。普遍采用楷体作为宋体的斜体。
fandol字体方案经常会出现如下警告,这种警告通常是不影响正常编译的,除了看起来比较烦人之外没什么影响
1 2 Font "FandolSong-Regular" does not contain requested (fontspec) Script "CJK".
ctex 字体配置命令 通过对默认字体方案的解析可知,ctex中文字体配置的核心为如下三条命令(这几个命令实际是xeCJK宏包提供的)
1 2 3 4 5 6 \setCJKmainfont {<font name>}[<font features>]\setCJKsansfont {<font name>}[<font features>]\setCJKmonofont {<font name>}[<font features>]
其中必选项为字体名称,可选项通常用来指定对应的粗体和斜体版本。(旧版本的可选项位置在必选项之前,最新版本更改了顺序如上,但是仍然兼容旧版本的写法)
通常还会附带定义一些字体族
1 2 3 4 5 6 7 \setCJKfamilyfont { zhsong } { SimSun }\setCJKfamilyfont { zhhei } { SimHei }\setCJKfamilyfont { zhfs } { FangSong }\setCJKfamilyfont { zhkai } { KaiTi }\setCJKfamilyfont { zhyahei } { Microsoft~YaHei } [ BoldFont = *~Bold ]\setCJKfamilyfont { zhli } { LiSu }\setCJKfamilyfont { zhyou } { YouYuan }
此时可以使用下面的命令,这里加上括号可以限制作用范围,否则设置一直有效,直到下一次改变为止。
1 {\CJKfamily {zhkai} 中文字体(楷书)}
进一步的,还会将其封装为自定义命令(两种方式均可,第一种方式是ctex采用的,命令由xparse宏包提供)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 \NewDocumentCommand \songti { } { \CJKfamily { zhsong } }\NewDocumentCommand \heiti { } { \CJKfamily { zhhei } }\NewDocumentCommand \fangsong { } { \CJKfamily { zhfs } }\NewDocumentCommand \kaishu { } { \CJKfamily { zhkai } }\NewDocumentCommand \lishu { } { \CJKfamily { zhli } }\NewDocumentCommand \youyuan { } { \CJKfamily { zhyou } }\NewDocumentCommand \yahei { } { \CJKfamily { zhyahei } }\newcommand *{ \songti }{ \CJKfamily { zhsong }}\newcommand *{ \heiti }{ \CJKfamily { zhhei }}\newcommand *{ \kaishu }{ \CJKfamily { zhkai }}\newcommand *{ \fangsong }{ \CJKfamily { zhfs }}...
此时就可以使用\kaishu等命令更加便捷地切换局部的字体,例如
1 2 3 {\kaishu 这是楷体。} {\fangsong 这是仿宋。}
下面的自定义配置方案会保证\songti,\heiti,\kaishu和\fangsong这四个最基础的字体命令始终可以直接使用。
自定义字体配置 ctex采用的默认中文字体要么比较垃圾(例如fandol),要么不是完全开源的(例如中易宋体),甚至微软雅黑也不能商用, 因此在自行配置字体时普遍会选择设计更加优秀的,并且完全开源的字体(对于Windows必须将字体全局安装),主流的是以下两个方案:
思源字体系列(完全开源)
方正字体系列(仅有四个开源字体)
方正字体 方正仅有的四个开源字体如下,注意直接在官网下载的话,需要选择GBK编码的文件:
方正书宋:FZSSK.TTF,FZShuSong-Z01
方正黑体:FZHTK.TTF,FZHei-B01
方正楷体:FZKTK.TTF,FZKai-Z03
方正仿宋:FZFSK.TTF,FZFangSong-Z02
注意到ctex默认的founder方正字体方案中,并不仅仅是这几种字体,还有额外的非开源方正字体,并且在Windows系统上通常不会默认安装,因此在Windows上直接使用fontset=founder会因为缺字体而编译失败。
在安装了四种开源字体之后,方正开源字体配置如下(与ctex默认的founder方案相似但不一样,使用了更少的方正字体)
1 2 3 4 5 6 7 8 9 10 11 12 13 \setCJKmainfont {FZShuSong-Z01}[BoldFont={FZHei-B01},ItalicFont={FZKai-Z03}]\setCJKsansfont {FZHei-B01}\setCJKmonofont {FZFangSong-Z02}\setCJKfamilyfont {zhsong}{FZShuSong-Z01}\setCJKfamilyfont {zhhei}{FZHei-B01}\setCJKfamilyfont {zhkai}{FZKai-Z03}\setCJKfamilyfont {zhfs}{FZFangSong-Z02}\newcommand *{\songti }{\CJKfamily {zhsong}}\newcommand *{\heiti }{\CJKfamily {zhhei}}\newcommand *{\kaishu }{\CJKfamily {zhkai}}\newcommand *{\fangsong }{\CJKfamily {zhfs}}
另一种方正开源字体配置如下(参考ElegantLaTeX),更改了无衬线字体为楷书,并设置了相应的粗体
1 2 3 4 5 6 7 8 9 10 11 12 13 \setCJKmainfont {FZShuSong-Z01}[BoldFont={FZHei-B01},ItalicFont={FZKai-Z03}]\setCJKsansfont [BoldFont={FZHei-B01}]{FZKai-Z03}\setCJKmonofont [BoldFont={FZHei-B01}]{FZFangSong-Z02}\setCJKfamilyfont {zhsong}{FZShuSong-Z01}\setCJKfamilyfont {zhhei}{FZHei-B01}\setCJKfamilyfont {zhkai}{FZKai-Z03}[BoldFont={FZHei-B01}]\setCJKfamilyfont {zhfs}{FZFangSong-Z02}[BoldFont={FZHei-B01}]\newcommand *{\songti }{\CJKfamily {zhsong}}\newcommand *{\heiti }{\CJKfamily {zhhei}}\newcommand *{\kaishu }{\CJKfamily {zhkai}}\newcommand *{\fangsong }{\CJKfamily {zhfs}}
思源字体 思源字体由Adobe和Google联合开发,包括思源宋体 和思源黑体 两款字体,各有七个字重:ExtraLight、Light、Normal、Regular、Medium、Bold 和 Heavy。
Adobe将其命名为思源字体,英文名分别为Source Han Serif和Source Han Sans,字体仓库分别为Source Han Serif 和Source Han Sans 。
Google则将其命名为Noto CJK字体,英文名分别为Noto Serif CJK和Noto Sans CJK,字体仓库为Noto CJK 。除了思源宋体和思源黑体,Noto CJK系列还有一套等宽的中文字体(只有两个字重),名为Noto Sans Mono CJK。
这一系列字体文件的名称非常繁杂(因为是两家合作,并且需要考虑不同语言和地区习惯),可能使用如下的缩写表示:
语言特定版本 (Language-specific Fonts)
SC - 简体中文
TC - 繁体中文—台湾地区写法标准
HC - 繁体中文—香港地区写法标准
J - 日文
K - 韩文
地区子集版本 (Region-specific Subset Fonts)
CN - 中国大陆
TW - 台湾地区
HK - 香港地区
JP - 日本
KR - 韩国
当前的个人选择的是将简体中文SC后缀的两个字体各两个版本都下载安装到本地,每一个都包括7个不同字重的.otf文件,再加上一套等宽字体。 下载链接见各自仓库的Release页面
思源宋体一 Source Han Serif SC
思源黑体一 Source Han Sans SC
思源宋体二 Noto Serif CJK SC
思源黑体二 Noto Sans CJK SC
思源等宽字体 Noto Sans Mono CJK SC
使用思源字体时,很可能因为字体名称的异常导致编译失败,因为这套开源字体的名称过于复杂了,安装的字体和使用的字体可能后缀差了一点点,比如SC和CN分别代表简体中文和中国大陆,两者字体几乎一样,但是严格来说是不一样的字体。 按道理来说,应该有一个名为Source Han Mono的等宽字体与Noto Sans Mono对应,但是Adobe并没有发布单独的版本,只有一个没有维护的Github仓库,里面是所有字体的大杂烩,而且需要自行编译。
配置例如
1 2 3 \setCJKmainfont {Noto Serif CJK SC}\setCJKsansfont {Noto Sans CJK SC}\setCJKmonofont {Noto Sans Mono CJK SC}
注意这里没有字体命令例如\kaishu等,因为思源字体只有宋体和黑体以及等线体,并且有完整的字重分类。
参考方案 参考方案一(混合使用方正和思源字体)
1 2 3 4 5 6 \setCJKmainfont {FZShuSong-Z01}[BoldFont={Source Han Serif SC SemiBold}, ItalicFont=FZKai-Z03]\setCJKsansfont {FZHei-B01}[BoldFont={Source Han Sans SC Medium}]\setCJKmonofont {FZFangSong-Z02}
参考方案二(ustcthesis)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 \setCJKmainfont {Noto Serif CJK SC}[ UprightFont = * Light, BoldFont = * Bold, ItalicFont = FandolKai-Regular, ItalicFeatures = {Extension = .otf}, Script = CJK, ] \setCJKsansfont {Noto Sans CJK SC}[ BoldFont = * Medium, Script = CJK, ] \setCJKmonofont {Noto Sans Mono CJK SC}[ Script = CJK, ] \setCJKfamilyfont {zhsong}{Noto Serif CJK SC}[ UprightFont = * Light, UprightFont = * Bold, Script = CJK, ] \setCJKfamilyfont {zhhei}{Noto Sans CJK SC}[ BoldFont = * Medium, Script = CJK, ] \setCJKfamilyfont {zhfs}{FandolFang}[ Extension = .otf, UprightFont = *-Regular, ] \setCJKfamilyfont {zhkai}{FandolKai}[ Extension = .otf, UprightFont = *-Regular, ]
参考方案三(LaTeX工作室)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 \setCJKmainfont {Source Han Serif CN}[ UprightFont = *-Regular, BoldFont = *-Bold, ItalicFont = *-Regular, BoldItalicFont = *-Bold ] \setCJKsansfont {Noto Sans CJK SC}[ UprightFont = *-Regular, BoldFont = *-Bold, ItalicFont = *-Regular, BoldItalicFont = *-Bold ] \setCJKmonofont {Noto Sans Mono CJK SC}[ UprightFont = *-Regular, BoldFont = *-Bold, AutoFakeSlant = 0.2 ] \setCJKfamilyfont {zhsong}{Source Han Serif CN}[ UprightFont = *-Regular, BoldFont = *-Bold, ItalicFont = *-Regular, BoldItalicFont = *-Bold ] \setCJKfamilyfont {zhhei}{Noto Sans CJK SC}[ UprightFont = *-Regular, BoldFont = *-Bold, ItalicFont = *-Regular, BoldItalicFont = *-Bold ] \setCJKfamilyfont {zhxh}{Noto Sans CJK SC Light}
自定义方案 记录一下我自己使用的几个方案,只是定义了最核心的三个字体,不包括其它字体命令的定义,第一个纯方正的方案在beamer上的效果也挺好。
FZ 1 2 3 \setCJKmainfont {FZShuSong-Z01}[BoldFont={FZHei-B01},ItalicFont={FZKai-Z03}]\setCJKsansfont {FZKai-Z03}[BoldFont={FZHei-B01}]\setCJKmonofont {FZFangSong-Z02}[BoldFont={FZHei-B01}]
NotoCJK 1 2 3 4 5 6 7 8 9 10 11 12 13 \setCJKmainfont {Noto Serif CJK SC}[ UprightFont = * Light, BoldFont = * Bold, ItalicFont = FZKai-Z03, Script = CJK, ] \setCJKsansfont {Noto Sans CJK SC}[ BoldFont = * Medium, Script = CJK, ] \setCJKmonofont {Noto Sans Mono CJK SC}[ Script = CJK, ]
SourceHan 1 2 3 4 5 6 7 8 9 10 11 \setCJKmainfont {Source Han Serif SC}[ UprightFont = * Light, BoldFont = * Bold, ItalicFont = FZKai-Z03, Script = CJK, ] \setCJKsansfont {Source Han Sans SC}[ BoldFont = * Medium, Script = CJK, ] \setCJKmonofont {FZFangSong-Z02}
关于字体报错 记录一下遇到的字体报错以及解决办法。
LaTeX 在遇到字符缺失时默认并不会直接中止,而是会使用空白字符进行替换,并继续编译,在最后的警告信息也不会告诉我们具体出错的位置,这导致很难问题难以定位和处理。
我们可以手动修改 \tracinglostchars 以调整丢失字符的提示级别,默认级别为 1,产生简单的警告信息, 修改为 3,则会导致致命错误,立刻终止编译,并显示具体出错的位置。 在文档的开始部分加上下面的命令即可
中文字体缺少常见字 在排版中文文档时,有时会遇到如下字体错误:
1 2 Missing character: There is no ⾄ (U+2F84) in font SimSun/OT:script=hani;language=dflt;. <XeTeXinterchartoks>
这类报错通常是因为文档中包含了某些字形与常用汉字相似但 Unicode 编码不同的字符,这些字符并不被当前使用的中文字体支持,从而导致编译失败或输出空白。
例如下面两组字符是不一样的,肉眼可能难以区分(取决于编辑器和浏览器使用的字体)
正常字符(常用汉字)
Unicode
异常字符(康熙部首等)
Unicode
立
U+7ACB
⽴
U+2F74
网
U+7F51
⽹
U+2F79
至
U+81F3
⾄
U+2F84
可以直接复制下面的片段到文本编辑器中进行检查,会发现非常难以区分
这些生僻的字符通常不会由用户通过中文输入法输入,常见来源包括:
从 PDF 中直接选中文本复制
使用 OCR 软件自动提取文本
数学字体中的中文逗号 在使用中文时,可能会遇到如下警告
1 Missing character: There is no , (U+FF0C) in font [lmroman7-regular]:mapping=tex-text;!
这个警告是关于中文全角的,我们在正文中使用中文全角是不会触发这个警告的,但是在某些特殊的环境中可能出现,需要重点排查数学环境中是否误用了中文全角的逗号,例如