我正在编写一个需要提取某些字形尺寸的包。该包将支持 xelatex 和 lualatex。在我的测试中,xelatex 始终通过其 \XeTeXglyphbounds 接口返回准确的字形尺寸。Lualatex 提供的解决方案这里不会返回 .ttf 文件的准确字形尺寸,但会返回 .otf 文件的准确字形尺寸。以下是您需要亲自查看的两个文件:
sidebearings.lua(在代码顶部添加了一些内容这里):
--- sidebearings.lua
packagedata = packagedata or { }
packagedata.sidebearings = { }
local sidebearings = packagedata.sidebearings
local utfbyte = utf.byte
local texsprint = tex.sprint
local get_sidebearings = function (id, char)
local tfmdata = font.getfont (id)
if not (tfmdata and tfmdata.shared) then
return 0, 0
end
local descriptions = tfmdata.shared.rawdata.descriptions
local glyphdata = descriptions [char]
if not glyphdata then
--- font lacks the glyph
return 0, 0, 0, 0
end
local boundingbox = glyphdata.boundingbox
local lside = boundingbox [1] or 0
local wd = boundingbox [3] or glyphdata.width
local rside = glyphdata.width - wd
local tside = glyphdata.height or 0
local bside = glyphdata.depth or 0
--- If you would like to print the values to terminal
inspect (glyphdata)
return lside / 100, rside / 100, tside / 100, bside / 100
end
local sidebearings = function (id, char, side)
char = utfbyte (char)
local lside, rside, tside, bside = get_sidebearings (id, char)
if side == "left" then
texsprint (tostring (lside), "pt")
elseif side == "right" then
texsprint (tostring (rside), "pt")
elseif side == "top" then
texsprint (tostring (tside), "pt")
elseif side == "bottom" then
texsprint (tostring (bside), "pt")
end
end
packagedata.sidebearings.left = function (char)
return sidebearings (font.current (), char, "left")
end
packagedata.sidebearings.right = function (char)
return sidebearings (font.current (), char, "right")
end
packagedata.sidebearings.top = function (char)
return sidebearings (font.current (), char, "top")
end
packagedata.sidebearings.bottom = function (char)
return sidebearings (font.current (), char, "bottom")
end
和主文件 sidebearings.tex:
\documentclass[notitlepage,letterpaper]{article}
\usepackage[letterpaper,left=0in,right=0in,top=0in,bottom=0in]{geometry}
\usepackage{fontspec}
\usepackage{microtype}
\ifdefined \directlua
\directlua {require "sidebearings"}
\def \lsidebearing #1{%
\directlua {packagedata.sidebearings.left [[#1]]}%
}
\def \rsidebearing #1{%
\directlua {packagedata.sidebearings.right [[#1]]}%
}
\def \tsidebearing #1{%
\directlua {packagedata.sidebearings.top [[#1]]}%
}
\def \bsidebearing #1{%
\directlua {packagedata.sidebearings.bottom [[#1]]}%
}
\else
\def \lsidebearing #1{%
\ifnum\the\XeTeXcharglyph\expandafter`#1=0
0pt%
\else%
%\number \XeTeXglyphbounds1 \the \XeTeXcharglyph`#1 sp% %for output in unit sp
\the \XeTeXglyphbounds1 \the \XeTeXcharglyph\expandafter`#1%
\fi%
}
\def \rsidebearing #1{%
\ifnum\the\XeTeXcharglyph\expandafter`#1=0
0pt%
\else%
\the \XeTeXglyphbounds3 \the \XeTeXcharglyph\expandafter`#1%
\fi%
}
\def \tsidebearing #1{%
\ifnum\the\XeTeXcharglyph\expandafter`#1=0
0pt%
\else%
\the \XeTeXglyphbounds2 \the \XeTeXcharglyph\expandafter`#1%
\fi%
}
\def \bsidebearing #1{%
\ifnum\the\XeTeXcharglyph\expandafter`#1=0
0pt%
\else%
\the \XeTeXglyphbounds4 \the \XeTeXcharglyph\expandafter`#1%
\fi%
}
\fi
\setmainfont{Verdana}% switch to Aleo-Regular when testing Aleo
\def \test #1{[#1] left: \lsidebearing {#1}, right: \rsidebearing {#1}, bottom: \bsidebearing {#1}, top: \tsidebearing {#1}\par}
\begin{document}
\thispagestyle{plain}
\test a
\test b
\test y
\test z
\test а
\test б
\test ю
\test я
\fontname\font
\end{document}
我使用>> xelatex sidebearings.tex
和运行了此代码>> lualatex sidebearings.tex
针对多个 .otf 和 .ttf 字体。从下面的屏幕截图可以看出,xelatex 和 lualatex 对 .otf 字体 Aleo 返回相同的值可在此处免费获取以及 .ttf 字体 Verdana 的不同值(通常作为系统字体免费提供)。在这两种情况下,xelatex 都是准确的,lualatex 对于 .ttf 文件是不准确的。据我观察,.ttf 文件的字形尺寸总是正确值的 2.05 倍左右,但我不确定这是否适用于所有字体。sidebearings.lua 文件是否缺少一个 if 语句,该语句确保将 .ttf 字体的尺寸除以某个因子?
答案1
问题在于除以 100:该值以字体单位表示。1 个字体单位相当于字体大小除以tfmdata.units_per_em
。对于 OTF 字体,这通常是 1000,字体大小为 10pt,因此系数为 10pt/1000=1/100。您无需对此进行硬编码,而是使用实际值:
--- sidebearings.lua
packagedata = packagedata or { }
packagedata.sidebearings = { }
local sidebearings = packagedata.sidebearings
local utfbyte = utf.byte
local texsprint = tex.sprint
local get_sidebearings = function (id, char)
local tfmdata = font.getfont (id)
if not (tfmdata and tfmdata.shared) then
return 0, 0
end
local descriptions = tfmdata.shared.rawdata.descriptions
local glyphdata = descriptions [char]
if not glyphdata then
--- font lacks the glyph
return 0, 0, 0, 0
end
local boundingbox = glyphdata.boundingbox
local lside = boundingbox [1] or 0
local wd = boundingbox [3] or glyphdata.width
local rside = glyphdata.width - wd
local tside = glyphdata.height or 0
local bside = glyphdata.depth or 0
local factor = tfmdata.size / tfmdata.units_per_em
--- If you would like to print the values to terminal
inspect (glyphdata)
return lside * factor, rside * factor, tside * factor, bside * factor
end
local sidebearings = function (id, char, side)
char = utfbyte (char)
local lside, rside, tside, bside = get_sidebearings (id, char)
if side == "left" then
texsprint (tostring (lside), "sp")
elseif side == "right" then
texsprint (tostring (rside), "sp")
elseif side == "top" then
texsprint (tostring (tside), "sp")
elseif side == "bottom" then
texsprint (tostring (bside), "sp")
end
end
packagedata.sidebearings.left = function (char)
return sidebearings (font.current (), char, "left")
end
packagedata.sidebearings.right = function (char)
return sidebearings (font.current (), char, "right")
end
packagedata.sidebearings.top = function (char)
return sidebearings (font.current (), char, "top")
end
packagedata.sidebearings.bottom = function (char)
return sidebearings (font.current (), char, "bottom")
end
\documentclass[notitlepage,letterpaper]{article}
\usepackage[letterpaper,left=0in,right=0in,top=0in,bottom=0in]{geometry}
\usepackage{fontspec}
\usepackage{microtype}
\ifdefined \directlua
\directlua {require "sidebearings"}
\def \lsidebearing #1{%
\the\dimexpr\directlua {packagedata.sidebearings.left [[#1]]}\relax%
}
\def \rsidebearing #1{%
\the\dimexpr\directlua {packagedata.sidebearings.right [[#1]]}\relax%
}
\def \tsidebearing #1{%
\the\dimexpr\directlua {packagedata.sidebearings.top [[#1]]}\relax%
}
\def \bsidebearing #1{%
\the\dimexpr\directlua {packagedata.sidebearings.bottom [[#1]]}\relax%
}
\else
\def \lsidebearing #1{%
\ifnum\the\XeTeXcharglyph\expandafter`#1=0
0pt%
\else%
%\number \XeTeXglyphbounds1 \the \XeTeXcharglyph`#1 sp% %for output in unit sp
\the \XeTeXglyphbounds1 \the \XeTeXcharglyph\expandafter`#1%
\fi%
}
\def \rsidebearing #1{%
\ifnum\the\XeTeXcharglyph\expandafter`#1=0
0pt%
\else%
\the \XeTeXglyphbounds3 \the \XeTeXcharglyph\expandafter`#1%
\fi%
}
\def \tsidebearing #1{%
\ifnum\the\XeTeXcharglyph\expandafter`#1=0
0pt%
\else%
\the \XeTeXglyphbounds2 \the \XeTeXcharglyph\expandafter`#1%
\fi%
}
\def \bsidebearing #1{%
\ifnum\the\XeTeXcharglyph\expandafter`#1=0
0pt%
\else%
\the \XeTeXglyphbounds4 \the \XeTeXcharglyph\expandafter`#1%
\fi%
}
\fi
\setmainfont{Verdana}% switch to Aleo-Regular when testing Aleo
\def \test #1{[#1] left: \lsidebearing {#1}, right: \rsidebearing {#1}, bottom: \bsidebearing {#1}, top: \tsidebearing {#1}\par}
\begin{document}
\thispagestyle{plain}
\test a
\test b
\test y
\test z
\test а
\test б
\test ю
\test я
\fontname\font
\end{document}
(我无法添加屏幕截图,因为我没有字体)