TrueType 字体的 StemV 值

StemV value of the TrueType font

我正在将 TrueType 字体嵌入到 pdf 中,因此需要为其创建描述符字典。 必填字段中有 StemV,我还没有找到 ttf 中存储此信息的位置。 我想我在某处看到了它是 CVT 程序的一部分的提示,但没有具体说明。

所以,我的问题是如何找出给定 TrueType 字体的 StemV 值。我想直接从 ttf 文件中读取这个值(而不是使用 ie windows API),因为我想编写跨平台解决方案。


更新:

Grep-ed LibreOffice 5.1.0.3 源,似乎在导出为 pdf 时,FontDescriptor 是在 vcl/source/gdi/pdfwriter_impl.cxx 中生成的,方法 PDFWriterImpl::emitFontDescriptor()。在那里,大约第 3888 行是以下代码:

// According to PDF reference 1.4 StemV is required
// seems a tad strange to me, but well ...
aLine.append( "\n"
              "/StemV 80\n" );

现在的问题是为什么是 80,而不是 42?不过说真的,如果像 LibreOffice 这样的项目使用硬编码常量,这似乎表明该值要么没有存储到字体文件中,要么读取它的成本非常高(即需要实现 TrueType 字体引擎来解释字体程序)。

顺便说一句,对于那些想知道这个 StemV 是什么的人 - 在“PDF 参考 第六版”,描述为 "The thickness, measured horizontally, of the dominant vertical stems of glyphs in the font".

根据 ISO 32000-1:2008,虽然 StemH 是可选的,但 StemV 是必需的(参见 Table 122)。 las,对于从哪里获取这些数据似乎没有明确的共识。

该变量可能源自 Adob​​e 的原始 Type 1 (CFF) 字体格式:

The entry StdVW is an array with only one real number entry expressing the dominant width of vertical stems (measured horizontally in character space units). Typically, this will be the width of straight stems in lower case letters. (For an italic font program, give the width of the vertical stem measured at an angle perpendicular to the stem direction.) For example:

/StdVW [85] def

(Adobe Type 1 字体格式,1993 年 2 月,版本 1.1,第 42 页)

这是 /Private CFF 字体字典中的一个可选条目。

但是,Werner Lemberg 表示 (http://blog.gmane.org/gmane.comp.fonts.freetype.devel/month=20130601)

The StemV value is not used by the PDF engine if the embedded font is either a Type 1 or CFF font; in that case the value from the private dictionary gets used. For a CID font, the value associated with the glyph's font DICT gets used.

In case there is no StemV value in the PDF, the following algorithm applies ...

这增加了混乱,因为它在 PDF 规范中被标记为 "Required"。

其他一些工具包的尝试

Apache FOP 注释在其 'goals' 下 Fonts

.. if [important], parse the .pfb file to extract it when building the FOP xml metric file ..

(http://www.cs.helsinki.fi/group/xmltools/formatters/fop/fop-0.20.5/build/site/dev/fonts.html)

PDFLib 使用 FreeType,并且 header 文件 ft_font.h 包含一个列表:

 +---------------------------------------------------------------------------+
Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. |
 +---------------------------------------------------------------------------+
(.. omitted..)    

/*
 * these defaults are used when the stem value
 * must be derived from the name (unused)
 */
#define FNT_STEMV_MIN        50     /* minimum StemV value */
#define FNT_STEMV_LIGHT      71     /* light StemV value */
#define FNT_STEMV_NORMAL    109     /* normal StemV value */
#define FNT_STEMV_MEDIUM    125     /* mediumbold StemV value */
#define FNT_STEMV_SEMIBOLD  135     /* semibold StemV value */
#define FNT_STEMV_BOLD      165     /* bold StemV value */
#define FNT_STEMV_EXTRABOLD 201     /* extrabold StemV value */
#define FNT_STEMV_BLACK     241     /* black StemV value */

注意 "unused"。此列表也仅出现在旧版本的 FreeType 中。

PrawnPDF 只是说 (http://prawnpdf.org/docs/0.11.1/Prawn/Font/TTF.html)

stemV()
not sure how to compute this for true-type fonts...

Apache FontBox 中的 TrueType 嵌入器做出有根据的猜测:

// StemV - there's no true TTF equivalent of this, so we estimate it
fd.setStemV(fd.getFontBoundingBox().getWidth() * .13f);

(https://pdfbox.apache.org/download.cgi) - 我觉得我必须补充一点,总比没有好,但差距很小。对于大多数字体,词干宽度和边界框之间的关系并不是这么简单。还有一些著名的字体会变胖 "inwards",因此它们的边界框实际上具有完全相同的值。

进一步的搜索让我回到了 1998 年的 UseNet post:

.ttf tables, and PDF's StemV value

From: John Bley
Date: Tue, 16 Jun 1998 17:09:19 GMT
When embedding a TrueType font in PDF, I require a vertical stem width value - I can get all the other values (ascent, descent, italic angle, etc.) that I need from various .ttf tables, but I can't seem to locate or calculate the average or normal vertical (or horizontal) stem width anywhere. By watching an embedded PDF font, I know that the "hint" in the 'OS/2' table is not enough - it's a highly precise value, not a 1-10 kind of scale. Any clues? Thanks for your time!

The value is not in TrueType fonts. You have to calculate it by analysis of, say, the cap I glyph. Don't worry too much about putting in a precise value: the value will only ever be used if the font is not present with the PDF file, when a vaguely similar font will be used instead. -- Laurence

(http://www.truetype-typography.com/ttqa_1998.htm)

“'OS/2' table”提示大概是 usWeightClass。虽然它的值定义在 100 到 900 的范围内,但这不是一个连续的范围。只使用了整个第 100 个,因此它是 1-9 的比例(不是上面问题中提到的 1-10)。比例源自 Microsoft 的字体定义,它只有这 9 个不同的值。 (请注意,ft_font.h 文件仅列出了 8 个预定义的词干值。这是另一个问题。)


(不确定的)InDesign 测试

我使用 Adob​​e InDesign CS4 创建了一个小型测试 PDF,使用字体 Aller 的浅色、常规和粗体,以及 Arial 的常规、粗体和黑色字体(这些都是 TTF 字体),发现 InDesign 写出StemV 的 as

Aller-Light      68
Aller-Regular   100
Aller-Bold      144
Arial            88
Arial-Bold      136
Arial-Black     200

这表明 InDesign 使用某种试探法来计算每个单独字体的词干宽度,而不依赖于基于 table 的固定权重。不像"the width of an uppercase 'I'"那么简单,分别是69、102、147(Aller)和94.7、144.5、221.68(Arial)设计单位。我特意使用无衬线字体进行了测试,因为衬线字体上的衬线需要估计字形中间某处的宽度。

我使用 InDesign CC 2014 导出相同的文档并获得完全相同的值。对于如何找出 InDesign 从何处获取这些值,我没有进一步的想法。

(稍后补充:)Minion Pro 是 CFF 风格的 OpenType 字体,因此它可能包含有效的 StdVW 值。经过测试,我发现确实如此:79 StdVW。非常值得注意:InDesign 使用此值,而是将其导出为 /StemV 80。 Minion Pro Bold 的值,128, 正确的,但在这一点上,我肯定这可能纯属巧合。由于这两个已经不同,我没有进一步的动机去检查 Minion Pro Semibold 或 Minion Black。


TL、DR 摘要:

  • 如果您嵌入的是 Type 1 (CFF) 字体,您可以随意填写任何内容,实际值将从字体数据中读取
    • ...除非它不在那里。
  • 如果要嵌入 TrueType 字体,则需要提供合适的值。

最差的解决方案似乎是从 OS/2 header 中读取 usWeightClass 并将其直接映射到合理的值。

这是 PDFLib 实际使用的: (来自:https://fossies.org/dox/PDFlib-Lite-7.0.5p3/ft__font_8c_source.html

#define FNT_STEMV_WEIGHT 65.0
#define FNT_STEMV_MIN 50
fnt_weight2stemv(int weight)
{
    double w = weight / FNT_STEMV_WEIGHT;
    return (int) (FNT_STEMV_MIN + w * w + 0.5);
}

据推测,使用的 'weight' 参数将是 'OS/2'.usWeightClass