pdf_ravager 0.0.7 → 0.0.8
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.
- data/.travis.yml +9 -3
- data/README.md +4 -1
- data/Rakefile +19 -4
- data/lib/pdf_ravager/ravager.rb +41 -11
- data/lib/pdf_ravager/version.rb +1 -1
- data/pdf_ravager.gemspec +5 -4
- data/spec/integration/integration_helper.rb +58 -0
- data/spec/integration/multiline_text_field/expected.png +0 -0
- data/spec/integration/multiline_text_field/pdf +0 -0
- data/spec/integration/multiline_text_field/spec.rb +20 -0
- data/spec/integration/text_field/expected.png +0 -0
- data/spec/integration/text_field/pdf +0 -0
- data/spec/integration/text_field/spec.rb +20 -0
- data/spec/{pdf_spec.rb → unit/pdf_spec.rb} +1 -1
- data/spec/unit/unit_helper.rb +2 -0
- metadata +45 -10
data/.travis.yml
CHANGED
@@ -2,7 +2,13 @@ language: ruby
|
|
2
2
|
rvm:
|
3
3
|
- "1.9.2"
|
4
4
|
- "1.9.3"
|
5
|
-
- jruby-19mode
|
5
|
+
- jruby-19mode
|
6
6
|
- rbx-19mode
|
7
|
-
|
8
|
-
|
7
|
+
matrix:
|
8
|
+
allow_failures:
|
9
|
+
- rvm: jruby-19mode
|
10
|
+
before_install:
|
11
|
+
- sudo add-apt-repository "deb http://archive.canonical.com/ $(lsb_release -sc) partner" -y
|
12
|
+
- sudo apt-get update -y
|
13
|
+
- sudo apt-get install acroread ghostscript -y
|
14
|
+
|
data/README.md
CHANGED
@@ -82,4 +82,7 @@ check 'relation.parent'
|
|
82
82
|
Copyright (c) 2012 Abe Voelker. Released under the terms of the
|
83
83
|
MIT license. See LICENSE for details.
|
84
84
|
|
85
|
-
[
|
85
|
+
The [version of iText][2] vendored is licensed under the LGPL.
|
86
|
+
|
87
|
+
[1]: http://partners.adobe.com/public/developer/xml/index_arch.html
|
88
|
+
[2]: http://itext.svn.sourceforge.net/viewvc/itext/tags/iText_4_2_0/
|
data/Rakefile
CHANGED
@@ -1,10 +1,25 @@
|
|
1
1
|
require 'rspec'
|
2
|
+
require 'rspec/core/rake_task'
|
2
3
|
require 'rake/testtask'
|
3
4
|
require 'bundler'
|
4
5
|
|
5
|
-
Rake::TestTask.new do |t|
|
6
|
+
Rake::TestTask.new('spec:unit') do |t|
|
6
7
|
t.libs << ["lib", "spec"]
|
7
|
-
t.pattern = "spec
|
8
|
-
end
|
8
|
+
t.pattern = "spec/**/*_spec.rb"
|
9
|
+
end
|
9
10
|
|
10
|
-
|
11
|
+
if RUBY_PLATFORM =~ /java/
|
12
|
+
# Integration tests can only run on JRuby
|
13
|
+
RSpec::Core::RakeTask.new('spec:integration') do |spec|
|
14
|
+
spec.pattern = "spec/**/*spec.rb"
|
15
|
+
spec.rspec_opts = ['--backtrace']
|
16
|
+
end
|
17
|
+
|
18
|
+
task :spec => ['spec:unit', 'spec:integration']
|
19
|
+
else
|
20
|
+
task :spec => ['spec:unit']
|
21
|
+
end
|
22
|
+
|
23
|
+
task :default => :spec
|
24
|
+
|
25
|
+
Bundler::GemHelper.install_tasks
|
data/lib/pdf_ravager/ravager.rb
CHANGED
@@ -38,23 +38,40 @@ module PDFRavager
|
|
38
38
|
# First try AcroForms method of setting value
|
39
39
|
@afields.setField(SOM.short_name(name), value)
|
40
40
|
rescue java.lang.NullPointerException
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
41
|
+
end
|
42
|
+
# Also look for the XDP node and set that value
|
43
|
+
# Note: the double-load is to work around a Nokogiri bug I found:
|
44
|
+
# https://github.com/sparklemotion/nokogiri/issues/781
|
45
|
+
doc = Nokogiri::XML(Nokogiri::XML::Document.wrap(@xfa.getDomDocument).to_xml)
|
46
|
+
node_type = type == :checkbox ? 'integer' : 'text'
|
47
|
+
doc.xpath("//*[local-name()='field'][@name='#{name}']").each do |node|
|
48
|
+
value_node = node.at_xpath("*[local-name()='value']")
|
49
|
+
if value_node
|
50
|
+
text_node = value_node.at_xpath("*[local-name()='#{node_type}']")
|
51
|
+
if text_node
|
52
|
+
# Complete node structure already exists - just set the value
|
53
|
+
text_node.content = value
|
54
|
+
else
|
55
|
+
# <value> node exists, but without child <text> node
|
56
|
+
Nokogiri::XML::Builder.with(value_node) do |xml|
|
57
|
+
xml.text_ {
|
58
|
+
xml.send("#{node_type}_", value)
|
59
|
+
}
|
60
|
+
end
|
61
|
+
end
|
62
|
+
else
|
63
|
+
# No <value> node exists - create whole structure
|
47
64
|
Nokogiri::XML::Builder.with(node) do |xml|
|
48
65
|
xml.value_ {
|
49
|
-
xml.
|
66
|
+
xml.send("#{node_type}_") {
|
50
67
|
xml.text value
|
51
68
|
}
|
52
69
|
}
|
53
70
|
end
|
54
71
|
end
|
55
|
-
@xfa.setDomDocument(doc.to_java)
|
56
|
-
@xfa.setChanged(true)
|
57
72
|
end
|
73
|
+
@xfa.setDomDocument(doc.to_java)
|
74
|
+
@xfa.setChanged(true)
|
58
75
|
end
|
59
76
|
|
60
77
|
def destroy
|
@@ -81,14 +98,27 @@ module PDFRavager
|
|
81
98
|
def set_rich_text_field(name, value)
|
82
99
|
doc = Nokogiri::XML(Nokogiri::XML::Document.wrap(@xfa.getDomDocument).to_xml)
|
83
100
|
doc.xpath("//*[local-name()='field'][@name='#{name}']").each do |node|
|
84
|
-
|
85
|
-
|
101
|
+
value_node = node.at_xpath("*[local-name()='value']")
|
102
|
+
if value_node
|
103
|
+
# <value> node exists - just create <exData>
|
104
|
+
Nokogiri::XML::Builder.with(value_node) do |xml|
|
86
105
|
xml.exData('contentType' => 'text/html') do
|
87
106
|
xml.body_('xmlns' => "http://www.w3.org/1999/xhtml", 'xmlns:xfa' => "http://www.xfa.org/schema/xfa-data/1.0/") do
|
88
107
|
xml << value # Note: this value is not sanitized/escaped!
|
89
108
|
end
|
90
109
|
end
|
91
110
|
end
|
111
|
+
else
|
112
|
+
# No <value> node exists - create whole structure
|
113
|
+
Nokogiri::XML::Builder.with(node) do |xml|
|
114
|
+
xml.value_ do
|
115
|
+
xml.exData('contentType' => 'text/html') do
|
116
|
+
xml.body_('xmlns' => "http://www.w3.org/1999/xhtml", 'xmlns:xfa' => "http://www.xfa.org/schema/xfa-data/1.0/") do
|
117
|
+
xml << value # Note: this value is not sanitized/escaped!
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
92
122
|
end
|
93
123
|
end
|
94
124
|
@xfa.setDomDocument(doc.to_java)
|
data/lib/pdf_ravager/version.rb
CHANGED
data/pdf_ravager.gemspec
CHANGED
@@ -12,10 +12,11 @@ Gem::Specification.new do |s|
|
|
12
12
|
|
13
13
|
s.add_dependency "json"
|
14
14
|
s.add_dependency "nokogiri"
|
15
|
-
s.add_development_dependency "bundler",
|
16
|
-
s.add_development_dependency "minitest",
|
17
|
-
s.add_development_dependency "rspec",
|
18
|
-
s.add_development_dependency "rake",
|
15
|
+
s.add_development_dependency "bundler", "~> 1.0"
|
16
|
+
s.add_development_dependency "minitest", "~> 4.1"
|
17
|
+
s.add_development_dependency "rspec", "~> 2.11"
|
18
|
+
s.add_development_dependency "rake", "~> 0.9"
|
19
|
+
s.add_development_dependency "chunky_png", "~> 1.2"
|
19
20
|
|
20
21
|
s.files = `git ls-files`.split("\n")
|
21
22
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
require 'rspec'
|
3
|
+
require 'pdf_ravager'
|
4
|
+
require 'securerandom'
|
5
|
+
require 'chunky_png'
|
6
|
+
|
7
|
+
def mktemp
|
8
|
+
# the tests are already dependent on Linux, so /tmp/ usage should be OK
|
9
|
+
"/tmp/#{SecureRandom.uuid}"
|
10
|
+
end
|
11
|
+
|
12
|
+
def pdf_to_ps(pdf_file, out_file=nil)
|
13
|
+
out_file ||= "#{mktemp}.ps"
|
14
|
+
system("acroread -toPostScript -markupsOn -pairs #{pdf_file} #{out_file} >/dev/null 2>&1")
|
15
|
+
out_file
|
16
|
+
end
|
17
|
+
|
18
|
+
def ps_to_png(ps_file, out_file=nil)
|
19
|
+
out_file ||= "#{mktemp}.png"
|
20
|
+
system("gs -dSAFER -dBATCH -dNOPAUSE -r150 -sDEVICE=png16m -dTextAlphaBits=4 -sOutputFile=#{out_file} #{ps_file} >/dev/null 2>&1")
|
21
|
+
out_file
|
22
|
+
end
|
23
|
+
|
24
|
+
def pdf_to_png(pdf_file)
|
25
|
+
ps_to_png(pdf_to_ps(pdf_file))
|
26
|
+
end
|
27
|
+
|
28
|
+
# code taken from http://jeffkreeftmeijer.com/2011/comparing-images-and-creating-image-diffs/
|
29
|
+
def png_diff(img1, img2)
|
30
|
+
images = [
|
31
|
+
ChunkyPNG::Image.from_file(img1),
|
32
|
+
ChunkyPNG::Image.from_file(img2)
|
33
|
+
]
|
34
|
+
|
35
|
+
output = ChunkyPNG::Image.new(images.first.width, images.last.width, ChunkyPNG::Color::WHITE)
|
36
|
+
|
37
|
+
diff = []
|
38
|
+
|
39
|
+
images.first.height.times do |y|
|
40
|
+
images.first.row(y).each_with_index do |pixel, x|
|
41
|
+
unless pixel == images.last[x,y]
|
42
|
+
score = Math.sqrt(
|
43
|
+
(ChunkyPNG::Color::r(images.last[x,y]) - ChunkyPNG::Color::r(pixel)) ** 2 +
|
44
|
+
(ChunkyPNG::Color::g(images.last[x,y]) - ChunkyPNG::Color::g(pixel)) ** 2 +
|
45
|
+
(ChunkyPNG::Color::b(images.last[x,y]) - ChunkyPNG::Color::b(pixel)) ** 2
|
46
|
+
) / Math.sqrt(ChunkyPNG::Color::MAX ** 2 * 3)
|
47
|
+
|
48
|
+
output[x,y] = ChunkyPNG::Color::grayscale(ChunkyPNG::Color::MAX - (score * ChunkyPNG::Color::MAX).round)
|
49
|
+
diff << score
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
num_pixels_changed = diff.length
|
55
|
+
pct_changed = (num_pixels_changed == 0) ? 0 : (diff.inject(:+) / images.first.pixels.length) * 100
|
56
|
+
|
57
|
+
[num_pixels_changed, pct_changed]
|
58
|
+
end
|
Binary file
|
Binary file
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../integration_helper'
|
2
|
+
|
3
|
+
describe 'a PDF with a multiline text field' do
|
4
|
+
describe 'filled with FOO' do
|
5
|
+
before(:each) do
|
6
|
+
p = pdf do
|
7
|
+
text 'multilinetext', 'FOO' * 10000
|
8
|
+
end
|
9
|
+
pdf_file = File.join(File.dirname(__FILE__), "pdf")
|
10
|
+
@pdf_file = "#{mktemp}.pdf"
|
11
|
+
@pdf = p.ravage pdf_file, :out_file => @pdf_file
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should match expected.png when rendered' do
|
15
|
+
png = pdf_to_png(@pdf_file)
|
16
|
+
pix_diff, pct_diff = png_diff(png, File.join(File.dirname(__FILE__), "expected.png"))
|
17
|
+
pix_diff.should == 0
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
Binary file
|
Binary file
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'integration/integration_helper'
|
2
|
+
|
3
|
+
describe 'a PDF with a text field' do
|
4
|
+
describe 'filled with foo' do
|
5
|
+
before(:each) do
|
6
|
+
p = pdf do
|
7
|
+
text 'text_field', 'foo'
|
8
|
+
end
|
9
|
+
pdf_file = File.join(File.dirname(__FILE__), "pdf")
|
10
|
+
@pdf_file = "#{mktemp}.pdf"
|
11
|
+
@pdf = p.ravage pdf_file, :out_file => @pdf_file
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should match expected.png when rendered' do
|
15
|
+
png = pdf_to_png(@pdf_file)
|
16
|
+
pix_diff, pct_diff = png_diff(png, File.join(File.dirname(__FILE__), "expected.png"))
|
17
|
+
pix_diff.should be 0
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pdf_ravager
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.8
|
4
5
|
prerelease:
|
5
|
-
version: 0.0.7
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Abe Voelker
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-11-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: json
|
@@ -17,13 +17,15 @@ dependencies:
|
|
17
17
|
requirements:
|
18
18
|
- - ! '>='
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version:
|
20
|
+
version: !binary |-
|
21
|
+
MA==
|
21
22
|
none: false
|
22
23
|
requirement: !ruby/object:Gem::Requirement
|
23
24
|
requirements:
|
24
25
|
- - ! '>='
|
25
26
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
27
|
+
version: !binary |-
|
28
|
+
MA==
|
27
29
|
none: false
|
28
30
|
prerelease: false
|
29
31
|
type: :runtime
|
@@ -33,13 +35,15 @@ dependencies:
|
|
33
35
|
requirements:
|
34
36
|
- - ! '>='
|
35
37
|
- !ruby/object:Gem::Version
|
36
|
-
version:
|
38
|
+
version: !binary |-
|
39
|
+
MA==
|
37
40
|
none: false
|
38
41
|
requirement: !ruby/object:Gem::Requirement
|
39
42
|
requirements:
|
40
43
|
- - ! '>='
|
41
44
|
- !ruby/object:Gem::Version
|
42
|
-
version:
|
45
|
+
version: !binary |-
|
46
|
+
MA==
|
43
47
|
none: false
|
44
48
|
prerelease: false
|
45
49
|
type: :runtime
|
@@ -107,6 +111,22 @@ dependencies:
|
|
107
111
|
none: false
|
108
112
|
prerelease: false
|
109
113
|
type: :development
|
114
|
+
- !ruby/object:Gem::Dependency
|
115
|
+
name: chunky_png
|
116
|
+
version_requirements: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - ~>
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '1.2'
|
121
|
+
none: false
|
122
|
+
requirement: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - ~>
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '1.2'
|
127
|
+
none: false
|
128
|
+
prerelease: false
|
129
|
+
type: :development
|
110
130
|
description: DSL to aid filling out AcroForms PDF and XFA documents
|
111
131
|
email: abe@abevoelker.com
|
112
132
|
executables: []
|
@@ -124,8 +144,16 @@ files:
|
|
124
144
|
- lib/pdf_ravager/ravager.rb
|
125
145
|
- lib/pdf_ravager/version.rb
|
126
146
|
- pdf_ravager.gemspec
|
127
|
-
- spec/
|
147
|
+
- spec/integration/integration_helper.rb
|
148
|
+
- spec/integration/multiline_text_field/expected.png
|
149
|
+
- spec/integration/multiline_text_field/pdf
|
150
|
+
- spec/integration/multiline_text_field/spec.rb
|
151
|
+
- spec/integration/text_field/expected.png
|
152
|
+
- spec/integration/text_field/pdf
|
153
|
+
- spec/integration/text_field/spec.rb
|
128
154
|
- spec/spec_helper.rb
|
155
|
+
- spec/unit/pdf_spec.rb
|
156
|
+
- spec/unit/unit_helper.rb
|
129
157
|
- vendor/iText-4.2.0.jar
|
130
158
|
homepage: https://github.com/abevoelker/pdf_ravager
|
131
159
|
licenses: []
|
@@ -137,13 +165,21 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
137
165
|
requirements:
|
138
166
|
- - ! '>='
|
139
167
|
- !ruby/object:Gem::Version
|
140
|
-
|
168
|
+
segments:
|
169
|
+
- 0
|
170
|
+
version: !binary |-
|
171
|
+
MA==
|
172
|
+
hash: 2
|
141
173
|
none: false
|
142
174
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
143
175
|
requirements:
|
144
176
|
- - ! '>='
|
145
177
|
- !ruby/object:Gem::Version
|
146
|
-
|
178
|
+
segments:
|
179
|
+
- 0
|
180
|
+
version: !binary |-
|
181
|
+
MA==
|
182
|
+
hash: 2
|
147
183
|
none: false
|
148
184
|
requirements: []
|
149
185
|
rubyforge_project:
|
@@ -152,4 +188,3 @@ signing_key:
|
|
152
188
|
specification_version: 3
|
153
189
|
summary: DSL to aid filling out AcroForms PDF and XFA documents
|
154
190
|
test_files: []
|
155
|
-
...
|