acts_as_flying_saucer 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/README.markdown +153 -0
- data/Rakefile +2 -0
- data/acts_as_flying_saucer.gemspec +21 -0
- data/lib/acts_as_flying_saucer.rb +15 -0
- data/lib/acts_as_flying_saucer/acts_as_flying_saucer_controller.rb +98 -0
- data/lib/acts_as_flying_saucer/config.rb +22 -0
- data/lib/acts_as_flying_saucer/java/jar/acts_as_flying_saucer.jar +0 -0
- data/lib/acts_as_flying_saucer/java/src/Xhtml2Pdf.java +20 -0
- data/lib/acts_as_flying_saucer/java/src/encryptPdf.java +20 -0
- data/lib/acts_as_flying_saucer/version.rb +3 -0
- data/lib/acts_as_flying_saucer/xhtml2pdf.rb +36 -0
- metadata +80 -0
data/Gemfile
ADDED
data/README.markdown
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
acts\_as\_flying\_saucer
|
2
|
+
=====================
|
3
|
+
|
4
|
+
acts\_as\_flying\_saucer is a library that allows to save rendered views as pdf documents using the [Flying Saucer][1] java library.
|
5
|
+
|
6
|
+
[1]: https://xhtmlrenderer.dev.java.net/
|
7
|
+
|
8
|
+
Install
|
9
|
+
-------
|
10
|
+
|
11
|
+
Grab the last version from Github:
|
12
|
+
|
13
|
+
sudo gem install acts_as_flying_saucer
|
14
|
+
|
15
|
+
|
16
|
+
Requirements
|
17
|
+
------------
|
18
|
+
|
19
|
+
JDK 1.5.x or 1.6.x
|
20
|
+
|
21
|
+
Usage
|
22
|
+
-----
|
23
|
+
### Rails
|
24
|
+
Just call the acts\_as\_flying\_saucer method inside the controller you want to enable to generate pdf documents.
|
25
|
+
Then you can call the render\_pdf method.
|
26
|
+
It accepts the same options as ActionController::Base#render plus the following ones:
|
27
|
+
|
28
|
+
|
29
|
+
:pdf\_file - absolute path for the generated pdf file.
|
30
|
+
|
31
|
+
:send\_file - sends the generated pdf file to the browser. It's the hash the ActionController::Streaming#send\_file method will receive.
|
32
|
+
|
33
|
+
:password attach password for generated pdf
|
34
|
+
|
35
|
+
:debug_html - (boolean expected) generates html output to the browser for debugging purposes
|
36
|
+
|
37
|
+
class FooController < ActionController::Base
|
38
|
+
acts_as_flying_saucer
|
39
|
+
|
40
|
+
def create
|
41
|
+
render_pdf :template => 'foo/pdf_template'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
|
48
|
+
Examples
|
49
|
+
--------
|
50
|
+
|
51
|
+
# Renders the template located at '/foo/bar/pdf.html.erb' and stores the pdf
|
52
|
+
# in the temp path with a filename based on its md5 digest
|
53
|
+
render_pdf :file => '/foo/bar/pdf.html.erb'
|
54
|
+
|
55
|
+
# renders the template located at 'app/views/foo.html.erb' and saves the pdf
|
56
|
+
# in '/www/docs/foo.pdf'
|
57
|
+
render_pdf :template => 'foo', :pdf_file => '/www/docs/foo.pdf'
|
58
|
+
|
59
|
+
# renders the 'app/views/foo.html.erb' template, saves the pdf in the temp path
|
60
|
+
# and sends it to the browser with the name 'bar.pdf'
|
61
|
+
render_pdf :template => 'foo', :send_file => { :filename => 'bar.pdf' }
|
62
|
+
|
63
|
+
# To send file with password protection
|
64
|
+
render_pdf :template => 'foo', :send_file => { :filename => 'bar.pdf' },:password=>"xxx"
|
65
|
+
Now pdf is password protected
|
66
|
+
|
67
|
+
Easy as pie
|
68
|
+
|
69
|
+
While converting the xhtml document into a pdf, the css stylesheets and images should be referenced with absolute URLs(either local or remote) or Flying Saucer will not be able to access them.
|
70
|
+
If there is no asset host defined, it will set automatically during the pdf generation so the parser can access the requested resources:
|
71
|
+
|
72
|
+
View rendered in the browser:
|
73
|
+
|
74
|
+
<%= stylesheet_link_tag("styles.css") %>
|
75
|
+
#<link href="/stylesheets/styles.css?1228586784" media="screen" rel="stylesheet" type="text/css" />
|
76
|
+
|
77
|
+
|
78
|
+
<%= image_tag("rails.png") %>
|
79
|
+
# <img alt="Rails" src="/images/rails.png?1228433051" />
|
80
|
+
|
81
|
+
View rendered as pdf:
|
82
|
+
|
83
|
+
<%= stylesheet_link_tag("styles.css") %>
|
84
|
+
#<link href="http://localhost:3000/stylesheets/styles.css" media="print" rel="stylesheet" type="text/css" />
|
85
|
+
|
86
|
+
|
87
|
+
<%= image_tag("rails.png") %>
|
88
|
+
# <img alt="Rails" src="http://localhost:3000/images/rails.png" />
|
89
|
+
|
90
|
+
The stylesheet media type will be set to 'print' if none was given(otherwise it would not be parsed)
|
91
|
+
|
92
|
+
If you need to distinguish if the view is being rendered in the browser or as a pdf, you can use the @pdf\_mode variable, whose value will be set to :create
|
93
|
+
when generating the pdf version
|
94
|
+
|
95
|
+
Sinatra
|
96
|
+
-------
|
97
|
+
get '/' do
|
98
|
+
content_type 'application/pdf'
|
99
|
+
html_content = erb :index
|
100
|
+
render_pdf(:template=>html_content,:pdf_file=>"test.pdf",
|
101
|
+
:send_file=> {:file_name=>"test.pdf",:stream=>false},:password=>"xxx")
|
102
|
+
end
|
103
|
+
Ruby
|
104
|
+
----
|
105
|
+
class Pdf
|
106
|
+
def generate_pdf(input_file_html,output_pdf)
|
107
|
+
options = ActsAsFlyingSaucer::Config.options.merge({:input_file=>input_file_html,:output_file=>output_pdf})
|
108
|
+
ActsAsFlyingSaucer::Xhtml2Pdf.write_pdf(options)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
Configuration
|
113
|
+
-------------
|
114
|
+
|
115
|
+
These are the default settings which can be overwritten in your enviroment configuration file:
|
116
|
+
|
117
|
+
ActsAsFlyingSaucer::Config.options = {
|
118
|
+
:java_bin => "java", # java binary
|
119
|
+
:classpath_separator => ':', # classpath separator. unixes system use ':' and windows ';'
|
120
|
+
:tmp_path => "/tmp", # path where temporary files will be stored
|
121
|
+
:max_memory_mb=>512,
|
122
|
+
:nailgun =>false
|
123
|
+
}
|
124
|
+
|
125
|
+
|
126
|
+
Advance Configuration (TODO: Manually)
|
127
|
+
-------------------
|
128
|
+
Now acts_as_flying_saucer call java each time on creating pdf this will speed down speed of generaion of pdf.To overcome this start nailgun server that reads data from specific port and rendered pdf.so there is no need to launch the jvm everytime a new pdf is generated.
|
129
|
+
|
130
|
+
So to start nailgun with acts_as_flying_saucer plugin:
|
131
|
+
|
132
|
+
<code>
|
133
|
+
./script/plugin install git://github.com/amardaxini/nailgun.git
|
134
|
+
</code>
|
135
|
+
|
136
|
+
Start nailgun server.Before starting nailgun server make sure that your **classpath environment variable** set and point to jre/lib
|
137
|
+
|
138
|
+
<code>
|
139
|
+
script/nailgun start
|
140
|
+
</code>
|
141
|
+
<code>
|
142
|
+
rake nailgun
|
143
|
+
</code>
|
144
|
+
Generate pdf with nailgun you have to overwrite Configuration make **nailgun option to true**
|
145
|
+
Now after making nailgun option true run
|
146
|
+
|
147
|
+
<code>rake acts_as_flying_saucer</code>
|
148
|
+
|
149
|
+
<code>
|
150
|
+
script/flying_saucer_nailgun
|
151
|
+
</code>
|
152
|
+
|
153
|
+
Now you are ready with nailgun.
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "acts_as_flying_saucer/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "acts_as_flying_saucer"
|
7
|
+
s.version = ActsAsFlyingSaucer::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Amar Daxini"]
|
10
|
+
s.email = ["amardaxini@gmail.com"]
|
11
|
+
s.homepage = "http://rubygems.org/gems/acts_as_flying_saucer"
|
12
|
+
s.summary = %q{XHTML to PDF using Flying Saucer java library}
|
13
|
+
s.description = %q{XHTML to PDF using Flying Saucer java library}
|
14
|
+
|
15
|
+
s.rubyforge_project = "acts_as_flying_saucer"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'acts_as_flying_saucer/config'
|
2
|
+
require 'acts_as_flying_saucer/xhtml2pdf'
|
3
|
+
require 'acts_as_flying_saucer/acts_as_flying_saucer_controller'
|
4
|
+
if defined?(Rails)
|
5
|
+
ActionController::Base.send(:include, ActsAsFlyingSaucer::Controller)
|
6
|
+
elsif defined?(Sinatra)
|
7
|
+
Sinatra::Base.send(:include, ActsAsFlyingSaucer::Controller)
|
8
|
+
class Sinatra::Base
|
9
|
+
acts_as_flying_saucer
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module ActsAsFlyingSaucer
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# ActsAsFlyingSaucer
|
2
|
+
module ActsAsFlyingSaucer
|
3
|
+
|
4
|
+
module Controller
|
5
|
+
def self.included(base)
|
6
|
+
base.extend(ClassMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
# ClassMethods
|
12
|
+
#
|
13
|
+
module ClassMethods
|
14
|
+
|
15
|
+
# acts_as_flying_saucer
|
16
|
+
#
|
17
|
+
def acts_as_flying_saucer
|
18
|
+
self.send(:include, ActsAsFlyingSaucer::Controller::InstanceMethods)
|
19
|
+
class_eval do
|
20
|
+
attr_accessor :pdf_mode
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# InstanceMethods
|
26
|
+
#
|
27
|
+
module InstanceMethods
|
28
|
+
|
29
|
+
# render_pdf
|
30
|
+
#
|
31
|
+
def render_pdf(options = {})
|
32
|
+
|
33
|
+
# host = ActionController::Base.asset_host
|
34
|
+
# ActionController::Base.asset_host = request.protocol + request.host_with_port if host.blank?
|
35
|
+
#
|
36
|
+
# logger.debug("#{host} - #{host.nil?} - #{ActionController::Base.asset_host}")
|
37
|
+
|
38
|
+
self.pdf_mode = :create
|
39
|
+
if defined?(Rails)
|
40
|
+
html = render_to_string options
|
41
|
+
if options[:debug_html]
|
42
|
+
# ActionController::Base.asset_host = host
|
43
|
+
response.header["Content-Type"] = "text/html; charset=utf-8"
|
44
|
+
render :text => html and return
|
45
|
+
end
|
46
|
+
#sinatra
|
47
|
+
elsif defined?(Sinatra)
|
48
|
+
html = options[:template]
|
49
|
+
if options[:debug_html]
|
50
|
+
response.header["Content-Type"] = "text/html; charset=utf-8"
|
51
|
+
response.body << html and return
|
52
|
+
end
|
53
|
+
end
|
54
|
+
# saving the file
|
55
|
+
tmp_dir = ActsAsFlyingSaucer::Config.options[:tmp_path]
|
56
|
+
html_digest = Digest::MD5.hexdigest(html)
|
57
|
+
input_file =File.join(File.expand_path("#{tmp_dir}"),"#{html_digest}.html")
|
58
|
+
|
59
|
+
#logger.debug("html file: #{input_file}")
|
60
|
+
|
61
|
+
output_file = (options.has_key?(:pdf_file)) ? options[:pdf_file] : File.join(File.expand_path("#{tmp_dir}"),"#{html_digest}.pdf")
|
62
|
+
password = (options.has_key?(:password)) ? options[:password] : ""
|
63
|
+
|
64
|
+
|
65
|
+
generate_options = ActsAsFlyingSaucer::Config.options.merge({
|
66
|
+
:input_file => input_file,
|
67
|
+
:output_file => output_file,
|
68
|
+
:html => html,
|
69
|
+
})
|
70
|
+
|
71
|
+
ActsAsFlyingSaucer::Xhtml2Pdf.write_pdf(generate_options)
|
72
|
+
if password != ""
|
73
|
+
op=output_file.split(".")
|
74
|
+
op.pop
|
75
|
+
op << "a"
|
76
|
+
op=op.to_s+".pdf"
|
77
|
+
output_file_name = op
|
78
|
+
ActsAsFlyingSaucer::Xhtml2Pdf.encrypt_pdf(generate_options,output_file_name,password)
|
79
|
+
output_file = op
|
80
|
+
end
|
81
|
+
# restoring the host
|
82
|
+
# ActionController::Base.asset_host = host
|
83
|
+
|
84
|
+
# sending the file to the client
|
85
|
+
if options[:send_file]
|
86
|
+
|
87
|
+
send_file_options = {
|
88
|
+
:filename => File.basename(output_file)
|
89
|
+
#:x_sendfile => true,
|
90
|
+
}
|
91
|
+
send_file_options.merge!(options[:send_file]) if options.respond_to?(:merge)
|
92
|
+
send_file(output_file, send_file_options)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module ActsAsFlyingSaucer
|
2
|
+
|
3
|
+
class Config
|
4
|
+
# default options
|
5
|
+
class << self
|
6
|
+
attr_accessor :options
|
7
|
+
end
|
8
|
+
ActsAsFlyingSaucer::Config.options = {
|
9
|
+
:java_bin => "java",
|
10
|
+
:classpath_separator => ':',
|
11
|
+
:tmp_path => "/tmp",
|
12
|
+
:run_mode => :once,
|
13
|
+
:max_memory_mb => 512,
|
14
|
+
:nailgun=> false
|
15
|
+
}
|
16
|
+
class << self
|
17
|
+
attr_accessor :options
|
18
|
+
end
|
19
|
+
# cattr_accessor :options
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
Binary file
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import java.io.*;
|
2
|
+
import org.xhtmlrenderer.pdf.ITextRenderer;
|
3
|
+
|
4
|
+
public class Xhtml2Pdf
|
5
|
+
{
|
6
|
+
public static void main(String[] args) throws Exception {
|
7
|
+
|
8
|
+
String input = args[0];
|
9
|
+
String url = new File(input).toURI().toURL().toString();
|
10
|
+
String output = args[1];
|
11
|
+
|
12
|
+
OutputStream os = new FileOutputStream(output);
|
13
|
+
ITextRenderer renderer = new ITextRenderer();
|
14
|
+
renderer.setDocument(url);
|
15
|
+
renderer.layout();
|
16
|
+
renderer.createPDF(os);
|
17
|
+
os.close();
|
18
|
+
|
19
|
+
}
|
20
|
+
}
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import java.io.*;
|
2
|
+
import org.xhtmlrenderer.pdf.ITextRenderer;
|
3
|
+
import com.lowagie.text.pdf.PdfReader;
|
4
|
+
import com.lowagie.text.pdf.PdfWriter;
|
5
|
+
import com.lowagie.text.pdf.PdfEncryptor;
|
6
|
+
public class encryptPdf
|
7
|
+
{
|
8
|
+
public static void main(String[] args) throws Exception {
|
9
|
+
|
10
|
+
String input = args[0];
|
11
|
+
String output = args[1];
|
12
|
+
String password = args[2];
|
13
|
+
|
14
|
+
PdfReader pr = new PdfReader(input);
|
15
|
+
OutputStream os = new FileOutputStream(output);
|
16
|
+
PdfEncryptor.encrypt(pr,os, false,password,password, PdfWriter.AllowAssembly |
|
17
|
+
PdfWriter.AllowCopy | PdfWriter.AllowDegradedPrinting | PdfWriter.AllowFillIn | PdfWriter.AllowModifyAnnotations | PdfWriter.AllowModifyContents | PdfWriter.AllowPrinting | PdfWriter.AllowScreenReaders);
|
18
|
+
os.close();
|
19
|
+
}
|
20
|
+
}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module ActsAsFlyingSaucer
|
2
|
+
|
3
|
+
# Xhtml2Pdf
|
4
|
+
#
|
5
|
+
class Xhtml2Pdf
|
6
|
+
def self.write_pdf(options)
|
7
|
+
if !File.exists?(options[:input_file])
|
8
|
+
File.open(options[:input_file], 'w') do |file|
|
9
|
+
file << options[:html]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
java_dir = File.join(File.expand_path(File.dirname(__FILE__)), "java")
|
14
|
+
class_path = "'.#{options[:classpath_separator]}#{java_dir}/jar/acts_as_flying_saucer.jar'"
|
15
|
+
|
16
|
+
if options[:nailgun]
|
17
|
+
command = "#{Nailgun::NgCommand::NGPATH} Xhtml2Pdf #{options[:input_file]} #{options[:output_file]}"
|
18
|
+
else
|
19
|
+
command = "#{options[:java_bin]} -Xmx512m -Djava.awt.headless=true -cp #{class_path} acts_as_flying_saucer.Xhtml2Pdf #{options[:input_file]} #{options[:output_file]}"
|
20
|
+
end
|
21
|
+
system(command)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.encrypt_pdf(options,output_file_name,password)
|
25
|
+
java_dir = File.join(File.expand_path(File.dirname(__FILE__)), "java")
|
26
|
+
class_path = "'.#{options[:classpath_separator]}#{java_dir}/jar/acts_as_flying_saucer.jar'"
|
27
|
+
if options[:nailgun]
|
28
|
+
command = "#{Nailgun::NgCommand::NGPATH} encryptPdf #{options[:input_file]} #{options[:output_file]}"
|
29
|
+
else
|
30
|
+
command = "#{options[:java_bin]} -Xmx#{options[:max_memory_mb]}m -Djava.awt.headless=true -cp #{class_path} acts_as_flying_saucer.encryptPdf #{options[:output_file]} #{output_file_name} #{password}"
|
31
|
+
end
|
32
|
+
system(command)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: acts_as_flying_saucer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Amar Daxini
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-03-24 00:00:00 +05:30
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: XHTML to PDF using Flying Saucer java library
|
23
|
+
email:
|
24
|
+
- amardaxini@gmail.com
|
25
|
+
executables: []
|
26
|
+
|
27
|
+
extensions: []
|
28
|
+
|
29
|
+
extra_rdoc_files: []
|
30
|
+
|
31
|
+
files:
|
32
|
+
- .gitignore
|
33
|
+
- Gemfile
|
34
|
+
- README.markdown
|
35
|
+
- Rakefile
|
36
|
+
- acts_as_flying_saucer.gemspec
|
37
|
+
- lib/acts_as_flying_saucer.rb
|
38
|
+
- lib/acts_as_flying_saucer/acts_as_flying_saucer_controller.rb
|
39
|
+
- lib/acts_as_flying_saucer/config.rb
|
40
|
+
- lib/acts_as_flying_saucer/java/jar/acts_as_flying_saucer.jar
|
41
|
+
- lib/acts_as_flying_saucer/java/src/Xhtml2Pdf.java
|
42
|
+
- lib/acts_as_flying_saucer/java/src/encryptPdf.java
|
43
|
+
- lib/acts_as_flying_saucer/version.rb
|
44
|
+
- lib/acts_as_flying_saucer/xhtml2pdf.rb
|
45
|
+
has_rdoc: true
|
46
|
+
homepage: http://rubygems.org/gems/acts_as_flying_saucer
|
47
|
+
licenses: []
|
48
|
+
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options: []
|
51
|
+
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 3
|
60
|
+
segments:
|
61
|
+
- 0
|
62
|
+
version: "0"
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
hash: 3
|
69
|
+
segments:
|
70
|
+
- 0
|
71
|
+
version: "0"
|
72
|
+
requirements: []
|
73
|
+
|
74
|
+
rubyforge_project: acts_as_flying_saucer
|
75
|
+
rubygems_version: 1.3.7
|
76
|
+
signing_key:
|
77
|
+
specification_version: 3
|
78
|
+
summary: XHTML to PDF using Flying Saucer java library
|
79
|
+
test_files: []
|
80
|
+
|