├── .rspec ├── Gemfile ├── spec ├── princely_spec.rb ├── spec_helper.rb └── princely │ ├── version_spec.rb │ ├── logging_spec.rb │ ├── executable_spec.rb │ └── pdf_spec.rb ├── Rakefile ├── lib ├── princely │ ├── stdout_logger.rb │ ├── version.rb │ ├── logging.rb │ ├── rails.rb │ ├── executable.rb │ ├── asset_support.rb │ ├── pdf_helper.rb │ └── pdf.rb └── princely.rb ├── .gitignore ├── .travis.yml ├── MIT-LICENSE ├── princely.gemspec └── README.md /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --format progress 3 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | gemspec -------------------------------------------------------------------------------- /spec/princely_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | class TestLogger; end 4 | 5 | describe Princely do 6 | end 7 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler/gem_tasks' 2 | require 'rspec/core/rake_task' 3 | 4 | RSpec::Core::RakeTask.new(:spec) 5 | 6 | task :default => :spec -------------------------------------------------------------------------------- /lib/princely/stdout_logger.rb: -------------------------------------------------------------------------------- 1 | module Princely 2 | class StdoutLogger 3 | def self.info(msg) 4 | puts msg 5 | end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /lib/princely/version.rb: -------------------------------------------------------------------------------- 1 | module Princely 2 | class Version 3 | class << self 4 | def version 5 | '2.1.0' 6 | end 7 | 8 | def to_s 9 | version 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | Gemfile.lock 7 | InstalledFiles 8 | _yardoc 9 | coverage 10 | doc/ 11 | lib/bundler/man 12 | pkg 13 | rdoc 14 | spec/reports 15 | test/tmp 16 | test/version_tmp 17 | tmp 18 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'princely' 2 | 3 | RSpec.configure do |config| 4 | config.run_all_when_everything_filtered = true 5 | config.filter_run :focus 6 | #config.expect_with(:rspec) { |c| c.syntax = :should } 7 | 8 | config.order = 'random' 9 | end 10 | -------------------------------------------------------------------------------- /spec/princely/version_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'princely/version' 3 | 4 | describe Princely::Version do 5 | let(:version) { '9.9.9' } 6 | before { 7 | allow(Princely::Version).to receive(:version).and_return(version) 8 | } 9 | 10 | it "prints the version" do 11 | expect(Princely::Version.to_s).to eql(version) 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | before_install: 3 | - gem install bundler 4 | install: 5 | - bundle install 6 | before_script: 7 | - wget https://www.princexml.com/download/prince_11-1_ubuntu12.04_amd64.deb 8 | - sudo dpkg -i prince_11-1_ubuntu12.04_amd64.deb 9 | script: 10 | - bundle exec rspec spec 11 | rvm: 12 | - 2.2.3 13 | - 2.1.0 14 | - 2.0.0 15 | - 1.9.3 16 | - ruby-head 17 | -------------------------------------------------------------------------------- /lib/princely/logging.rb: -------------------------------------------------------------------------------- 1 | module Princely 2 | module Logging 3 | 4 | class << self 5 | attr_accessor :logger, :filename 6 | 7 | def logger 8 | @logger ||= defined?(Rails) ? Rails.logger : StdoutLogger 9 | end 10 | 11 | def filename 12 | pathname = defined?(Rails) ? Rails.root : Princely.root 13 | @filename ||= pathname.join 'log', 'prince.log' 14 | end 15 | end 16 | 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/princely/rails.rb: -------------------------------------------------------------------------------- 1 | require 'princely/pdf_helper' 2 | 3 | if Mime::Type.lookup_by_extension(:pdf) != 'application/pdf' 4 | Mime::Type.register 'application/pdf', :pdf 5 | end 6 | 7 | if defined?(Rails) 8 | if Rails::VERSION::MAJOR >= 5 9 | ActionController::Base.send(:prepend, Princely::PdfHelper) 10 | else 11 | ActionController::Base.send(:include, Princely::PdfHelper) 12 | end 13 | ActionController::Base.send(:include, Princely::AssetSupport) if 14 | (Rails::VERSION::MAJOR == 3 && Rails::VERSION::MINOR > 0) || 15 | (Rails::VERSION::MAJOR >= 4) 16 | end 17 | -------------------------------------------------------------------------------- /spec/princely/logging_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'princely/logging' 3 | 4 | module Princely 5 | describe Logging do 6 | describe "filename=" do 7 | it "sets the log file" do 8 | Princely::Logging.filename = "palakir" 9 | expect(Princely::Logging.filename).to eql("palakir") 10 | Princely::Logging.filename = nil # clean up 11 | end 12 | end 13 | 14 | describe "logger=" do 15 | it "sets the logger" do 16 | Princely::Logging.logger = TestLogger 17 | expect(Princely::Logging.logger).to eql(TestLogger) 18 | Princely::Logging.logger = nil # clean up 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/princely/executable.rb: -------------------------------------------------------------------------------- 1 | module Princely 2 | class Executable 3 | attr_reader :path 4 | 5 | def initialize(path=nil) 6 | @path = path || default_executable_path 7 | 8 | check_for_executable 9 | end 10 | 11 | def check_for_executable 12 | raise "Cannot find prince command-line app in $PATH" if !@path || @path.length == 0 13 | raise "Cannot find prince command-line app at #{@exe_path}" unless File.executable?(@path) 14 | end 15 | 16 | def default_executable_path 17 | if Princely.ruby_platform =~ /mswin32|minigw32/ 18 | "C:/Program Files/Prince/Engine/bin/prince" 19 | else 20 | `which prince`.chomp 21 | end 22 | end 23 | 24 | def join(options) 25 | ([path] + Array(options)).join(' ') 26 | end 27 | end 28 | end -------------------------------------------------------------------------------- /lib/princely/asset_support.rb: -------------------------------------------------------------------------------- 1 | module Princely 2 | module AssetSupport 3 | def localize_html_string(html_string, asset_path = nil) 4 | html_string = html_string.to_str 5 | # Make all paths relative, on disk paths... 6 | html_string.gsub!(".com:/",".com/") # strip out bad attachment_fu URLs 7 | html_string.gsub!( /src=["']+([^:]+?)["']/i ) do |m| 8 | asset_src = asset_path ? "#{asset_path}/#{$1}" : asset_file_path($1) 9 | %Q{src="#{asset_src}"} # re-route absolute paths 10 | end 11 | 12 | # Remove asset ids on images with a regex 13 | html_string.gsub!( /src=["'](\S+\?\d*)["']/i ) { |m| %Q{src="#{$1.split('?').first}"} } 14 | html_string 15 | end 16 | 17 | def asset_file_path(asset) 18 | # Remove /assets/ from generated names and try and find a matching asset 19 | Rails.application.assets ||= Sprockets::Environment.new 20 | Rails.application.assets.find_asset(asset.gsub(%r{/assets/}, "")).try(:pathname) || asset 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2007 [name of plugin creator] 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /princely.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | require File.expand_path('../lib/princely/version', __FILE__) 3 | 4 | Gem::Specification.new do |s| 5 | s.name = "princely" 6 | s.version = Princely::Version.to_s 7 | s.authors = ["Michael Bleigh", "Jared Fraser"] 8 | s.date = "2016-06-16" 9 | s.description = "A wrapper for the PrinceXML PDF generation library." 10 | s.summary = "A simple Rails wrapper for the PrinceXML PDF generation library." 11 | s.email = %w[michael@intridea.com dev@jsf.io] 12 | s.files = %w[ 13 | MIT-LICENSE 14 | README.md 15 | Rakefile 16 | lib/princely.rb 17 | lib/princely/asset_support.rb 18 | lib/princely/executable.rb 19 | lib/princely/logging.rb 20 | lib/princely/pdf.rb 21 | lib/princely/pdf_helper.rb 22 | lib/princely/rails.rb 23 | lib/princely/stdout_logger.rb 24 | lib/princely/version.rb 25 | ] 26 | s.homepage = "http://github.com/mbleigh/princely" 27 | s.require_paths = %w[lib] 28 | s.rubygems_version = "1.8.11" 29 | 30 | s.license = 'MIT' 31 | 32 | s.add_development_dependency('rspec') 33 | s.add_development_dependency('rake') 34 | end 35 | 36 | -------------------------------------------------------------------------------- /lib/princely.rb: -------------------------------------------------------------------------------- 1 | # PrinceXML Ruby interface. 2 | # http://www.princexml.com 3 | # 4 | # Original code by Seth @ Subimage LLC 5 | # - http://subimage.com/blog/2007/05/29/html-css-to-pdf-using-ruby-on-rails/ 6 | # 7 | # 8 | # USAGE 9 | # ----------------------------------------------------------------------------- 10 | # princely = Princely.new 11 | # html_string = render_to_string(:template => 'some_document') 12 | # send_data( 13 | # princely.pdf_from_string(html_string), 14 | # :filename => 'some_document.pdf' 15 | # :type => 'application/pdf' 16 | # ) 17 | # 18 | require 'logger' 19 | require 'pathname' 20 | require 'princely/rails' if defined?(Rails) 21 | 22 | module Princely 23 | autoload :StdoutLogger, 'princely/stdout_logger' 24 | autoload :AssetSupport, 'princely/asset_support' 25 | autoload :Pdf, 'princely/pdf' 26 | autoload :Logging, 'princely/logging' 27 | autoload :Executable, 'princely/executable' 28 | 29 | class << self 30 | def executable 31 | @custom_executable || Princely::Executable.new 32 | end 33 | 34 | def executable=(custom_executable) 35 | @custom_executable = custom_executable 36 | end 37 | 38 | def root 39 | Pathname.new(File.expand_path('../', __FILE__)) 40 | end 41 | 42 | def ruby_platform 43 | RUBY_PLATFORM 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /spec/princely/executable_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | module Princely 4 | describe Executable do 5 | context 'without executable checks' do 6 | before do 7 | allow_any_instance_of(Princely::Executable).to receive(:check_for_executable) 8 | end 9 | 10 | describe '#join' do 11 | let(:path) { '/some/path' } 12 | let(:executable) { Princely::Executable.new(path) } 13 | 14 | it 'joins an array of options' do 15 | expect(executable.join(['--opt', '--oopt'])).to eql("#{path} --opt --oopt") 16 | end 17 | 18 | it 'converts non-arrays to arrays' do 19 | expect(executable.join('--workworkwork')).to eql("#{path} --workworkwork") 20 | end 21 | end 22 | 23 | describe "executable_path" do 24 | it "returns a path for windows" do 25 | allow(Princely).to receive(:ruby_platform).and_return('mswin32') 26 | expect(Princely::Executable.new.path).to eql("C:/Program Files/Prince/Engine/bin/prince") 27 | end 28 | 29 | it "returns a path for OS X" do 30 | allow(Princely).to receive(:ruby_platform).and_return('x86_64-darwin12.0.0') 31 | expect(Princely::Executable.new.path).to eql(`which prince`.chomp) 32 | end 33 | end 34 | end 35 | 36 | describe "check_for_executable" do 37 | it "raises an error if path does not exist" do 38 | expect { Princely::Executable.new("/some/fake/path") }.to raise_error(RuntimeError) 39 | end 40 | 41 | it "raises an error if blank" do 42 | expect { Princely::Executable.new("") }.to raise_error(RuntimeError) 43 | end 44 | end 45 | 46 | end 47 | end -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Princely 2 | 3 | Princely is a simple wrapper for the [Prince XML PDF generation library](http://www.princexml.com). 4 | The plugin will also automatically register the PDF MimeType so that you can use 5 | pdf as a format in Rails controller `respond_to` blocks. 6 | 7 | ## Example 8 | 9 | ```ruby 10 | class Provider::EstimatesController < Provider::BaseController 11 | # You can render PDF templates simply by 12 | # using the :pdf option on render templates. 13 | def show 14 | respond_to do |format| 15 | format.html 16 | format.pdf do 17 | render :pdf => 'file_name', 18 | :template => 'controller/action', 19 | :handlers => %w[erb], 20 | :formats => %w[pdf], 21 | :stylesheets => %w[application prince], 22 | :layout => 'pdf', 23 | :locals => { :foo => 'bar' }, 24 | :disposition => 'inline', # PDF will be sent inline, means you can load it inside an iFrame or Embed 25 | :relative_paths => true # Modify asset paths to make them relative. See [the AssetSupport module](/lib/princely/asset_support.rb) 26 | end 27 | end 28 | end 29 | 30 | # Alternatively, you can use make_and_send_pdf to render out a PDF for the 31 | # action without a respond_to block. 32 | def pdf 33 | make_and_send_pdf "file_name" 34 | end 35 | end 36 | ``` 37 | 38 | ## Render Defaults 39 | 40 | The defaults for the render options are as follows: 41 | 42 | layout: false 43 | template: the template for the current controller/action 44 | locals: none 45 | stylesheets: none 46 | disposition: attachment (created PDF file will be sent as download) 47 | relative_paths: true 48 | server_flag: true 49 | javascript_flag: false 50 | timeout: none 51 | 52 | ## Contributors 53 | 54 | * Maintainer: Jared Fraser ([modsognir](https://github.com/modsognir)) 55 | * Gemification and more: Nic Williams 56 | * Based on code by: Seth B ([subimage](https://github.com/subimage)) 57 | * [Other Contributors](https://github.com/mbleigh/princely/contributors) 58 | 59 | ## Resources 60 | 61 | * Copyright (c) 2007-2013 Michael Bleigh and Intridea, Inc., released under the MIT license. 62 | -------------------------------------------------------------------------------- /lib/princely/pdf_helper.rb: -------------------------------------------------------------------------------- 1 | require 'princely' 2 | require 'princely/asset_support' 3 | 4 | module Princely 5 | module PdfHelper 6 | def self.included(base) 7 | base.send :alias_method, :render_without_princely, :render 8 | base.send :alias_method, :render, :render_with_princely 9 | end 10 | 11 | def self.prepended(base) 12 | base.send :alias_method, :render_without_princely, :render 13 | base.send :alias_method, :render, :render_with_princely 14 | end 15 | 16 | def render_with_princely(options = nil, *args, &block) 17 | if options.is_a?(Hash) && options.has_key?(:pdf) 18 | options[:name] ||= options.delete(:pdf) 19 | make_and_send_pdf(options.delete(:name), options) 20 | else 21 | render_without_princely(options, *args, &block) 22 | end 23 | end 24 | 25 | private 26 | 27 | def make_pdf(options = {}) 28 | options = { 29 | :stylesheets => [], 30 | :layout => false, 31 | :template => File.join(controller_path, action_name), 32 | :relative_paths => true, 33 | :server_flag => true, 34 | :media => nil, 35 | :javascript_flag => false 36 | }.merge(options) 37 | 38 | prince = Princely::Pdf.new(options.slice(:server_flag, :javascript_flag, :media)) 39 | # Sets style sheets on PDF renderer 40 | prince.add_style_sheets(*options[:stylesheets].collect{|style| asset_file_path(style)}) 41 | 42 | html_string = render_to_string(options.slice(:template, :layout, :handlers, :formats, :locals)) 43 | 44 | html_string = localize_html_string(html_string, Rails.public_path) if options[:relative_paths] 45 | 46 | # Send the generated PDF file from our html string. 47 | if filename = options[:filename] || options[:file] 48 | prince.pdf_from_string_to_file(html_string, filename) 49 | else 50 | prince.pdf_from_string(html_string) 51 | end 52 | end 53 | 54 | def asset_file_path(asset) 55 | asset = asset.to_s.gsub('.css', '') 56 | File.join(config.stylesheets_dir, "#{asset}.css") 57 | end 58 | alias_method :stylesheet_file_path, :asset_file_path 59 | 60 | def make_and_send_pdf(pdf_name, options = {}) 61 | options = {:disposition => 'attachment'}.merge(options) 62 | send_data( 63 | make_pdf(options), 64 | :filename => "#{pdf_name}.pdf", 65 | :type => 'application/pdf', 66 | :disposition => options[:disposition] 67 | ) 68 | end 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /spec/princely/pdf_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Princely::Pdf do 4 | let(:html_doc) { "Hello World"} 5 | before(:each) do 6 | Princely.executable = nil 7 | allow_any_instance_of(Princely::Executable).to receive(:check_for_executable) 8 | end 9 | 10 | it "generates a PDF from HTML" do 11 | pdf = Princely::Pdf.new.pdf_from_string html_doc 12 | expect(pdf).to start_with("%PDF-1.4") 13 | expect(pdf.rstrip).to end_with("%%EOF") 14 | pdf.length > 100 15 | end 16 | 17 | describe "logger" do 18 | it "defaults to STDOUT" do 19 | prince = Princely::Pdf.new 20 | expect(prince.logger).to eql(Princely::StdoutLogger) 21 | end 22 | 23 | it "can be set" do 24 | LoggerClass = Class.new 25 | prince = Princely::Pdf.new(:logger => LoggerClass.new) 26 | expect(prince.logger).to be_an_instance_of(LoggerClass) 27 | end 28 | end 29 | 30 | describe "log_file" do 31 | it "defaults in Rails" do 32 | Princely::Logging.filename = nil 33 | # Fake Rails for this test. 34 | Rails = double(:root => Pathname.new('in_rails'), :logger => nil) 35 | 36 | prince = Princely::Pdf.new 37 | expect(prince.log_file.to_s).to eql('in_rails/log/prince.log') 38 | 39 | # Unfake Rails 40 | Object.send(:remove_const, :Rails) 41 | end 42 | 43 | it "defaults outside of Rails" do 44 | Princely::Logging.filename = nil 45 | 46 | outside_rails = Pathname.new('outside_rails') 47 | allow(Princely).to receive(:root).and_return(outside_rails) 48 | 49 | prince = Princely::Pdf.new 50 | expect(prince.log_file).to eql(outside_rails.join('log/prince.log')) 51 | end 52 | end 53 | 54 | describe "exe_path" do 55 | let(:prince) { Princely::Pdf.new(:path => '/tmp/fake') } 56 | 57 | before(:each) do 58 | allow(prince).to receive(:log_file).and_return('/tmp/test_log') 59 | end 60 | 61 | it "appends default options" do 62 | expect(prince.exe_path).to eql("/tmp/fake --input=html --server --log=/tmp/test_log ") 63 | end 64 | 65 | it "adds stylesheet paths" do 66 | prince.style_sheets = " -s test.css " 67 | expect(prince.exe_path).to eql("/tmp/fake --input=html --server --log=/tmp/test_log -s test.css ") 68 | end 69 | 70 | it "adds the media type" do 71 | prince = Princely::Pdf.new(:path => '/tmp/fake', :media => "print_special") 72 | allow(prince).to receive(:log_file).and_return('/tmp/test_log') 73 | expect(prince.exe_path).to eql("/tmp/fake --input=html --server --log=/tmp/test_log --media=print_special ") 74 | end 75 | 76 | it "adds the javascript flag" do 77 | prince = Princely::Pdf.new(:path => '/tmp/fake', :javascript_flag => true) 78 | allow(prince).to receive(:log_file).and_return('/tmp/test_log') 79 | expect(prince.exe_path).to eql("/tmp/fake --input=html --server --log=/tmp/test_log --javascript ") 80 | end 81 | end 82 | end 83 | -------------------------------------------------------------------------------- /lib/princely/pdf.rb: -------------------------------------------------------------------------------- 1 | require 'timeout' 2 | 3 | module Princely 4 | class Pdf 5 | attr_accessor :executable, :style_sheets, :logger, :log_file, :server_flag, :media, :javascript_flag, :timeout 6 | 7 | # Initialize method 8 | # 9 | def initialize(options={}) 10 | options = { 11 | :path => nil, 12 | :executable => Princely.executable, 13 | :log_file => nil, 14 | :logger => nil, 15 | :server_flag => true, 16 | :media => nil, 17 | :javascript_flag => false 18 | }.merge(options) 19 | @executable = options[:path] ? Princely::Executable.new(options[:path]) : options[:executable] 20 | @style_sheets = '' 21 | @log_file = options[:log_file] 22 | @logger = options[:logger] 23 | @server_flag = options[:server_flag] 24 | @media = options[:media] 25 | @javascript_flag = options[:javascript_flag] 26 | @timeout = options[:timeout] 27 | end 28 | 29 | # Returns the instance logger or Princely default logger 30 | def logger 31 | @logger || Princely::Logging.logger 32 | end 33 | 34 | # Returns the instance log file or Princely default log file 35 | def log_file 36 | @log_file || Princely::Logging.filename 37 | end 38 | 39 | # Sets stylesheets... 40 | # Can pass in multiple paths for css files. 41 | # 42 | def add_style_sheets(*sheets) 43 | @style_sheets << sheets.map { |sheet| " -s #{sheet} " }.join(' ') 44 | end 45 | 46 | # Returns fully formed executable path with any command line switches 47 | # we've set based on our variables. 48 | # 49 | def exe_path 50 | @executable.join(executable_options) 51 | end 52 | 53 | def executable_options 54 | options = [] 55 | options << "--input=html" 56 | options << "--server" if @server_flag 57 | options << "--log=#{log_file}" 58 | options << "--media=#{media}" if media 59 | options << "--javascript" if @javascript_flag 60 | options << @style_sheets 61 | options 62 | end 63 | 64 | # Makes a pdf from a passed in string. 65 | # 66 | # Returns PDF as a stream, so we can use send_data to shoot 67 | # it down the pipe using Rails. 68 | # 69 | def pdf_from_string(string, output_file = '-') 70 | with_timeout do 71 | pdf = initialize_pdf_from_string(string, output_file, {:output_to_log_file => false}) 72 | pdf.close_write 73 | result = pdf.gets(nil) 74 | pdf.close_read 75 | result.force_encoding('BINARY') if RUBY_VERSION >= "1.9" 76 | 77 | result 78 | end 79 | end 80 | 81 | def pdf_from_string_to_file(string, output_file) 82 | with_timeout do 83 | pdf = initialize_pdf_from_string(string, output_file) 84 | pdf.close 85 | end 86 | end 87 | 88 | protected 89 | 90 | def with_timeout(&block) 91 | if timeout 92 | Timeout.timeout(timeout, &block) 93 | else 94 | block.call 95 | end 96 | end 97 | 98 | def initialize_pdf_from_string(string, output_file, options = {}) 99 | options = {:log_command => true, :output_to_log_file => true}.merge(options) 100 | path = exe_path 101 | # Don't spew errors to the standard out...and set up to take IO 102 | # as input and output 103 | path << " --media=#{media}" if media 104 | path << " --silent - -o #{output_file}" 105 | path << " >> '#{log_file}' 2>> '#{log_file}'" if options[:output_to_log_file] 106 | 107 | log_command path if options[:log_command] 108 | 109 | # Actually call the prince command, and pass the entire data stream back. 110 | pdf = IO.popen(path, "w+") 111 | pdf.puts string 112 | pdf 113 | end 114 | 115 | def log_command(path) 116 | logger.info "\n\nPRINCE XML PDF COMMAND" 117 | logger.info path 118 | logger.info '' 119 | end 120 | end 121 | end 122 | --------------------------------------------------------------------------------