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.
128
(which may or may not be because of its Boldness). – Sharpshooter