Jono
Jono

Reputation: 2054

Finding glyph width in C# (private font)

In order to embed a font in a PDF, one needs to determine a set of glyph widths (for inclusion in the metadata). In order to make the calculations about the page area consumed by text as it flows, one needs to know the same information.

I am considering using C# on a web server to generate PDF documents. The fonts are not (and cannot be) installed; they can be loaded from TTF files/streams. I need to know how much of the "page" is going to be used so that I can handle text overflow correctly, and also need to provide the glyph widths if the font is to be embedded.

System.Drawing.Text.PrivateFontCollection can get me the "cell"'s ascent/descent and line spacing, which is useful for the vertical calculation, but I also need to make a horizontal calculation.

Is there a way to access a private (i.e. non-installed) font's glyph widths from C# without resorting to this: How to get glyph widths by parsing a TTF font file?

Upvotes: 2

Views: 1377

Answers (1)

Jono
Jono

Reputation: 2054

The GlyphTypeface class in System.Windows.Media (PresentationCore.dll) provides access to the advance widths in fractions of an em. PDF font descriptors require widths as integers in thousandths of an em.

using System;
using System.Windows.Media; // requires PresentationCore.dll

namespace ConsoleAppFontMetrics
{
    internal class Metrics
    {
        internal static void PrintWidths(string path)
        {
            var ffs = Fonts.GetFontFamilies(path);
            foreach (var ff in ffs)
            {
                foreach (var t in ff.GetTypefaces())
                {
                    Console.WriteLine(t.Style);
                    if (t.TryGetGlyphTypeface(out GlyphTypeface gt))
                    {
                        foreach (var ctg in gt.CharacterToGlyphMap)
                        {
                            var width = (int)Math.Round(gt.AdvanceWidths[ctg.Value] * 1000);

                            Console.WriteLine($"{(char)ctg.Key} ({ctg.Key}) Width = {width}");
                        }
                    }
                }
            }
        }
    }
}

Running the above code for my TrueType font gives me this:

Normal
a (97) Width = 1160
b (98) Width = 1663
c (99) Width = 2065

The output matches the metadata inside a previously exported PDF (from another program) with the font embedded.

8 0 obj
<<
/Type/Font
/Subtype/TrueType
/Name/F2
/BaseFont/XXXXXX
/FontDescriptor 7 0 R
/FirstChar 97
/LastChar 99
/Widths[1160 1663 2065]
>>
endobj

Upvotes: 2

Related Questions