CTeX-org / ctex-kit

Macro Packages and Scripts for Chinese TeX users
982 stars 124 forks source link

jiazhu:竖排夹注内行距过宽 #508

Closed tanukihee closed 4 years ago

tanukihee commented 4 years ago

代码:

\documentclass{ltjtarticle}
\usepackage{jiazhu}
\begin{document}
本文本文\jiazhu{割注割注}本文本文
\end{document}

效果如图 image

可见夹注内行距过宽,且整体偏右。

而横排时效果很好

\documentclass{ltjarticle}
\usepackage{jiazhu}
\begin{document}
本文本文\jiazhu{割注割注}本文本文
\end{document}

image

tanukihee commented 4 years ago

按《日本語組版処理の要件》,「割注そのものの行間は,一般に 0 である.つまり,行間をとらない」(夹注行距,一般为 0),也许需要增加调整夹注行距以及竖排基线位置的功能。 image image

tanukihee commented 4 years ago

baselineshift 功能似乎会同时影响夹住后的正文基线位置

\documentclass{ltjarticle}
\usepackage{jiazhu}

\jiazhuset{
    baselineshift=-9pt
}
\begin{document}
本文本文\jiazhu{割注割注}本文本文
\end{document}

image

我认为这个功能应该只影响夹注的基线位置

qinglee commented 4 years ago

jiazhu 是一个高度实验性的宏包,还没有经过充分测试,目前的状态是仅仅能保证编译不报错,输出效果很难保证。

tanukihee commented 4 years ago

对于同一字体,在 LuaLaTeX 和 XeTeX 下行距不同 LuaLaTeX

\documentclass{ltjarticle}
\usepackage{luatexja-fontspec}
\usepackage{jiazhu}
\setmainjfont{Source Han Serif CN}
\begin{document}
本文本文\jiazhu{割注割注割注割注割注割注}本文本文
\end{document}

image

XeTeX

\documentclass{ctexart}
\usepackage{jiazhu}
\setCJKmainfont{Source Han Serif CN}
\begin{document}
本文本文\jiazhu{割注割注割注割注割注割注}本文本文
\end{document}

image

在 XeTeX 环境下行距更窄,更美观。

RuixiZhang42 commented 4 years ago

https://www.w3.org/TR/2012/NOTE-jlreq-20120403/ja/#inline_cutting_note

割注とは [……] 縦組での利用が多く,横組での例は非常に少ない.

直排场合下,夹注基本不出现「横躺」的西文,所以要求用「零行间距」密排夹注,也还合理。

横排用夹注太异常了,如果用户在夹注里面写西文,还坚持零行间距,那么小写字母的下降部一定会跟第二行的汉字打架的。

tanukihee commented 4 years ago

所以也许可以加一个「调整夹注行距」的功能? 不过夹注里写西文也不太合适吧

RuixiZhang42 commented 4 years ago

@tanukihee @qinglee 啊!夹注的行距过宽,跟横排直排无关,跟编译引擎也无关呀!

原因是你用了不一样的 document class……

可以修改 \@@_boot:nn 的定义:

\usepackage{jiazhu}
\usepackage{etoolbox}
\ExplSyntaxOn
\makeatletter
\patchcmd\__jiazhu_boot:nn
  {%
    \exp_args:Nxx \fontsize
      { \fp_eval:n { \l__jiazhu_ratio_fp * \f@size } }
      { \fp_eval:n { \l__jiazhu_ratio_fp * \f@baselineskip } }
  }{%
    \exp_args:Nxx \fontsize
      { \fp_eval:n { \l__jiazhu_ratio_fp * \f@size } }
      { \fp_eval:n { \l__jiazhu_ratio_fp * \f@size } }
  }{}{}
\makeatother
\ExplSyntaxOff

@qinglee 由于 document classes 预设的行距不可控,我觉得应该预设夹注行距等于夹注字号,即上述提到的方案,然后提供 linespread 用户接口。这样改的默认方案,一来是根据《日本語組版処理の要件》实现的,二来 discourage 用户往夹注里面写西文,三来用户实在想扩大行距也支持。

RuixiZhang42 commented 4 years ago

@qinglee 基线(或者中线)的对齐问题是这段代码引入的: https://github.com/CTeX-org/ctex-kit/blob/4ab8fa717a6c572238200274f689f9f4929e72b4/jiazhu/jiazhu.dtx#L504-L509

其中这个 hard-coded 的 0.8 是经验值,应该提供用户接口。

RuixiZhang42 commented 4 years ago

改倒也挺简单,例子从 jiazhu-test.tex 来的:

jiazhu

黑色全角方块是刻意加进去的,作诊断用。在 Windows 里编译,字体是中易宋体,仍然无法完美对齐(黑方块底端应该与中线对齐),甚是诡异。

下移量需要严格推导,已经在下面一条评论中给出方案。

RuixiZhang42 commented 4 years ago

总算推出来了,不仅夹注文字居中,夹注前后追加的括弧也居中:

jiazhu3

推导过程

derivation2

代码

需要直排的话,把 \ideographht 改成 1/2 就好了。

\documentclass{ctexart}

\usepackage{jiazhu}

\jiazhuset { opening = 〔 , closing = 〕 , shortcut = | }

\newcommand*\ideographht{220/256}
\newcommand*\ideographdp{36/256}

\usepackage{etoolbox}
\ExplSyntaxOn
\makeatletter
% 第一处修改,夹注内默认零行间距
\patchcmd\__jiazhu_boot:nn
  {%
    \exp_args:Nxx \fontsize
      { \fp_eval:n { \l__jiazhu_ratio_fp * \f@size } }
      { \fp_eval:n { \l__jiazhu_ratio_fp * \f@baselineskip } }
  }{%
    \lineskip = \z@skip
    \exp_args:Nxx \fontsize
      { \fp_eval:n { \l__jiazhu_ratio_fp * \f@size } }
      { \fp_eval:n { \l__jiazhu_ratio_fp * \f@size } }
  }{}{}
% 第二处修改,计算居中对齐的下移量
\cs_set_protected:Npn \__jiazhu_put_box:N #1
  {
    \box_move_down:nn
      {
        \l__jiazhu_unit_dim*\ideographht
        - \l__jiazhu_outer_unit_dim*\ideographht
        + (
            \l__jiazhu_lines_int \tex_baselineskip:D
            - \tex_baselineskip:D
            + \l__jiazhu_outer_unit_dim
            - \l__jiazhu_unit_dim
          ) / 2
      }
      { \box_use_drop:N #1 }
  }
% 第三处修改,夹注 opening、closing 符号的下移量需要另外计算
\cs_new_protected:Npn \__jiazhu_put_punct_box:N #1
  {
    \box_move_down:nn
      {
        \fp_eval:n
          { \l__jiazhu_bracket_ratio_fp * ( \ideographht - 0.5 ) }
        \l__jiazhu_unit_dim
        - \l__jiazhu_outer_unit_dim*\ideographht
        + \l__jiazhu_outer_unit_dim / 2
      }
      { \box_use_drop:N #1 }
  }
\patchcmd\__jiazhu_put_opening_box:
  {%
    \__jiazhu_put_box:N
  }{%
    \__jiazhu_put_punct_box:N
  }{}{}
\patchcmd\__jiazhu_put_closing_box:
  {%
    \__jiazhu_put_box:N
  }{%
    \__jiazhu_put_punct_box:N
  }{}{}
% 画一个黑色的全角方块
\patchcmd\__jiazhu_boot:nn
  {%
    \hbox_set:Nn \l__jiazhu_text_box { #2 \tex_unskip:D }
  }{%
    \hbox_set:Nn \l__jiazhu_text_box
      {
        \rule[-\dimexpr\f@size\p@*\ideographdp\relax]{\f@size\p@}{\f@size\p@}
        #2
        \tex_unskip:D
      }
  }{}{}
% 画正文底线、顶线、中线
\newcommand*\drawbounds{%
  \leavevmode
  \hbox to\z@{%
    \hss
    \rule[-\dimexpr\f@size\p@*\ideographdp\relax]{5in}{\dimexpr\f@size\p@/64\relax}%
    \hss
  }%
  \hbox to\z@{%
    \hss
    \rule[\dimexpr\f@size\p@*\ideographht-\f@size\p@/64\relax]{5in}{\dimexpr\f@size\p@/64\relax}%
    \hss
  }%
  \hbox to\z@{%
    \hss
    \rule[\dimexpr(\f@size\p@*\ideographht-\f@size\p@*\ideographdp)/2-\f@size\p@/128\relax]{5in}{\dimexpr\f@size\p@/64\relax}%
    \hss
  }%
}
  \cs_if_exist_use:NT \xeCJKsetup
    { { AllowBreakBetweenPuncts } }
\makeatother
\ExplSyntaxOff

\begin{document}

\setlength\parskip{10pt}

世祖光武皇帝讳秀,字文叔,|{测礼“{祖有功而宗有德}”,光武中兴,故庙称世祖。谥法:“能绍前业曰光,克定祸乱曰武。”伏侯古今注曰:“秀之字曰茂。伯、仲、叔、季,兄弟之次。长兄伯升,次仲,故字文叔焉。”}南阳\drawbounds 蔡阳人,|{南阳,郡,今邓州县也。蔡阳,县,故城在今随州枣阳县西南。}高祖九世之孙也,

\jiazhuset { format = \linespread{1.5} }

世祖光武皇帝讳秀,字文叔,|{测礼“{祖有功而宗有德}”,光武中兴,故庙称世祖。谥法:“能绍前业曰光,克定祸乱曰武。”伏侯古今注曰:“秀之字曰茂。伯、仲、叔、季,兄弟之次。长兄伯升,次仲,故字文叔焉。”}南阳\drawbounds 蔡阳人,|{南阳,郡,今邓州县也。蔡阳,县,故城在今随州枣阳县西南。}高祖九世之孙也,

\jiazhuset { format = {} , lines = 3 }

世祖光武皇帝讳秀,字文叔,|{测礼“{祖有功而宗有德}”,光武中兴,故庙称世祖。谥法:“能绍前业曰光,克定祸乱曰武。”伏侯古今注曰:“秀之字曰茂。伯、仲、叔、季,兄弟之次。长兄伯升,次仲,故字文叔焉。”}南阳\drawbounds 蔡阳人,|{南阳,郡,今邓州县也。蔡阳,县,故城在今随州枣阳县西南。}高祖九世之孙也,

\jiazhuset { ratio=0.6 , lines = 2 }

世祖光武皇帝讳秀,字文叔,|{测礼“{祖有功而宗有德}”,光武中兴,故庙称世祖。谥法:“能绍前业曰光,克定祸乱曰武。”伏侯古今注曰:“秀之字曰茂。伯、仲、叔、季,兄弟之次。长兄伯升,次仲,故字文叔焉。”}南阳\drawbounds 蔡阳人,|{南阳,郡,今邓州县也。蔡阳,县,故城在今随州枣阳县西南。}高祖九世之孙也,

\end{document}
qinglee commented 4 years ago

@qinglee 基线(或者中线)的对齐问题是这段代码引入的: https://github.com/CTeX-org/ctex-kit/blob/4ab8fa717a6c572238200274f689f9f4929e72b4/jiazhu/jiazhu.dtx#L504-L509

其中这个 hard-coded 的 0.8 是经验值,应该提供用户接口。

  • 直排模式下,这个值应该统一修改为 0.5
  • 横排模式下,不同字体的汉字字框高度是不一样的,思源系列应该是 0.88,中易系列应该是 0.859375,华文系列才是 0.8
  • 凡是跟 \strutbox 相关的代码也需要留意,针对西文优化的 \strut 不一定跟汉字中线居中对齐。

确实,当时写到这里的时候就知道中线对齐会有问题,0.8 只是图方便取的一个值,这个值依赖于字体。

可以提供选项让用户自行设置 \ideographht\ideographdp。但这对一般用户来说,设置这些值,可能有些困难。也许我们可以像 pLaTeX 设置 \Cht\Cdp 一样,选一个汉字作为标志,把它放入盒子中,实际量取他的高度和深度,作为字体的数据,自动调整 \ideographht\ideographdp

qinglee commented 4 years ago

总算推出来了,不仅夹注文字居中,夹注前后追加的括弧也居中:

……

非常感谢!把你加入共同作者了,你如果有时间和兴趣,可以直接在 dtx 里修改。

RuixiZhang42 commented 4 years ago

@qinglee pLaTeX 的 \Cht\Cdp 是基于 JFM (pTeX-extended TFM) 的参数,每一个 ideograph 都有统一的高度、深度,这个参数度量的是「字框」。

一旦转到 OpenType 字体,参数就不一致了。这时,引擎直接读取「字面」的高度、深度,也就是说每个字的高度、深度都不一样,加起来的总高度也比字框的总高度要小。参见 https://github.com/CTeX-org/ctex-kit/issues/464#issuecomment-563459255

也就是说,在 XeTeX、LuaTeX 下,「选定标准字测量、再计算」这个方法不可靠。

常用字体的 \ideographht\ideographdp 值可以通过表格形式写进用户手册(华文、中易、Adobe 各自的产品相对统一,方正的则高矮不一),也当趁机「推广排印教育」,鼓励用户「去了解、去设置」。

qinglee commented 4 years ago

@RuixiZhang42 luatexja 也模拟了 pTeX 的 JFM,每一个汉字都被打包到盒子里,设置好统一的高度和深度后再输出,所以对 pTeX 和 luateja 来说,汉字的高度和深度是由 JFM 决定的,跟字体关系不大,也就是说我们的测量结果不可靠。

XeTeX 可以设置 \XeTeXuseglyphmetrics 为零,让所有的汉字也使用统一的字框,但由此测量产生的结果好像不能反映字体的真实情况,也不可靠。

RuixiZhang42 commented 4 years ago

@qinglee 其实,我在想可不可以用中文字体里面的 U+2588 (Full Block) 作为可靠的度量……

修改的代码还得多调一会儿,今天试排思源字体出了点小问题,不过计算公式应该是没错的,这周有空就 push。直排调 \ideographht0.5 大概这样:

jiazhuzhipai

qinglee commented 4 years ago

@RuixiZhang42 还是别选特征字度量了,直接让用户设置 \ideographht 好了。

公式我也细看了,应该没问题。

tanukihee commented 4 years ago

最新的 jiazhu 中,夹注前后的括号放大了 2.5 倍,但好像并未居中,而是底部对齐的? image

tanukihee commented 4 years ago

最新的 jiazhu 中,夹注前后的括号放大了 2.5 倍,但好像并未居中,而是底部对齐的? image

抱歉,括号是相对正文居中对齐的,只不过是中易宋体的基线位置较低,默认的 ideographht = 0.8 与中易宋体不搭配造成夹注位置偏低,让括号看起来像是底部对齐了一样。

按下图 image 夹注前后括号应该刚好是夹注字号的两倍,而夹注字号不一定需要是正文字号的二分之一,如图中正文字号 9 点,夹注字号 6 点,前后括号字号 12 点,对应的 jiazhuset 应该是 ratio = 0.6667 , bracketratio = 2 ,也许应该把 bracketratio = 2 设为默认值?

RuixiZhang42 commented 4 years ago

@tanukihee 之前预设 ideographht=0.88,现在改为预设 ideographht=0.5 供直排用。横排数值请参考用户手册 ideographht 那部分的表格。

之前预设的 ratio=0.5 的确太小了(正文五号,夹注只有 5.25bp),也很影响页面灰度。现在改为预设 ratio=2/3(正文五号,夹注 7bp)。bracketratio 也相应地改为预设 2

baselineshift 有 bug,有了新的对齐算法之后也没啥用了,未来(即发布前)可能会移除。

qinglee commented 4 years ago

@RuixiZhang42 baselineshift 本意不是解决这里的对齐问题。

按照目前的实现,夹注前后的正文其实是放在不同的段落的,大概示意如下:

夹注前正文$$通过 \predisplaysize 获取前一行的剩余宽度$$\jiazhu{夹注}夹注后正文

前后的正文行距可能不统一,比如极端的例子:

夹注前正文\jiazhu{夹注}夹注后\rule{0pt}{20pt}正文

image 当然,这里是为了示意生造的例子,正常情况下不会出现这种情况,但我觉得保留一个调整的接口还是必要的。

RuixiZhang42 commented 4 years ago

@qinglee 原来如此!是我理解有误,以为 baselineshift 本意是仅仅为了调整夹注的位置而已……

这样看来,设了 baselineshift 的效果就应该是后面的正文一起被移,所以是个 feature 而不是 bug……这个生造的例子可以换个包装出现在用户手册里~~

tanukihee commented 4 years ago

两个问题想请教一下

  1. 在有 openingclosing 的括号的前提下,beforeskipafterskip 的距离是从哪里开始,如何计算的?
  2. beforeskipafterskip 的长度若为相对长度,是相对于什么的长度?

通过粗略观察,在 xeCJK 下,距离计算是从被「彻底削掉空白」后的括号边缘开始计算,而 luatexja 下是从半宽括号开始计算的。

代码与效果图如下,其中画字框借鉴了@RuixiZhang42 先生在 #488 中的代码

xe

\documentclass{ctexart}
\usepackage{jiazhu}

\jiazhuset{
    beforeskip = 0\ccwd,
    afterskip = 1\ccwd,
    ratio = 1/2,
    ideohtratio = 0.88
}

\setCJKmainfont{Source Han Serif CN}

\usepackage{xcolor}
\setlength{\fboxrule}{0.15625pt}
\setlength{\fboxsep}{-\fboxrule}
\newcommand*{\cstrut}{\rule[\dimexpr-1em*120/1000\relax]{0pt}{1em}}
\newcommand*{\drawfwbox}{\textcolor[HTML]{9999FF}{\fbox{\cstrut\quad}}}
\newcommand*{\drawhwbox}{\textcolor[HTML]{9999FF}{\fbox{\cstrut\enskip}}}

\begin{document}

\leavevmode\rlap{%
    \drawfwbox
    \drawfwbox
    \drawhwbox
    \drawfwbox
}%
正文\jiazhu[opening = (]{夹注夹注}

\leavevmode\rlap{%
    \drawfwbox
    \drawfwbox
    \drawfwbox
    \drawfwbox
}%
\jiazhu[closing = )]{夹注夹注}正文
\end{document}

image

lua

\documentclass{ltjarticle}
\usepackage{jiazhu}

\jiazhuset{
    beforeskip = 0\zw,
    afterskip = 1\zw,
    ratio = 1/2,
    ideohtratio = 0.88
}

\usepackage{luatexja-fontspec}
\setmainjfont{Source Han Serif CN}

\usepackage{xcolor}
\setlength{\fboxrule}{0.15625pt}
\setlength{\fboxsep}{-\fboxrule}
\newcommand*{\cstrut}{\rule[\dimexpr-1\zw*120/1000\relax]{0pt}{1\zw}}
\newcommand*{\drawfwbox}{\textcolor[HTML]{9999FF}{\fbox{\cstrut\hspace{1\zw}}}}
\newcommand*{\drawhwbox}{\textcolor[HTML]{9999FF}{\fbox{\cstrut\hspace{0.5\zw}}}}

\begin{document}

\leavevmode\rlap{%
    \drawfwbox
    \drawfwbox
    \drawhwbox
    \drawfwbox
}%
正文\jiazhu[opening = (]{夹注夹注}

\leavevmode\rlap{%
    \drawfwbox
    \drawfwbox
    \drawfwbox
    \drawfwbox
}%
\jiazhu[closing = )]{夹注夹注}正文
\end{document}

image (从 lua-visual-debug 中看,luatexja 似乎还会对夹注汉字间进行压缩?而且行距也被撑开了) image 插空盒子后效果如下 image image 可见的确是从半宽括号开始计算的

同样可看出,若在 beforeskipafterskip 中使用相对长度,似乎是相对于夹注字号的长度(虽然 afterskip = 1\ccwd,但 ratio = 1/2,图中表现出宽度只有正文字号宽度的一半),这一点要不要在文档里说明一下?

qinglee commented 4 years ago
  1. 是从括号的字符边缘开始算的,xeCJK 和 luatexja 的结果不一致,是因为它们对标点的处理不完全一样,结果有差异;
  2. 相对于夹注的字号;
  3. luatexja 对 kanjiskip 的初始设置是 \z@ plus .4pt minus .5pt,有 shrink 部分,按 jiazhu 的实现,可能会导致夹注汉字间距被压缩。
RuixiZhang42 commented 4 years ago

@tanukihee 建议新的「提议」、「问题」另开 issue,也方便 commit 做 reference……这个关于 beforeskip/afterskip 的问题就不用新开了,留在这里吧……

拓展一下 @qinglee 的回答:

  1. xeCJK 重构会涉及到「opening+偏右半边」这种标点,如果我们最后决定「统一抹掉左边二分空」而不是现在的「抹掉全部空白」,那么 xeCJKluatexja 会更相似。
  2. 夹注两端有括弧时,一般不再留多余的空白,所以 beforeskip/afterskip 此时也不应该有正值。既然都没有了,也不会纠结相对于哪个 em 了。

需要注意的一点是,「xeCJKluatexja 100% 一致」是很困难的(很多东西涉及到 primitive,在引擎层面就不一致了),更主要的是没有这个必要。就像 kanjiskip 允许收缩这种设定,用在假名、少量汉字的日文里合适,用在几乎全汉字的中文(尤其是繁体中文)里就不合适。

tanukihee commented 4 years ago

谢谢回答,主要是我能猜出部分来,就没有新开了,只是验证一下 总之谢谢 @qinglee 与 @RuixiZhang42 的解答!