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.
Hello!
I’ve tried your approach but i get the error ‘Render and/or redirect were called multiple times in this action.’ on the line of send_data.
I’m using Rails 3, do you know what can be wrong?
Thanks!
Randy, thank you for this excellent help. I am running into a problem with the Websnap library and so far have not received a response from the author (although it has not been 24 hours; I am on a deadline).
When I do WebSnap::Snapper.new (args) I get “private method `chomp’ called for nil:NilClass”. Have you encountered this and if so, how did you get around it?
Thanks for any help you can provide.
Scott
Scott, I am not sure about that without seeing the code. Also, my example is going WebSnap.new, not Websnap::Snapper.new. Could that be part of the issue?
Randy, thank you for the response. I went to the Websnap::Snapper.new thing as part of my troubleshooting and forgot to revert. I have added the code below. Also, I forgot to mention that I am coding this on Windows (long story) and I suspect that the issue may be because I cannot find wkhtmltoimage-proxy in the path… even though the path is set.
format.png { # pulled from http://www.randygirard.com/…
html = render :action => “show.html.erb”, :layout => “application.html.erb”
Rails.logger.debug(“html: ” + html.inspect)
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 => “dashboard.png”, :type => “image/png”, :disposition => ‘inline’
}
Somebody has fix the issue?
‘Render and/or redirect were called multiple times in this action.’ on the line of send_data
Thanks
to avoid double rendering, call render_to_string instead of render