How to edit or write on existing PDF with Ruby?

27,886

Solution 1

you have to definitely check out Prawn gem, by which you can generate any custom pdf files. You can actually use prawn to write in text into existing pdfs by treating the existing PDF as a template for your new Prawn document.

For example:

filename = "#{Prawn::DATADIR}/pdfs/multipage_template.pdf"
Prawn::Document.generate("full_template.pdf", :template => filename) do
  text "THis content is written on the first page of the template", :align => :center
end

This will write text onto the first page of the old pdf.

See more here: http://prawn.majesticseacreature.com/manual.pdf

Solution 2

Since Prawn has removed the template feature (it was full of bugs) the easiest way I've found is the following:

  1. Use Prawn to generate a PDF with ONLY the dynamic parts you want to add.
  2. Use PDF::Toolkit (which wraps PDFtk) to combine the Prawn PDF with the original.

Rough Example:

require 'prawn'
require 'pdf/toolkit'

template_filename = 'some/dir/Awesome-Graphics.pdf'
prawn_filename = 'temp.pdf'
output_filename = 'output.pdf'

Prawn::Document.generate(prawn_filename) do
  # Generate whatever you want here.
  text_box "This is some new text!", :at => [100, 300]
end

PDF::Toolkit.pdftk(prawn_filename, "background", template_filename, "output", output_filename)

Solution 3

I recommend prawn for generating PDFs and then using combine_pdf to combine two generated PDFs together into one. I use it like this and it works just fine.

Short example (from the README) of how to combine two PDFs:

company_logo = CombinePDF.load("company_logo.pdf").pages[0]
pdf = CombinePDF.load "content_file.pdf"
pdf.pages.each { |page| page << company_logo } # notice the << operator is on a page and not a PDF object.
pdf.save "content_with_logo.pdf"

Solution 4

You don't need to use a combination of gems you can use just one gem!

Working with PDF's is really challenging in Ruby/Rails (so I have found out!)

This is the way I was able to add text dynamically to a PDF in rails.

add this gem to your gem file gem combine_pdf

and then you can use code like this:

# get the record from the database to add dynamically to the pdf
user = User.last

# get the existing pdf
pdf = CombinePDF.load "#{Rails.root}/public/pdf/existing_pdf.pdf"

# create a textbox and add it to the existing pdf on page 2
pdf.pages[1].textbox "#{user.first_name} #{user.last_name}", height: 20, width: 70, y: 596, x: 72

# output the new pdf which now contains your dynamic data
pdf.save "#{Rails.root}/public/pdf/output#{Time.now.to_s}.pdf"

You can find details of the textbox method here: https://www.rubydoc.info/gems/combine_pdf/0.2.5/CombinePDF/Page_Methods#textbox-instance_method

I spent days on this working through a number of different gems: prawn wicked_pdf pdfkit fillable_pdf

But this was by far the most smooth solution for me as of 2019.

I hope this saves someone a lot of time so they don't have to go through all the trial and error I had to with PDF's!!

Solution 5

The best I can think of is Rails-latex, it doesn't allow you to edit existing PDF files but it would allow you to set up template *.tex.erb which you may dynamically modify and compile them into PDF format (along with dvi and a number of others).

Share:
27,886
Hans de Wit
Author by

Hans de Wit

TL;DR: I can't complain :) I lead teams of Ruby on Rails and ReactJS developers. I feel very lucky to be at the very start of the Decisely's software division: from 1st line of code to the deployed suite of applications that help make Decisely and its wonderful people successful at their jobs. Being able to build a team of great software engineers from scratch is a privilege. https://twitter.com/ashovik https://github.com/alex-kovshovik https://shovik.com https://vindeals.ca/about

Updated on July 23, 2022

Comments

  • Hans de Wit
    Hans de Wit almost 2 years

    I have a couple of PDF template files with complex content and several blank regions/areas in them. I need to be able to write text in those blank regions and save the resulting PDFs in a folder.

    I googled for answers on this question quite intensively, but I didn't find definite answers. One of the better solutions is PDF::Toolkit, but it would require the purchase of Adobe Acrobat to add replaceable attributes to existing PDF documents.

    The PHP world is blessed with FPDI that can be used to simply open a PDF file and write/draw on it over the existing content. There is a Ruby port of this library, but the last commit for it happened at the beginning of 2009. Also that project doesn't look like it is widely used and supported.

    The question is: What is the better Ruby way of editing, writing or drawing on existing PDFs?

    This question also doesn't seem to be answered on here. These questions are related, but not really the same:

  • Hans de Wit
    Hans de Wit over 12 years
    Thank you for this answer, but editing existing PDFs is a requirement in my case. For creating new PDFs something like prawn would've worked for me...
  • Hans de Wit
    Hans de Wit over 12 years
    This indeed looks like a great tool, but since it is not open source (not free) - we'll have to consider the price. The version we can use is about $2100 - this is a lot of our low budget small project. Also this probably could not be considered a "Rails-way", since it is so expensive :) I'll probably go ahead with PDF::Toolkit and use it to populate PDF attributes values, instead of drawing on PDF. But thank you for this answer - I really appreciate it!
  • Hans de Wit
    Hans de Wit over 12 years
    Yep, I've considered it (and even listed in my question), but editing existing PDFs is a requirement for my project. Thank you for the answer.
  • Joel Meador
    Joel Meador over 12 years
    Yeah, it's always hard to bite off a cost that big in the beginning. Purchased Prince XML for making PDFs a while back, and it seemed like a lot of money at the time, but it has paid off.
  • Hans de Wit
    Hans de Wit over 12 years
    I use Prince XML for one of my other projects too - it works, but not for this case I'm trying to tackle unfortunately.
  • Sebastien
    Sebastien almost 12 years
    I have this problem, any idea? stackoverflow.com/questions/12076299/…
  • Matt Schwartz
    Matt Schwartz over 11 years
    I use exactly this method to extensively add text to existing PDFs. Why doesn't this answer work for you?
  • Michael Reinsch
    Michael Reinsch almost 10 years
    Support for templates was dropped in Prawn 0.13.0, disabled by default in 0.14.0, and extracted in 0.15.0. - from github.com/prawnpdf/prawn-templates
  • Myst
    Myst almost 9 years
    After template support was deprecated in Prawn (as detailed in @MichaelReinsch's post), I ended up writing a Ruby implementation for combining PDF files, stamping them, merging them (in sequence as well as one on top of the other), adding simple text, extracting PDF fonts and other simple tasks. This gem had been mentioned in Paweł Gościcki's answer later on: combine_pdf
  • quetzalcoatl
    quetzalcoatl about 8 years
    It's worth noticing that version "n-1" - v7 - is provided for free, with source code pdflib.com/en/download/free-software/pdflib-lite-7 - through, it is not supported. I also don't know how much "lite" is cut down on features.
  • lindes
    lindes over 6 years
    I found that this didn't work well for me, because the "logo" file (for me, it was an overall template, that I was just adding a little bit of text to) would cover up whatever I'd added (using Prawn::PDF, similar to some other answers). I found this to solve it for me, though (replacing what's inside the block on line 3 in this answer): page.replace(company_logo.copy << page)
  • Jason Swett
    Jason Swett over 5 years
    This worked for me with what I think is a clearer solution than the PDF::Toolkit route which didn't work for me.
  • Code Tree
    Code Tree about 4 years
    wow :) I don't know why there is low upvote to this answer..this should be at the top.. you have given the complete working code and an elegant solution..
  • Sami Birnbaum
    Sami Birnbaum about 4 years
    @CodeTree Thanks, glad it saved you all the pain I went through! Feel free to upvote so it can help more people!