如果您熟悉amsthm
,您可能知道定理的默认字体是斜体。如果您将内联数学放入定理中(或者更一般地,放入斜体文本中),它会以某种方式向左移动,这与内容仅排版为纯文本时的情况不同。
对于单独的大写字母(如)来说$U$
,这种情况尤其明显,在我看来,这在视觉上令人不悦。有没有办法修复此行为(除了将符号写成非数学字母)?也许使用某种斜体(非)校正?
这是一个非常简单的工作示例:
\documentclass{article}
\usepackage{amsmath,amsthm}
\newtheorem{theorem}{Theorem}
\begin{document}
\begin{theorem}
Consider the following:
Let $U$ and $V$ be open sets (math mode).
Let U and V be open sets (pure text).
\end{theorem}
\end{document}
正如您在输出中看到的那样,$U$
和$V$
字母相对于纯文本向左移动(如果图像太小而看不到偏移,您可以放大图像)。结果,它们后面有一个很大的间隙,在我看来看起来相当丑陋。
答案1
我很沮丧,无法修复 CM 字体的问题,因为我amsthm
经常使用,而且我喜欢普通的定理风格,希望它们的正文是斜体的。所以我尝试改进由亨德里克·沃格特在斜体文本中的数学字母间距错误。下面是一个工作示例,它依赖于定义一个新的定理样式:fixedplain
。
如果您想在使用 AMS 普通定理样式时使用以下代码来固定数学字母的位置,请注意以下几点:
\usepackage{amsthm}
你需要在使用之前和之后放置“补丁开始”和“补丁结束”之间的内容\newtheorem
- 它只会影响定理主体
- 它将尝试确定内联数学符号是否以
$...$
字母开始或结束,并应用一些水平跳过来模拟斜体文本的通常文本流,从而消除通常会出现的向左不必要的移动; - 它将尝试模仿默认字体 (cmr10) 的行为,并且可能最终导致其他字体的偏移错误(尽管如果您仅更改字体大小,它或多或少可能是正确的)。但是,请参见下文如何为其他字体生成偏移表;
- 它会错误地检测
$2^n$
以字母结尾的例如,但你可以通过使用来修复它$2^{n}$
; - 如果需要,您仍然可以通过使用来获得标准行为
\(...\)
; - 它通过
$
激活来工作。因此,它将失败:- 每当你使用
$$...$$
显示数学时(但这被认为是不好的做法,你应该避免使用它,请参阅为什么\[
…\]
比$$…$$更好?) - 如果您将 重叠起来,则可能会失败,并可能出现编译错误,
$
如果您需要在 内部进行数学运算,则可能会发生这种情况\text{...}
(尽管如此,我还是无法找到一种合理的方法,会导致有效的内联数学输入导致编译错误)。但在这种情况下,您可以使用\(
和\)
进行内部数学运算,至少可以避免错误。
- 每当你使用
\documentclass{article}
\usepackage{amsthm,xcolor}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Start of patch
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\makeatletter
\def\fix@mchar#1#2#3{%
\expandafter\edef\csname mcl@#1\endcsname{#2}%
\expandafter\edef\csname mcr@#1\endcsname{#3}%
}
\fix@mchar a{+1.168}{+0.972}\fix@mchar b{+1.199}{+0.319}\fix@mchar c{+1.162}{+0.397}
\fix@mchar d{+1.043}{+0.862}\fix@mchar e{+1.156}{+0.890}\fix@mchar f{-1.500}{+3.336}
\fix@mchar g{+0.664}{+1.127}\fix@mchar h{+0.362}{+1.194}\fix@mchar i{+0.837}{+1.250}
\fix@mchar j{-0.534}{+2.108}\fix@mchar k{+0.362}{+1.603}\fix@mchar l{+0.866}{+1.837}
\fix@mchar m{+0.863}{+1.001}\fix@mchar n{+0.863}{+0.970}\fix@mchar o{+1.158}{+0.246}
\fix@mchar p{+0.832}{+0.381}\fix@mchar q{+1.073}{+1.163}\fix@mchar r{+0.863}{+1.662}
\fix@mchar s{+0.325}{+1.037}\fix@mchar t{+0.992}{+1.401}\fix@mchar u{+0.849}{+0.904}
\fix@mchar v{+0.847}{+1.479}\fix@mchar w{+0.853}{+1.529}\fix@mchar x{+0.351}{+1.817}
\fix@mchar y{+0.826}{+1.100}\fix@mchar z{+0.230}{+1.705}\fix@mchar A{+0.132}{-0.123}
\fix@mchar B{+0.274}{+1.419}\fix@mchar C{+1.662}{+2.411}\fix@mchar D{+0.270}{+1.207}
\fix@mchar E{+0.299}{+1.712}\fix@mchar F{+0.299}{+2.078}\fix@mchar G{+1.662}{+1.334}
\fix@mchar H{+0.277}{+2.528}\fix@mchar I{+0.300}{+2.346}\fix@mchar J{+0.087}{+2.076}
\fix@mchar K{+0.280}{+2.267}\fix@mchar L{+0.277}{+0.880}\fix@mchar M{+0.301}{+2.686}
\fix@mchar N{+0.284}{+2.536}\fix@mchar O{+1.662}{+1.434}\fix@mchar P{+0.270}{+1.669}
\fix@mchar Q{+1.541}{+1.406}\fix@mchar R{+0.252}{+0.272}\fix@mchar S{+0.322}{+1.715}
\fix@mchar T{+2.385}{+2.169}\fix@mchar U{+2.377}{+2.649}\fix@mchar V{+2.417}{+3.155}
\fix@mchar W{+2.291}{+2.885}\fix@mchar X{+0.167}{+2.666}\fix@mchar Y{+2.617}{+3.323}
\fix@mchar Z{+0.254}{+2.329}
\def\get@lastchar#1#2${%
\if\relax#2\relax%
#1%
\else%
\if#2 %
#2%
\else
\get@lastchar#2$%
\fi%
\fi%
}
\def\get@firstchar#1#2${#1}
\let\math@org=$
\newlength\mylength
\def\itinlinemath#1{%
\edef\leftskip@csname{mcl@\expandafter\get@firstchar\detokenize{#1}$}%
\edef\rightskip@csname{mcr@\expandafter\get@lastchar\detokenize{#1}$}%
\math@org%
\ifcsname\leftskip@csname\endcsname%
\null\mskip\csname\leftskip@csname\endcsname mu%
\fi%
#1%
\ifcsname\rightskip@csname\endcsname%
\mskip-\csname\rightskip@csname\endcsname mu%
\fi%
\math@org%
}
\begingroup
\catcode`\$=13
\gdef\activateitalicmath{%
\catcode`\$=13%
\def${\math@org}%
\def${\math@org}%
\def$##1${\itinlinemath{##1}}%
}
\endgroup
\newtheoremstyle{fixedplain}{\topsep}{\topsep}{\itshape\activateitalicmath}{0pt}{\bfseries}{.}{5pt plus 1pt minus 1pt}{}
%Remove the following line to disable patch and restore default behavior
\theoremstyle{fixedplain}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% End of patch
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newtheorem{theorem}{Theorem}
\begin{document}
\begin{theorem}[Single letters]
If $U$ or $V$ and $X$, and $f$ from $j$. Let $T$ be $S$ if $Y$.
\end{theorem}
\begin{theorem}[Unaffected math]
If $2U^2$ or $+V_1$ and $-X\alpha$, and $\frac f2$ from $2+j^{x}$. Let $\overline{T}$ be ${{S}}$ if \(Y\).
\end{theorem}
\end{document}
这是结果(采用下面的默认行为)。
以下是各种场景的测试。
为了“模仿”斜体字体的行为并生成字母的偏移表,这是我一直在使用的 LaTeX 代码。
\documentclass{article}
\usepackage[paperheight=40cm,paperwidth=5cm,margin=0pt]{geometry}
\pagestyle{empty}
\def\refrule{\raisebox{-1ex}{\rule{2em}{4ex}}}
\def\glyph#1{%
\par%
\noindent%
{\refrule} #1 {\refrule} $#1$ {\refrule}%
}
\def\multiglyph #1#2.{
\glyph#1%
\ifx&%
\else%
\multiglyph#2.
\fi%
}
\begin{document}
\raggedright\itshape\multiglyph abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.
\end{document}
然后,该文件被以下 Python 脚本编译并转换为 png 图像(使用 imagemagick),然后该脚本将计算每个字符的近似左右偏移量。它只是实验性的,但至少它对 cmr10 有效,并且似乎能给出一致的结果。如果您想使用其他字体,只需更改上述文件的开头以加载您的字体,然后重新启动 Python 脚本。
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
import subprocess
def open_image(path):
i = Image.open(path).convert('L')
a = np.frombuffer(i.tobytes(), np.uint8).astype(np.float32)
return a.reshape((i.size[1], i.size[0]))
subprocess.run("pdflatex glyphs.tex", check = True, shell = True)
subprocess.run("convert -density 1000 glyphs.pdf glyphs.png", check = True, shell = True)
image = open_image("glyphs.png")
image[:, 0] = 255
glyph_centers = []
rule_width, rule_height = 0.0, 0
in_glyph = False
for k in range(image.shape[0]):
bounds = np.where(np.diff(image[k]))[0]
glyph_found = len(bounds) > 5
if in_glyph ^ glyph_found:
if glyph_found:
glyph_top = k
left_before, left_after, left_height, right_before, right_after, right_height = 0.0, 0.0, 0, 0.0, 0.0, 0
else:
left_before /= left_height
left_after /= left_height
right_before /= right_height
right_after /= right_height
glyph_centers.append([left_before, left_after, right_before, right_after])
in_glyph = glyph_found
if in_glyph:
lengths = (bounds - np.roll(bounds, 1))[1::2]
rules = np.sort(np.argpartition(lengths, -3)[-3:])
rule_width += np.sum(bounds[rules * 2 + 1] - bounds[rules * 2])
rule_height += 1
a, b = bounds[rules[0] * 2 + 2], bounds[rules[1] * 2 - 1]
image[k, a + 1: b + 1] = 127
if b > a:
left_before += a - bounds[rules[0] * 2 + 1]
left_after += bounds[rules[1] * 2] - b
left_height += 1
a, b = bounds[rules[1] * 2 + 2], bounds[rules[2] * 2 - 1]
image[k, a + 1: b + 1] = 127
if b > a:
right_before += a - bounds[rules[1] * 2 + 1]
right_after += bounds[rules[2] * 2] - b
right_height += 1
rule_width = rule_width / (3 * rule_height)
assert(len(glyph_centers) == 52)
k = 0
ruletoem = 2 # Rule is 2 em large
emtomu = 18 # 1em -> 18 mu
f = open("cmr10.fix","wt") #Change file name as needed
for c in "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ":
delta_before = (glyph_centers[k][0] - glyph_centers[k][2]) / rule_width * ruletoem * emtomu
delta_after = (glyph_centers[k][3] - glyph_centers[k][1]) / rule_width * ruletoem * emtomu
s = "\\fix@mchar {:}{{{:+.3f}}}{{{:+.3f}}}\n".format(c, delta_before, delta_after)
f.write(s)
k += 1
f.close()