/
phantom.rb
153 lines (137 loc) · 4.55 KB
/
phantom.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
require 'uri'
require 'json'
require 'shellwords'
module Shrimp
class NoExecutableError < StandardError
def initialize
msg = "No phantomjs executable found at #{Shrimp.configuration.phantomjs}\n"
msg << ">> Please install phantomjs - http://phantomjs.org/download.html"
super(msg)
end
end
class ImproperSourceError < StandardError
def initialize(msg = nil)
super("Improper Source: #{msg}")
end
end
class RenderingError < StandardError
def initialize(msg = nil)
super("Rendering Error: #{msg}")
end
end
class Phantom
attr_accessor :source, :configuration, :outfile
attr_reader :options, :cookies, :result, :error
SCRIPT_FILE = File.expand_path('../rasterize.js', __FILE__)
# Public: Runs the phantomjs binary
#
# Returns the stdout output of phantomjs
def run
@error = nil
@result = `#{cmd}`
unless $?.exitstatus == 0
@error = @result
@result = nil
end
@result
end
def run!
@error = nil
@result = `#{cmd}`
unless $?.exitstatus == 0
@error = @result
@result = nil
raise RenderingError.new(@error)
end
@result
end
# Public: Returns the phantom rasterize command
def cmd
cookie_file = dump_cookies
format, zoom, margin, orientation = options[:format], options[:zoom], options[:margin], options[:orientation]
rendering_time, timeout = options[:rendering_time], options[:rendering_timeout]
viewport_width, viewport_height = options[:viewport_width], options[:viewport_height]
max_redirect_count = options[:max_redirect_count]
@outfile ||= "#{options[:tmpdir]}/#{Digest::MD5.hexdigest((Time.now.to_i + rand(9001)).to_s)}.pdf"
command_config_file = "--config=#{options[:command_config_file]}"
[
Shrimp.configuration.phantomjs,
command_config_file,
SCRIPT_FILE,
@source.to_s.shellescape,
@outfile,
format,
zoom,
margin,
orientation,
cookie_file,
rendering_time,
timeout,
viewport_width,
viewport_height,
max_redirect_count
].join(" ")
end
# Public: initializes a new Phantom Object
#
# url_or_file - The url of the html document to render
# options - a hash with options for rendering
# * format - the paper format for the output eg: "5in*7.5in", "10cm*20cm", "A4", "Letter"
# * zoom - the viewport zoom factor
# * margin - the margins for the pdf
# * command_config_file - the path to a json configuration file for command-line options
# cookies - hash with cookies to use for rendering
# outfile - optional path for the output file a Tempfile will be created if not given
#
# Returns self
def initialize(url_or_file, options = { }, cookies={ }, outfile = nil)
@source = Source.new(url_or_file)
@options = Shrimp.configuration.default_options.merge(options)
@cookies = cookies
@outfile = File.expand_path(outfile) if outfile
raise NoExecutableError.new unless File.exists?(Shrimp.configuration.phantomjs)
end
# Public: renders to pdf
# path - the destination path defaults to outfile
#
# Returns the path to the pdf file
def to_pdf(path=nil)
@outfile = File.expand_path(path) if path
self.run
@outfile
end
# Public: renders to pdf
# path - the destination path defaults to outfile
#
# Returns a File Handle of the Resulting pdf
def to_file(path=nil)
self.to_pdf(path)
File.new(@outfile)
end
# Public: renders to pdf
# path - the destination path defaults to outfile
#
# Returns the binary string of the pdf
def to_string(path=nil)
File.open(self.to_pdf(path)).read
end
def to_pdf!(path=nil)
@outfile = File.expand_path(path) if path
self.run!
@outfile
end
def to_file!(path=nil)
self.to_pdf!(path)
File.new(@outfile)
end
def to_string!(path=nil)
File.open(self.to_pdf!(path)).read
end
private
def dump_cookies
host = @source.url? ? URI::parse(@source.to_s).host : "/"
json = @cookies.inject([]) { |a, (k, v)| a.push({ :name => k, :value => v, :domain => host }); a }.to_json
File.open("#{options[:tmpdir]}/#{rand}.cookies", 'w') { |f| f.puts json; f }.path
end
end
end