Generate large volume of PDF files using wicked pdf Gem

Generate large volume of PDF files using wicked pdf Gem

To install and use wicked_pdf try articles like below.

Generate PDF with gem wicked_pdf
Mission: Turn any rails view into PDF. BEFORE AFTER Video…
Complete guide to generating PDFs with gem wicked_pdf
wicked_pdf - gem to generate PDF from HTML.

Here when using wicked pdf internally it uses wkhtmltopdf binary to convert HTML to PDF. When one process uses this binary others have to wait until the operation is done. When creating multiple PDF files concurrently in rails background jobs we seen it take lot of time to generate PDF.

So the idea is to move this part alone to some server-less solutions. We are using Google cloud function

The Ruby Runtime | Cloud Functions Documentation | Google Cloud

Create a folder pdf-generator and then add Gemfile

mkdir pdf-generation
cd pdf-generation
touch Gemfile
touch app.rb
# download wkhtmltopdf linux binary and put it inside this folder
source "https://rubygems.org"

# Include the Ruby Functions Framework as a dependency.
gem "functions_framework", "~> 0.5"
gem 'wicked_pdf'
gem 'pry'

Gemfile

require "functions_framework"
require "wicked_pdf"
require 'json'
require 'pry'

wk_path = if RbConfig::CONFIG['host_os'].match? /linux/
            './wkhtmltopdf_ubuntu'
          else
            './wkhtmltopdf_mac'
          end

WickedPdf.config = {
  exe_path:                 wk_path,
  enable_local_file_access: true
}

FunctionsFramework.http "create" do |request|
  json = JSON.parse(request.body.read) rescue {}
  margin_top, margin_bottom = if json['margins']
                                json['margins']
                              elsif json['header_html']
                                [60, 10]
                              else
                                [0, 0]
                              end

  header = json['header_html'] ? { content: json['header_html'] } : {}

  WickedPdf.new.pdf_from_string(
    json['body_html'],
    margin:      { top: margin_top, bottom: margin_bottom },
    header:      header,
    encoding:    'utf8',
    orientation: (json['orientation'] || 'Portrait')
  )
end

app.rb

run this command bundle exec functions-framework-ruby --target create

Inside rails app run this code

export PDF_GEN_URL=http://localhost:8080

Write this code in your application

class GeneratePdf
  include HTTParty

  def self.do(body_html, header_html = nil, margins = [], **options)
    body = { body_html: body_html }
    body.merge!(margins: margins) if margins.present?
    body.merge!(header_html: header_html) if header_html.present?
    body.merge!(**options)
    return "" if Rails.env.test?
    post("#{ENV['PDF_GEN_URL']}", body: body.to_json).response.body
  end
end

app/services/generate_pdf.rb

bundle exec rails c
 File.open("#{Rails.root}/tmp/new.pdf", 'wb') {|f| f.write(GeneratePdf.do('<p style="color: red">Hello</p>')) }

Then you host it to google cloud functions and change the url in production. Since it is autoscaled we generated upto 1,00 PDF concurrently. We generate around 200K PDF files per month which cost around less than $2 including discounts.


Notes:

It's 2024 wkhtmltopdf has been deprecated and there is also a discussion in wicked_pdf gem about this. Use it if you don't have any other choice.

Long term plans given the deprecation of wkhtmltopdf? · Issue #1081 · mileszs/wicked_pdf
Issue description I apologize if this is the wrong forum to ask in. I have searched the issues and docs, I didn’t find any sort of position on the future of this project with respect to the wkhtmlt…

Thanks for the above article authors and Thanks for reading!