LuaLaTeX 字形尺寸正确性取决于字体扩展

LuaLaTeX 字形尺寸正确性取决于字体扩展

我正在编写一个需要提取某些字形尺寸的包。该包将支持 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 字体的尺寸除以某个因子?

a) Aleo 常规(.otf 文件,lualatex 和 xelatex 均准确): 在此处输入图片描述

b)Verdana Regular(.ttf文件,xelatex准确,lualatex不准确): 在此处输入图片描述

答案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}

(我无法添加屏幕截图,因为我没有字体)

相关内容