pdf_ravager 0.2.0 → 0.2.1
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.
- checksums.yaml +4 -4
- data/.travis.yml +3 -0
- data/Gemfile +2 -3
- data/LICENSE +1 -1
- data/README.md +40 -6
- data/lib/pdf_ravager/field_types/xfa.rb +17 -38
- data/lib/pdf_ravager/fields/rich_text.rb +12 -39
- data/lib/pdf_ravager/strategies/smart.rb +16 -1
- data/lib/pdf_ravager/strategies/xfa.rb +18 -36
- data/lib/pdf_ravager/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: af97c49b1e6876971dd1d81e67f5169044970df8
|
4
|
+
data.tar.gz: e5575521306846de1411f15f4b23ca1b601d5e65
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 36993a4b30050636d312d5df41d4542e7fbc6722c0da83fbe87d41e042aab3c4cc30735275ef35a9a67c791abb47c9c629b9847784c8db391190401421a13e9c
|
7
|
+
data.tar.gz: bc2d3c2348865ac36164344aab42027374d62d2cdb6890ab14a0dc21a954deb89c12e979d43c7b1648ef21f585ea29710ff6ab2959adcb12a614c1aa6822fc23
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
@@ -4,8 +4,7 @@ gemspec
|
|
4
4
|
|
5
5
|
platforms :jruby do
|
6
6
|
# Necessary for `rake release` on JRuby
|
7
|
-
gem
|
8
|
-
gem 'bouncy-castle-java'
|
7
|
+
gem 'jruby-openssl', '~> 0.9'
|
9
8
|
end
|
10
9
|
|
11
|
-
gem
|
10
|
+
gem 'simplecov', '~> 0.8', :require => false
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,14 +1,26 @@
|
|
1
|
-
|
1
|
+
PDF Ravager
|
2
|
+
===========
|
3
|
+
[][gem]
|
4
|
+
[][travis]
|
5
|
+
[][codeclimate]
|
6
|
+
[][gemnasium]
|
7
|
+
|
8
|
+
[gem]: https://rubygems.org/gems/pdf_ravager
|
9
|
+
[travis]: http://travis-ci.org/abevoelker/pdf_ravager
|
10
|
+
[codeclimate]: https://codeclimate.com/github/abevoelker/pdf_ravager
|
11
|
+
[gemnasium]: https://gemnasium.com/abevoelker/pdf_ravager
|
2
12
|
|
3
13
|
JRuby-only DSL for filling out AcroForms PDF or XFA documents.
|
4
14
|
|
5
|
-
|
15
|
+
Description
|
16
|
+
-----------
|
6
17
|
|
7
18
|
This library uses a combination of a simple DSL and a minimal façade over the
|
8
19
|
last free version of the Java iText library to aid in filling out AcroForms PDF
|
9
20
|
or XFA documents.
|
10
21
|
|
11
|
-
|
22
|
+
Synopsis
|
23
|
+
--------
|
12
24
|
|
13
25
|
```ruby
|
14
26
|
require 'pdf_ravager'
|
@@ -58,7 +70,28 @@ end
|
|
58
70
|
|
59
71
|
Note: `pdf` has been deprecated and will be removed in a future release.
|
60
72
|
|
61
|
-
|
73
|
+
Usage
|
74
|
+
-----
|
75
|
+
|
76
|
+
### Strategies
|
77
|
+
|
78
|
+
By default, PDF Ravager uses a `:smart` strategy for populating PDFs which
|
79
|
+
first attempts to fill fields using the `:acro_forms` strategy, then
|
80
|
+
applies the `:xfa` strategy to fields that were unable to be populated with
|
81
|
+
`:acro_forms`. If you know which strategy you want ahead of time (e.g. your
|
82
|
+
form is strictly a static AcroForm or a dynamic XFA), you can set it in
|
83
|
+
the template initializer like so:
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
template = PDFRavager::Template.new(strategy: :xfa) do |p|
|
87
|
+
# ...
|
88
|
+
end
|
89
|
+
```
|
90
|
+
|
91
|
+
Valid options are:
|
92
|
+
* `:smart`
|
93
|
+
* `:acro_forms`
|
94
|
+
* `:xfa`
|
62
95
|
|
63
96
|
### Field Names
|
64
97
|
To query and modify a form's field names, use a tool such as Adobe
|
@@ -99,9 +132,10 @@ pdf do |p|
|
|
99
132
|
end
|
100
133
|
```
|
101
134
|
|
102
|
-
|
135
|
+
Copyright
|
136
|
+
---------
|
103
137
|
|
104
|
-
Copyright (c) 2012-
|
138
|
+
Copyright (c) 2012-2014 Abe Voelker. Released under the terms of the
|
105
139
|
MIT license. See LICENSE for details.
|
106
140
|
|
107
141
|
The [version of iText][2] vendored is licensed under the LGPL.
|
@@ -16,48 +16,27 @@ module PDFRavager
|
|
16
16
|
@value.to_s
|
17
17
|
end
|
18
18
|
|
19
|
-
def set_xfa_value(
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
doc.xpath(xfa_name)
|
27
|
-
rescue Nokogiri::XML::XPath::SyntaxError
|
28
|
-
[]
|
29
|
-
end
|
30
|
-
# otherwise, we'll loosely match the field name anywhere in the document:
|
31
|
-
loose_match = doc.xpath("//*[local-name()='field'][@name='#{xfa_name}']")
|
32
|
-
matched_nodes = strict_match.any? ? strict_match : loose_match
|
33
|
-
matched_nodes.each do |node|
|
34
|
-
value_node = node.at_xpath("*[local-name()='value']")
|
35
|
-
if value_node
|
36
|
-
text_node = value_node.at_xpath("*[local-name()='#{xfa_node_type}']")
|
37
|
-
if text_node
|
38
|
-
# Complete node structure already exists - just set the value
|
39
|
-
text_node.content = xfa_value
|
40
|
-
else
|
41
|
-
# <value> node exists, but without child <text> node
|
42
|
-
Nokogiri::XML::Builder.with(value_node) do |xml|
|
43
|
-
xml.text_ {
|
44
|
-
xml.send("#{xfa_node_type}_", xfa_value)
|
45
|
-
}
|
46
|
-
end
|
47
|
-
end
|
19
|
+
def set_xfa_value(node)
|
20
|
+
value_node = node.at_xpath("*[local-name()='value']")
|
21
|
+
if value_node
|
22
|
+
child_node = value_node.at_xpath("*[local-name()='#{xfa_node_type}']")
|
23
|
+
if child_node
|
24
|
+
# Complete node structure already exists - just set the value
|
25
|
+
child_node.content = xfa_value
|
48
26
|
else
|
49
|
-
#
|
50
|
-
Nokogiri::XML::Builder.with(
|
51
|
-
xml.
|
52
|
-
xml.send("#{xfa_node_type}_") {
|
53
|
-
xml.text xfa_value
|
54
|
-
}
|
55
|
-
}
|
27
|
+
# Must create child <#{xfa_node_type}> node
|
28
|
+
Nokogiri::XML::Builder.with(value_node) do |xml|
|
29
|
+
xml.send("#{xfa_node_type}_", xfa_value)
|
56
30
|
end
|
57
31
|
end
|
32
|
+
else
|
33
|
+
# No <value> node exists - create whole structure
|
34
|
+
Nokogiri::XML::Builder.with(node) do |xml|
|
35
|
+
xml.value_ {
|
36
|
+
xml.send("#{xfa_node_type}_", xfa_value)
|
37
|
+
}
|
38
|
+
end
|
58
39
|
end
|
59
|
-
xfa.setDomDocument(doc.to_java)
|
60
|
-
xfa.setChanged(true)
|
61
40
|
end
|
62
41
|
|
63
42
|
end
|
@@ -15,46 +15,19 @@ module PDFRavager
|
|
15
15
|
self.name == other.name && self.value == other.value
|
16
16
|
end
|
17
17
|
|
18
|
-
def set_xfa_value(
|
19
|
-
|
20
|
-
#
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
loose_match = doc.xpath("//*[local-name()='field'][@name='#{xfa_name}']")
|
31
|
-
matched_nodes = strict_match.any? ? strict_match : loose_match
|
32
|
-
matched_nodes.each do |node|
|
33
|
-
value_node = node.at_xpath("*[local-name()='value']")
|
34
|
-
if value_node
|
35
|
-
# <value> node exists - just create <exData>
|
36
|
-
Nokogiri::XML::Builder.with(value_node) do |xml|
|
37
|
-
xml.exData('contentType' => 'text/html') do
|
38
|
-
xml.body_('xmlns' => "http://www.w3.org/1999/xhtml", 'xmlns:xfa' => "http://www.xfa.org/schema/xfa-data/1.0/") do
|
39
|
-
xml << xfa_value # Note: this value is not sanitized/escaped!
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
else
|
44
|
-
# No <value> node exists - create whole structure
|
45
|
-
Nokogiri::XML::Builder.with(node) do |xml|
|
46
|
-
xml.value_ do
|
47
|
-
xml.exData('contentType' => 'text/html') do
|
48
|
-
xml.body_('xmlns' => "http://www.w3.org/1999/xhtml", 'xmlns:xfa' => "http://www.xfa.org/schema/xfa-data/1.0/") do
|
49
|
-
xml << xfa_value # Note: this value is not sanitized/escaped!
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
18
|
+
def set_xfa_value(node)
|
19
|
+
value_node = node.at_xpath("*[local-name()='value']")
|
20
|
+
value_node && value_node.remove # we will replace the whole <value> node
|
21
|
+
Nokogiri::XML::Builder.with(node) do |xml|
|
22
|
+
xml.value_ {
|
23
|
+
xml.exData('contentType' => 'text/html') {
|
24
|
+
xml.body_('xmlns' => "http://www.w3.org/1999/xhtml",
|
25
|
+
'xmlns:xfa' => "http://www.xfa.org/schema/xfa-data/1.0/") {
|
26
|
+
xml << xfa_value
|
27
|
+
}
|
28
|
+
}
|
29
|
+
}
|
55
30
|
end
|
56
|
-
xfa.setDomDocument(doc.to_java)
|
57
|
-
xfa.setChanged(true)
|
58
31
|
end
|
59
32
|
|
60
33
|
end
|
@@ -4,6 +4,16 @@ module PDFRavager
|
|
4
4
|
def initialize(stamper)
|
5
5
|
@acro_form = Strategies::AcroForm.new(stamper)
|
6
6
|
@xfa = Strategies::XFA.new(stamper)
|
7
|
+
afields = stamper.getAcroFields
|
8
|
+
@type = if afields.getXfa.isXfaPresent
|
9
|
+
if afields.getFields.empty?
|
10
|
+
:dynamic_xfa
|
11
|
+
else
|
12
|
+
:static_xfa
|
13
|
+
end
|
14
|
+
else
|
15
|
+
:acro_form
|
16
|
+
end
|
7
17
|
end
|
8
18
|
|
9
19
|
def set_field_values(template)
|
@@ -15,7 +25,12 @@ module PDFRavager
|
|
15
25
|
end
|
16
26
|
|
17
27
|
def set_read_only
|
18
|
-
|
28
|
+
case @type
|
29
|
+
when :acro_form, :static_xfa
|
30
|
+
@acro_form.set_read_only
|
31
|
+
when :dynamic_xfa
|
32
|
+
@xfa.set_read_only
|
33
|
+
end
|
19
34
|
end
|
20
35
|
end
|
21
36
|
end
|
@@ -6,9 +6,7 @@ module PDFRavager
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def set_field_values(template)
|
9
|
-
|
10
|
-
# https://github.com/sparklemotion/nokogiri/issues/781
|
11
|
-
doc = Nokogiri::XML(Nokogiri::XML::Document.wrap(@xfa.getDomDocument).to_xml)
|
9
|
+
doc = to_nokogiri_xml
|
12
10
|
template.fields.select{|f| f.respond_to?(:set_xfa_value)}.each do |f|
|
13
11
|
# first, assume the user-provided field name is an xpath and use it directly:
|
14
12
|
strict_match =
|
@@ -17,44 +15,20 @@ module PDFRavager
|
|
17
15
|
rescue Nokogiri::XML::XPath::SyntaxError
|
18
16
|
[]
|
19
17
|
end
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
text_node = value_node.at_xpath("*[local-name()='#{f.xfa_node_type}']")
|
27
|
-
if text_node
|
28
|
-
# Complete node structure already exists - just set the value
|
29
|
-
text_node.content = f.xfa_value
|
30
|
-
else
|
31
|
-
# <value> node exists, but without child <text> node
|
32
|
-
Nokogiri::XML::Builder.with(value_node) do |xml|
|
33
|
-
xml.text_ {
|
34
|
-
xml.send("#{f.xfa_node_type}_", f.xfa_value)
|
35
|
-
}
|
36
|
-
end
|
37
|
-
end
|
38
|
-
else
|
39
|
-
# No <value> node exists - create whole structure
|
40
|
-
Nokogiri::XML::Builder.with(node) do |xml|
|
41
|
-
xml.value_ {
|
42
|
-
xml.send("#{f.xfa_node_type}_") {
|
43
|
-
xml.text f.xfa_value
|
44
|
-
}
|
45
|
-
}
|
46
|
-
end
|
47
|
-
end
|
18
|
+
if strict_match.any?
|
19
|
+
strict_match.each{|node| f.set_xfa_value(node) }
|
20
|
+
else
|
21
|
+
# otherwise, we'll loosely match the field name anywhere in the document:
|
22
|
+
loose_match = doc.xpath("//*[local-name()='field'][@name='#{f.xfa_name}']")
|
23
|
+
loose_match.each{|node| f.set_xfa_value(node) }
|
48
24
|
end
|
49
25
|
end
|
50
|
-
@xfa.
|
51
|
-
|
52
|
-
x.setChanged(true)
|
53
|
-
end
|
26
|
+
@xfa.setDomDocument(doc.to_java)
|
27
|
+
@xfa.setChanged(true)
|
54
28
|
end
|
55
29
|
|
56
30
|
def set_read_only
|
57
|
-
doc =
|
31
|
+
doc = to_nokogiri_xml
|
58
32
|
doc.xpath("//*[local-name()='field']").each do |node|
|
59
33
|
node["access"] = "readOnly"
|
60
34
|
end
|
@@ -62,6 +36,14 @@ module PDFRavager
|
|
62
36
|
@xfa.setChanged(true)
|
63
37
|
end
|
64
38
|
|
39
|
+
private
|
40
|
+
|
41
|
+
def to_nokogiri_xml
|
42
|
+
# the double-load is to work around a Nokogiri bug I found:
|
43
|
+
# https://github.com/sparklemotion/nokogiri/issues/781
|
44
|
+
Nokogiri::XML(Nokogiri::XML::Document.wrap(@xfa.getDomDocument).to_xml)
|
45
|
+
end
|
46
|
+
|
65
47
|
end
|
66
48
|
end
|
67
49
|
end
|
data/lib/pdf_ravager/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pdf_ravager
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Abe Voelker
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-04-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|