Search code examples
c++fontsghostscriptpostscript

Measure postscript font width in C++


This cannot be so hard, but I simply don't manage. Neither google nor stackoverflow or the documentation of ubuntu or ghostscript were helpful.

I am generating postscript from C++. I place the text word by word to handle line-wrap. For deciding where to place the next word and whether it fits into the current line I rely on freetype to measure the "advance" of each glyph.

The text is a mix of normal text and source code, so I have two fonts involved. I chose Helvetica for normal text and Courier for source code, since both are readily available in postscript and don't need to be embedded. The problematic part of my postscript output is not significantly more complicated than

(Helvetica) findfont 11 scalefont setfont
40 100 moveto (hello world) show
123 100 moveto (hello again) show   % I care for the first number

Of course, there is a proper eps header etc.

I did not manage to locate the font files on my ubuntu 16.04 system, so I downloaded best guesses from free font websites. It turns out that they apparently differ from those used by my postscript interpreter. At least, after converting to a PDF with epstopdf (which comes with LaTeX as far as I know), I see that my Helvetica font is too wide and my Courier font is too narrow, so that word spacing is off, up to the point that long words overlap with the subsequent word.

My question: how can I get font width measurements matching those of the postscript interpreter?

  • I am not even sure whether the question is well-posed, but somehow I do assume that there is one and only one reference Helvetica font, so that postscript output looks the same on all systems and printers.
  • Making freetype load the correct fonts would probably be the easiest solution, but I do not know how to find the files.
  • A source for downloading the exactly matching fonts would also solve the problem, although having them twice would be odd.
  • Even better, asking a postscript interpreter like ghostscript for the ground truth would be preferable, but the ghostscript library documentation is sparse and I did not find any examples.
  • I could create a postscript file that prints the width of the text obtained with textwidth, convert to a pdf, and extract the text. That would be ugly and slow, and I'd like to go for a proper C++ solution.

Progress in any of these or maybe other directions would be absolutely great!


Solution

  • The fonts you are using should have a .afm (Adobe Font Metrics) file, which you can read the font metrics from if its a PostScript font. Its also true that the 'base 13' fonts should be the same in terms of metrics across all PostScript implementations. Of course, if you are using a TrueType font to get the metrics from then they may well differ from a PostScript font.

    You haven't said what PostScript interpreter you are using, it may be that its not using a standard font, but my guess is you are using a TrueType font from your Ubuntu which doesn't quite match the PostScript ones you are using in your 'interpreter'. If memory serves you can look in /etc/fonts/fonts.conf to see where your fonts are stored.

    FWIW Ghostscript ships with implementations of the base 13 fonts which are matched to the Adobe fonts, PostScript interpreters should match those. We don't however ship the AFM files, but you can load the fonts into Fontographer, or use FreeType, or simply get the advance width by using stringwidth (not textwidth) in a PostScript program.

    I wouldn't have said Ghostscript's docuemntation is 'sparse'. Difficult to find what you want, maybe, but there's lots of documentation there. Just use.htm, the basic information, is a 265Kb HTML file.

    The final alternative, of course, is to download the fonts you are actually using in the PostScript program, then you know that they match the metrics you used to create the PostScript in the first place. As with PDF, this is highly recommended, especially for fonts outside the base 13, as its the only way to get reliable output.