DEV Community

Jonathan Hooper
Jonathan Hooper

Posted on

How to write on a PDF with Ruby using Prawn

If you’ve ever needed to programmatically add text to a PDF in Ruby, then you know how tricky it can be. PDFs are complex, and finding tools that are both effective and up-to-date can be a challenge. Many guides rely on deprecated tools or outdated information. In this post, I'll walk through a solution I came up with using two tools:

  • Prawn: The fast, nimble PDF writer for Ruby
  • CombinePDF: The Ruby gem that combines PDFs

My approach looks like this:

  1. Create a new overlay PDF with the text I want on my existing PDF using Prawn
  2. Use CombinePDF to overlay the new PDF over the existing one so the text appears in the correct spot

This two-step approach is necessary because Prawn excels at creating new PDFs but does not support modifying existing ones. Meanwhile, CombinePDF makes it easy to manipulate and merge existing PDFs. By combining these tools, you get the best of both worlds—precision in adding text and flexibility in working with existing documents.

Create a New Overlay PDF Using Prawn

Using Prawn is pretty straightforward. The Prawn manual has a bunch of helpful tips about what its PDF DSL can do. That is where you want to start to figure out how to arrange text, manipulate pages, and work with shapes.

As an example, getting things going looks like this:

document = Prawn::Document.new
document.text_box "Hello, world", at: [20, 650], width: 200
document.start_new_page
document.text_box "Some other words", at: [30, 500], width: 300
Enter fullscreen mode Exit fullscreen mode

Overlay the New PDF Over the Existing One

To overlay the new PDF, you need to take three steps:

  1. Create a base PDF to hold your result: This acts as a container for the final combined document.
  2. Load your existing PDF and add it to the base PDF: This ensures that the original content remains intact and serves as the foundation for the overlay.
  3. Add your overlay PDF to the base PDF: This step places your new content in the correct position over the existing content, completing the merge.

That all comes together to look like this:

require 'combine_pdf'
require 'prawn'

# Let's create our base PDF to hold our result
output_pdf = CombinePDF.new

# Now let's read the PDF we want to write on and add it to the result
existing_pdf = CombinePDF.load('/path/to/existing.pdf')
existing_pdf.pages.each do |existing_pdf_page|
  output_pdf << existing_pdf_page
end

# Let's use Prawn to create our overlay
overlay_document = Prawn::Document.new
overlay_document.text_box "Hello, world", at: [20, 650], width: 200

# Now we'll add the pages of our overlay PDF to our base PDF
overlay_pdf = CombinePDF.parse(overlay_document.render)
overlay_pdf.pages.each_with_index do |overlay_pdf_page, index|
  if output_pdf.pages[index]
    output_pdf.pages[index] << overlay_pdf_page
  else
    raise "Overlay PDF has more pages than the existing PDF."
  end
end

# Finally, we'll render the result
output_pdf.save('output.pdf')
Enter fullscreen mode Exit fullscreen mode

Top comments (0)