Skip to content

jiazhu: 传统直排半高夹注正文对齐求助 #714

Description

@chianjin

中文传统直排要求正文垂直方向对齐。在ratio=0.5,夹注字符尺寸是正文的一半,当夹注字数除以 4 余数为 1、2 的时候,夹注本身的宽度是夹注字体尺寸的奇数倍,就会造成正文在垂直对齐错位半个正文字符。(附图左边情形)我最初解决这个问题的方法是在夹注末尾手动插入全角空格,强行使得夹注宽度是夹注字符尺寸的偶数倍。

感谢 @qinglee 给出的一个 Patch,保证了夹注的宽度总是夹注字体尺寸的偶数倍,解决了正文垂直对齐的问题。(附图中间情形)这个方案会出现夹注的第一行比第二行多出 2 个或 3 个字符的情形。但是总是感觉不够美观。

\cs_set_protected:Npn \__jiazhu_dim_normalize:N ##1 {
  \int_set:Nn \l_tmpa_int { \dim_ratio:nn { ##1 } { \l__jiazhu_unit_dim } }
  \int_if_even:nF { \l_tmpa_int } { \int_incr:N \l_tmpa_int }
  \dim_set:Nn ##1 { \l__jiazhu_unit_dim * \l_tmpa_int }
}
\cs_set_protected:Npn \__jiazhu_extract_max_width:N ##1 {
  \dim_set:Nn \l__jiazhu_width_dim { \box_wd:N ##1 }
  \dim_set_eq:NN \l__jiazhu_max_dim \l__jiazhu_width_dim
}

我现在的临时手工解决方案是不再采用这个 patch,手动在夹注末尾和正文之间插入\hspace{0.5em}增加空白来对齐。(附图右边的情形)

是否可以通过判断,夹注本身宽度为夹注字符尺寸奇数倍的时候,自动在夹注末尾和正文之间自动插入一个夹注字符高度的空白?本身水平有限,虽然读了夹注包的源代码,没有读懂而无从下手。请求帮助。感谢。

zhvt

Activity

  1. muzimuzhi commented on May 16, 2024

    @muzimuzhi
    Member

    请提供一个简单又完整的例子。

  2. chianjin commented on May 16, 2024

    @chianjin
    Author

    1. 对应附图左边情形的完整代码

    \documentclass[a4paper]{book}
    \usepackage{xeCJK}
    \usepackage{atbegshi}
    \usepackage{jiazhu}
    \defaultCJKfontfeatures { RawFeature= { vertical:+vert:+vhal } }
    \setCJKmainfont{SimSun}
    
    \jiazhuset{
      beforeskip=0pt,
      afterskip=0pt,
      ratio=0.5
    }
    
    \textwidth=420pt
    \parindent=0pt
    
    \AtBeginShipout{
      \global\setbox\AtBeginShipoutBox\vbox{%
        \special{pdf: put @thispage <</Rotate 90>>}%
        \box\AtBeginShipoutBox}%
    }
    
    \begin{document}
    \fontsize{20pt}{20pt}\selectfont
    
    康誥曰克明德
      \jiazhu{康誥周書克能也}
    大甲曰顧諟天之明命
      \jiazhu{大讀作泰諟古是字大甲商書顧謂常目在之也諟猶此也或曰審也
        天之明命即天之所以與我而我之所以爲德者也常目在之則無時不明
        矣}
    帝典曰克明峻德
      \jiazhu {峻書作俊帝典堯典虞書峻大也皆自明也結所引書皆言自明
        己德之意}
    \end{document}

    2. 对应附图中间情形的代码

    \documentclass[a4paper]{book}
    \usepackage{xeCJK}
    \usepackage{atbegshi}
    \usepackage{jiazhu}
    \defaultCJKfontfeatures { RawFeature= { vertical:+vert:+vhal } }
    \setCJKmainfont{SimSun}
    
    \ExplSyntaxOn
    \cs_set_protected:Npn \__jiazhu_dim_normalize:N #1 {
      \int_set:Nn \l_tmpa_int { \dim_ratio:nn { #1 } { \l__jiazhu_unit_dim } }
      \int_if_even:nF { \l_tmpa_int } { \int_incr:N \l_tmpa_int }
      \dim_set:Nn #1 { \l__jiazhu_unit_dim * \l_tmpa_int }
    }
    \cs_set_protected:Npn \__jiazhu_extract_max_width:N #1 {
      \dim_set:Nn \l__jiazhu_width_dim { \box_wd:N #1 }
      \dim_set_eq:NN \l__jiazhu_max_dim \l__jiazhu_width_dim
    }
    \ExplSyntaxOff
    
    \jiazhuset{
      beforeskip=0pt,
      afterskip=0pt,
      ratio=0.5
    }
    
    \textwidth=420pt
    \parindent=0pt
    
    \AtBeginShipout{
      \global\setbox\AtBeginShipoutBox\vbox{%
        \special{pdf: put @thispage <</Rotate 90>>}%
        \box\AtBeginShipoutBox}%
    }
    
    \begin{document}
    \fontsize{20pt}{20pt}\selectfont
    
    康誥曰克明德
      \jiazhu{康誥周書克能也}
    大甲曰顧諟天之明命
      \jiazhu{大讀作泰諟古是字大甲商書顧謂常目在之也諟猶此也或曰審也
        天之明命即天之所以與我而我之所以爲德者也常目在之則無時不明
        矣}
    帝典曰克明峻德
      \jiazhu {峻書作俊帝典堯典虞書峻大也皆自明也結所引書皆言自明
        己德之意}
    \end{document}

    3. 对应附图右侧情形的代码

    \documentclass[a4paper]{book}
    \usepackage{xeCJK}
    \usepackage{atbegshi}
    \usepackage{jiazhu}
    \defaultCJKfontfeatures { RawFeature= { vertical:+vert:+vhal } }
    \setCJKmainfont{SimSun}
    
    \jiazhuset{
      beforeskip=0pt,
      afterskip=0pt,
      ratio=0.5
    }
    
    \textwidth=420pt
    \parindent=0pt
    
    \AtBeginShipout{
      \global\setbox\AtBeginShipoutBox\vbox{%
        \special{pdf: put @thispage <</Rotate 90>>}%
        \box\AtBeginShipoutBox}%
    }
    
    \begin{document}
    \fontsize{20pt}{20pt}\selectfont
    
    康誥曰克明德
      \jiazhu{康誥周書克能也}
    大甲曰顧諟天之明命
      \jiazhu{大讀作泰諟古是字大甲商書顧謂常目在之也諟猶此也或曰審也
        天之明命即天之所以與我而我之所以爲德者也常目在之則無時不明矣}
    \hspace{0.5em}帝典曰克明峻德
      \jiazhu {峻書作俊帝典堯典虞書峻大也皆自明也結所引書皆言自明
        己德之意}
    \end{document}
  3. chianjin commented on May 17, 2024

    @chianjin
    Author

    经尝试,得到一个无需手工插入空白解决方案的,修改\cs_set_protected:Npn定义增加一个判断。

          \cs_set_protected:Npn \__jiazhu_processing:
            {
                \__jiazhu_split_lines:
                \__jiazhu_put_closing_box:
                \__jiazhu_good_break:
                \__jiazhu_hskip:N \l__jiazhu_after_skip_tl
    +           \int_set:Nn \l_tmpa_int { \dim_ratio:nn { \l__jiazhu_max_dim } { \l__jiazhu_unit_dim } }
    +           \int_if_odd:nT \l_tmpa_int { \skip_horizontal:n { \l__jiazhu_unit_dim } }
              \group_end:
              \tex_ignorespaces:D
            }
  4. changed the title [-]夹注:传统直排半高夹注正文对齐求助[/-] [+]jiazhu: 传统直排半高夹注正文对齐求助[/+] on Jul 15, 2026
  5. added theissue type on Jul 28, 2026
  6. Liam0205 commented on Aug 3, 2026

    @Liam0205
    Contributor

    确认这个问题仍然存在,并实测比较了本 issue 里已提出的两个方案。环境:xelatex(TeX Live 2026),jiazhu.sty 由 l3build unpack 生成;本机无 SimSun,用 Noto Serif CJK SC 替代(\l__jiazhu_unit_dim 只取 \f@size pt 而不查字体度量,所以换字体不影响机制)。

    #714 夹注盒宽与正文字网格

    (灰线为 20pt 正文字网格,粗竖线标出夹注结束、正文恢复处。复现文件
    jiazhu714-mwe.tex、盒宽扫描探针
    jiazhu714-sweep-width.tex,
    连同上图源码见 issues/714/。)

    复现与根因

    跑报告者「附图左边情形」的完整代码,用 pdftotext -bbox 提字形坐标后按 20pt 正文网格归一:

    col= 0.000  startGrid=  0.000  n=6 康誥曰克明德
    col= 0.000  startGrid=  8.000  n=9 大甲曰顧諟天之明命
    col= 1.209  startGrid= 10.500  n=7 帝典曰克明峻德   <-- 偏离网格 0.5 格
    

    第三段正文起点偏离整数网格恰好半个正文字宽(10pt),与报告者描述一致。

    根因是夹注最终盒宽总是夹注字宽的整数倍,而不是正文字宽的整数倍。\__jiazhu_dim_normalize:N 只用 \l__jiazhu_unit_dim(= 夹注字宽)做取整基准,正文字宽 \l__jiazhu_outer_unit_dim 完全没参与。扫描夹注字数 n=1..12(ratio=0.5、正文 20pt、夹注 10pt、lines=2):

    n 1 2 3 4 5 6 7 8 9 10 11 12
    盒宽/夹注字宽 1 1 2 2 3 3 4 4 5 5 6 6

    即 ceil(n/2) 个夹注字宽。ratio=0.5 时一个正文字宽 = 两个夹注字宽,所以该值为奇数即错位半个正文字,也就是 n mod 4 ∈ {1,2}——与报告者「夹注字数除以 4 余数为 1、2」逐字吻合。

    两个方案的实测比较

    qinglee 的 patch(向上取偶) 对齐确实解决了,但代价是行长分配不均:

    n 1 2 3 4 5 6 7 8 9 10 11 12
    盒宽/夹注字宽 2 2 2 2 4 4 4 4 6 6 6 6

    \jiazhu{一二三四五}(n=5)实测分行:基线是首行 3 字 + 次行 2 字,patch 后变成首行 4 字 + 次行 1 字。因为它改的是排版宽度,放宽到偶数倍后 TeX 把多出的位置全给首行,所以必然影响分行——正是报告者说的「第一行比第二行多出 2 个或 3 个字符」。

    报告者自己的第二方案(末尾补一个夹注字宽) 盒宽序列和分行都与基线完全一致(n=5 仍是 3+2),因为它改的是盒子之后的间距而非排版宽度。这是它优于 qinglee 方案的地方。

    但它会在正文行接近排满时把行推到溢出。扫描 \hsize(夹注 5 字,盒宽 3 个夹注字宽,判为奇数所以补 10pt):

    \hsize 基线 Overfull 补白后
    200pt 无 无
    205pt 5.0pt 15.0pt
    210pt 无 10.0pt

    \hsize=210pt 是干净的反例:基线不溢出,补白使它溢出正好一个夹注字宽。补的是固定长度 \skip_horizontal:,不可收缩,且位于 \__jiazhu_good_break: 的 \penalty -100 之后——断在那个 penalty 时它被丢弃、对齐失效;不断在那里时又强行占位、可能顶出溢出。要落地必须处理这两端。

    该方案的判别式本身是可靠的:它用 \l__jiazhu_max_dim 而非最终盒宽判奇偶,我扫了 30 组(\textwidth 200pt/120pt,夹注 1..57 字,含大量跨行),两者奇偶始终一致,0 例不符。跨行情形下补白也照样生效。

    两个坑,两个方案都没绕过

    括弧盒子使两者都失效。 括弧不进入 \l__jiazhu_max_dim,但进入正文行总宽度:

    设置 opening 宽 closing 宽
    closing=】 0.0pt 20.0pt
    opening=【,closing=】 7.6pt 20.0pt

    】 是 20.0pt(两个夹注字宽,不改变奇偶,所以无害),但 【 是 7.6pt,既不是夹注字宽也不是正文字宽的整数倍(bracketratio=2 使括弧字号为 20pt,但 【 在该字体里 advance 不是全角)。实测正文行偏离网格:

    情形 行宽/正文字宽 偏离
    报告者方案,无括弧 9.000 0.000 ✓
    报告者方案,closing=】 10.001 +0.001 ✓
    报告者方案,opening=【,closing=】 10.379 +0.379 ✗

    所以两个方案都只在不用 opening 括弧时成立。本 issue 的样例没用括弧,#713 用的是 shortcut=【】(走 shortcut 分隔符而非 opening/closing 键),所以两位报告者都没撞上。要通用地修,判别式得按「夹注排出后正文行的累计宽度」取余,而不是按夹注内容盒宽。

    两者都硬编码「偶数」,隐含假设 ratio=0.5。 ratio=2/3 时一个正文字宽 = 1.5 个夹注字宽,「偶数倍夹注字宽」不等于「整数倍正文字宽」,判别式失效。一般化的写法是直接按正文字宽取余补齐:

    \dim_set:Nn \l_tmpa_dim
      { \l__jiazhu_outer_unit_dim
        - \dim_eval:n { <盒宽> - \l__jiazhu_outer_unit_dim
            * \int_div_truncate:nn { <盒宽> } { \l__jiazhu_outer_unit_dim } } }
    \dim_compare:nNnF \l_tmpa_dim = \l__jiazhu_outer_unit_dim
      { \skip_horizontal:N \l_tmpa_dim }

    实测 ratio=0.5 时补 10pt/20pt,与报告者方案等效;ratio=2/3(夹注字宽 13.33333pt)时补 6.66667pt/13.33334pt/0.00002pt,把盒宽补齐到 20pt 整数倍。注意 ratio=2/3 下夹注字宽本身不是 pt 整数,取余会残留 0.00002pt 量级舍入,需判断是否可接受。

    未验证的部分

    • 未在真实 SimSun 上验证(机制与字体度量无关,但没实测)。
    • 上面的 ceil(n/2) 是 lines=2 的特例,未验证 lines>=3 的规律。
    • 括弧影响已实测,但没有试出一个能同时处理括弧与跨行的判别式写法。
    • 「补白被行尾断点丢弃」只做了推理(补白在 \penalty -100 之后,TeX 断在 penalty 处会丢弃其后 glue),没构造出实际断在那里的样例实测。溢出那一侧已实测。
    • 还有个前置问题想请维护者定:这该做成默认行为还是新选项?传统直排需要它,横排夹注不需要。另外 jiazhu 目前没有任何自动回归测试(无 testfiles/、无 test/,build.lua 未设 testfiledir,dtx 末尾 %<*test> 只是目视样例,没有 .tlg 基线),上面任何改动都会改变排版输出,没有基线难以判断回归。
  7. added a commit that references this issue on Aug 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions