wicked_pdf 1.1.0 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.github/issue_template.md +15 -0
- data/.github/workflows/ci.yml +56 -0
- data/.rubocop.yml +62 -0
- data/.rubocop_todo.yml +81 -39
- data/CHANGELOG.md +194 -45
- data/README.md +136 -28
- data/Rakefile +12 -9
- data/gemfiles/5.0.gemfile +3 -1
- data/gemfiles/5.1.gemfile +8 -0
- data/gemfiles/5.2.gemfile +9 -0
- data/gemfiles/6.0.gemfile +10 -0
- data/gemfiles/6.1.gemfile +11 -0
- data/gemfiles/7.0.gemfile +11 -0
- data/generators/wicked_pdf/templates/wicked_pdf.rb +14 -5
- data/lib/generators/wicked_pdf_generator.rb +5 -9
- data/lib/wicked_pdf/binary.rb +65 -0
- data/lib/wicked_pdf/middleware.rb +1 -1
- data/lib/wicked_pdf/option_parser.rb +230 -0
- data/lib/wicked_pdf/pdf_helper.rb +35 -42
- data/lib/wicked_pdf/progress.rb +33 -0
- data/lib/wicked_pdf/railtie.rb +6 -44
- data/lib/wicked_pdf/tempfile.rb +33 -3
- data/lib/wicked_pdf/version.rb +1 -1
- data/lib/wicked_pdf/wicked_pdf_helper/assets.rb +200 -17
- data/lib/wicked_pdf/wicked_pdf_helper.rb +2 -1
- data/lib/wicked_pdf.rb +64 -275
- data/test/fixtures/database.yml +4 -0
- data/test/fixtures/manifest.js +3 -0
- data/test/functional/pdf_helper_test.rb +71 -0
- data/test/functional/wicked_pdf_helper_assets_test.rb +61 -0
- data/test/test_helper.rb +13 -8
- data/test/unit/wicked_pdf_binary_test.rb +26 -0
- data/test/unit/wicked_pdf_option_parser_test.rb +133 -0
- data/test/unit/wicked_pdf_test.rb +25 -146
- data/test/unit/wkhtmltopdf_location_test.rb +48 -0
- data/wicked_pdf.gemspec +20 -13
- metadata +79 -36
- data/.travis.yml +0 -57
- data/gemfiles/2.3.gemfile +0 -10
- data/gemfiles/3.0.gemfile +0 -12
- data/gemfiles/3.1.gemfile +0 -13
- data/gemfiles/3.2.gemfile +0 -12
- data/gemfiles/4.0.gemfile +0 -6
- data/gemfiles/4.1.gemfile +0 -6
- data/gemfiles/4.2.gemfile +0 -6
- data/gemfiles/rails_edge.gemfile +0 -6
@@ -1,17 +1,99 @@
|
|
1
|
-
require '
|
1
|
+
require 'net/http'
|
2
|
+
require 'delegate'
|
3
|
+
require 'stringio'
|
2
4
|
|
3
5
|
class WickedPdf
|
4
6
|
module WickedPdfHelper
|
5
7
|
module Assets
|
6
8
|
ASSET_URL_REGEX = /url\(['"]?([^'"]+?)['"]?\)/
|
7
9
|
|
10
|
+
class MissingAsset < StandardError; end
|
11
|
+
|
12
|
+
class MissingLocalAsset < MissingAsset
|
13
|
+
attr_reader :path
|
14
|
+
|
15
|
+
def initialize(path)
|
16
|
+
@path = path
|
17
|
+
super("Could not find asset '#{path}'")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class MissingRemoteAsset < MissingAsset
|
22
|
+
attr_reader :url, :response
|
23
|
+
|
24
|
+
def initialize(url, response)
|
25
|
+
@url = url
|
26
|
+
@response = response
|
27
|
+
super("Could not fetch asset '#{url}': server responded with #{response.code} #{response.message}")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class PropshaftAsset < SimpleDelegator
|
32
|
+
def content_type
|
33
|
+
super.to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_s
|
37
|
+
content
|
38
|
+
end
|
39
|
+
|
40
|
+
def filename
|
41
|
+
path.to_s
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class SprocketsEnvironment
|
46
|
+
def self.instance
|
47
|
+
@instance ||= Sprockets::Railtie.build_environment(Rails.application)
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.find_asset(*args)
|
51
|
+
instance.find_asset(*args)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class LocalAsset
|
56
|
+
attr_reader :path
|
57
|
+
|
58
|
+
def initialize(path)
|
59
|
+
@path = path
|
60
|
+
end
|
61
|
+
|
62
|
+
def content_type
|
63
|
+
Mime::Type.lookup_by_extension(File.extname(path).delete('.'))
|
64
|
+
end
|
65
|
+
|
66
|
+
def to_s
|
67
|
+
IO.read(path)
|
68
|
+
end
|
69
|
+
|
70
|
+
def filename
|
71
|
+
path.to_s
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
8
75
|
def wicked_pdf_asset_base64(path)
|
9
76
|
asset = find_asset(path)
|
10
|
-
raise
|
77
|
+
raise MissingLocalAsset, path if asset.nil?
|
78
|
+
|
11
79
|
base64 = Base64.encode64(asset.to_s).gsub(/\s+/, '')
|
12
80
|
"data:#{asset.content_type};base64,#{Rack::Utils.escape(base64)}"
|
13
81
|
end
|
14
82
|
|
83
|
+
# Using `image_tag` with URLs when generating PDFs (specifically large PDFs with lots of pages) can cause buffer/stack overflows.
|
84
|
+
#
|
85
|
+
def wicked_pdf_url_base64(url)
|
86
|
+
response = Net::HTTP.get_response(URI(url))
|
87
|
+
|
88
|
+
if response.is_a?(Net::HTTPSuccess)
|
89
|
+
base64 = Base64.encode64(response.body).gsub(/\s+/, '')
|
90
|
+
"data:#{response.content_type};base64,#{Rack::Utils.escape(base64)}"
|
91
|
+
else
|
92
|
+
Rails.logger.warn("[wicked_pdf] #{response.code} #{response.message}: #{url}")
|
93
|
+
nil
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
15
97
|
def wicked_pdf_stylesheet_link_tag(*sources)
|
16
98
|
stylesheet_contents = sources.collect do |source|
|
17
99
|
source = WickedPdfHelper.add_extension(source, 'css')
|
@@ -27,6 +109,33 @@ class WickedPdf
|
|
27
109
|
end.html_safe
|
28
110
|
end
|
29
111
|
|
112
|
+
def wicked_pdf_stylesheet_pack_tag(*sources)
|
113
|
+
return unless defined?(Webpacker)
|
114
|
+
|
115
|
+
if running_in_development?
|
116
|
+
stylesheet_pack_tag(*sources)
|
117
|
+
else
|
118
|
+
css_text = sources.collect do |source|
|
119
|
+
source = WickedPdfHelper.add_extension(source, 'css')
|
120
|
+
wicked_pdf_stylesheet_link_tag(webpacker_source_url(source))
|
121
|
+
end.join("\n")
|
122
|
+
css_text.respond_to?(:html_safe) ? css_text.html_safe : css_text
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def wicked_pdf_javascript_pack_tag(*sources)
|
127
|
+
return unless defined?(Webpacker)
|
128
|
+
|
129
|
+
if running_in_development?
|
130
|
+
javascript_pack_tag(*sources)
|
131
|
+
else
|
132
|
+
sources.collect do |source|
|
133
|
+
source = WickedPdfHelper.add_extension(source, 'js')
|
134
|
+
"<script type='text/javascript'>#{read_asset(webpacker_source_url(source))}</script>"
|
135
|
+
end.join("\n").html_safe
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
30
139
|
def wicked_pdf_image_tag(img, options = {})
|
31
140
|
image_tag wicked_pdf_asset_path(img), options
|
32
141
|
end
|
@@ -51,6 +160,16 @@ class WickedPdf
|
|
51
160
|
end
|
52
161
|
end
|
53
162
|
|
163
|
+
def wicked_pdf_asset_pack_path(asset)
|
164
|
+
return unless defined?(Webpacker)
|
165
|
+
|
166
|
+
if running_in_development?
|
167
|
+
asset_pack_path(asset)
|
168
|
+
else
|
169
|
+
wicked_pdf_asset_path webpacker_source_url(asset)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
54
173
|
private
|
55
174
|
|
56
175
|
# borrowed from actionpack/lib/action_view/helpers/asset_url_helper.rb
|
@@ -68,15 +187,25 @@ class WickedPdf
|
|
68
187
|
end
|
69
188
|
else
|
70
189
|
asset = find_asset(source)
|
71
|
-
|
190
|
+
if asset
|
191
|
+
# older versions need pathname, Sprockets 4 supports only filename
|
192
|
+
asset.respond_to?(:filename) ? asset.filename : asset.pathname
|
193
|
+
else
|
194
|
+
File.join(Rails.public_path, source)
|
195
|
+
end
|
72
196
|
end
|
73
197
|
end
|
74
198
|
|
75
199
|
def find_asset(path)
|
76
200
|
if Rails.application.assets.respond_to?(:find_asset)
|
77
|
-
Rails.application.assets.find_asset(path)
|
201
|
+
Rails.application.assets.find_asset(path, :base_path => Rails.application.root.to_s)
|
202
|
+
elsif defined?(Propshaft::Assembly) && Rails.application.assets.is_a?(Propshaft::Assembly)
|
203
|
+
PropshaftAsset.new(Rails.application.assets.load_path.find(path))
|
204
|
+
elsif Rails.application.respond_to?(:assets_manifest)
|
205
|
+
asset_path = File.join(Rails.application.assets_manifest.dir, Rails.application.assets_manifest.assets[path])
|
206
|
+
LocalAsset.new(asset_path) if File.file?(asset_path)
|
78
207
|
else
|
79
|
-
|
208
|
+
SprocketsEnvironment.find_asset(path, :base_path => Rails.application.root.to_s)
|
80
209
|
end
|
81
210
|
end
|
82
211
|
|
@@ -93,27 +222,43 @@ class WickedPdf
|
|
93
222
|
end
|
94
223
|
|
95
224
|
def precompiled_or_absolute_asset?(source)
|
96
|
-
Rails.configuration.assets
|
225
|
+
!Rails.configuration.respond_to?(:assets) ||
|
226
|
+
Rails.configuration.assets.compile == false ||
|
97
227
|
source.to_s[0] == '/' ||
|
98
228
|
source.to_s.match(/\Ahttps?\:\/\//)
|
99
229
|
end
|
100
230
|
|
101
231
|
def read_asset(source)
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
232
|
+
asset = find_asset(source)
|
233
|
+
return asset.to_s.force_encoding('UTF-8') if asset
|
234
|
+
|
235
|
+
unless precompiled_or_absolute_asset?(source)
|
236
|
+
raise MissingLocalAsset, source if WickedPdf.config[:raise_on_missing_assets]
|
237
|
+
|
238
|
+
return
|
239
|
+
end
|
240
|
+
|
241
|
+
pathname = asset_pathname(source)
|
242
|
+
if pathname =~ URI_REGEXP
|
243
|
+
read_from_uri(pathname)
|
244
|
+
elsif File.file?(pathname)
|
245
|
+
IO.read(pathname)
|
246
|
+
elsif WickedPdf.config[:raise_on_missing_assets]
|
247
|
+
raise MissingLocalAsset, pathname if WickedPdf.config[:raise_on_missing_assets]
|
111
248
|
end
|
112
249
|
end
|
113
250
|
|
114
251
|
def read_from_uri(uri)
|
115
|
-
|
116
|
-
|
252
|
+
response = Net::HTTP.get_response(URI(uri))
|
253
|
+
|
254
|
+
unless response.is_a?(Net::HTTPSuccess)
|
255
|
+
raise MissingRemoteAsset.new(uri, response) if WickedPdf.config[:raise_on_missing_assets]
|
256
|
+
|
257
|
+
return
|
258
|
+
end
|
259
|
+
|
260
|
+
asset = response.body
|
261
|
+
asset.force_encoding('UTF-8') if asset
|
117
262
|
asset = gzip(asset) if WickedPdf.config[:expect_gzipped_remote_assets]
|
118
263
|
asset
|
119
264
|
end
|
@@ -125,6 +270,44 @@ class WickedPdf
|
|
125
270
|
rescue Zlib::GzipFile::Error
|
126
271
|
nil
|
127
272
|
end
|
273
|
+
|
274
|
+
def webpacker_source_url(source)
|
275
|
+
return unless webpacker_version
|
276
|
+
|
277
|
+
# In Webpacker 3.2.0 asset_pack_url is introduced
|
278
|
+
if webpacker_version >= '3.2.0'
|
279
|
+
if (host = Rails.application.config.asset_host)
|
280
|
+
asset_pack_path(source, :host => host)
|
281
|
+
else
|
282
|
+
asset_pack_url(source)
|
283
|
+
end
|
284
|
+
else
|
285
|
+
source_path = asset_pack_path(source)
|
286
|
+
# Remove last slash from root path
|
287
|
+
root_url[0...-1] + source_path
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
def running_in_development?
|
292
|
+
return unless webpacker_version
|
293
|
+
|
294
|
+
# :dev_server method was added in webpacker 3.0.0
|
295
|
+
if Webpacker.respond_to?(:dev_server)
|
296
|
+
Webpacker.dev_server.running?
|
297
|
+
else
|
298
|
+
Rails.env.development? || Rails.env.test?
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
def webpacker_version
|
303
|
+
if defined?(Shakapacker)
|
304
|
+
require 'shakapacker/version'
|
305
|
+
Shakapacker::VERSION
|
306
|
+
elsif defined?(Webpacker)
|
307
|
+
require 'webpacker/version'
|
308
|
+
Webpacker::VERSION
|
309
|
+
end
|
310
|
+
end
|
128
311
|
end
|
129
312
|
end
|
130
313
|
end
|
@@ -23,8 +23,9 @@ class WickedPdf
|
|
23
23
|
|
24
24
|
def wicked_pdf_javascript_src_tag(jsfile, options = {})
|
25
25
|
jsfile = WickedPdfHelper.add_extension(jsfile, 'js')
|
26
|
+
type = ::Mime.respond_to?(:[]) ? ::Mime[:js] : ::Mime::JS # ::Mime[:js] cannot be used in Rails 2.3.
|
26
27
|
src = "file:///#{WickedPdfHelper.root_path.join('public', 'javascripts', jsfile)}"
|
27
|
-
content_tag('script', '', { 'type' =>
|
28
|
+
content_tag('script', '', { 'type' => type, 'src' => path_to_javascript(src) }.merge(options))
|
28
29
|
end
|
29
30
|
|
30
31
|
def wicked_pdf_javascript_include_tag(*sources)
|
data/lib/wicked_pdf.rb
CHANGED
@@ -1,48 +1,52 @@
|
|
1
1
|
# wkhtml2pdf Ruby interface
|
2
|
-
# http://
|
2
|
+
# http://wkhtmltopdf.org/
|
3
3
|
|
4
4
|
require 'logger'
|
5
5
|
require 'digest/md5'
|
6
6
|
require 'rbconfig'
|
7
|
+
require 'open3'
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
else
|
11
|
-
require 'open3'
|
12
|
-
end
|
13
|
-
|
14
|
-
begin
|
15
|
-
require 'active_support/core_ext/module/attribute_accessors'
|
16
|
-
rescue LoadError
|
17
|
-
require 'active_support/core_ext/class/attribute_accessors'
|
18
|
-
end
|
19
|
-
|
20
|
-
begin
|
21
|
-
require 'active_support/core_ext/object/blank'
|
22
|
-
rescue LoadError
|
23
|
-
require 'active_support/core_ext/blank'
|
24
|
-
end
|
9
|
+
require 'active_support/core_ext/module/attribute_accessors'
|
10
|
+
require 'active_support/core_ext/object/blank'
|
25
11
|
|
26
12
|
require 'wicked_pdf/version'
|
27
13
|
require 'wicked_pdf/railtie'
|
14
|
+
require 'wicked_pdf/option_parser'
|
28
15
|
require 'wicked_pdf/tempfile'
|
16
|
+
require 'wicked_pdf/binary'
|
29
17
|
require 'wicked_pdf/middleware'
|
18
|
+
require 'wicked_pdf/progress'
|
30
19
|
|
31
20
|
class WickedPdf
|
32
21
|
DEFAULT_BINARY_VERSION = Gem::Version.new('0.9.9')
|
33
|
-
BINARY_VERSION_WITHOUT_DASHES = Gem::Version.new('0.12.0')
|
34
|
-
EXE_NAME = 'wkhtmltopdf'.freeze
|
35
22
|
@@config = {}
|
36
|
-
cattr_accessor :config
|
37
|
-
|
23
|
+
cattr_accessor :config, :silence_deprecations
|
24
|
+
|
25
|
+
include Progress
|
26
|
+
|
27
|
+
def self.config=(config)
|
28
|
+
::Kernel.warn 'WickedPdf.config= is deprecated and will be removed in future versions. Use WickedPdf.configure instead.' unless @@silence_deprecations
|
29
|
+
|
30
|
+
@@config = config
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.configure
|
34
|
+
config = OpenStruct.new(@@config)
|
35
|
+
yield config
|
36
|
+
|
37
|
+
@@config.merge! config.to_h
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.clear_config
|
41
|
+
@@config = {}
|
42
|
+
end
|
38
43
|
|
39
44
|
def initialize(wkhtmltopdf_binary_path = nil)
|
40
|
-
@
|
41
|
-
|
42
|
-
raise "Bad #{EXE_NAME}'s path: #{@exe_path}" unless File.exist?(@exe_path)
|
43
|
-
raise "#{EXE_NAME} is not executable" unless File.executable?(@exe_path)
|
45
|
+
@binary = Binary.new(wkhtmltopdf_binary_path, DEFAULT_BINARY_VERSION)
|
46
|
+
end
|
44
47
|
|
45
|
-
|
48
|
+
def binary_version
|
49
|
+
@binary.version
|
46
50
|
end
|
47
51
|
|
48
52
|
def pdf_from_html_file(filepath, options = {})
|
@@ -52,51 +56,58 @@ class WickedPdf
|
|
52
56
|
def pdf_from_string(string, options = {})
|
53
57
|
options = options.dup
|
54
58
|
options.merge!(WickedPdf.config) { |_key, option, _config| option }
|
55
|
-
string_file =
|
56
|
-
string_file.
|
57
|
-
string_file.
|
58
|
-
string_file.close
|
59
|
-
|
60
|
-
pdf = pdf_from_html_file(string_file.path, options)
|
61
|
-
pdf
|
59
|
+
string_file = WickedPdf::Tempfile.new('wicked_pdf.html', options[:temp_path])
|
60
|
+
string_file.write_in_chunks(string)
|
61
|
+
pdf_from_html_file(string_file.path, options)
|
62
62
|
ensure
|
63
|
-
|
63
|
+
if options[:delete_temporary_files] && string_file
|
64
|
+
string_file.close!
|
65
|
+
elsif string_file
|
66
|
+
string_file.close
|
67
|
+
end
|
64
68
|
end
|
65
69
|
|
66
|
-
def pdf_from_url(url, options = {})
|
70
|
+
def pdf_from_url(url, options = {}) # rubocop:disable Metrics/CyclomaticComplexity
|
67
71
|
# merge in global config options
|
68
72
|
options.merge!(WickedPdf.config) { |_key, option, _config| option }
|
69
|
-
generated_pdf_file =
|
70
|
-
command = [@
|
71
|
-
command
|
72
|
-
command +=
|
73
|
+
generated_pdf_file = WickedPdf::Tempfile.new('wicked_pdf_generated_file.pdf', options[:temp_path])
|
74
|
+
command = [@binary.path]
|
75
|
+
command.unshift(@binary.xvfb_run_path) if options[:use_xvfb]
|
76
|
+
command += option_parser.parse(options)
|
73
77
|
command << url
|
74
78
|
command << generated_pdf_file.path.to_s
|
75
79
|
|
76
80
|
print_command(command.inspect) if in_development_mode?
|
77
81
|
|
78
|
-
|
79
|
-
|
82
|
+
if track_progress?(options)
|
83
|
+
invoke_with_progress(command, options)
|
84
|
+
else
|
85
|
+
_out, err, status = Open3.capture3(*command)
|
86
|
+
err = [status.to_s, err].join("\n") if !err.empty? || !status.success?
|
80
87
|
end
|
81
88
|
if options[:return_file]
|
82
89
|
return_file = options.delete(:return_file)
|
83
90
|
return generated_pdf_file
|
84
91
|
end
|
85
|
-
|
86
|
-
generated_pdf_file.
|
87
|
-
|
92
|
+
|
93
|
+
pdf = generated_pdf_file.read_in_chunks
|
94
|
+
|
95
|
+
raise "Error generating PDF\n Command Error: #{err}" if options[:raise_on_all_errors] && !err.empty?
|
88
96
|
raise "PDF could not be generated!\n Command Error: #{err}" if pdf && pdf.rstrip.empty?
|
97
|
+
|
89
98
|
pdf
|
90
|
-
rescue => e
|
99
|
+
rescue StandardError => e
|
91
100
|
raise "Failed to execute:\n#{command}\nError: #{e}"
|
92
101
|
ensure
|
102
|
+
clean_temp_files
|
93
103
|
generated_pdf_file.close! if generated_pdf_file && !return_file
|
94
104
|
end
|
95
105
|
|
96
106
|
private
|
97
107
|
|
98
108
|
def in_development_mode?
|
99
|
-
return Rails.env == 'development' if defined?(Rails)
|
109
|
+
return Rails.env == 'development' if defined?(Rails.env)
|
110
|
+
|
100
111
|
RAILS_ENV == 'development' if defined?(RAILS_ENV)
|
101
112
|
end
|
102
113
|
|
@@ -105,238 +116,16 @@ class WickedPdf
|
|
105
116
|
end
|
106
117
|
|
107
118
|
def print_command(cmd)
|
108
|
-
|
109
|
-
end
|
110
|
-
|
111
|
-
def retrieve_binary_version
|
112
|
-
_stdin, stdout, _stderr = Open3.popen3(@exe_path + ' -V')
|
113
|
-
@binary_version = parse_version(stdout.gets(nil))
|
114
|
-
rescue
|
115
|
-
DEFAULT_BINARY_VERSION
|
116
|
-
end
|
117
|
-
|
118
|
-
def parse_version(version_info)
|
119
|
-
match_data = /wkhtmltopdf\s*(\d*\.\d*\.\d*\w*)/.match(version_info)
|
120
|
-
if match_data && (2 == match_data.length)
|
121
|
-
Gem::Version.new(match_data[1])
|
122
|
-
else
|
123
|
-
DEFAULT_BINARY_VERSION
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
def parse_options(options)
|
128
|
-
[
|
129
|
-
parse_extra(options),
|
130
|
-
parse_others(options),
|
131
|
-
parse_global(options),
|
132
|
-
parse_outline(options.delete(:outline)),
|
133
|
-
parse_header_footer(:header => options.delete(:header),
|
134
|
-
:footer => options.delete(:footer),
|
135
|
-
:layout => options[:layout]),
|
136
|
-
parse_cover(options.delete(:cover)),
|
137
|
-
parse_toc(options.delete(:toc)),
|
138
|
-
parse_basic_auth(options)
|
139
|
-
].flatten
|
140
|
-
end
|
141
|
-
|
142
|
-
def parse_extra(options)
|
143
|
-
return [] if options[:extra].nil?
|
144
|
-
return options[:extra].split if options[:extra].respond_to?(:split)
|
145
|
-
options[:extra]
|
119
|
+
Rails.logger.debug '[wicked_pdf]: ' + cmd
|
146
120
|
end
|
147
121
|
|
148
|
-
def
|
149
|
-
|
150
|
-
user, passwd = Base64.decode64(options[:basic_auth]).split(':')
|
151
|
-
['--username', user, '--password', passwd]
|
152
|
-
else
|
153
|
-
[]
|
154
|
-
end
|
122
|
+
def option_parser
|
123
|
+
@option_parser ||= OptionParser.new(binary_version)
|
155
124
|
end
|
156
125
|
|
157
|
-
def
|
158
|
-
|
159
|
-
return value.collect { |v| make_option(name, v, type) }
|
160
|
-
end
|
161
|
-
if type == :name_value
|
162
|
-
parts = value.to_s.split(' ')
|
163
|
-
["--#{name.tr('_', '-')}", *parts]
|
164
|
-
elsif type == :boolean
|
165
|
-
if value
|
166
|
-
["--#{name.tr('_', '-')}"]
|
167
|
-
else
|
168
|
-
[]
|
169
|
-
end
|
170
|
-
else
|
171
|
-
["--#{name.tr('_', '-')}", value.to_s]
|
172
|
-
end
|
173
|
-
end
|
126
|
+
def clean_temp_files
|
127
|
+
return unless option_parser.hf_tempfiles.present?
|
174
128
|
|
175
|
-
|
176
|
-
if binary_version < BINARY_VERSION_WITHOUT_DASHES
|
177
|
-
"--#{name}"
|
178
|
-
else
|
179
|
-
name
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
def make_options(options, names, prefix = '', type = :string)
|
184
|
-
return [] if options.nil?
|
185
|
-
names.collect do |o|
|
186
|
-
if options[o].blank?
|
187
|
-
[]
|
188
|
-
else
|
189
|
-
make_option("#{prefix.blank? ? '' : prefix + '-'}#{o}",
|
190
|
-
options[o],
|
191
|
-
type)
|
192
|
-
end
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
def parse_header_footer(options)
|
197
|
-
r = []
|
198
|
-
[:header, :footer].collect do |hf|
|
199
|
-
next if options[hf].blank?
|
200
|
-
opt_hf = options[hf]
|
201
|
-
r += make_options(opt_hf, [:center, :font_name, :left, :right], hf.to_s)
|
202
|
-
r += make_options(opt_hf, [:font_size, :spacing], hf.to_s, :numeric)
|
203
|
-
r += make_options(opt_hf, [:line], hf.to_s, :boolean)
|
204
|
-
if options[hf] && options[hf][:content]
|
205
|
-
@hf_tempfiles = [] unless defined?(@hf_tempfiles)
|
206
|
-
@hf_tempfiles.push(tf = WickedPdfTempfile.new("wicked_#{hf}_pdf.html"))
|
207
|
-
tf.write options[hf][:content]
|
208
|
-
tf.flush
|
209
|
-
options[hf][:html] = {}
|
210
|
-
options[hf][:html][:url] = "file:///#{tf.path}"
|
211
|
-
end
|
212
|
-
unless opt_hf[:html].blank?
|
213
|
-
r += make_option("#{hf}-html", opt_hf[:html][:url]) unless opt_hf[:html][:url].blank?
|
214
|
-
end
|
215
|
-
end unless options.blank?
|
216
|
-
r
|
217
|
-
end
|
218
|
-
|
219
|
-
def parse_cover(argument)
|
220
|
-
arg = argument.to_s
|
221
|
-
return [] if arg.blank?
|
222
|
-
# Filesystem path or URL - hand off to wkhtmltopdf
|
223
|
-
if argument.is_a?(Pathname) || (arg[0, 4] == 'http')
|
224
|
-
[valid_option('cover'), arg]
|
225
|
-
else # HTML content
|
226
|
-
@hf_tempfiles ||= []
|
227
|
-
@hf_tempfiles << tf = WickedPdfTempfile.new('wicked_cover_pdf.html')
|
228
|
-
tf.write arg
|
229
|
-
tf.flush
|
230
|
-
[valid_option('cover'), tf.path]
|
231
|
-
end
|
232
|
-
end
|
233
|
-
|
234
|
-
def parse_toc(options)
|
235
|
-
return [] if options.nil?
|
236
|
-
r = [valid_option('toc')]
|
237
|
-
unless options.blank?
|
238
|
-
r += make_options(options, [:font_name, :header_text], 'toc')
|
239
|
-
r += make_options(options, [:xsl_style_sheet])
|
240
|
-
r += make_options(options, [:depth,
|
241
|
-
:header_fs,
|
242
|
-
:text_size_shrink,
|
243
|
-
:l1_font_size,
|
244
|
-
:l2_font_size,
|
245
|
-
:l3_font_size,
|
246
|
-
:l4_font_size,
|
247
|
-
:l5_font_size,
|
248
|
-
:l6_font_size,
|
249
|
-
:l7_font_size,
|
250
|
-
:level_indentation,
|
251
|
-
:l1_indentation,
|
252
|
-
:l2_indentation,
|
253
|
-
:l3_indentation,
|
254
|
-
:l4_indentation,
|
255
|
-
:l5_indentation,
|
256
|
-
:l6_indentation,
|
257
|
-
:l7_indentation], 'toc', :numeric)
|
258
|
-
r += make_options(options, [:no_dots,
|
259
|
-
:disable_links,
|
260
|
-
:disable_back_links], 'toc', :boolean)
|
261
|
-
r += make_options(options, [:disable_dotted_lines,
|
262
|
-
:disable_toc_links], nil, :boolean)
|
263
|
-
end
|
264
|
-
r
|
265
|
-
end
|
266
|
-
|
267
|
-
def parse_outline(options)
|
268
|
-
r = []
|
269
|
-
unless options.blank?
|
270
|
-
r = make_options(options, [:outline], '', :boolean)
|
271
|
-
r += make_options(options, [:outline_depth], '', :numeric)
|
272
|
-
end
|
273
|
-
r
|
274
|
-
end
|
275
|
-
|
276
|
-
def parse_margins(options)
|
277
|
-
make_options(options, [:top, :bottom, :left, :right], 'margin', :numeric)
|
278
|
-
end
|
279
|
-
|
280
|
-
def parse_global(options)
|
281
|
-
r = []
|
282
|
-
unless options.blank?
|
283
|
-
r += make_options(options, [:orientation,
|
284
|
-
:dpi,
|
285
|
-
:page_size,
|
286
|
-
:page_width,
|
287
|
-
:title])
|
288
|
-
r += make_options(options, [:lowquality,
|
289
|
-
:grayscale,
|
290
|
-
:no_pdf_compression], '', :boolean)
|
291
|
-
r += make_options(options, [:image_dpi,
|
292
|
-
:image_quality,
|
293
|
-
:page_height], '', :numeric)
|
294
|
-
r += parse_margins(options.delete(:margin))
|
295
|
-
end
|
296
|
-
r
|
297
|
-
end
|
298
|
-
|
299
|
-
def parse_others(options)
|
300
|
-
r = []
|
301
|
-
unless options.blank?
|
302
|
-
r += make_options(options, [:proxy,
|
303
|
-
:username,
|
304
|
-
:password,
|
305
|
-
:encoding,
|
306
|
-
:user_style_sheet,
|
307
|
-
:viewport_size,
|
308
|
-
:window_status])
|
309
|
-
r += make_options(options, [:cookie,
|
310
|
-
:post], '', :name_value)
|
311
|
-
r += make_options(options, [:redirect_delay,
|
312
|
-
:zoom,
|
313
|
-
:page_offset,
|
314
|
-
:javascript_delay], '', :numeric)
|
315
|
-
r += make_options(options, [:book,
|
316
|
-
:default_header,
|
317
|
-
:disable_javascript,
|
318
|
-
:enable_plugins,
|
319
|
-
:disable_internal_links,
|
320
|
-
:disable_external_links,
|
321
|
-
:print_media_type,
|
322
|
-
:disable_smart_shrinking,
|
323
|
-
:use_xserver,
|
324
|
-
:no_background,
|
325
|
-
:no_stop_slow_scripts], '', :boolean)
|
326
|
-
end
|
327
|
-
r
|
328
|
-
end
|
329
|
-
|
330
|
-
def find_wkhtmltopdf_binary_path
|
331
|
-
possible_locations = (ENV['PATH'].split(':') + %w(/usr/bin /usr/local/bin ~/bin)).uniq
|
332
|
-
exe_path ||= WickedPdf.config[:exe_path] unless WickedPdf.config.empty?
|
333
|
-
exe_path ||= begin
|
334
|
-
detected_path = (defined?(Bundler) ? `bundle exec which wkhtmltopdf` : `which wkhtmltopdf`).chomp
|
335
|
-
detected_path.present? && detected_path
|
336
|
-
rescue
|
337
|
-
nil
|
338
|
-
end
|
339
|
-
exe_path ||= possible_locations.map { |l| File.expand_path("#{l}/#{EXE_NAME}") }.find { |location| File.exist?(location) }
|
340
|
-
exe_path || ''
|
129
|
+
option_parser.hf_tempfiles.each { |file| File.delete(file) }
|
341
130
|
end
|
342
131
|
end
|