Posted by Seamus on Thursday, October 06, 2011.

Stamp PDFs with Prawn and Pdftk

In order to generate PDFs with a standard template, Brighter Planet uses a combination of Prawn and Pdftk.

First, we generate the content pages:

screenshot of PDF generated by Prawn (page 1) screenshot of PDF generated by Prawn (page 2)

Here’s what the code for that looks like:

require 'prawn'
Prawn::Document.generate('content.pdf', :top_margin => 126, :right_margin => 72, :bottom_margin => 72, :left_margin => 72) do |pdf|
  pdf.text "Sustainability report for Acme", :size => 18
  pdf.move_down 12
  pdf.text "Executive summary", :style => :bold
  pdf.move_down 12
  pdf.text "Lorem ipsum"
  pdf.start_new_page
  pdf.text "Analysis"
  pdf.move_down 12
  pdf.table([['Lorem', 'ipsum'], ['sit', 'amet']], :width => 468, :header => true)
  pdf.number_pages "Page <page> of <total>", :at => [432, -4], :width => 100
end

Then we apply our standard template:

screenshot of blank Brighter Planet template

Which creates the final product (94Kb):

screenshot of completed sustainability report (page 1) screenshot of completed sustainability report (page 2)

Here’s the Pdftk command to do that:

pdftk content.pdf stamp template.pdf output final.pdf

Final code

require 'prawn'
Prawn::Document.generate('content.pdf', :top_margin => 126, :right_margin => 72, :bottom_margin => 72, :left_margin => 72) do |pdf|
  pdf.text "Sustainability report for Acme", :size => 18
  pdf.move_down 12
  pdf.text "Executive summary", :style => :bold
  pdf.move_down 12
  pdf.text "Lorem ipsum"
  pdf.start_new_page
  pdf.text "Analysis"
  pdf.move_down 12
  pdf.table([['Lorem', 'ipsum'], ['sit', 'amet']], :width => 468, :header => true)
  pdf.number_pages "Page <page> of <total>", :at => [432, -4], :width => 100
end

require 'posix/spawn'
::POSIX::Spawn::Child.new 'pdftk', 'content.pdf', 'stamp', 'template.pdf', 'output', 'final.pdf'

Why not use Prawn’s native :template option?

Prawn currently can’t automatically apply a template to every page.

You could force it:

Prawn::Document.generate('bigger_and_dirtier_final.pdf', [...], :template => 'template.pdf') do |pdf|
  # [...]
  pdf.start_new_page :template => 'template.pdf'
  # [...]
end
  • This is not practical for multi-page tables because you don’t control when new pages start.
  • The resulting PDF is 200% bigger (180Kb) because the template data is duplicated for every page.
  • Prawn’s text rendering seems less reliable when using a template. For example, pdf.text "This should be bold", :style => :bold sometimes won’t work (sorry for not reproducing that behavior in my example, didn’t have time.)
  • Finally you may run into problems with Adobe Reader.

Bottom line: Pdftk is more efficient and reliable than the current version of Prawn for stamping templates.

What blog is this?

Safety in Numbers is Brighter Planet's blog about climate science, Ruby, Rails, data, transparency, and, well, us.

Who's behind this?

We're Brighter Planet, the world's leading computational sustainability platform.

Who's blogging here?

  1. Patti Prairie CEO