使用 LuaTeX 修补字体

使用 LuaTeX 修补字体

我不喜欢\textperiodcenteredOpenType 中 Latin Modern 字体的 U+00B7 间距。与 Computer Modern 不同(事实上,与我系统上的任何字体都不同),LM 为字符提供了相当宽的侧边距。无论如何,我认为这是个错误,因此已将其报告给 Bogusław Jackowski阵风

但是,在我等待 Jacko 修复这个问题的同时,LuaTeX 字体修补(参见,例如非侵入式字距/间距修改:有哪些选项?) 可用于在运行时调整此字符的侧边距吗?如何实现此类修补?

(通过实验,我确定点两侧的字距为 -0.25em 时,其间距与句点“。”相同,所以这就是我想要削减字形边界框的量。)


下面的代码说明了这个问题。在我的实际代码中,我使用的是 Unicode 中点 (U+00B7) “·”,并且它的使用是在宏中,该宏的定义被复制\cs_set_eq:到另一个宏中(通过),因此重新定义\textperiodcentered和重新定义都\newunicodechar无法直接提供帮助。(这我的代码存在问题,我将修复它;上面的问题对我来说仍然很有趣。)

\documentclass{article}
\newif\ifot\ottrue
\ifot
  \usepackage{fontspec} % uses LM OpenType
\fi
\begin{document}
\ifot LMRoman OTF: \else Computer Modern: \fi
800\textperiodcentered 555\textperiodcentered 1212
\end{document}

\ottrue两次单独运行(第一次使用,第二次使用)的结果\otfalse如下:

LM 间距错误演示

Computer Modern 版本在印刷上是正确的,或者至少与使用任何其他字体的结果相似。尝试在任何应用程序中渲染文本“800·555·1212”(使用 U+00B7“·”),将 LMRoman 与其他字体进行比较;它很少有如此宽的侧边距。(Lucida 字体,例如,本网站上使用的,是我见过的其他的。)

答案1

从...开始这个答案,以下功能文件应该可以满足您的要求:

languagesystem DFLT dflt;
languagesystem latn dflt;
feature kern {
    pos periodcentered <-250 0 -500 0> ;
} kern;

(根据规格,尖括号中的值表示 x 位置、y 位置、x 前进和 y 前进,按此顺序以设计单位给出,又名。。em

你可以使用以下命令加载功能文件(我们称之为LMRoman.fea):

\setmainfont[FeatureFile=LMRoman.fea]{Latin Modern Roman}

答案2

如果在 textcomp 的帮助下使用 real char,则可以获得与 type1 lmodern 相同的间距:

\documentclass{article}
\usepackage{lmodern} % uses LM Type1
\usepackage[T1]{fontenc}
\usepackage{textcomp}

\begin{document}
800\textperiodcentered 555\textperiodcentered 1212
\end{document}

在此处输入图片描述

答案3

  1. LM Type1 字体有 U+00B7,type1 字体中的字符可以显示为 OpenType 版本。例如:

    \documentclass{article}
    \usepackage{lmodern}
    \begin{document}
    800\char189 555\char189 1212
    \end{document}
    
  2. 该命令的\textperiodcentered作用与\cdot文本模式相同。这两个命令映射到同一个字符。

    % filename: test.tex
    \documentclass{article}
    \usepackage{lmodern}
    \pagestyle{empty}
    \begin{document}
    \textperiodcentered$\cdot$
    \end{document}
    

    使用pdffonts test.pdfPDF 输出中获取字体的信息:

    name                                 type              emb sub uni object ID
    ------------------------------------ ----------------- --- --- --- ---------
    SQTJQN+LMMathSymbols10-Regular       Type 1            yes yes no       4  0
    
  3. 所以,这不是字体的错误,而是字符映射的错误。

答案4

让我们做一些实验texdef

> texdef -t latex textperiodcentered

\textperiodcentered:
macro:->\OMS-cmd \textperiodcentered \OMS\textperiodcentered

> texdef -t latex -p textcomp textperiodcentered

\textperiodcentered:
macro:->\TS1-cmd \textperiodcentered \TS1\textperiodcentered

这是什么意思?我们慢慢来。诸如\<dENC>-cmdwhere<dENC>是已知编码的大写名称之类的命令会检查该命令是否<cENC><arg>已定义、where<cENC>是当前编码以及<arg>是之后的第一个标记\<dENC>-cmd(“d” 表示“默认”)。如果是,则<cENC><arg>使用,否则<dENC><arg>使用。

示例(我将跳过不重要的细节)。LaTeX 将\textperiodcentered其扩展为

\OMS-cmd \textperiodcentered \OMS\textperiodcentered

如果当前编码是OT1(如您的\otfalse设置),LaTeX 会尝试查看是否已\OT1\textperiodcentered定义(如果不使用一些技巧,则无法发出该命令,内部反斜杠是名称的一部分),但未定义。因此,将遵循“默认分支”,这相当于执行

{\fontencoding{OMS}\selectfont \OMS\textperiodcentered}

因此\char"1从与 OMS 编码相关的字体进行打印,通常是数学符号字体​​,它没有在数学中自动添加的边距。

如果当前编码是EU1(如您的\ottrue设置),则检查定义性\EU1\textperiodcentered成功,因此所做的只是

\EU1\textperiodcentered

没有任何不必要的分组,以\char"00B7当前字体打印。此字形具有由字体设计者选择的侧边距。

所做textcomp的就是将与 关联的默认编码更改\textperiodcenteredTS1,但效果类似;唯一的区别是默认将使用来自文本伴随字体的字符。

如果您想要更改 的工作方式,只需修改其针对(XeLaTeX) 或(LuaLaTeX) 编码\textperiodcentered的定义即可。宏将扩展为正确的编码。EU1EU2\encodingdefault

\documentclass{article}
\usepackage{fontspec}
\AtBeginDocument{%
  \DeclareTextCommand{\textperiodcentered}{\encodingdefault}{\kern-.25em\char"00B7\kern-.25em }%
}
\begin{document}

800\textperiodcentered 555\textperiodcentered 1212
\end{document}

在此处输入图片描述

总之,这绝对不是一个错误,而是预期的行为。OpenType 字体可以有一个“U+2E31 WORD SEPARATOR MIDDLE DOT”字符,它没有侧边距(恐怕不是 Latin Modern OT)。


其他字体的居中间隔较小;一个很好的猜测似乎是宽度为 0.25em,如以下示例所示:

\documentclass{article}
\usepackage{fontspec}
\usepackage{xparse}
\NewDocumentCommand{\periodsep}{}{\makebox[.25em]{\symbol{"00B7}}}


\begin{document}

\newcommand{\test}{800\periodsep 555\periodsep 1212\par
800\symbol{"00B7}555\symbol{"00B7}1212\par\medskip}

\test

\fontspec{Linux Libertine O}\test

\fontspec{TeX Gyre Termes}\test

\fontspec{TeX Gyre Pagella}\test
\end{document}

如果您的应用程序不直接使用该字符,而是通过宏生成它,这似乎是最好的方法。

在此处输入图片描述

\periodsep或者,你可以接受中心周期的任何宽度,除非它超过固定阈值,方法是将的定义更改为

\NewDocumentCommand{\periodsep}{}
 {%
  \ifdim\fontcharwd\font"00B7>.3em % threshold value
    \makebox[.25em]{\symbol{"00B7}}%
  \else
    \symbol{"00B7}%
  \fi
 }

相关内容