How to create PDF’s and Images from your website in Rails

I am going to show you how to generate both a pdf and image from a single action in a controller using the awesome, wkhtmltopdf library. This also uses PDFKit and WebSnap gems available on GitHub. This example assumes the following:

  • wkhtmltopdf and wkhtmltoimage are already installed and accessible on in the PATH.
  • You have an html page setup to display the record.
  • You have created a pdf CSS file to help display the pdf, if you so choose.
# config/initializers/mime_types.rb
Mime::Type.register "application/pdf", :pdf
Mime::Type.register "image/png", :png

# app/controllers/items_controller.rb
def show
  @item = Item.find(params[:id])
  
  respond_to do |format|
    format.html { }
    format.pdf {
      html = render(:action => "show.html.erb")
      
      kit = PDFKit.new( html, :zoom => 0.75 )
      kit.stylesheets << File.join(RAILS_ROOT,
                                   "public",
                                   "stylesheets",
                                   "pdf.css")
      
      send_data kit.to_pdf, :filename => "item.pdf",
                            :type => "application/pdf",
                            :disposition => "inline"
    }
    format.png {
      html = render :action => "show.html.erb",
                    :layout => "application.html.erb"

      # I am nil’ing these options out because my version of wkhtmltoimage does
      # not support the scale options and I do not want to crop the image.
      snap = WebSnap.new(html, :format => "png",
                               :"scale-h" => nil,
                               :"scale-w" => nil,
                               :"crop-h" => nil,
                               :"crop-w" => nil,
                               :quality => 100,
                               :"crop-x" => nil,
                               :"crop-y" => nil)

      send_data snap.to_bytes, :filename => "item.png",
                               :type => "image/png",
                               :disposition => "inline"
    }
  end
end

Now you should be able to access three distinct views, each producing a different result

http://example.com/items/1 # => Generates an html page.
http://example.com/items/1.pdf # => Generates a pdf of the html page.
http://example.com/items/1.png # => Generates a png of the html page.

You could easily also add more image types by just created another block for each format, and changing the :format to whatever one you would like.