Files
ouc_latex_template/fonts.tex
T
laoyang 8aa979739a 字体统一:建公共字体目录,全部改用开源可商用字体 (#6)
七个模板原先分两套做法:幻灯片/fonts(49MB 鸿蒙 18 个字重)与
科技报告/font(92MB,含 5 款方正商业字体),其余模板直接调系统
SimSun/SimHei/KaiTi/FangSong/Times New Roman。换机器就编不出来,
方正系列也不允许随仓库分发。

统一到仓库根的 fonts/ + fonts.tex:
- OUC Serif(思源宋体 SC 子集)   —— 宋体
- OUC Sans(思源黑体 SC 子集)    —— 黑体
- OUC Kai(霞鹜文楷子集)          —— 楷体
- Zhuque Fangsong(朱雀仿宋)      —— 仿宋
- TeX Gyre Termes                  —— 西文 Times 等价(度量逐字相同)
- HarmonyOS Sans                   —— 幻灯片/科技报告原有字体

fonts.tex 是唯一允许声明字体的地方,7 个模板全部 \input 它。
字体体积 141MB -> 49MB(去掉重复),全库共用一套最小集合。

几处踩过的坑(均已写进源码注释):
- \newCJKfontfamily 与 ctex 默认 fontset 冲突会中断编译,改用
  \setCJKfamilyfont + \def
- \newfontfamily 缺粗体档会让 \bfseries 静默失效,四档必须全给
- UprightFont= 与主参数不能同时给,否则文件名被拼两次
- Path= 相对编译时工作目录,不是相对 .sty
- ×/□/○ 等符号按 Unicode 区段被判成西文,需 \xeCJKDeclareCharClass
- 中文斜体的 ItalicFont 与主字体不在同一目录,须在 ItalicFeatures
  里单独写 Path/Extension(否则报 OUCKai-Regular cannot be found)

顺带:
- 科技报告 report.tex 的字体演示正文改为新字体名(原文写着方正系列)
- 试卷归档封面新模板并入本库
- 科技报告 shell 命令框底色改海大蓝(#5 遗留)

验证(7 个模板 8 个 PDF 全量重编 + 逐行 A/B 对照):
- 错误 0,缺字 0
- 幻灯片 362 行逐行完全一致,零漂移
- 年度考核登记表 / 劳务发放说明表 / 试卷题型示例 / 参考答案 文本完全一致
- 课程执行大纲 仅 2 处断字连字符差异(throughout、processing),
  1 条 6.39pt Overfull 已论证不可见(距纸张右边缘仍有 20.7mm)
- 科技报告 内嵌字体方正归零,只剩 OUC Serif/Sans/Kai + Zhuque
- 全库正文 857 个非 ASCII 字符,四款中文字体(含粗体)覆盖 100%
2026-10-27 00:43:14 +08:00

274 lines
13 KiB
TeX
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
%======================================================================
% oucfonts.tex —— 中国海洋大学模板库的公共字体入口
%
% 本文件是仓库内**唯一**允许声明字体的地方。七个模板全部通过
% \input{../fonts.tex}
% 取字体,不再各自写 \setCJKmainfont / \setmainfont。
%
% 为什么是 .tex + \input 而不是 .sty + \usepackage:
% \usepackage 走 LaTeX 的 package 机制,要求 \ProvidesPackage 的名字
% 与 \usepackage 的参数严格一致。我们从子目录用相对路径调用
% (\usepackage{../oucfonts}),名字必然对不上,会报
% "You have requested package `../oucfonts' but the package provides
% `oucfonts'." 的警告。用 \input 直接插入文件内容,没有这个问题,
% 而且对宏包加载顺序的控制也更直接。
%
% ------------------------------------------------------------------
% 用法
% ------------------------------------------------------------------
% \documentclass[UTF8,fontset=none]{ctexart}
% \input{../fonts.tex}
%
% ⚠️ 必须保留 fontset=none:否则 ctex 会先按系统字体配一套,
% 再被这里覆盖,既浪费又有平台依赖。
%
% ⚠️ Path=../fonts/ 是相对**模板目录**的(编译时的工作目录)。
% 在本模板目录下 xelatex 编译即可,不要从仓库根调用。
%
% ------------------------------------------------------------------
% 提供的字族命令
% ------------------------------------------------------------------
% \songti 宋体(衬线正文) OUC Serif ← 思源宋体 SC 子集
% \heiti 黑体(无衬线标题) OUC Sans ← 思源黑体 SC 子集
% \kaiti 楷体 OUC Kai ← 霞鹜文楷子集
% \fangsong 仿宋 Zhuque Fangsong ← 朱雀仿宋
% \tnr 西文 Times 等价 TeX Gyre Termes
% \tnrb 西文 Times 粗体 TeX Gyre Termes Bold
% \hm 鸿蒙 Sans SC 幻灯片/科技报告 原有字体
% \hmlatin 鸿蒙 Sans(西文) 幻灯片/科技报告 原有字体
%
% 正文字体:中文 OUC Serif,西文 TeX Gyre Termes。
%
% 本文件**可重复** \input(用 \ifdefined 保护),方便多个 .sty 各自引用。
%
% ------------------------------------------------------------------
% 字体来源与授权(全部允许免费商用与再分发)
% ------------------------------------------------------------------
% OUC Serif / OUC Sans 思源宋体/黑体 SC 的 GB2312 子集,
% Adobe 原版 SIL OFL 1.1。改名以符合 OFL §3
% (原 Reserved Font Name 为 "Source")。
% OUC Kai 霞鹜文楷 GB2312 子集,SIL OFL 1.1。
% Zhuque Fangsong 朱雀仿宋,OFL 1.1。
% TeX Gyre Termes GUST Font License(GPL + 字体例外)。
% HarmonyOS Sans 华为,官方声明可免费商用。
%
% 详细来源、版本与被裁剪的字符集见 fonts/README.md。
% **本模板库不含任何商业字体**(无方正、无 SimSun/SimHei/KaiTi/FangSong、
% 无 Times New Roman)。
%======================================================================
\ifdefined\OUCFontsLoaded
\endinput
\else
\def\OUCFontsLoaded{1}
\fi
\RequirePackage{fontspec}
\RequirePackage{xeCJK}
%======================================================================
% 一、西文主字体:TeX Gyre Termes(Times 的度量兼容开源替代)
%
% Termes 与 Times New Roman 字符宽度逐字相同,因此原有的西文断行、
% 表格列宽、行内公式对齐都不会因为换字体而漂。
%======================================================================
\setmainfont{texgyretermes}[
Extension = .otf,
Path = ../fonts/tex-gyre-termes/,
UprightFont = *-regular,
BoldFont = *-bold,
ItalicFont = *-italic,
BoldItalicFont = *-bolditalic,
]
%======================================================================
% 二、中文主字体
%
% 宋体为正文,黑体为强调。二者的粗体都是字体自带的真粗体,
% 不再用 AutoFakeBold 算法描边 —— 描边出来的粗体笔画会糊在一起,
% 尤其小字号下(原模板 14pt 的宋体会糊成一团)。
%
% ⚠️ 这里用 \setCJKmainfont 而不是 \setCJKfamilyfont + \def:
% \setCJKmainfont 会顺带把 \CJKrmdefault 指到新族上,正文默认
% 字体才真的换过来。若文档是 ctex 默认 fontset,ctex 早已设过
% \CJKrmdefault,xeCJK 会打一条
% Package xeCJK Warning: Redefining CJKfamily `\CJKrmdefault'
% 这是**预期**行为(我们就是要覆盖 ctex 按系统字体配的那套),
% 不影响输出,也无害;看到它不必处理。
%
% ------------------------------------------------------------------
% 斜体与粗斜体:中文没有真正的斜体字形,中文排版惯例是「用楷体代
% 斜体、用仿宋代粗斜体」(《党政机关公文格式》与 Word 的中文默认
% 行为都是这么做的)。原科技报告模板正是
% ItalicFont = 方正楷体
% BoldItalicFont = 方正仿宋
% 这里保持同样的语义映射:楷体 → OUC Kai,仿宋 → Zhuque Fangsong。
%
% ⚠️ 各档位的字体在**不同目录**里,不能共用主选项的 Path/Extension。
% 必须在该档位的 *Features 里单独写一套 Path + Extension +
% UprightFont —— 主 Path 会被继承,若不在 Features 里覆盖,就会
% 拿 ../fonts/ouc-serif/ 去拼 OUCKai-Regular.ttf,报
% "The font "OUCKai-Regular" cannot be found"。
%
% ⚠️ 只在 \setCJKmainfont 上给了斜体,**不影响** \songti / \heiti /
% \kaiti / \fangsong 这几个字族命令 —— 它们是独立的字体族,各自
% 没有斜体档。要中文斜体就用默认正文(或先 \songti 再 \textit,
% 此时 \textit 落回 \CJKrmdefault 也就是 OUC Serif 的斜体)。
%======================================================================
\setCJKmainfont{OUCSerif}[
Extension = .otf,
Path = ../fonts/ouc-serif/,
UprightFont = *-Regular,
BoldFont = *-Bold,
ItalicFont = OUCKai-Regular,
ItalicFeatures = {
Extension = .ttf,
Path = ../fonts/ouc-kai/,
UprightFont = *-Regular,
BoldFont = *-Bold,
},
BoldItalicFont = ZhuqueFangsong-Regular,
BoldItalicFeatures = {
Extension = .ttf,
Path = ../fonts/zhuque-fangsong/,
UprightFont = *-Regular,
},
]
%======================================================================
% 三、字族命令
%
% ⚠️ 这里**不能**用 \newCJKfontfamily / \newfontfamily。
% 原因:只要文档用了 ctex 的默认 fontset(即 \documentclass 里没写
% fontset=none),ctex 就已经定义了 \songti / \heiti / \kaiti /
% \fangsong,而这两个命令底层是 LaTeX3 的 \NewDocumentCommand,
% 命令已存在时会抛
% ! LaTeX3 Error: Control sequence \songti already defined.
% 并**中断编译**(试卷/ouckey.sty 就是这种情况,报 4 个错误)。
% 用 \providecommand 先占位也没用 —— \newCJKfontfamily 仍然报。
%
% 正确写法分两步:
% 1. \setCJKfamilyfont{族名}[选项]{字体} 只登记字体,不建命令,
% 同名重复登记只是覆盖,永远不报错;
% 2. \def\songti{\CJKfamily{族名}} 纯 \def,从不管旧定义。
% 这也是 ctex 自己定义 \songti 的方式。
%======================================================================
% 宋体
\setCJKfamilyfont{OUCSong}[
Extension = .otf,
Path = ../fonts/ouc-serif/,
UprightFont = *-Regular,
BoldFont = *-Bold,
]{OUCSerif}
\def\songti{\CJKfamily{OUCSong}}
% 黑体
\setCJKfamilyfont{OUCHei}[
Extension = .otf,
Path = ../fonts/ouc-sans/,
UprightFont = *-Regular,
BoldFont = *-Bold,
]{OUCSans}
\def\heiti{\CJKfamily{OUCHei}}
% 楷体(霞鹜文楷)
% 顺带提供 \kaishu 别名:ctex 的默认 fontset 用 \kaishu,而原模板多用
% \kaiti,两个名字都指同一族,免得改接时漏改一处就静默回落系统字体。
\setCJKfamilyfont{OUCKai}[
Extension = .ttf,
Path = ../fonts/ouc-kai/,
UprightFont = *-Regular,
BoldFont = *-Bold,
]{OUCKai}
\def\kaiti{\CJKfamily{OUCKai}}
\def\kaishu{\CJKfamily{OUCKai}}
% 仿宋(朱雀仿宋,只有常规一档,无粗体)
% ⚠️ 需要粗体的场合请改用 \heiti 或 \songti,不要指望 \fangsong 变粗。
\setCJKfamilyfont{OUCFang}[
Extension = .ttf,
Path = ../fonts/zhuque-fangsong/,
UprightFont = *-Regular,
]{ZhuqueFangsong}
\def\fangsong{\CJKfamily{OUCFang}}
% 西文:显式取 Times 形态(原模板里 \tnr / \tnrb / \sunfont 的替代)
%
% ⚠️ 四个档位必须全给。只给 UprightFont 的话,在 \bfseries 环境里会落到
% "Font shape `TU/texgyretermes/b/n' undefined" 并静默替换,
% 表现为加粗失效(试卷的 \TNRB 与 \qnum 都会踩到)。
\newfontfamily\tnr{texgyretermes}[
Extension = .otf,
Path = ../fonts/tex-gyre-termes/,
UprightFont = *-regular,
BoldFont = *-bold,
ItalicFont = *-italic,
BoldItalicFont = *-bolditalic,
]
\newfontfamily\tnrb{texgyretermes}[
Extension = .otf,
Path = ../fonts/tex-gyre-termes/,
UprightFont = *-bold,
BoldFont = *-bold,
ItalicFont = *-bolditalic,
BoldItalicFont = *-bolditalic,
]
% 鸿蒙 Sans:幻灯片与科技报告原有字体,保留以维持这两个模板的原有观感
% ⚠️ 鸿蒙的文件名以下划线分隔(HarmonyOS_Sans_SC_Regular.ttf),
% 不是 OHM 风格的 "族名-字重",所以这里不能写 *-Regular 通配,
% 必须显式给完整文件名。
% ⚠️ 用了 UprightFont 就**不要**再给主参数 {字体名}。给了两个,fontspec
% 会把主参数当文件名、UprightFont 当变体名再拼一次,报
% "The font HarmonyOS_Sans_SC_Regular.ttf cannot be found"。
% 正确写法是只留主参数(下面这种),或用 Extension + UprightFont。
\setCJKfamilyfont{OUCHM}[
Path = ../fonts/harmonyos-sans/,
BoldFont = HarmonyOS_Sans_SC_Bold.ttf,
]{HarmonyOS_Sans_SC_Regular.ttf}
\def\hm{\CJKfamily{OUCHM}}
\newfontfamily\hmlatin{HarmonyOS_Sans_Regular.ttf}[
Path = ../fonts/harmonyos-sans/,
BoldFont = HarmonyOS_Sans_Bold.ttf,
ItalicFont = HarmonyOS_Sans_Regular_Italic.ttf,
BoldItalicFont = HarmonyOS_Sans_Bold_Italic.ttf,
]
%======================================================================
% 四、把几个「长得像西文、其实该走中文」的符号归入 CJK 字符类
%
% 顺序很重要:必须在 \setCJKmainfont 之后、正文开始之前。
% 下面这些 \xeCJKDeclareCharClass 是**全局**生效的,一次即可。
%
% 为什么要这么做:xeCJK 按 Unicode 区段分类,下面这些字符落在
% Latin-1 / General Punctuation / Geometric Shapes,默认都被判成
% **西文**,交给 fontspec 的西文字体(Termes)。后果有两层:
% ① 宽度错:× 在 SimSun/思源里本来是 1.0 em 全角,被当西文排
% 就只剩 0.56 em,与汉字不齐、基线也偏(\heiti{××} 尤其明显);
% ② 缺字:□(U+25A1)Termes 里根本没有,直接报
% "Missing character: There is no □ (U+25A1)",印出来是空白。
% 而 \heiti / \fangsong 只切 CJK 字体族,管不到它们 —— 包一层没用。
%======================================================================
\xeCJKDeclareCharClass{CJK}{"00D7} % × 乘号(占位符 ××× 最常用)
\xeCJKDeclareCharClass{CJK}{"2014} % — 破折号(em dash)
\xeCJKDeclareCharClass{CJK}{"25A1} % □ 白方框(勾选框 □ 同意 □ 不同意)
\xeCJKDeclareCharClass{CJK}{"25A0} % ■ 实心方框
\xeCJKDeclareCharClass{CJK}{"25CB} % ○ 白圆圈(单选题选项圈)
\xeCJKDeclareCharClass{CJK}{"25CF} % ● 实心圆
\xeCJKDeclareCharClass{CJK}{"2610} % ☐ 选票框
\xeCJKDeclareCharClass{CJK}{"2611} % ☑ 打勾选票框
\xeCJKDeclareCharClass{CJK}{"2612} % ☒ 打叉选票框
\xeCJKDeclareCharClass{CJK}{"221A} % √ 根号(勾选/判卷常用)
\xeCJKDeclareCharClass{CJK}{"203B} % ※ 参考标记
%======================================================================
% 五、行距
%
% 这里不全局改 \linespread,因为各模板需求不同(科技报告依赖 ctex
% 默认值,试卷归档封面/课程执行大纲/年度考核登记表必须归 1 才能
% 还原 docx 的精确行高)。只提供工具命令,由各模板自行调用。
%======================================================================
\newcommand{\ouclinespread}[1]{\linespread{#1}\relax}
\endinput