Skip to content

Instantly share code, notes, and snippets.

@swistak
Last active January 3, 2016 06:38
Show Gist options
  • Save swistak/8423518 to your computer and use it in GitHub Desktop.
Save swistak/8423518 to your computer and use it in GitHub Desktop.
require 'fileutils'
require 'logger'
require 'erb'
# Pdf generation service based on wkhtmltopdf.
class PdfGenerator
class WkhtmltopdfError < RuntimeError; end
DPI = 96 # Pixels in inch
DPC = (DPI / 2.54) # = 37.795 Pixels in centimeter
# See http://madalgo.au.dk/~jakobt/wkhtmltoxdoc/wkhtmltopdf-0.9.9-doc.html
#
# Options without argument just take true, rest should have string as value.
# To disable option set it to false.
PDF_OPTIONS = {
'quiet' => true,
# Header is disabled.
# 'header-html' => 'header.html',
# 'footer-html' => 'footer.html',
'print-media-type' => true,
# 'disable-smart-shrinking' => true,
'page-size' => 'A4',
'margin-top' => '0.5cm',
'margin-right' => '0.5cm',
'margin-bottom' => '1cm',
'margin-left' => '0.5cm',
'encoding' => "UTF-8",
}
PDF_DIR = 'pdfs'
FileUtils.mkdir_p(PDF_DIR)
attr_accessor :error_message
attr_accessor :note
def logger
defined?(Rails) ? Rails.logger : (@logger ||= Logger.new($stdout))
end
def pdf_options
PDF_OPTIONS
end
def note_url
'index.html'
end
def pdf_path
File.join(PDF_DIR, "ramki.pdf")
end
def wkhtmltopdf
@wkhtmltopdf ||= begin
pdf_command = [
`ls -1 bin/wkhtmltopdf* 2>/dev/null`.split("\n").last,
`which wkhtmltopdf`
].detect{|c| !c.nil? }
raise("Cannot locate wkhtmltopdf in #{Dir.pwd} or $PATH") if pdf_command.nil?
pdf_command.strip
end
end
def xvfb_wrapper
"" #'xvfb-run -s "-screen 0, 1600x1200x24"'
end
# wkhtmltopdf [OPTIONS]... <input file> [More input files] <output file>
def pdf_command
normalized_options = pdf_options.map{|k, v|
v ? "--#{k} #{v == true ? "" : v}" : nil
}.compact.join(" ")
"#{xvfb_wrapper} #{wkhtmltopdf} #{normalized_options} #{note_url} #{pdf_path}"
end
def render
File.open('index.html', 'w') do |f|
f.write ERB.new(File.read('index.html.erb')).result
end
end
# Generates a pdf.
def generate
render
perform
end
# Performs a pdf generation.
def perform
logger.debug "Running: " + pdf_command
# See http://mentalized.net/journal/2010/03/08/5_ways_to_run_commands_from_ruby/
redirection = " 2>&1"
@out = IO.popen(pdf_command + redirection, "wb+") do |pdf|
pdf.close_write
pdf.gets(nil)
end
unless $? == 0
self.error_message = "Failed to generate pdf via: #{wkhtmltopdf}. Exit code: #{$?}."
raise(WkhtmltopdfError, error_message, caller[1..-1])
end
end
end
if __FILE__ == $0
PdfGenerator.new.generate
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment