Archive for October, 2006

Ruby pdf-writer 1.1.3 and embedding fonts

Tuesday, October 17th, 2006

I’ve been working with some interesting stuff with Ruby and PDF generating lately at work. This includes Ruby code reading one standard file format (used ie. for printing invoices by print houses here in Finland) and then converting that file format into similar looking PDF with pdf-writer Ruby library. we already had invoice generating in that file format and those print houses aren’t too good in providing services for PDF invoices if you want to archive or send PDF invoices, so we ended up using the same file and that makes invoice layout maintaining a lot easier.

Only problem with that above is that print houses provide standard and custom made layout templates which contain static graphical elements for the printed pages. Only the content text with few control codes are in the file format itself. Due this I also created small application for reading SVG files with Ruby REXML, converting the SVG files into structured arrays and hashes. From there the application writes it into Ruby code file which contains code lines for reproducing the SVG graphics in PDF with pdf-writer. So it’s sort of svg to pdf-writer rb converter. This static approach was decided for better performance. There’s no point parsing and converting the svg each time we need the static graphical elements.

The SVG converter supports about 70-80% of SVG specifications, which is all the basic stuff including the path curves for more complex graphics. This makes it possible to use other PDF files (when converted into SVG) or Adobe Illustrator (application I use here at work for vector graphics) to create invoice layouts.

Unfortunately I cannot share any of that, even if I wanted to, because that has been made during my work time.

However there’s something I can share to contribute something for all pdf-writer users. That is some help on embedding TrueType/OpenType and Type1 fonts. I had lots of troubles doing that and I did some debugging with Adobe Illustrator written PDF files and other PDF files. I had to dig the pdf-writer source code as well to see what’s going on. Not to mention the requirement for the AFM files. When I got some PDF files out I was just getting the famous “The font contains a bad /BBox” error message and it was so frusturating when the pdf-writer manual was incomplete on this matter.

Today I’m much wiser on those issues. I even had to do some changes for the pdf-writer source code to get the font-embedding to work properly. In addition to the changes I found perfect OpenSource tool called TTF2PT1 for creating the AFM/PFB files of TrueType fonts. There’s also link for downloading Windows binaries, which was great time saver for me.

First apply the patch to your pdf-writer. The patch includes replacements for the two changed files and diff files if you want to use patch instead of just replacing the files. What I changed is how the font files are handled. There even was a syntax error in the pdf-writer preventing the font embedding from working. In addition the TrueType license checking code was not working properly, atleast on the fonts I tried, so I removed that check from the code. Just make sure you’re using fonts which you are allowed to embed into your PDF files.

What the pdf-writer manual did not mention is the fact that the font files need to be renamed to same name as the FontName data in the AFM file. It just does not work unless you do that. Also the select_font() call takes the file name as parameter. My pdf-writer patch fixes select_font() a bit so you don’t have to give the .afm extension of the file name when using select_font(). That was also something the pdf-writer manual decided not to tell us.

The pdf-writer manual does tell that you need the AFM files (the PDF specification requires that information and pdf-writer doesn’t know how to extract this info by itself). You can use the TTF2PT1 program to convert TTF file into pair of AFM and PFB files. pdf-writer does prefer the PFB over TTF file if you have both in the fonts directory. To setup the fonts directories you can use the following code:

PDF::Writer::FONT_PATH << "./fonts"
PDF::Writer::FontMetrics::METRICS_PATH << "./fonts"

I prefer this, so I can have application specific font files. Copy your TTF font file(s) into that directory and use the following command to convert the font into AFM and PFB file pair:

ttf2pt1 -GFA -b -p ttf myfontfile.ttf

The open the AFM file into text editor and see the line starting with “FontName”. Take the font name and rename the 3 files with that name. For example if you had font “SF Movie Poster.ttf” you’d get files “SFMoviePoster.ttf”, “SFMoviePoster.pfb” and “SFMoviePoster.afm” because the AFM file has line “FontName SFMoviePoster”. As far I as I know the FontName should never contain spaces.

Now in pdf-writer you use this font name with select_font() method. For example:

pdf = PDF::Writer.new(:paper => "A4")
pdf.fill_color Color::RGB::Black
pdf.stroke_color Color::RGB::Black
pdf.select_font "SFMoviePoster"
pdf.add_text 10, 200, "Text with embedded font."
pdf.save_as "test.pdf"

And that’s about it. The generated PDF should open in Acrobat Reader without any error messages and the text is written with the given font. Also the font is shown as embedded font in the Acrobat document properties.