fillable-pdf 0.6 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +2 -1
- data/.rubocop.yml +35 -0
- data/.travis.yml +10 -0
- data/{LICENSE.txt → LICENSE.md} +4 -0
- data/README.md +156 -125
- data/Rakefile +9 -1
- data/ext/font-asian-7.1.12.jar +0 -0
- data/ext/forms-7.1.12.jar +0 -0
- data/ext/io-7.1.12.jar +0 -0
- data/ext/kernel-7.1.12.jar +0 -0
- data/ext/layout-7.1.12.jar +0 -0
- data/ext/slf4j-api-1.7.29.jar +0 -0
- data/ext/slf4j-simple-1.7.29.jar +0 -0
- data/fillable-pdf.gemspec +9 -4
- data/lib/field.rb +11 -10
- data/lib/fillable-pdf.rb +82 -49
- data/lib/fillable-pdf/itext.rb +1 -2
- data/lib/fillable-pdf/version.rb +2 -2
- data/lib/kernel.rb +9 -0
- metadata +59 -10
- data/ext/itext5-itextpdf-5.5.12.jar +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4c6c8de9fa4ada4510bb7107e520ce0d32a6723888d30aba6d76e4e398e544cf
|
4
|
+
data.tar.gz: cade4f5c56cca602d963121aa7f5bd4291c30f5d8f7ef4247b26af01168d1f40
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c09781488b61c8d77d0b08ce978a17d6fb0f124b22bfbb38a278973e78aaabbf8dd746e2a6c253d83e498ad045623f4662563bbd63254d004b668e120b2928a
|
7
|
+
data.tar.gz: 94f466d2a1af9f91d8262e3b84c482a8bda5dc2ff122fa58aa168592b93314954bfce1f8c5f454e8d38e8a1b0f0b1e5d921251703bd96cab3e0602e321d90761
|
data/.gitignore
CHANGED
data/.rubocop.yml
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require:
|
2
|
+
- rubocop-performance
|
3
|
+
|
4
|
+
AllCops:
|
5
|
+
Exclude:
|
6
|
+
- .git/**/*
|
7
|
+
|
8
|
+
Layout/EmptyLineAfterGuardClause:
|
9
|
+
Enabled: false
|
10
|
+
|
11
|
+
Layout/LineLength:
|
12
|
+
Exclude:
|
13
|
+
- fillable-pdf.gemspec
|
14
|
+
Max: 120
|
15
|
+
|
16
|
+
Layout/SpaceInsideHashLiteralBraces:
|
17
|
+
Enabled: false
|
18
|
+
|
19
|
+
Naming/AccessorMethodName:
|
20
|
+
Enabled: false
|
21
|
+
|
22
|
+
Naming/FileName:
|
23
|
+
Enabled: false
|
24
|
+
|
25
|
+
Style/Documentation:
|
26
|
+
Enabled: false
|
27
|
+
|
28
|
+
Style/FrozenStringLiteralComment:
|
29
|
+
Enabled: false
|
30
|
+
|
31
|
+
Style/GuardClause:
|
32
|
+
Enabled: false
|
33
|
+
|
34
|
+
Style/MutableConstant:
|
35
|
+
Enabled: false
|
data/.travis.yml
ADDED
data/{LICENSE.txt → LICENSE.md}
RENAMED
@@ -1,3 +1,7 @@
|
|
1
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
2
|
+
|
3
|
+
However, you must also adhere to the [iText License](https://github.com/itext/itext7) when using this gem in your project.
|
4
|
+
|
1
5
|
The MIT License (MIT)
|
2
6
|
|
3
7
|
Copyright (c) 2016 Vadim Kononov
|
data/README.md
CHANGED
@@ -1,15 +1,16 @@
|
|
1
|
+
|
1
2
|
# FillablePDF
|
2
3
|
|
3
4
|
[![Gem Version](https://badge.fury.io/rb/fillable-pdf.svg)](https://rubygems.org/gems/fillable-pdf)
|
5
|
+
[![Build Status](https://api.travis-ci.org/vkononov/fillable-pdf.svg?branch=master)](http://travis-ci.org/vkononov/fillable-pdf)
|
4
6
|
|
5
7
|
FillablePDF is an extremely simple and lightweight utility that bridges iText and Ruby in order to fill out fillable PDF forms or extract field values from previously filled out PDF forms.
|
6
8
|
|
7
|
-
|
8
9
|
## Installation
|
9
10
|
|
10
11
|
**Ensure that your `JAVA_HOME` variable is set before installing this gem (see examples below).**
|
11
12
|
|
12
|
-
*
|
13
|
+
* OSX: `/Library/Java/JavaVirtualMachines/jdk-12.0.2.jdk/Contents/Home`
|
13
14
|
* Ubuntu/CentOS: `/usr/lib/jvm/java-1.8.0-openjdk`
|
14
15
|
|
15
16
|
Add this line to your application's Gemfile:
|
@@ -38,108 +39,134 @@ First of all, you should open a fillable PDF file:
|
|
38
39
|
pdf = FillablePDF.new 'input.pdf'
|
39
40
|
```
|
40
41
|
|
41
|
-
|
42
|
-
|
43
|
-
```ruby
|
44
|
-
# return true if the form has any fillable fields
|
45
|
-
# output example: true
|
46
|
-
pdf.any_fields?
|
47
|
-
```
|
48
|
-
|
49
|
-
```ruby
|
50
|
-
# get the total number of fillable form fields
|
51
|
-
# output example: 10
|
52
|
-
pdf.num_fields
|
53
|
-
```
|
54
|
-
|
55
|
-
```ruby
|
56
|
-
# retrieve a single field value by field name
|
57
|
-
# output example: 'Richard'
|
58
|
-
pdf.get_field(:full_name)
|
59
|
-
```
|
60
|
-
|
61
|
-
```ruby
|
62
|
-
# retrieve a numeric field type by field value
|
63
|
-
# numeric types should
|
64
|
-
# output example: 4
|
65
|
-
pdf.get_field_type(:football)
|
66
|
-
|
67
|
-
# list of all field types
|
68
|
-
Field::CHECKBOX
|
69
|
-
Field::COMBO
|
70
|
-
Field::LIST
|
71
|
-
Field::NONE
|
72
|
-
Field::PUSHBUTTON
|
73
|
-
Field::RADIOBUTTON
|
74
|
-
Field::SIGNATURE
|
75
|
-
Field::TEXT
|
76
|
-
```
|
77
|
-
|
78
|
-
```ruby
|
79
|
-
# retrieve a hash of field name and values
|
80
|
-
# output example: {:last_name=>"Rahl", :first_name=>"Richard"}
|
81
|
-
pdf.get_fields
|
82
|
-
```
|
83
|
-
|
84
|
-
```ruby
|
85
|
-
# set the value of a single field by field name
|
86
|
-
# result: changes the value of 'first_name' to 'Richard'
|
87
|
-
pdf.set_field(:first_name, 'Richard')
|
88
|
-
```
|
42
|
+
> **Always remember to close your document once you're finished working with it in order to avoid memory leaks:**
|
89
43
|
|
90
44
|
```ruby
|
91
|
-
|
92
|
-
# result: changes the values of 'first_name' and 'last_name'
|
93
|
-
pdf.set_fields(first_name: 'Richard', last_name: 'Rahl')
|
45
|
+
pdf.close
|
94
46
|
```
|
95
47
|
|
96
|
-
|
97
|
-
# rename field (i.e. change the name of the field)
|
98
|
-
# this action also moves the field to the end of the hash
|
99
|
-
# result: renames field name 'last_name' to 'surname'
|
100
|
-
pdf.rename_field(:last_name, :surname)
|
101
|
-
```
|
102
|
-
|
103
|
-
```ruby
|
104
|
-
# remove field (i.e. delete field and its value)
|
105
|
-
# result: physically removes field 'last_name' from document
|
106
|
-
pdf.remove_field(:last_name)
|
107
|
-
```
|
108
|
-
|
109
|
-
```ruby
|
110
|
-
# get an array of all field names in the document
|
111
|
-
# output example: [:first_name, :last_name]
|
112
|
-
pdf.keys
|
113
|
-
```
|
48
|
+
## Instance Methods
|
114
49
|
|
115
|
-
|
116
|
-
# get an array of all field values in the document
|
117
|
-
# output example: ["Rahl", "Richard"]
|
118
|
-
pdf.values
|
119
|
-
```
|
120
|
-
|
121
|
-
Once the PDF is filled out you can either overwrite it or save it as another file:
|
122
|
-
|
123
|
-
```ruby
|
124
|
-
pdf.save
|
125
|
-
|
126
|
-
pdf.save_as('output.pdf')
|
127
|
-
```
|
128
|
-
|
129
|
-
Or if you prefer to flatten the file (i.e. make it non-editable), you can instead use:
|
130
|
-
|
131
|
-
```ruby
|
132
|
-
pdf.save(true)
|
133
|
-
|
134
|
-
pdf.save_as('output.pdf', true)
|
135
|
-
```
|
50
|
+
An instance of `FillablePDF` has the following methods at its disposal:
|
136
51
|
|
52
|
+
* `any_fields?`
|
53
|
+
*Determines whether the form has any fields.*
|
54
|
+
```ruby
|
55
|
+
pdf.any_fields?
|
56
|
+
# output example: true
|
57
|
+
```
|
58
|
+
|
59
|
+
* `num_fields`
|
60
|
+
*Returns the total number of fillable form fields.*
|
61
|
+
```ruby
|
62
|
+
# output example: 10
|
63
|
+
pdf.num_fields
|
64
|
+
```
|
65
|
+
|
66
|
+
* `field`
|
67
|
+
*Retrieves the value of a field given its unique field name.*
|
68
|
+
```ruby
|
69
|
+
pdf.field(:full_name)
|
70
|
+
# output example: 'Richard'
|
71
|
+
```
|
72
|
+
|
73
|
+
* `field_type`
|
74
|
+
*Retrieves the numeric type of a field given its unique field name.*
|
75
|
+
```ruby
|
76
|
+
pdf.field_type(:football)
|
77
|
+
# output example: 4
|
78
|
+
|
79
|
+
# list of all field types
|
80
|
+
Field::BUTTON
|
81
|
+
Field::CHOICE
|
82
|
+
Field::SIGNATURE
|
83
|
+
Field::TEXT
|
84
|
+
```
|
85
|
+
|
86
|
+
* `fields`
|
87
|
+
*Retrieves a hash of all fields and their values.*
|
88
|
+
```ruby
|
89
|
+
pdf.fields
|
90
|
+
# output example: {first_name: "Richard", last_name: "Rahl"}
|
91
|
+
```
|
92
|
+
|
93
|
+
* `set_field`
|
94
|
+
*Sets the value of a field given its unique field name and value.*
|
95
|
+
```ruby
|
96
|
+
pdf.set_field(:first_name, 'Richard')
|
97
|
+
# result: changes the value of 'first_name' to 'Richard'
|
98
|
+
```
|
99
|
+
|
100
|
+
* `set_fields`
|
101
|
+
*Sets the values of multiple fields given a set of unique field names and values.*
|
102
|
+
```ruby
|
103
|
+
pdf.set_fields(first_name: 'Richard', last_name: 'Rahl')
|
104
|
+
# result: changes the values of 'first_name' and 'last_name'
|
105
|
+
```
|
106
|
+
|
107
|
+
* `rename_field`
|
108
|
+
*Renames a field given its unique field name and the new field name.*
|
109
|
+
```ruby
|
110
|
+
pdf.rename_field(:last_name, :surname)
|
111
|
+
# result: renames field name 'last_name' to 'surname'
|
112
|
+
# NOTE: this action does not take effect until the document is saved
|
113
|
+
```
|
114
|
+
|
115
|
+
* `remove_field`
|
116
|
+
*Removes a field from the document given its unique field name.*
|
117
|
+
```ruby
|
118
|
+
pdf.remove_field(:last_name)
|
119
|
+
# result: physically removes field 'last_name' from document
|
120
|
+
```
|
121
|
+
|
122
|
+
* `names`
|
123
|
+
*Returns a list of all field keys used in the document.*
|
124
|
+
```ruby
|
125
|
+
pdf.names
|
126
|
+
# output example: [:first_name, :last_name]
|
127
|
+
```
|
128
|
+
|
129
|
+
* `values`
|
130
|
+
*Returns a list of all field values used in the document.*
|
131
|
+
```ruby
|
132
|
+
pdf.values
|
133
|
+
# output example: ["Rahl", "Richard"]
|
134
|
+
```
|
135
|
+
|
136
|
+
* `save`
|
137
|
+
*Overwrites the previously opened PDF document and flattens it if requested.*
|
138
|
+
```ruby
|
139
|
+
pdf.save
|
140
|
+
# result: document is saved without flatenning
|
141
|
+
pdf.save_as(flatten: true)
|
142
|
+
# result: document is saved with flatenning
|
143
|
+
```
|
144
|
+
|
145
|
+
* `save_as`
|
146
|
+
*Saves the filled out PDF document in a given path and flattens it if requested.*
|
147
|
+
```ruby
|
148
|
+
pdf.save_as('output.pdf')
|
149
|
+
# result: document is saved in a given path without flatenning
|
150
|
+
pdf.save_as('output.pdf', flatten: true)
|
151
|
+
# result: document is saved in a given path with flatenning
|
152
|
+
```
|
153
|
+
|
154
|
+
**NOTE:** Saving the file automatically closes the input file, so you would need to reinitialize the `FillabePDF` class before making any more changes or saving another copy.
|
155
|
+
|
156
|
+
* `close`
|
157
|
+
*Closes the PDF document discarding all unsaved changes.*
|
158
|
+
```ruby
|
159
|
+
pdf.close
|
160
|
+
# result: document is closed
|
161
|
+
```
|
137
162
|
|
138
163
|
## Example
|
139
164
|
|
140
|
-
The following example [
|
165
|
+
The following example [example.rb](example/run.rb) and the input file [input.pdf](example/input.pdf) are located in the `test` directory. It uses all of the methods that are described above and generates the output files [output.pdf](example/output.pdf) and [output.flat.pdf](example/output.flat.pdf).
|
141
166
|
|
142
167
|
```ruby
|
168
|
+
require 'fillable-pdf'
|
169
|
+
|
143
170
|
# opening a fillable PDF
|
144
171
|
pdf = FillablePDF.new('input.pdf')
|
145
172
|
|
@@ -159,12 +186,12 @@ pdf.set_fields(football: 'Yes', baseball: 'Yes',
|
|
159
186
|
pdf.set_field(:date, Time.now.strftime('%B %e, %Y'))
|
160
187
|
|
161
188
|
# list of fields
|
162
|
-
puts "Fields hash: #{pdf.
|
189
|
+
puts "Fields hash: #{pdf.fields}"
|
163
190
|
|
164
191
|
puts
|
165
192
|
|
166
|
-
# list of field
|
167
|
-
puts "Keys: #{pdf.
|
193
|
+
# list of field names
|
194
|
+
puts "Keys: #{pdf.names}"
|
168
195
|
|
169
196
|
puts
|
170
197
|
|
@@ -174,10 +201,10 @@ puts "Values: #{pdf.values}"
|
|
174
201
|
puts
|
175
202
|
|
176
203
|
# Checking field type
|
177
|
-
if pdf.
|
178
|
-
puts "Field 'football' is of type
|
204
|
+
if pdf.field_type(:football) == Field::BUTTON
|
205
|
+
puts "Field 'football' is of type BUTTON"
|
179
206
|
else
|
180
|
-
puts "Field 'football' is not of type
|
207
|
+
puts "Field 'football' is not of type BUTTON"
|
181
208
|
end
|
182
209
|
|
183
210
|
puts
|
@@ -185,45 +212,47 @@ puts
|
|
185
212
|
# Renaming field
|
186
213
|
pdf.rename_field :last_name, :surname
|
187
214
|
puts "Renamed field 'last_name' to 'surname'"
|
188
|
-
puts "New keys: #{pdf.keys}"
|
189
215
|
|
190
216
|
puts
|
191
217
|
|
192
218
|
# Removing field
|
193
219
|
pdf.remove_field :nascar
|
194
220
|
puts "Removed field 'nascar'"
|
195
|
-
puts "New keys: #{pdf.keys}"
|
196
|
-
|
197
221
|
puts
|
198
222
|
|
199
223
|
# printing the name of the person used inside the PDF
|
200
|
-
puts "Signatory: #{pdf.
|
224
|
+
puts "Signatory: #{pdf.field(:first_name)} #{pdf.field(:last_name)}"
|
225
|
+
|
226
|
+
# saving the filled out PDF in another file
|
227
|
+
pdf.save_as('output.pdf')
|
228
|
+
|
229
|
+
# saving another copy of the filled out PDF in another file and making it non-editable
|
230
|
+
pdf = FillablePDF.new('output.pdf')
|
231
|
+
pdf.save_as 'output.flat.pdf', flatten: true
|
232
|
+
|
233
|
+
# closing the document
|
234
|
+
pdf.close
|
235
|
+
```
|
201
236
|
|
202
|
-
|
203
|
-
pdf.save_as('output.pdf', true)
|
237
|
+
The example above produces the following output and also generates the output file [output.pdf](example/output.pdf).
|
204
238
|
|
205
239
|
```
|
240
|
+
The form has a total of 8 fields.
|
206
241
|
|
207
|
-
|
208
|
-
|
209
|
-
The form has a total of 8 fields.
|
210
|
-
|
211
|
-
Fields hash: {:last_name=>"Rahl", :first_name=>"Richard", :football=>"Yes", :baseball=>"Yes", :basketball=>"Yes", :nascar=>"Yes", :hockey=>"Yes", :date=>"July 19, 2017"}
|
212
|
-
|
213
|
-
Keys: [:last_name, :first_name, :football, :baseball, :basketball, :nascar, :hockey, :date]
|
214
|
-
|
215
|
-
Values: ["Rahl", "Richard", "Yes", "Yes", "Yes", "Yes", "Yes", "July 19, 2017"]
|
216
|
-
|
217
|
-
Field 'football' is of type CHECKBOX
|
218
|
-
|
219
|
-
Renamed field 'last_name' to 'surname'
|
220
|
-
New keys: [:first_name, :football, :baseball, :basketball, :nascar, :hockey, :date, :surname]
|
221
|
-
|
222
|
-
Removed field 'nascar'
|
223
|
-
New keys: [:first_name, :football, :baseball, :basketball, :hockey, :date, :surname]
|
224
|
-
|
225
|
-
Signatory: Richard
|
242
|
+
Fields hash: {:last_name=>"Rahl", :first_name=>"Richard", :football=>"Yes", :baseball=>"Yes", :basketball=>"Yes", :nascar=>"Yes", :hockey=>"Yes", :date=>"August 30, 2019"}
|
226
243
|
|
244
|
+
Keys: [:last_name, :first_name, :football, :baseball, :basketball, :nascar, :hockey, :date]
|
245
|
+
|
246
|
+
Values: ["Rahl", "Richard", "Yes", "Yes", "Yes", "Yes", "Yes", "August 30, 2019"]
|
247
|
+
|
248
|
+
Field 'football' is of type BUTTON
|
249
|
+
|
250
|
+
Renamed field 'last_name' to 'surname'
|
251
|
+
|
252
|
+
Removed field 'nascar'
|
253
|
+
|
254
|
+
Signatory: Richard Rahl
|
255
|
+
```
|
227
256
|
|
228
257
|
## Contributing
|
229
258
|
|
@@ -236,4 +265,6 @@ The example above produces the following output and also generates the output fi
|
|
236
265
|
|
237
266
|
## License
|
238
267
|
|
239
|
-
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
268
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
269
|
+
|
270
|
+
However, you must also adhere to the [iText License](https://github.com/itext/itext7) when using this gem in your project.
|
data/Rakefile
CHANGED
Binary file
|
Binary file
|
data/ext/io-7.1.12.jar
ADDED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/fillable-pdf.gemspec
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
lib = File.expand_path('
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
2
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
3
|
require 'fillable-pdf/version'
|
4
4
|
|
@@ -13,11 +13,16 @@ Gem::Specification.new do |spec|
|
|
13
13
|
spec.homepage = 'https://github.com/vkononov/fillable-pdf'
|
14
14
|
spec.license = 'MIT'
|
15
15
|
|
16
|
-
spec.files
|
16
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
17
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(example|test|spec|features)/}) }
|
18
|
+
end
|
17
19
|
spec.bindir = 'exe'
|
18
20
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
21
|
spec.require_paths = %w[ext lib]
|
20
22
|
|
21
|
-
spec.
|
22
|
-
spec.
|
23
|
+
spec.add_development_dependency 'bundler', '~> 2.0'
|
24
|
+
spec.add_development_dependency 'minitest', '~> 5.0'
|
25
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
26
|
+
|
27
|
+
spec.add_runtime_dependency 'rjb', '~> 1.6'
|
23
28
|
end
|
data/lib/field.rb
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
require_relative 'fillable-pdf/itext'
|
2
|
+
require_relative 'kernel'
|
2
3
|
|
3
4
|
class Field
|
4
|
-
|
5
|
+
# PdfName has a constant "A" and a constant "a". Unfortunately, RJB does not differentiate
|
6
|
+
# between these constants and tries to create the same constant ("A") for both, which causes
|
7
|
+
# an annoying warning "already initialized constant Rjb::Com_itextpdf_kernel_pdf_PdfName::A".
|
8
|
+
# As long as RJB has not fixed this issue, this warning will remain suppressed.
|
9
|
+
suppress_warnings { PDF_NAME = Rjb.import('com.itextpdf.kernel.pdf.PdfName') }
|
5
10
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
RADIOBUTTON = ACRO_FIELDS.FIELD_TYPE_RADIOBUTTON
|
12
|
-
SIGNATURE = ACRO_FIELDS.FIELD_TYPE_SIGNATURE
|
13
|
-
TEXT = ACRO_FIELDS.FIELD_TYPE_TEXT
|
14
|
-
end
|
11
|
+
BUTTON = PDF_NAME.Btn.toString
|
12
|
+
CHOICE = PDF_NAME.Ch.toString
|
13
|
+
SIGNATURE = PDF_NAME.Sig.toString
|
14
|
+
TEXT = PDF_NAME.Tx.toString
|
15
|
+
end
|
data/lib/fillable-pdf.rb
CHANGED
@@ -4,20 +4,31 @@ require 'securerandom'
|
|
4
4
|
|
5
5
|
class FillablePDF
|
6
6
|
# required Java imports
|
7
|
-
BYTE_STREAM = Rjb.import
|
8
|
-
|
9
|
-
|
7
|
+
BYTE_STREAM = Rjb.import 'com.itextpdf.io.source.ByteArrayOutputStream'
|
8
|
+
PDF_READER = Rjb.import 'com.itextpdf.kernel.pdf.PdfReader'
|
9
|
+
PDF_WRITER = Rjb.import 'com.itextpdf.kernel.pdf.PdfWriter'
|
10
|
+
PDF_DOCUMENT = Rjb.import 'com.itextpdf.kernel.pdf.PdfDocument'
|
11
|
+
PDF_ACRO_FORM = Rjb.import 'com.itextpdf.forms.PdfAcroForm'
|
12
|
+
PDF_FORM_FIELD = Rjb.import 'com.itextpdf.forms.fields.PdfFormField'
|
10
13
|
|
11
14
|
##
|
12
|
-
# Opens a given fillable PDF file and prepares it for modification.
|
13
|
-
#
|
14
|
-
# @param [String]
|
15
|
-
#
|
16
|
-
def initialize(
|
17
|
-
|
18
|
-
@
|
19
|
-
|
20
|
-
|
15
|
+
# Opens a given fillable-pdf PDF file and prepares it for modification.
|
16
|
+
#
|
17
|
+
# @param [String|Symbol] file_path the name of the PDF file or file path
|
18
|
+
#
|
19
|
+
def initialize(file_path)
|
20
|
+
raise IOError, "File at `#{file_path}' is not found" unless File.exist?(file_path)
|
21
|
+
@file_path = file_path
|
22
|
+
begin
|
23
|
+
@byte_stream = BYTE_STREAM.new
|
24
|
+
@pdf_reader = PDF_READER.new @file_path
|
25
|
+
@pdf_writer = PDF_WRITER.new @byte_stream
|
26
|
+
@pdf_doc = PDF_DOCUMENT.new @pdf_reader, @pdf_writer
|
27
|
+
@pdf_form = PDF_ACRO_FORM.getAcroForm(@pdf_doc, true)
|
28
|
+
@form_fields = @pdf_form.getFormFields
|
29
|
+
rescue StandardError => ex
|
30
|
+
raise "#{ex.message} (input file may be corrupt, incompatible, or may not have any forms)"
|
31
|
+
end
|
21
32
|
end
|
22
33
|
|
23
34
|
##
|
@@ -26,38 +37,40 @@ class FillablePDF
|
|
26
37
|
# @return true if form has fields, false otherwise
|
27
38
|
#
|
28
39
|
def any_fields?
|
29
|
-
num_fields
|
40
|
+
num_fields.positive?
|
30
41
|
end
|
31
42
|
|
32
43
|
##
|
33
|
-
# Returns the total number of form fields.
|
44
|
+
# Returns the total number of fillable form fields.
|
34
45
|
#
|
35
46
|
# @return the number of fields
|
36
47
|
#
|
37
48
|
def num_fields
|
38
|
-
@
|
49
|
+
@form_fields.size
|
39
50
|
end
|
40
51
|
|
41
52
|
##
|
42
53
|
# Retrieves the value of a field given its unique field name.
|
43
54
|
#
|
44
|
-
# @param [String] key the field name
|
55
|
+
# @param [String|Symbol] key the field name
|
45
56
|
#
|
46
57
|
# @return the value of the field
|
47
58
|
#
|
48
|
-
def
|
49
|
-
|
59
|
+
def field(key)
|
60
|
+
pdf_field(key).getValueAsString
|
61
|
+
rescue NoMethodError
|
62
|
+
raise "unknown key name `#{key}'"
|
50
63
|
end
|
51
64
|
|
52
65
|
##
|
53
66
|
# Retrieves the numeric type of a field given its unique field name.
|
54
67
|
#
|
55
|
-
# @param [String] key the field name
|
68
|
+
# @param [String|Symbol] key the field name
|
56
69
|
#
|
57
70
|
# @return the type of the field
|
58
71
|
#
|
59
|
-
def
|
60
|
-
|
72
|
+
def field_type(key)
|
73
|
+
pdf_field(key).getFormType.toString
|
61
74
|
end
|
62
75
|
|
63
76
|
##
|
@@ -65,12 +78,12 @@ class FillablePDF
|
|
65
78
|
#
|
66
79
|
# @return the hash of field keys and values
|
67
80
|
#
|
68
|
-
def
|
69
|
-
iterator = @
|
81
|
+
def fields
|
82
|
+
iterator = @form_fields.keySet.iterator
|
70
83
|
map = {}
|
71
84
|
while iterator.hasNext
|
72
85
|
key = iterator.next.toString
|
73
|
-
map[key.to_sym] =
|
86
|
+
map[key.to_sym] = field(key)
|
74
87
|
end
|
75
88
|
map
|
76
89
|
end
|
@@ -78,11 +91,11 @@ class FillablePDF
|
|
78
91
|
##
|
79
92
|
# Sets the value of a field given its unique field name and value.
|
80
93
|
#
|
81
|
-
# @param [String] key the field name
|
82
|
-
# @param [String] value the field value
|
94
|
+
# @param [String|Symbol] key the field name
|
95
|
+
# @param [String|Symbol] value the field value
|
83
96
|
#
|
84
97
|
def set_field(key, value)
|
85
|
-
|
98
|
+
pdf_field(key).setValue(value.to_s)
|
86
99
|
end
|
87
100
|
|
88
101
|
##
|
@@ -97,20 +110,20 @@ class FillablePDF
|
|
97
110
|
##
|
98
111
|
# Renames a field given its unique field name and the new field name.
|
99
112
|
#
|
100
|
-
# @param [String] old_key the field name
|
101
|
-
# @param [String] new_key the field name
|
113
|
+
# @param [String|Symbol] old_key the field name
|
114
|
+
# @param [String|Symbol] new_key the field name
|
102
115
|
#
|
103
116
|
def rename_field(old_key, new_key)
|
104
|
-
|
117
|
+
pdf_field(old_key).setFieldName(new_key.to_s)
|
105
118
|
end
|
106
119
|
|
107
120
|
##
|
108
121
|
# Removes a field from the document given its unique field name.
|
109
122
|
#
|
110
|
-
# @param [String] key the field name
|
123
|
+
# @param [String|Symbol] key the field name
|
111
124
|
#
|
112
125
|
def remove_field(key)
|
113
|
-
@
|
126
|
+
@pdf_form.removeField(key.to_s)
|
114
127
|
end
|
115
128
|
|
116
129
|
##
|
@@ -118,8 +131,8 @@ class FillablePDF
|
|
118
131
|
#
|
119
132
|
# @return array of field names
|
120
133
|
#
|
121
|
-
def
|
122
|
-
iterator = @
|
134
|
+
def names
|
135
|
+
iterator = @form_fields.keySet.iterator
|
123
136
|
set = []
|
124
137
|
set << iterator.next.toString.to_sym while iterator.hasNext
|
125
138
|
set
|
@@ -131,31 +144,45 @@ class FillablePDF
|
|
131
144
|
# @return array of field values
|
132
145
|
#
|
133
146
|
def values
|
134
|
-
iterator = @
|
147
|
+
iterator = @form_fields.keySet.iterator
|
135
148
|
set = []
|
136
|
-
set <<
|
149
|
+
set << field(iterator.next.toString) while iterator.hasNext
|
137
150
|
set
|
138
151
|
end
|
139
152
|
|
140
153
|
##
|
141
|
-
# Overwrites the previously opened PDF
|
154
|
+
# Overwrites the previously opened PDF document and flattens it if requested.
|
142
155
|
#
|
143
156
|
# @param [bool] flatten true if PDF should be flattened, false otherwise
|
144
157
|
#
|
145
|
-
def save(flatten
|
158
|
+
def save(flatten: false)
|
146
159
|
tmp_file = SecureRandom.uuid
|
147
|
-
save_as(tmp_file, flatten)
|
148
|
-
File.rename tmp_file, @
|
160
|
+
save_as(tmp_file, flatten: flatten)
|
161
|
+
File.rename tmp_file, @file_path
|
149
162
|
end
|
150
163
|
|
151
164
|
##
|
152
|
-
# Saves the filled out PDF
|
165
|
+
# Saves the filled out PDF document in a given path and flattens it if requested.
|
153
166
|
#
|
154
|
-
# @param [String]
|
155
|
-
# @param [
|
167
|
+
# @param [String] file_path the name of the PDF file or file path
|
168
|
+
# @param [Hash] flatten: true if PDF should be flattened, false otherwise
|
156
169
|
#
|
157
|
-
def save_as(
|
158
|
-
|
170
|
+
def save_as(file_path, flatten: false)
|
171
|
+
if @file_path == file_path
|
172
|
+
save(flatten: flatten)
|
173
|
+
else
|
174
|
+
File.open(file_path, 'wb') { |f| f.write(finalize(flatten: flatten)) && f.close }
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
##
|
179
|
+
# Closes the PDF document discarding all unsaved changes.
|
180
|
+
#
|
181
|
+
# @return [Boolean] true if document is closed, false otherwise
|
182
|
+
#
|
183
|
+
def close
|
184
|
+
@pdf_doc.close
|
185
|
+
@pdf_doc.isClosed
|
159
186
|
end
|
160
187
|
|
161
188
|
private
|
@@ -163,11 +190,17 @@ class FillablePDF
|
|
163
190
|
##
|
164
191
|
# Writes the contents of the modified fields to the previously opened PDF file.
|
165
192
|
#
|
166
|
-
# @param [
|
193
|
+
# @param [Hash] flatten: true if PDF should be flattened, false otherwise
|
167
194
|
#
|
168
|
-
def finalize(flatten)
|
169
|
-
@
|
170
|
-
|
195
|
+
def finalize(flatten: false)
|
196
|
+
@pdf_form.flattenFields if flatten
|
197
|
+
close
|
171
198
|
@byte_stream.toByteArray
|
172
199
|
end
|
200
|
+
|
201
|
+
def pdf_field(key)
|
202
|
+
field = @form_fields.get(key.to_s)
|
203
|
+
raise "unknown key name `#{key}'" if field.nil?
|
204
|
+
field
|
205
|
+
end
|
173
206
|
end
|
data/lib/fillable-pdf/itext.rb
CHANGED
data/lib/fillable-pdf/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
|
2
|
-
VERSION = '0.
|
1
|
+
class FillablePDF
|
2
|
+
VERSION = '0.9.0'
|
3
3
|
end
|
data/lib/kernel.rb
ADDED
metadata
CHANGED
@@ -1,29 +1,71 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fillable-pdf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vadim Kononov
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-05-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: minitest
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '5.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '5.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.0'
|
13
55
|
- !ruby/object:Gem::Dependency
|
14
56
|
name: rjb
|
15
57
|
requirement: !ruby/object:Gem::Requirement
|
16
58
|
requirements:
|
17
59
|
- - "~>"
|
18
60
|
- !ruby/object:Gem::Version
|
19
|
-
version: '1.
|
61
|
+
version: '1.6'
|
20
62
|
type: :runtime
|
21
63
|
prerelease: false
|
22
64
|
version_requirements: !ruby/object:Gem::Requirement
|
23
65
|
requirements:
|
24
66
|
- - "~>"
|
25
67
|
- !ruby/object:Gem::Version
|
26
|
-
version: '1.
|
68
|
+
version: '1.6'
|
27
69
|
description: FillablePDF is an extremely simple and lightweight utility that bridges
|
28
70
|
iText and Ruby in order to fill out fillable PDF forms or extract field values from
|
29
71
|
previously filled out PDF forms.
|
@@ -34,18 +76,27 @@ extensions: []
|
|
34
76
|
extra_rdoc_files: []
|
35
77
|
files:
|
36
78
|
- ".gitignore"
|
79
|
+
- ".rubocop.yml"
|
80
|
+
- ".travis.yml"
|
37
81
|
- Gemfile
|
38
|
-
- LICENSE.
|
82
|
+
- LICENSE.md
|
39
83
|
- README.md
|
40
84
|
- Rakefile
|
41
85
|
- bin/console
|
42
86
|
- bin/setup
|
43
|
-
- ext/
|
87
|
+
- ext/font-asian-7.1.12.jar
|
88
|
+
- ext/forms-7.1.12.jar
|
89
|
+
- ext/io-7.1.12.jar
|
90
|
+
- ext/kernel-7.1.12.jar
|
91
|
+
- ext/layout-7.1.12.jar
|
92
|
+
- ext/slf4j-api-1.7.29.jar
|
93
|
+
- ext/slf4j-simple-1.7.29.jar
|
44
94
|
- fillable-pdf.gemspec
|
45
95
|
- lib/field.rb
|
46
96
|
- lib/fillable-pdf.rb
|
47
97
|
- lib/fillable-pdf/itext.rb
|
48
98
|
- lib/fillable-pdf/version.rb
|
99
|
+
- lib/kernel.rb
|
49
100
|
homepage: https://github.com/vkononov/fillable-pdf
|
50
101
|
licenses:
|
51
102
|
- MIT
|
@@ -65,10 +116,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
65
116
|
- - ">="
|
66
117
|
- !ruby/object:Gem::Version
|
67
118
|
version: '0'
|
68
|
-
requirements:
|
69
|
-
|
70
|
-
rubyforge_project:
|
71
|
-
rubygems_version: 2.6.13
|
119
|
+
requirements: []
|
120
|
+
rubygems_version: 3.1.2
|
72
121
|
signing_key:
|
73
122
|
specification_version: 4
|
74
123
|
summary: Fill out or extract field values from simple fillable PDF forms using iText.
|
Binary file
|