# wkhtml2pdf Ruby interface
# http://wkhtmltopdf.org/
require 'logger'
require 'digest/md5'
require 'rbconfig'
require 'open3'
require 'ostruct'
require 'active_support/core_ext/module/attribute_accessors'
require 'active_support/core_ext/object/blank'
require 'wicked_pdf/version'
require 'wicked_pdf/railtie'
require 'wicked_pdf/option_parser'
require 'wicked_pdf/tempfile'
require 'wicked_pdf/binary'
require 'wicked_pdf/middleware'
require 'wicked_pdf/progress'
class WickedPdf
DEFAULT_BINARY_VERSION = Gem::Version.new('0.9.9')
@@config = {}
cattr_accessor :config, :silence_deprecations
include Progress
def self.config=(config)
::Kernel.warn 'WickedPdf.config= is deprecated and will be removed in future versions. Use WickedPdf.configure instead.' unless @@silence_deprecations
@@config = config
end
def self.configure
config = OpenStruct.new(@@config)
yield config
@@config.merge! config.to_h
end
def self.clear_config
@@config = {}
end
def initialize(wkhtmltopdf_binary_path = nil)
@binary = Binary.new(wkhtmltopdf_binary_path, DEFAULT_BINARY_VERSION)
end
def binary_version
@binary.version
end
def pdf_from_html_file(filepath, options = {})
pdf_from_url("file:///#{filepath}", options)
end
def pdf_from_string(string, options = {})
options = options.dup
options.merge!(WickedPdf.config) { |_key, option, _config| option }
string_file = WickedPdf::Tempfile.new('wicked_pdf.html', options[:temp_path])
string_file.write_in_chunks(string)
pdf_from_html_file(string_file.path, options)
ensure
if options[:delete_temporary_files] && string_file
string_file.close!
elsif string_file
string_file.close
end
end
def pdf_from_url(url, options = {}) # rubocop:disable Metrics/CyclomaticComplexity
# merge in global config options
options.merge!(WickedPdf.config) { |_key, option, _config| option }
generated_pdf_file = WickedPdf::Tempfile.new('wicked_pdf_generated_file.pdf', options[:temp_path])
command = [@binary.path]
command.unshift(@binary.xvfb_run_path) if options[:use_xvfb]
command += option_parser.parse(options)
command << url
command << generated_pdf_file.path.to_s
print_command(command.inspect) if in_development_mode?
if track_progress?(options)
invoke_with_progress(command, options)
else
_out, err, status = Open3.capture3(*command)
err = [status.to_s, err].join("\n") if !err.empty? || !status.success?
end
if options[:return_file]
return_file = options.delete(:return_file)
return generated_pdf_file
end
pdf = generated_pdf_file.read_in_chunks
raise "Error generating PDF\n Command Error: #{err}" if options[:raise_on_all_errors] && !err.empty?
raise "PDF could not be generated!\n Command Error: #{err}" if pdf && pdf.rstrip.empty?
pdf
rescue StandardError => e
raise "Failed to execute:\n#{command}\nError: #{e}"
ensure
clean_temp_files
generated_pdf_file.close! if generated_pdf_file && !return_file
end
private
def in_development_mode?
return Rails.env == 'development' if defined?(Rails.env)
RAILS_ENV == 'development' if defined?(RAILS_ENV)
end
def on_windows?
RbConfig::CONFIG['target_os'] =~ /mswin|mingw/
end
def print_command(cmd)
Rails.logger.debug '[wicked_pdf]: ' + cmd
end
def option_parser
@option_parser ||= OptionParser.new(binary_version)
end
def clean_temp_files
return unless option_parser.hf_tempfiles.present?
option_parser.hf_tempfiles.each { |file| File.delete(file) }
end
end