13

What I'm trying to do is generate a PDF using Prawn, while having some language specific characters.

And as a result I'm getting the following error:

raise Prawn::Errors::IncompatibleStringEncoding,
   "Your document includes text that's not compatible with the  Windows-1252 character set.\n" \
   "If you need full UTF-8 support, use TTF fonts instead of PDF's built-in fonts\n."

So I tried changing the font by doing this:

# app/models/prawn/change_font_decorator.rb

Prawn::Document.generate("output.pdf") do
  font_families.update("Arial" => {
    :normal => Rails.root.join("app/assets/fonts/OpenSans-Regular.ttf"),
    :italic => Rails.root.join("app/assets/fonts/OpenSans-Regular.ttf"),
    :bold => Rails.root.join("app/assets/fonts/OpenSans-Regular.ttf"),
    :bold_italic => Rails.root.join("app/assets/fonts/OpenSans-Regular.ttf")
  })
  font "Arial"
end

Yet, I'm getting the same error when trying to generate a PDF file.

Any ideas on how to solve this?

oxfist
  • 749
  • 6
  • 22
Catalin
  • 811
  • 2
  • 8
  • 18

4 Answers4

31

The prawn manual is an excellent reference, and includes sections on font usage. The "External Fonts" section is particularly relevant to your issue.

Here's a basic case that should work, although it doesn't support bold and italic:

Prawn::Document.generate("output.pdf") do
  font Rails.root.join("app/assets/fonts/OpenSans-Regular.ttf")
  text "Euro €"
end

To also use bold and italic, it's best to register a font family that doesn't conflict with one of the standard PDF fonts:

Prawn::Document.generate("output.pdf") do
  font_families.update("OpenSans" => {
    :normal => Rails.root.join("app/assets/fonts/OpenSans-Regular.ttf"),
    :italic => Rails.root.join("app/assets/fonts/OpenSans-Regular.ttf"),
    :bold => Rails.root.join("app/assets/fonts/OpenSans-Regular.ttf"),
    :bold_italic => Rails.root.join("app/assets/fonts/OpenSans-Regular.ttf")
  })
  font "OpenSans"
  text "Euro €"
end

Where do I put the above code?

If you are inheriting from Prawn::Document you can try out the following:

class SpreeInvoicePdf < Prawn::Document
  require 'prawn'

  def initialize(quote, line_items)
    self.font_families.update("OpenSans" => {
                                :normal => Rails.root.join("vendor/assets/fonts/Open_Sans/OpenSans-Regular.ttf"),
                                :italic => Rails.root.join("vendor/assets/fonts/Open_Sans/OpenSans-Italic.ttf"),
                                :bold => Rails.root.join("vendor/assets/fonts/Open_Sans/OpenSans-Bold.ttf"),
                                :bold_italic => Rails.root.join("vendor/assets/fonts/Open_Sans/OpenSans-BoldItalic.ttf")
    })

    font "OpenSans"

  # etc.

You will of course need to go to Google fonts and download the fonts and place it in the vendor/assets/fonts/Open_Sans/ directory.

BenKoshy
  • 33,477
  • 14
  • 111
  • 80
James Healy
  • 14,557
  • 4
  • 33
  • 43
  • 1
    How to implement that in table cell? – Abdelkrim Tabet Aoul Feb 22 '18 at 08:37
  • Your answer totally solved a problem I that I have been tearing my head over for two weeks. Your second paragraph specifically. The key is to map all fontfaces to "regular". In my case, I was mapping ":normal" to "regular", ":bold" to "bold", etc, and was totally at a loss what I was doing wrong. Thanks!!! – Chidozie Nnachor May 08 '19 at 21:38
3

If you're building your PDF using initialize, you can simply update your font families in the initialize method and then set the desired font.

class InvoicePdf < Prawn::Document

  def initialize()
    super()
    self.font_families.update("DejaVuSans" => {:normal => "#{Rails.root}/public/DejaVuSans.ttf"})
    font "DejaVuSans"
    business_logo
    invoice_items
    footer
  end

  def business_logo
    ##stuff here
  end

end
Patrick Jones
  • 51
  • 1
  • 6
  • How can one go about using a default font? I get the same error but I'm not setting any font `Prawn::Document.new(page_size: 'LETTER', margin: 0)` – Steven Aguilar Feb 05 '19 at 17:16
0

If you want to change the default font in the entire document, then clear the font_families first and add yours. Prawn has its own set of default fonts which will fall back to it after you change the font using @doc.font. The code below clears the 3 font families that Prawn has as fallback and leave only your default font which forces it to use it as true "default".

Prawn::Document.generate(filename) do |doc|
   doc.font_families.clear
   doc.font_families.update(
     "DejaVuSans" => {
        :bold => Rails.root.join("app/assets/font/DejaVuSans-Bold.ttf"),
        :italic => Rails.root.join("app/assets/font/DejaVuSansOblique.ttf"),
        :normal => Rails.root.join("app/assets/font/DejaVuSans.ttf"),
     }
    )
    # more code
end
Abraham
  • 311
  • 2
  • 8
-2

I actually went into the gems folder and into Prawn/font.rb.

I found the following function:

def font_families
  @font_families ||= Hash.new { |h,k| h[k] = {} }.merge!(
    { "Courier"     => { :bold        => "Courier-Bold",
                         :italic      => "Courier-Oblique",
                         :bold_italic => "Courier-BoldOblique",
                         :normal      => "Courier" },

      "Times-Roman" => { :bold         => "Times-Bold",
                         :italic       => "Times-Italic",
                         :bold_italic  => "Times-BoldItalic",
                         :normal       => "Times-Roman" },

      "Helvetica"   => { :bold         => "Helvetica-Bold",
                         :italic       => "Helvetica-Oblique",
                         :bold_italic  => "Helvetica-BoldOblique",
                         :normal       => "Helvetica" }              
    })
end

I edited it to include Arial:

def font_families
  @font_families ||= Hash.new { |h,k| h[k] = {} }.merge!(
    { "Courier"     => { :bold        => "Courier-Bold",
                         :italic      => "Courier-Oblique",
                         :bold_italic => "Courier-BoldOblique",
                         :normal      => "Courier" },

      "Times-Roman" => { :bold         => "Times-Bold",
                         :italic       => "Times-Italic",
                         :bold_italic  => "Times-BoldItalic",
                         :normal       => "Times-Roman" },

      "Helvetica"   => { :bold         => "Helvetica-Bold",
                         :italic       => "Helvetica-Oblique",
                         :bold_italic  => "Helvetica-BoldOblique",
                         :normal       => "Helvetica" },

            "Arial" => { :normal => "public/fonts/arial.ttf",
                          :italic => "public/fonts/ariali.ttf.ttf",
                          :bold => "public/fonts/arialbd.ttf",
                          :bold_italic => "public/fonts/arialbi.ttf"}              
    })
end

and viola! it worked!

AZB
  • 7
  • 4