fillable-pdf 1.1.1 → 1.1.3
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/README.md +30 -22
- data/ext/{commons-9.7.0.jar → commons-9.7.1.jar} +0 -0
- data/ext/{font-asian-9.7.0.jar → font-asian-9.7.1.jar} +0 -0
- data/ext/{forms-9.7.0.jar → forms-9.7.1.jar} +0 -0
- data/ext/{io-9.7.0.jar → io-9.7.1.jar} +0 -0
- data/ext/{kernel-9.7.0.jar → kernel-9.7.1.jar} +0 -0
- data/ext/{layout-9.7.0.jar → layout-9.7.1.jar} +0 -0
- data/lib/fillable-pdf/version.rb +1 -1
- data/lib/fillable-pdf.rb +18 -8
- metadata +11 -11
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2cdd748940498c34c3e4f19f91f83cfc47fcf34dda1d10eb07e05f7aef9c7d57
|
|
4
|
+
data.tar.gz: a98954a86876c759716a8919a24f54c175ec97eb0eddd19bc2b9aaa844bdd6cb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bb4104898a7feb6a16338aae323b3d1285f8fb5dd2458e48d5e936ca17ed27fc407289c68db0a466105bbe06fc1100cfd5a8cfa92873f6f6b731692ee385bfaf
|
|
7
|
+
data.tar.gz: 07430fe63ccbbec3e4c7c5191d6831b767320b87ed6ea0bd0542c11d41e10fe8c7883ce7d396fe7cc31f029d425fb87e055e3af01bd44358cf8d3b99010e17ca
|
data/README.md
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
|
|
2
2
|
# FillablePDF
|
|
3
3
|
|
|
4
|
-
[](https://rubygems.org/gems/fillable-pdf)
|
|
5
|
-
[](https://rubygems.org/gems/fillable-pdf)
|
|
5
|
+
[](https://github.com/vkononov/fillable-pdf/blob/main/.github/workflows/test.yml)
|
|
6
|
+
[](https://github.com/vkononov/fillable-pdf/blob/main/.github/workflows/test.yml)
|
|
7
|
+
[](https://github.com/vkononov/fillable-pdf/actions/workflows/test.yml)
|
|
8
|
+
[](https://github.com/vkononov/fillable-pdf/actions/workflows/lint.yml)
|
|
9
|
+
[](https://opensource.org/license/MIT)
|
|
8
10
|
|
|
9
11
|
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.
|
|
10
12
|
|
|
11
|
-
Supports
|
|
13
|
+
Supports **Ruby 2.4 → latest** and **JDK 8 → latest**, with the full Ruby/Java matrix tested daily in CI.
|
|
12
14
|
|
|
13
15
|
[](https://www.buymeacoffee.com/vkononov)
|
|
14
16
|
|
|
@@ -16,7 +18,7 @@ Supports `Ruby >= 2.4.0` with `JDK >= 8`
|
|
|
16
18
|
|
|
17
19
|
1. Phusion Passenger's [smart spawning](https://www.phusionpassenger.com/library/indepth/ruby/spawn_methods/#the-smart-spawning-method) is not supported. Please see [Deployment with Phusion Passenger + Nginx](#deployment-with-phusion-passenger--nginx) for more information.
|
|
18
20
|
|
|
19
|
-
2. Puma workers (process forking) is not
|
|
21
|
+
2. Puma workers (process forking) is not supported due to an [issue](https://github.com/arton/rjb/issues/88) with the [rjb](https://github.com/arton/rjb) gem dependency.
|
|
20
22
|
|
|
21
23
|
3. If the gem hangs in `development`, removing the following gems may fix the issue:
|
|
22
24
|
|
|
@@ -229,7 +231,7 @@ An instance of `FillablePDF` has the following methods at its disposal:
|
|
|
229
231
|
pdf.set_field('first_name', 'Richard', generate_appearance: false)
|
|
230
232
|
```
|
|
231
233
|
|
|
232
|
-
* `
|
|
234
|
+
* `set_fields(fields, generate_appearance: nil)`
|
|
233
235
|
*Sets the values of multiple fields given a set of unique field names and values, with an optional `generate_appearance` directive.*
|
|
234
236
|
|
|
235
237
|
```ruby
|
|
@@ -317,7 +319,7 @@ An instance of `FillablePDF` has the following methods at its disposal:
|
|
|
317
319
|
# result: document is saved in a given path with flattening
|
|
318
320
|
```
|
|
319
321
|
|
|
320
|
-
**NOTE:** Saving the file automatically closes the input file, so you would need to reinitialize the `
|
|
322
|
+
**NOTE:** Saving the file automatically closes the input file, so you would need to reinitialize the `FillablePDF` class before making any more changes or saving another copy.
|
|
321
323
|
|
|
322
324
|
* `save_as!(file_path, flatten: false)`
|
|
323
325
|
*Saves the filled out PDF document in a given path and flattens it if requested. Raises an error if the path matches the current file (use save() instead).*
|
|
@@ -452,15 +454,18 @@ Naturally, there are many downsides (in terms of efficiency, scalability, securi
|
|
|
452
454
|
|
|
453
455
|
## Example
|
|
454
456
|
|
|
455
|
-
The following [
|
|
457
|
+
The following [run.rb](example/run.rb) with [input.pdf](example/input.pdf) is located in the [example](example) directory. It uses most 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).
|
|
456
458
|
|
|
457
459
|
```ruby
|
|
458
460
|
require_relative '../lib/fillable-pdf'
|
|
459
461
|
|
|
462
|
+
# Get the directory where this script is located
|
|
463
|
+
EXAMPLE_DIR = __dir__
|
|
464
|
+
|
|
460
465
|
BASE64_PHOTO = 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==' # rubocop:disable Layout/LineLength
|
|
461
466
|
|
|
462
467
|
# opening a fillable PDF
|
|
463
|
-
pdf = FillablePDF.new('input.pdf')
|
|
468
|
+
pdf = FillablePDF.new(File.join(EXAMPLE_DIR, 'input.pdf'))
|
|
464
469
|
|
|
465
470
|
# total number of fields
|
|
466
471
|
if pdf.any_fields?
|
|
@@ -473,12 +478,15 @@ puts
|
|
|
473
478
|
|
|
474
479
|
# setting form fields
|
|
475
480
|
pdf.set_fields({first_name: 'Richard', last_name: 'Rahl'})
|
|
476
|
-
pdf.set_fields(
|
|
481
|
+
pdf.set_fields(
|
|
482
|
+
{football: 'Yes', baseball: 'Yes', basketball: 'Yes', nascar: 'Yes', hockey: 'Yes', rugby: 'Yes'},
|
|
483
|
+
generate_appearance: false
|
|
484
|
+
)
|
|
477
485
|
pdf.set_field(:date, Time.now.strftime('%B %e, %Y'))
|
|
478
486
|
pdf.set_field(:newsletter, 'Off') # uncheck the checkbox
|
|
479
487
|
pdf.set_field(:language, 'dart') # select a radio button option
|
|
480
488
|
pdf.set_image_base64(:photo, BASE64_PHOTO)
|
|
481
|
-
pdf.set_image(:signature, 'signature.png')
|
|
489
|
+
pdf.set_image(:signature, File.join(EXAMPLE_DIR, 'signature.png'))
|
|
482
490
|
|
|
483
491
|
# list of fields
|
|
484
492
|
puts "Fields hash: #{pdf.fields}"
|
|
@@ -515,11 +523,11 @@ pdf.remove_field :marketing
|
|
|
515
523
|
puts "Removed field 'marketing'"
|
|
516
524
|
|
|
517
525
|
# saving the filled out PDF in another file
|
|
518
|
-
pdf.save_as('output.pdf')
|
|
526
|
+
pdf.save_as(File.join(EXAMPLE_DIR, 'output.pdf'))
|
|
519
527
|
|
|
520
528
|
# saving another copy of the filled out PDF in another file and making it non-editable
|
|
521
|
-
pdf = FillablePDF.new('output.pdf')
|
|
522
|
-
pdf.save_as 'output.flat.pdf', flatten: true
|
|
529
|
+
pdf = FillablePDF.new(File.join(EXAMPLE_DIR, 'output.pdf'))
|
|
530
|
+
pdf.save_as File.join(EXAMPLE_DIR, 'output.flat.pdf'), flatten: true
|
|
523
531
|
|
|
524
532
|
# closing the document
|
|
525
533
|
pdf.close
|
|
@@ -528,19 +536,19 @@ pdf.close
|
|
|
528
536
|
The example above produces the following output and also generates the output file [output.pdf](example/output.pdf).
|
|
529
537
|
|
|
530
538
|
```text
|
|
531
|
-
The form has a total of
|
|
539
|
+
The form has a total of 14 fields.
|
|
532
540
|
|
|
533
|
-
Fields hash: {:
|
|
541
|
+
Fields hash: {last_name: "Rahl", first_name: "Richard", football: "Yes", baseball: "Yes", basketball: "Yes", date: "August 12, 2026", newsletter: "Off", nascar: "Yes", language: "dart", signature: "", photo: "", rugby: "Yes", hockey: "Yes", marketing: ""}
|
|
534
542
|
|
|
535
|
-
Keys: [:last_name, :first_name, :football, :baseball, :basketball, :
|
|
543
|
+
Keys: [:last_name, :first_name, :football, :baseball, :basketball, :date, :newsletter, :nascar, :language, :signature, :photo, :rugby, :hockey, :marketing]
|
|
536
544
|
|
|
537
|
-
Values: ["Rahl", "Richard", "Yes", "Yes", "Yes", "
|
|
545
|
+
Values: ["Rahl", "Richard", "Yes", "Yes", "Yes", "August 12, 2026", "Off", "Yes", "dart", "", "", "Yes", "Yes", ""]
|
|
538
546
|
|
|
539
547
|
Field 'football' is of type BUTTON
|
|
540
548
|
|
|
541
549
|
Renamed field 'last_name' to 'surname'
|
|
542
550
|
|
|
543
|
-
Removed field '
|
|
551
|
+
Removed field 'marketing'
|
|
544
552
|
```
|
|
545
553
|
|
|
546
554
|
## Contributing
|
|
@@ -554,6 +562,6 @@ Removed field 'nascar'
|
|
|
554
562
|
|
|
555
563
|
## License
|
|
556
564
|
|
|
557
|
-
The gem is available as open source under the terms of the [MIT License](
|
|
565
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/license/MIT).
|
|
558
566
|
|
|
559
|
-
However, you must also adhere to the [iText License](https://github.com/itext/
|
|
567
|
+
However, you must also adhere to the [iText License](https://github.com/itext/itext-java) when using this gem in your project.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
data/lib/fillable-pdf/version.rb
CHANGED
data/lib/fillable-pdf.rb
CHANGED
|
@@ -128,7 +128,7 @@ class FillablePDF # rubocop:disable Metrics/ClassLength
|
|
|
128
128
|
# @param [String|Symbol] key the field name
|
|
129
129
|
# @param [String|Symbol] file_path the name of the image file or image path
|
|
130
130
|
# @return [self] returns self for method chaining
|
|
131
|
-
# @raise [FileOperationError] if the image file is not found
|
|
131
|
+
# @raise [FileOperationError] if the image file is not found or the field has no visible area
|
|
132
132
|
# @raise [FieldNotFoundError] if the field does not exist
|
|
133
133
|
#
|
|
134
134
|
def set_image(key, file_path) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
@@ -136,13 +136,7 @@ class FillablePDF # rubocop:disable Metrics/ClassLength
|
|
|
136
136
|
raise FileOperationError, "File <#{file_path}> is not found" unless File.exist?(file_path)
|
|
137
137
|
|
|
138
138
|
begin
|
|
139
|
-
|
|
140
|
-
widgets = field.getWidgets
|
|
141
|
-
widget_dict = suppress_warnings { widgets.isEmpty ? field.getPdfObject : widgets.get(0).getPdfObject }
|
|
142
|
-
orig_rect = widget_dict.getAsRectangle(ITEXT::PdfName.Rect)
|
|
143
|
-
|
|
144
|
-
border_style = field.getWidgets.get(0).getBorderStyle
|
|
145
|
-
border_width = border_style.nil? ? 0 : border_style.getWidth
|
|
139
|
+
widget_dict, orig_rect, border_width = image_placement(key)
|
|
146
140
|
|
|
147
141
|
bounding_rectangle = ITEXT::Rectangle.new(
|
|
148
142
|
orig_rect.getWidth - (border_width * 2),
|
|
@@ -165,6 +159,8 @@ class FillablePDF # rubocop:disable Metrics/ClassLength
|
|
|
165
159
|
widget_dict.put(ITEXT::PdfName.AP, pdf_dict)
|
|
166
160
|
pdf_dict.put(ITEXT::PdfName.N, pdf_form_x_object.getPdfObject)
|
|
167
161
|
widget_dict.setModified
|
|
162
|
+
rescue FileOperationError
|
|
163
|
+
raise
|
|
168
164
|
rescue StandardError => e
|
|
169
165
|
raise FileOperationError, "Failed to set image for field '#{key}': #{e.message}"
|
|
170
166
|
end
|
|
@@ -393,6 +389,20 @@ class FillablePDF # rubocop:disable Metrics/ClassLength
|
|
|
393
389
|
field
|
|
394
390
|
end
|
|
395
391
|
|
|
392
|
+
# Dictionary, rectangle and border width of the field's first widget, falling
|
|
393
|
+
# back to the field itself when it has no widget annotations.
|
|
394
|
+
def image_placement(key)
|
|
395
|
+
field = pdf_field(key)
|
|
396
|
+
widgets = field.getWidgets
|
|
397
|
+
widget = widgets.isEmpty ? nil : widgets.get(0)
|
|
398
|
+
widget_dict = suppress_warnings { (widget || field).getPdfObject }
|
|
399
|
+
rect = widget_dict.getAsRectangle(ITEXT::PdfName.Rect)
|
|
400
|
+
raise FileOperationError, "Field '#{key}' has no visible area to place an image in" if rect.nil?
|
|
401
|
+
|
|
402
|
+
border_style = widget&.getBorderStyle
|
|
403
|
+
[widget_dict, rect, border_style.nil? ? 0 : border_style.getWidth]
|
|
404
|
+
end
|
|
405
|
+
|
|
396
406
|
def validate_input(key, value)
|
|
397
407
|
validate_field_name(key)
|
|
398
408
|
raise InvalidArgumentError, 'Field value cannot be nil' if value.nil?
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fillable-pdf
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.1.
|
|
4
|
+
version: 1.1.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Vadim Kononov
|
|
@@ -51,9 +51,9 @@ dependencies:
|
|
|
51
51
|
- - "~>"
|
|
52
52
|
- !ruby/object:Gem::Version
|
|
53
53
|
version: '1.6'
|
|
54
|
-
description:
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
description: Ruby wrapper for iText to work with AcroForm PDFs. Fill and read text
|
|
55
|
+
fields, checkboxes and radio buttons, add images to fields, rename or remove fields,
|
|
56
|
+
and flatten forms.
|
|
57
57
|
email:
|
|
58
58
|
- vadim@konoson.com
|
|
59
59
|
executables: []
|
|
@@ -62,12 +62,12 @@ extra_rdoc_files: []
|
|
|
62
62
|
files:
|
|
63
63
|
- LICENSE.md
|
|
64
64
|
- README.md
|
|
65
|
-
- ext/commons-9.7.
|
|
66
|
-
- ext/font-asian-9.7.
|
|
67
|
-
- ext/forms-9.7.
|
|
68
|
-
- ext/io-9.7.
|
|
69
|
-
- ext/kernel-9.7.
|
|
70
|
-
- ext/layout-9.7.
|
|
65
|
+
- ext/commons-9.7.1.jar
|
|
66
|
+
- ext/font-asian-9.7.1.jar
|
|
67
|
+
- ext/forms-9.7.1.jar
|
|
68
|
+
- ext/io-9.7.1.jar
|
|
69
|
+
- ext/kernel-9.7.1.jar
|
|
70
|
+
- ext/layout-9.7.1.jar
|
|
71
71
|
- ext/slf4j-api-2.0.18.jar
|
|
72
72
|
- ext/slf4j-simple-2.0.18.jar
|
|
73
73
|
- lib/fillable-pdf.rb
|
|
@@ -98,5 +98,5 @@ requirements:
|
|
|
98
98
|
- JDK >= 8
|
|
99
99
|
rubygems_version: 4.0.10
|
|
100
100
|
specification_version: 4
|
|
101
|
-
summary: Fill
|
|
101
|
+
summary: Fill, read, flatten and edit PDF form fields in Ruby with the iText engine
|
|
102
102
|
test_files: []
|