One of our clients is expanding to eastern Europe, here’s how we used Prawn’s fallback_fonts to adapt their PDF reports to show properly names used in those countries.

What is Prawn?

As you may probably know already, Prawn is a gem used to create PDF files in a very flexible way. It comes with 14 fonts out-of-the box, which are the standard 14 fonts. And also, contains DejaVu, Dustismo Roman and Panic Sans, as extra fonts.

The problem

By default, Prawn renders text using the Helvetica font, which supports a limited set of characters. So, when trying to render names with extended Unicode characters, like “Čedomir”, we’ll get an underscore “_” instead of the first capital letter.

Using fallback fonts

As changing the font for the whole document to say, DejaVu Sans was not an acceptable option, we had to rely on using it as a fallback font, in a way that when Prawn tried to render a non supported character with Helvetica, it would use the DejaVu font instead.

To do this, you need to do two things. First, load on your pdf generator file the font you want to use:

class PdfDocument < Prawn::Document
  def initialize()
    ...

    font_families["DejaVu"] = {
      normal: {
        :file => "#{Prawn::DATADIR}/fonts/DejaVuSans.ttf",
        :font => "DejaVu"
      }
    }

    ...
  end

  ...
end

Note that if you are using an old version of Prawn, you’ll have to use Prawn::BASEDIR}/data/fonts/DejaVuSans.ttf instead.

Then, when you need to render text, use the fallback_fonts option:

text("some text", fallback_fonts: ["DejaVu"])

And the unsupported characters will be shown in a different font, instead of showing and underscore.

Using fallback fonts globally

If you need the fallback fonts to work across your whole document to avoid having to edit all your calls to text, or if you need print data on a table, you can set the fallback fonts globally, just like this:

class PdfDocument < Prawn::Document
  def initialize()
    ...

    font_families["DejaVu"] = {
      normal: {
        :file => "#{Prawn::DATADIR}/fonts/DejaVuSans.ttf",
        :font => "DejaVu"
      }
    }

    ...
  end

  def fallback_fonts
    ["DejaVu"]
  end

  ...

  private

  ...
end

And leave your calls to text as they were before:

text("some text")

This way, the public method fallback_fonts will be automatically used by Prawn on every text rendering it does (even on tables!), saving you a lot of work and trouble.

Picture by ALpha at Flickr