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 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
require "rghost/ruby_ghost_config"
require "rghost/constants"
class RGhost::Engine
attr_reader :errors, :error, :output
DEFAULT_OPTIONS = {device: :pdf}
include RGhost::Constants::Devices
def initialize(document, options = {})
@document = document
@options = DEFAULT_OPTIONS.merge(options)
@errors = []
@error = false
@output = nil
@delete_input = true
end
def render(device = nil)
device ||= @options[:device]
tmp_filename = @options[:filename]
if tmp_filename
file_out = tmp_filename
else
tmp_filename ||= File.join(RGhost::Config::GS[:tmpdir], "#{object_id.abs}-#{rand(999999)}-#{Time.now.to_i}")
file_out = "#{tmp_filename}.#{device}"
end
external_encoding = RGhost::Config::GS[:external_encoding]
file_err = "#{tmp_filename}.rgerr"
multipage = @options[:multipage]
file_out.gsub!(/^(.*)\./, '\1_%04d.') if multipage
params = RGhost::Config::GS[:default_params].dup # default parameters gs engine
params << @document.additional_params.join(" ") unless @options[:convert]
params << "-I#{RGhost::Config::GS[:pslibdir]}"
params << "-dPDFSETTINGS=/#{@options[:quality]}" if @options[:device] == :pdf && @options[:quality]
params << "-I#{RGhost::Config::GS[:extensions].join(" -I")}" unless RGhost::Config::GS[:extensions].empty?
params << "-sDEVICE=#{device_for(device)}"
params.concat format_params(@options[:d], "-d") if @options[:d]
params.concat format_params(@options[:s], "-s") if @options[:s]
params << "-r#{@options[:resolution]}" if @options[:resolution]
params << "-g#{@options[:size]}" if @options[:size]
if @options[:range]
params << "-dFirstPage=#{@options[:range].first}"
params << "-dLastPage=#{@options[:range].last}"
end
params << "-sstdout=#{shellescape(file_err)}"
params << "-sOutputFile=#{shellescape(file_out)}"
params << @options[:raw] if @options[:raw]
case @document
when RGhost::Document
file_in = "#{tmp_filename}.rgin"
params.concat @document.gs_paper
mode = external_encoding.nil? ? "w" : "w:#{external_encoding}"
fi = File.open(file_in, mode)
fi.puts @document.ps
fi.close
when File
file_in = @document.path
# @delete_input=false unless @options[:debug]
when String
file_in = @document
else
raise "Cannot convert #{@document.class}. Supported classes are RGhost::Document or File or String."
end
params << shellescape(file_in)
if RGhost::Config::GS[:mode] == :gslib
require "rghost/rgengine"
gs = RGEngine.new
@error = !gs.render(params, params.size)
else
require "rghost/gs_alone"
gs = RGhost::GSAlone.new(params, @options[:debug])
@error = !gs.run
end
if @error # if error
@errors = File.open(file_err).readlines if File.exist?(file_err)
raise RGhost::RenderException.new(@errors.join(" ")) if RGhost::Config::GS[:raise_on_error]
elsif multipage
file_out.gsub!("_%04d", "_*")
@output = Dir.glob(file_out).map { |f| f }
else
@output = File.open(file_out)
end
begin
File.delete(file_err)
File.delete(file_in) unless @options[:debug] || @options[:convert]
rescue
end
log(params) if @options[:logfile]
@output
end
def clear_output
case @output
when File
@output.close
File.delete(@output.path)
when Array
@output.each do |f|
f.close
File.delete(f.path)
end
end
end
def error?
@error
end
private
def log(gp)
id = object_id.abs
flog = File.open(@options[:logfile], File::WRONLY | File::APPEND | File::CREAT)
flog.puts "[ID #{id}] created on #{Time.now}"
flog.puts "[#{id}] RUBY GS OPTIONS: #{@options.inspect}"
flog.puts "[#{id}] GS OPTIONS: #{gp.join(" ")}"
if @error
flog.puts "[#{id}] EXIT STATUS: ERROR"
flog.puts @errors.uniq.map { |m| "[#{id}] #{m}" }.to_s
else
flog.puts "[#{id}] EXIT STATUS: OK"
end
end
def format_params(v, pre = "-d")
r = []
case v
when Symbol
r << "#{pre}#{v}"
when Array
v.each do |av|
r << format_params(av, pre).to_s
end
when Hash
v.each do |k, v|
r << "#{pre}#{k}=#{v.to_s.delete(" ")}"
end
else
return ""
end
r
end
def shellescape(str)
# An empty argument will be skipped, so return empty quotes.
return "''" if str.empty?
str = str.dup
# Process as a single byte sequence because not all shell
# implementations are multibyte aware.
str.gsub!(/([^A-Za-z0-9_\-.,:\/@\n])/n, "\\\\\\1")
# A LF cannot be escaped with a backslash because a backslash + LF
# combo is regarded as line continuation and simply ignored.
str.gsub!("\n", "'\n'")
str
end
end
|