重写全部 README,只保留使用说明
17 个 README 统一改成使用说明书,去掉来源、踩坑、需求过程等内容。 只保留: - 怎么编译、跑几遍 - 文件结构 - 要改哪些参数(逐项列出宏名与含义) - 用到的命令(表格) - 版式参数 删除: - 原文件来源、抽取过程 - 踩坑记录、最小复现、实测数据 - 用户需求、工单号、历史沿革 - 改造前后对比 行数 4185 → 2261。 全库 16/16 编译通过。
This commit is contained in:
+62
-211
@@ -1,247 +1,98 @@
|
||||
# 特殊事项说明表 — 中国海洋大学 特殊事项说明表(LaTeX 版)
|
||||
# 特殊事项说明表
|
||||
|
||||
把报销用的《中国海洋大学特殊事项说明表》Word 版复刻为 LaTeX 模板。
|
||||
版式与原 `.docx` **逐点对齐**(见文末「实测偏差」),
|
||||
**不含任何真人信息**:事项描述是虚构的报销事由,三处日期留空待手写。
|
||||
|
||||
## 文件
|
||||
|
||||
| 文件 | 说明 |
|
||||
| :-- | :-- |
|
||||
| `特殊事项说明表.tex` | 主文件。填表只改第 1 节(4 个变量) |
|
||||
| `ouccsx.sty` | 版式包。页面/字体/行高/全部尺寸写在这里,附换算注释 |
|
||||
中国海洋大学报销用特殊事项说明表,A4 单页,含事项描述与三级签字审批。
|
||||
|
||||
## 编译
|
||||
|
||||
```bash
|
||||
cd 特殊事项说明表
|
||||
xelatex 特殊事项说明表.tex
|
||||
```
|
||||
|
||||
单页,跑一遍即可(无交叉引用)。
|
||||
或仓库根:`bash build.sh 特殊事项说明表`
|
||||
|
||||
需要 **XeLaTeX**,并安装 `ctex`、`geometry`、`fontspec`、`xeCJK`、`fancyhdr`。
|
||||
实测环境:TeX Live 2022。
|
||||
## 文件
|
||||
|
||||
## 改内容
|
||||
| 文件 | 说明 |
|
||||
|---|---|
|
||||
| `特殊事项说明表.tex` | 主文件,填内容改这里 |
|
||||
| `ouccsx.sty` | 版式包,一般不改 |
|
||||
|
||||
## 填写参数
|
||||
|
||||
全部在 `\begin{document}` 之前定义:
|
||||
|
||||
```latex
|
||||
\newcommand{\sxdesc}{% % 事项描述(必填)
|
||||
因项目研讨需要,前往菏泽进行项目研讨与系统演示,因携带大件演示设备,
|
||||
公共交通多有不便,因此采用自驾方式前往。}
|
||||
\newcommand{\sxdesc}{%
|
||||
因渤海湾生态环境监测浮标需要例行维护,前往昌邑近岸观测站更换传感器……}
|
||||
|
||||
\newcommand{\sxdateA}{} % 项目负责人签字处日期
|
||||
\newcommand{\sxdateB}{} % 单位负责人签字处日期
|
||||
\newcommand{\sxdateC}{} % 科技管理部门签字处日期
|
||||
\newcommand{\sxdateA}{} % 项目负责人签字处日期
|
||||
\newcommand{\sxdateB}{} % 单位负责人签字处日期
|
||||
\newcommand{\sxdateC}{} % 科技管理部门签字处日期
|
||||
```
|
||||
|
||||
就这四个。**表内其余文字全是学校规定原文,不要改** ——
|
||||
「兹证明该事项真实有效,本人愿意为此承担责任。」「学院对本单位科研
|
||||
经费使用承担监督和管理责任。」以及备注三条,都在 `ouccsx.sty` 里
|
||||
装配好了,改了就与原件不一致。
|
||||
| 参数 | 说明 |
|
||||
|---|---|
|
||||
| `\sxdesc` | 事项描述正文,可写多段(用 `\par` 分开) |
|
||||
| `\sxdateA` | 项目负责人签字处日期 |
|
||||
| `\sxdateB` | 单位负责人签字处日期 |
|
||||
| `\sxdateC` | 科技管理部门签字处日期 |
|
||||
|
||||
### 关于 `\sxdesc`
|
||||
### 日期怎么写
|
||||
|
||||
描述**可以写多段**,空行或 `\\` 分段都行,表格会自动让出空间:
|
||||
留空则印成「 年 月 日」供手写。要打印具体日期:
|
||||
|
||||
- 写短 → 空白落在「描述区」与「签名区」之间,签名区位置不动
|
||||
- 写长 → 空白被吃掉,签名区仍然不动
|
||||
|
||||
> 这是本模板比原 docx 更稳的地方。原件靠 R0 里的 **8 个空段** 给手写
|
||||
> 留白,描述一写长就把签名区顶到下一行(Word 里也一样)。本模板删掉
|
||||
> 那 8 个空段,改成「上下两半 + 中间 `\vfil`」,两头都不破版。
|
||||
|
||||
⚠️ 描述特别长时签名区会挤出行外 —— 这是内容超量的正常表现(Word 里
|
||||
写太多同样会把格子撑高),把描述删短即可,不是 bug。
|
||||
|
||||
### 关于三处日期
|
||||
|
||||
留空则印成「 年 月 日」,签字时手写。
|
||||
想直接打印就填年份:`\newcommand{\sxdateA}{2026}` 会印在「年」前面。
|
||||
|
||||
> 默认留空的理由同 `成绩构成说明`:印了年份就占掉手写空间,
|
||||
> 而且报销常常是事后补开,日期往往就是签字那天。
|
||||
|
||||
## 版式数据来源
|
||||
|
||||
全部尺寸从原 `.docx` 的 OOXML 里量出来,换算关系:
|
||||
|
||||
- 长度:`mm = twips ÷ 1440 × 25.4`,`pt = twips ÷ 20`
|
||||
- 字号:`w:sz` 是半磅值,`sz=21` ⇒ 10.5 pt
|
||||
- 行距:`w:line` 是 1/20 pt,`lineRule="exact"` 时即精确值
|
||||
|
||||
| 项目 | docx 原值 | 换算 |
|
||||
| :-- | :-- | :-- |
|
||||
| 纸张 | `pgSz 11906×16838` | A4 210×297 mm |
|
||||
| 页边距(上下) | `pgMar top/bottom 2155/1985` | 38.01 / 35.00 mm |
|
||||
| 页边距(左右) | `pgMar left/right 1588/1474` | 28.01 / 26.00 mm |
|
||||
| 表宽 | `tblW 9613` | 169.54 mm = 480.65 bp |
|
||||
| 表左缩进 | `tblInd −546` | −9.63 mm(把表顶出版心) |
|
||||
| 单元格内边距 | `tblCellMar 108` | 5.4 pt(左右),上下为 0 |
|
||||
| 边框 | `tblBorders sz=4` | 0.5 pt |
|
||||
| 字号 | 标题 `sz44`/正文 `sz21`/签字日期 `sz24`/页码 `sz28` | 22 / 10.5 / 12 / 14 pt |
|
||||
| 行距 | 标题 `line500`/备注 `line300`/表内未设 | 25 / 15 pt/Word 单倍(字号×1.3) |
|
||||
|
||||
表格结构:**单列 3 行**(`tblGrid` 只有一个 `gridCol`,每行一个 `tc`),
|
||||
即三行整宽方框上下叠。没有合并单元格、没有多列,所以没用 `tabularray`
|
||||
—— 手工 `\vbox` 叠三块反而更可控(行高精确、内线不重复、内容可用 `\vfil` 撑)。
|
||||
|
||||
### 行高为什么用实测值而不是 `trHeight`
|
||||
|
||||
`trHeight` 是 5091 / 1140 / 634 twips,`hRule="atLeast"`。
|
||||
`atLeast` 是「最小」,实际高度由内容撑开:
|
||||
|
||||
| 行 | `trHeight` | 实际被内容撑到 | 段落数 |
|
||||
| :-- | :-- | :-- | :-- |
|
||||
| R0 事项描述 | 254.55 pt | **284.00 bp** | 19 |
|
||||
| R1 单位负责人 | 57 pt | **58.35 bp** | 4 |
|
||||
| R2 科技管理 | 31.70 pt | **56.80 bp** | 4 |
|
||||
|
||||
照 `trHeight` 会让整表矮 40 bp。故取实测撑开后的高度。
|
||||
|
||||
## 六个必须知道的坑
|
||||
|
||||
这一节的每一条都是实测踩出来的,改 `ouccsx.sty` 之前务必看完。
|
||||
|
||||
### 1. 版心要取「表格宽度」,不是 docx 版心
|
||||
|
||||
原表宽 169.54 mm,比 docx 版心(156 mm)宽 13.54 mm,
|
||||
靠 `tblInd = −546 twips` 向左顶出版心。
|
||||
|
||||
若把 `geometry` 设成 docx 版心(`left = 28.01mm`),表格必然超出版心
|
||||
13.54 mm,报一条 `Overfull \hbox`,而且改内容时位置会漂。
|
||||
|
||||
⇒ 本包把版心**直接设成表格宽度**:`left = 16.47mm`、`totalwidth = 169.54mm`。
|
||||
表格正好填满版心,零 Overfull,与原件逐点相同。
|
||||
|
||||
代价:标题若用 `\centering` 会落在 287.03 bp,而原件在 300.41 bp(居中于
|
||||
docx 版心),偏左 13.4 bp。故标题另给 `\sxtitleindent` + `\sxtitlewidth`
|
||||
把中心校回去 —— **不要**把标题改成 `\centering`。
|
||||
|
||||
### 2. `\baselineskip` 管不了本表的行距
|
||||
|
||||
本表行距逐行不同(15.24 / 15.48 / 14.04 / 13.56 / 13.68 bp),
|
||||
因为 10.5 pt 与 12 pt 的字混排,Word 按「**下一行**字号 × 1.3」算。
|
||||
|
||||
而 `\baselineskip` **只在同一段落内部**管行距。一旦每行 `\par` 自成一段,
|
||||
段与段之间是另一套规则:
|
||||
|
||||
```
|
||||
段间基线距 = 上段末行深度 + \parskip + 本段首行字高
|
||||
```latex
|
||||
\newcommand{\sxdateA}{2026} % 只印年份
|
||||
\newcommand{\sxdateA}{2026}{10}{28} % 但这不是正确写法
|
||||
```
|
||||
|
||||
这里 `\parskip = 0`、首行字高由字体 ascent 定死,`\baselineskip` 根本没被读到。
|
||||
实测第一版所有行距被压成 13.51,12 pt 的签名行也没变高,整表矮 2.25 bp。
|
||||
正确写法是用完整版命令(三参数版本,写在同一行的花括号内):
|
||||
|
||||
⇒ 正解:不依赖 `\baselineskip`,逐行显式插胶:
|
||||
|
||||
```
|
||||
基线距 = 上盒深度 + \kern + 本盒高度
|
||||
⇒ \kern = 目标距 − 上盒深度 − 本盒高度
|
||||
```latex
|
||||
\newcommand{\sxdateA}{\sxdatefull{2026}{10}{28}}
|
||||
```
|
||||
|
||||
这就是 `\sx@bl` / `\sx@blp` 的全部内容。与字体度量彻底解耦:换字体、
|
||||
换字号、描述写长写短,行距一个 bp 都不变。
|
||||
要只印年份就用 `\newcommand{\sxdateA}{2026}`,其余留空手填。
|
||||
|
||||
唯一的例外是「段内折行的长句」—— 那是一个段落里的多行,规则不同,
|
||||
`\baselineskip` 在此**有效**,故 `\sx@blp` 仍给它。
|
||||
## 生成的表格
|
||||
|
||||
### 3. 块首行必须用 `\kern`,不能用 `\vskip`
|
||||
`\sxform` 一条命令印出整个表:
|
||||
|
||||
TeX 会**丢弃 `\vbox` 开头的胶**。用 `\vskip` 给的顶距会静默消失
|
||||
(实测「事项描述:」给 10.53 只落到 5.38,等于只剩字高)。
|
||||
`\kern` 不受这条约束,且照样计入盒高。
|
||||
|
||||
同理,块**末尾**不能用 `\vskip` 补空白(胶也被丢弃),
|
||||
要用 `\sx@bl` 的可选参数 `#1` 直接撑末盒的深度。
|
||||
|
||||
### 4. 负的 `\kern` 不能被挡
|
||||
|
||||
相邻两行的目标距可能小于「上盒深度 + 本盒高度」。例:年月日行是 12 pt 字,
|
||||
目标距 14.04,而 `2.99 + 12.06 = 15.05`,差值是 **−1.01**。
|
||||
|
||||
最初加了 `\ifdim\sx@tmp>\z@` 守卫,负值被静默吞掉 → 该行退回自然距 15.05,
|
||||
整块错位 10 bp。负 `\kern` 在 TeX 里完全合法(盒间轻微重叠),不该挡。
|
||||
|
||||
### 5. 多行段落:`\ht` 参照的是**末行**基线
|
||||
|
||||
`\vbox` 的 `\ht = 首行高度 + (n−1)·行距`,它的参考点是**末行基线**。
|
||||
|
||||
所以「上一行基线 → 本段首行基线」的距离不是 `pd + kern + ht`,
|
||||
而是 `pd + kern + ht − (n−1)·行距`。漏掉这一项,多行段自己被推下一整行,
|
||||
其后所有行跟着错(实测 0.48 而非 14.04)。
|
||||
|
||||
⇒ 用 `\prevgraf` 取段内行数,把 `(n−1)·行距` 加回 `kern`。`\dp` 不用改 ——
|
||||
`\vbox` 的 `\dp` 就是末行的真实深度。
|
||||
|
||||
⚠️⚠️ `\prevgraf` 有两道坎,两个都踩过:
|
||||
- 必须在 `\vbox` **内部**取 —— 盒一关闭就恢复成外层值(实测把 2 读成 0)
|
||||
- 必须在 `\par` **之后**取 —— 它是在段落断行那一步才被写入的(`\par` 前读到仍为 0)
|
||||
|
||||
### 6. `\vbox to N` 设的是**高度**,深度另计
|
||||
|
||||
若最后一项是带深度的 `\box`,`\vbox to N` 的 `\dp` 就是那个深度,
|
||||
**总高变成 `N + 深度`**。本表末行深 3.11,于是 R0 变成 287.11 而非 284.00,
|
||||
四条横线全部下移。
|
||||
|
||||
⇒ 末尾补一条 `\vskip\z@`:让末项变成胶(胶无深度),`\dp` 归零,
|
||||
总高才正好等于 `N`。见 `\sx@cellvf`。
|
||||
|
||||
## 与原件的有意差异
|
||||
|
||||
| 项 | docx | 本模板 | 说明 |
|
||||
| :-- | :-- | :-- | :-- |
|
||||
| 字体 | 宋体 SimSun | OUC Serif(思源宋体子集) | 原用系统字体。改仓库公共字体包 `../fonts/`,换机器/换系统都能编,且允许分发 |
|
||||
| 标题字体 | 方正小标宋简体 | OUC Serif **真粗体** | 小标宋是商业字体,本库不分发。按 `课程执行大纲/` 的既定做法换真粗体:小标宋本就是宋体的标题变体,真粗体比伪粗更接近,笔画不糊 |
|
||||
| 第 3 条备注编号 | 手打的「 3. 」,无 `numPr` | 与前两条统一排齐 | 唯一的位置差异:原件该条比前两条偏 0.36 bp。原件是漏配自动编号后手打的,属笔误;本模板统一对齐 |
|
||||
| R0 描述区留白 | 8 个空段 | 上下两半 + 中间 `\vfil` | 见上文「关于 `\sxdesc`」。描述长短不再影响签名区位置 |
|
||||
|
||||
除此之外**没有**任何版式差异。
|
||||
|
||||
## 实测偏差
|
||||
|
||||
不用肉眼看 PDF,直接用 `pymupdf` 取矢量坐标,与 Word 2007 导出的 PDF 逐项相减:
|
||||
|
||||
```python
|
||||
span['origin'] # 真实基线坐标(bbox 顶端受字形上伸部影响,误差约 2 bp)
|
||||
page.get_drawings() # 每条线的精确端点
|
||||
```latex
|
||||
\begin{document}
|
||||
\sxform
|
||||
\end{document}
|
||||
```
|
||||
|
||||
结果(33 个文字元素 + 6 条线,`dY`/`dX` 为「本模板 − 原件」,单位 bp):
|
||||
表格内容:
|
||||
|
||||
| 元素 | dY | dX |
|
||||
| :-- | :-- | :-- |
|
||||
| 标题 | 0.00 | −0.01 |
|
||||
| 四条表格横线 | 0.00 | — |
|
||||
| 事项描述 / 描述首行 / 次行 | 0.00 | +0.03 |
|
||||
| 兹证明 | 0.00 | +0.04 |
|
||||
| 项目负责人(签名) | 0.00 | +0.03 |
|
||||
| 年月日(三处,各 3 字) | 0.00 | +0.03 |
|
||||
| 项目负责人是 / 责任。/ 非科研经费 | 0.00 | +0.03 |
|
||||
| 本人证明 / 单位负责人 / 单位公章 | 0.00 | +0.03 |
|
||||
| 学院对本单位 | 0.00 | +0.03 |
|
||||
| 科技管理 / 负责人签字 / 单位公章 | 0.00 | +0.03 |
|
||||
| 备注四条 | −0.01 | −0.42 ~ −0.82 |
|
||||
| 页码 | 0.00 | 0.00 |
|
||||
| 区段 | 内容 |
|
||||
|---|---|
|
||||
| 标题 | 特殊事项说明表 |
|
||||
| 事项描述 | `\sxdesc` 的内容,占主表区 |
|
||||
| 签字栏 | 三处签字与日期 |
|
||||
| 表尾 | 说明条款 |
|
||||
|
||||
**33 个文字元素的 dY 全部 0.00**(< 0.005 mm),dX ≤ 0.04 bp,
|
||||
唯备注区 dX 偏 0.42~0.82 bp(约 0.15~0.29 mm,肉眼不可辨)——
|
||||
那是 OUC Serif 与 SimSun 的字宽差累积,不是定位误差。
|
||||
## 常用命令
|
||||
|
||||
像素级差分(150 dpi)总差异 3.03%,且每条差异带都精确落在有文字的行上,
|
||||
**没有整体错位的偏移带** —— 3% 全是字形轮廓不同造成的。
|
||||
| 命令 | 用途 |
|
||||
|---|---|
|
||||
| `\sxform` | 印出整张表 |
|
||||
| `\sxtitle{标题}` | 改主标题文字 |
|
||||
| `\sxtable` | 只印表格部分(不含标题) |
|
||||
| `\sxnotes` / `\sxnoteitem` | 表尾说明条目 |
|
||||
| `\sxfootcontent` | 表尾内容 |
|
||||
| `\sxfonttitle` / `\sxfontbody` / `\sxfontsign` / `\sxfontfoot` | 各区块字体设置 |
|
||||
|
||||
## 校验方法
|
||||
## 版式
|
||||
|
||||
量矢量而不是量像素:
|
||||
|
||||
```bash
|
||||
pdftocairo -svg 特殊事项说明表.pdf out.svg # 线条精确坐标
|
||||
pdftotext -bbox 特殊事项说明表.pdf out.xml # 字块坐标
|
||||
```
|
||||
A4,单页
|
||||
标题黑体,正文宋体,签字栏楷体
|
||||
三处签字:项目负责人 / 单位负责人 / 科技管理部门
|
||||
```
|
||||
|
||||
或用 `pymupdf`(本模板就是这么核的):`page.get_drawings()` 取线,
|
||||
`get_text('rawdict')` 取 `span['origin']` 作基线。
|
||||
## 注意
|
||||
|
||||
⚠️ 注意 `bp` 与 `pt` 的不同:PDF 用户单位是 **bp**(1/72 in),
|
||||
LaTeX 的 `pt` 是 1/72.27 in,差 0.375%。A4 上累积到 2 pt,
|
||||
超过一个字符宽。**本包凡与 PDF 对齐的几何量一律用 `bp`**。
|
||||
示例内容是虚构数据,使用时整段替换 `\sxdesc`。签字与日期栏留空手填。
|
||||
Reference in New Issue
Block a user