StemV value of the TrueType font
Asked Answered
C

2

5

I'm embedding a TrueType font into pdf and thus need to create descriptor dictionary for it. Among the required fields is StemV and I haven't found where in the ttf this info is stored. I think I saw an hint somewhere that it is part of the CVT program, but nothing specific.

So, my question is how to find out the StemV value for the given TrueType font. I want to read this value from the ttf file directly (as opposed to using ie windows API) as I want to write cross-platform solution.


Update:

Grep-ed LibreOffice 5.1.0.3 source and it seems that when exporting to pdf, the FontDescriptor is generated in vcl/source/gdi/pdfwriter_impl.cxx, method PDFWriterImpl::emitFontDescriptor(). There, around line 3888 is following code:

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

The question is now why is it 80, not 42? Seriously though, if project like LibreOffice uses hardcoded constant, it seems to indicate that the value is either not stored into font file or reading it is extremely costly (ie requires implementing TrueType font engine to interpret the font program).

BTW, for those who are wondering what this StemV is - in the "PDF Reference sixth edition" it is described as "The thickness, measured horizontally, of the dominant vertical stems of glyphs in the font".

Cissoid answered 18/2, 2016 at 15:10 Comment(4)
In a random PDF exported with InDesign (Adobe's current Flagship DTP application), I found a StemV value for Minion Pro as 80 as well – which is either a marvelous coincidence or even Adobe itself does not really care about that value. FYI only, for Minion Pro Bold the value is 128 (which may or may not be because of its Boldness).Sharpshooter
@RadLexus Thanks, that's good to know. All the common readers I have tested (Acrobat Reader, Linux's doc viewer, Foxit, pdf.js) work OK without the StemV value. So it seems not to be a critical parameter indeed. But I'd like to satisfy PDF/A so I thought to see is there a way to read this value... Now your remark about "Minion Pro Bold" makes me think - perhaps the StemV value is a simple function of font's Weight class? Ie normal is 400 which translates to StemV 80. 5*128 = 640, but thats between Semi-bold (600) and Bold (700)...Cissoid
The Font Weight indeed could be a good guide. I'm at work now (and really should not be checking SO) so cannot run extensive tests, but this theory can be verified if you have a font with lots of different weights, from Ultra Thin to Extra Black and everything in between.Sharpshooter
Yep, it could result in better formula than "80 for every font it is", but it requires that some "trustworthy" pdf creator is used to gather data... unfortunately I don't have access to such a tool.Cissoid
S
12

According to ISO 32000-1:2008, while StemH is optional, StemV is required (see Table 122). Alas, there doesn't seem to be a clear consensus on where to get this data from.

The variable is probably derived from Adobe's original Type 1 (CFF) font format:

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 Font Format, February 1993, Version 1.1, p. 42)

This is an optional entry in the /Private Dictionary of a CFF font.

However, Werner Lemberg states (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 ...

which adds to the confusion, since it is marked "Required" in the PDF specs.

Some other toolkits' attempts

Apache FOP notes in its 'goals' under 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 uses FreeType, and the header file ft_font.h contains a list:

 +---------------------------------------------------------------------------+
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 */

Note the "unused". This list also only appears in older versions of FreeType.

PrawnPDF just says (http://prawnpdf.org/docs/0.11.1/Prawn/Font/TTF.html)

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

The TrueType Embedder in Apache FontBox makes an educated guess:

// 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) - where I feel I must add that it's better than nothing, but only by a very narrow margin. For most fonts, the relationship between stem width and bounding box is not this simple. There are also some famous fonts that fatten "inwards" and so their bounding boxes actually have the exact same values.

Further searching led me all the way back to a 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)

The "'OS/2' table" hint, presumably, is usWeightClass. While its values are defined in the range from 100 to 900, this is not a continuous range. Only the entire 100ths are used, and so it's a scale from 1-9 (not 1-10 as mentioned in the question above). The scale is derived from Microsoft's font definitions, which only has these 9 distinct values. (Note that the ft_font.h file only lists 8 predefined stem values. Another problem, there.)


An (inconclusive) InDesign test

Using Adobe InDesign CS4, I created a small test PDF using the font Aller in Light, Regular, and Bold, and Arial in Regular, Bold, and Black weights (these are both TTF fonts) and found InDesign writes out the StemV's as

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

This shows InDesign uses some kind of heuristics to calculate the stem width for each individual font and does not rely on a fixed weight based table. It is not as simple as "the width of an uppercase 'I'", which are 69, 102, 147 (Aller) and 94.7, 144.5, 221.68 (Arial) design units, respectively. I tested deliberately with sans serif fonts, as the serifs on a serif font would need estimating the width somewhere halfway the glyph.

I exported the same document using InDesign CC 2014 and got the exact same values. I have no further ideas on how to find out where InDesign gets these values from.

(Later addition:) Minion Pro is a CFF flavour OpenType font and so it may contain a valid StdVW value. After testing, I found it does: 79 StdVW. Quite noteworthy: InDesign does not use this value but exports it as /StemV 80 instead. The value for Minion Pro Bold, 128, is correct but, at this point, I am positive this could be pure coincidence. With these two already different, I did not have further incentive to check either Minion Pro Semibold or Minion Black.


TL,DR Summary:

  • If you are embedding a Type 1 (CFF) font, you could fill in whatever you want, and the actual value will be read from the font data
    • ... except when it's not in there.
  • If you are embedding a TrueType font, you need to supply a good value.

The least worst solution seems to be to read usWeightClass out of the OS/2 header and map this directly to a reasonable value.

Sharpshooter answered 21/2, 2016 at 23:57 Comment(3)
Impressive research, thank you very much! It seems that requiring StemV for ttf font is kind of historic accident but it has been in so many standards that now we are stuck with it... or at least they should have also standardized how to calculate this value for ttf.Cissoid
@ain: you're welcome – it was very interesting (and slightly disappointing) to find out how little actually has been done in this field. I agree that the value was probably added in a time when embedding fonts was still an exception, rather than the rule. And it's really ironic that you need to go through all of this even though your ultimate goal is to embed your fonts "the proper way".Sharpshooter
Thanks, based on your research I'm going to use the following: stemv = 10 + 220 * ( weight - 50 ) / 900. This will map widths 50-950 to some sane values. Not sure if I should still even look at BBox widths?Graminivorous
C
0

This is what PDFLib actually uses: (from: 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);
}

presumably, the 'weight' argument used will be 'OS/2'.usWeightClass

Cung answered 5/9, 2021 at 9:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.