pdf_ravager 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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 Version](https://badge.fury.io/rb/pdf_ravager.png)][gem]
|
4
|
+
[![Build Status](https://secure.travis-ci.org/abevoelker/pdf_ravager.png)][travis]
|
5
|
+
[![Code Climate](https://codeclimate.com/github/abevoelker/pdf_ravager.png)][codeclimate]
|
6
|
+
[![Dependency Status](https://gemnasium.com/abevoelker/pdf_ravager.svg)][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
|