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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 2e531a833cf7701b907be49fc29b6885241bc2d5
4
- data.tar.gz: e59582332f1377cd3bbef6d5fe53adf02f8e764b
2
+ SHA256:
3
+ metadata.gz: 4c6c8de9fa4ada4510bb7107e520ce0d32a6723888d30aba6d76e4e398e544cf
4
+ data.tar.gz: cade4f5c56cca602d963121aa7f5bd4291c30f5d8f7ef4247b26af01168d1f40
5
5
  SHA512:
6
- metadata.gz: c021fe8a59d2397e3e54174d1cd109e40b3aa0fe740296f39582aeaa486ef0e302139aed079ec729a0cfde465d81c90c09bd756278bcf5591cced8bc15636dc5
7
- data.tar.gz: aadd836fbfa70a083dd76b71ea1766b53fb0f2eafb8bba1a5ede6267a7e13abaafbd5dc9be767de6ce962b1c1f9ad1ef3d726c23f74c0c3ced4e815efffc179a
6
+ metadata.gz: 9c09781488b61c8d77d0b08ce978a17d6fb0f124b22bfbb38a278973e78aaabbf8dd746e2a6c253d83e498ad045623f4662563bbd63254d004b668e120b2928a
7
+ data.tar.gz: 94f466d2a1af9f91d8262e3b84c482a8bda5dc2ff122fa58aa168592b93314954bfce1f8c5f454e8d38e8a1b0f0b1e5d921251703bd96cab3e0602e321d90761
data/.gitignore CHANGED
@@ -10,4 +10,5 @@
10
10
  /Gemfile.lock
11
11
  /pkg/
12
12
  /spec/reports/
13
- /tmp/
13
+ /tmp/
14
+ tmp.pdf
@@ -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
@@ -0,0 +1,10 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.6.4
7
+ jdk:
8
+ - openjdk8
9
+ before_install:
10
+ - gem install bundler -v 2.0.2
@@ -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
- * OSX: `/Library/Java/JavaVirtualMachines/jdk-9.0.1.jdk/Contents/Home`
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
- An instance of `FillablePDF` has the following methods at its disposal:
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
- # set the values of multiple fields by field names
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
- ```ruby
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
- ```ruby
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 [test.rb](test/test.rb) and the input file [input.pdf](test/input.pdf) are located in the `test` directory. It uses all of the methods that are described above and generates the output file [output.pdf](test/output.pdf).
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.get_fields}"
189
+ puts "Fields hash: #{pdf.fields}"
163
190
 
164
191
  puts
165
192
 
166
- # list of field keys
167
- puts "Keys: #{pdf.keys}"
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.get_field_type(:football) == Field::CHECKBOX
178
- puts "Field 'football' is of type CHECKBOX"
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 CHECKBOX"
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.get_field(:first_name)} #{pdf.get_field(:last_name)}"
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
- # saving the filled out PDF in another file and making it non-editable
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
- The example above produces the following output and also generates the output file [output.pdf](test/output.pdf).
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
@@ -1,2 +1,10 @@
1
1
  require 'bundler/gem_tasks'
2
- task default: :spec
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << 'test'
6
+ t.libs << 'lib'
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task default: :test
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -1,4 +1,4 @@
1
- lib = File.expand_path('../lib', __FILE__)
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 = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
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.requirements << '>= JDK 5.0'
22
- spec.add_runtime_dependency 'rjb', '~> 1.5'
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
@@ -1,14 +1,15 @@
1
1
  require_relative 'fillable-pdf/itext'
2
+ require_relative 'kernel'
2
3
 
3
4
  class Field
4
- ACRO_FIELDS = Rjb.import('com.itextpdf.text.pdf.AcroFields')
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
- CHECKBOX = ACRO_FIELDS.FIELD_TYPE_CHECKBOX
7
- COMBO = ACRO_FIELDS.FIELD_TYPE_COMBO
8
- LIST = ACRO_FIELDS.FIELD_TYPE_LIST
9
- NONE = ACRO_FIELDS.FIELD_TYPE_NONE
10
- PUSHBUTTON = ACRO_FIELDS.FIELD_TYPE_PUSHBUTTON
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
@@ -4,20 +4,31 @@ require 'securerandom'
4
4
 
5
5
  class FillablePDF
6
6
  # required Java imports
7
- BYTE_STREAM = Rjb.import('java.io.ByteArrayOutputStream')
8
- FILE_READER = Rjb.import('com.itextpdf.text.pdf.PdfReader')
9
- PDF_STAMPER = Rjb.import('com.itextpdf.text.pdf.PdfStamper')
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] file the name of the PDF file or file path
15
- #
16
- def initialize(file)
17
- @file = file
18
- @byte_stream = BYTE_STREAM.new
19
- @pdf_stamper = PDF_STAMPER.new FILE_READER.new(@file), @byte_stream
20
- @acro_fields = @pdf_stamper.getAcroFields
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 > 0
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
- @acro_fields.getFields.size
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 get_field(key)
49
- @acro_fields.getField key.to_s
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 get_field_type(key)
60
- @acro_fields.getFieldType key.to_s
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 get_fields
69
- iterator = @acro_fields.getFields.keySet.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] = get_field key
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
- @acro_fields.setField key.to_s, value.to_s
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
- @acro_fields.renameField old_key.to_s, new_key.to_s
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
- @acro_fields.removeField key.to_s
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 keys
122
- iterator = @acro_fields.getFields.keySet.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 = @acro_fields.getFields.keySet.iterator
147
+ iterator = @form_fields.keySet.iterator
135
148
  set = []
136
- set << get_field(iterator.next.toString) while iterator.hasNext
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 file and flattens it if requested.
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 = false)
158
+ def save(flatten: false)
146
159
  tmp_file = SecureRandom.uuid
147
- save_as(tmp_file, flatten)
148
- File.rename tmp_file, @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 file with a given file and flattens it if requested.
165
+ # Saves the filled out PDF document in a given path and flattens it if requested.
153
166
  #
154
- # @param [String] file the name of the PDF file or file path
155
- # @param [bool] flatten true if PDF should be flattened, false otherwise
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(file, flatten = false)
158
- File.open(file, 'wb') { |f| f.write(finalize(flatten)) && f.close }
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 [bool] flatten true if PDF should be flattened, false otherwise
193
+ # @param [Hash] flatten: true if PDF should be flattened, false otherwise
167
194
  #
168
- def finalize(flatten)
169
- @pdf_stamper.setFormFlattening flatten
170
- @pdf_stamper.close
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
@@ -1,4 +1,3 @@
1
1
  require 'rjb'
2
2
 
3
- # http://github.com/itext/itextpdf/releases/latest
4
- Rjb.load(File.expand_path('../../ext/itext5-itextpdf-5.5.12.jar', __dir__))
3
+ Rjb.load(Dir.glob(File.expand_path('../../ext/*.jar', __dir__)).join(':'))
@@ -1,3 +1,3 @@
1
- module FillablePDF
2
- VERSION = '0.6'.freeze
1
+ class FillablePDF
2
+ VERSION = '0.9.0'
3
3
  end
@@ -0,0 +1,9 @@
1
+ module Kernel
2
+ def suppress_warnings
3
+ original_verbosity = $VERBOSE
4
+ $VERBOSE = nil
5
+ result = yield
6
+ $VERBOSE = original_verbosity
7
+ result
8
+ end
9
+ end
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: '0.6'
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: 2017-12-12 00:00:00.000000000 Z
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.5'
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.5'
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.txt
82
+ - LICENSE.md
39
83
  - README.md
40
84
  - Rakefile
41
85
  - bin/console
42
86
  - bin/setup
43
- - ext/itext5-itextpdf-5.5.12.jar
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
- - ">= JDK 5.0"
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.