Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

StemV value of the TrueType font

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".

like image 913
ain Avatar asked Jan 07 '23 15:01

ain


1 Answers

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.

like image 160
Jongware Avatar answered Jan 09 '23 10:01

Jongware