fillable-pdf 0.9.1 → 0.9.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +18 -0
- data/.travis.yml +1 -1
- data/README.md +251 -113
- data/ext/commons-7.2.3.jar +0 -0
- data/ext/{font-asian-7.1.12.jar → font-asian-7.2.3.jar} +0 -0
- data/ext/forms-7.2.3.jar +0 -0
- data/ext/io-7.2.3.jar +0 -0
- data/ext/kernel-7.2.3.jar +0 -0
- data/ext/layout-7.2.3.jar +0 -0
- data/ext/slf4j-api-1.7.32.jar +0 -0
- data/ext/slf4j-simple-1.7.32.jar +0 -0
- data/fillable-pdf.gemspec +5 -0
- data/lib/field.rb +4 -6
- data/lib/fillable-pdf/itext.rb +21 -0
- data/lib/{kernel.rb → fillable-pdf/kernel.rb} +0 -0
- data/lib/fillable-pdf/version.rb +1 -1
- data/lib/fillable-pdf.rb +69 -17
- metadata +16 -13
- 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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3295f6a5e77e53fb9ae16f59cb1456483daecf203857cd903fd84622336f9d35
|
4
|
+
data.tar.gz: 4bb925c8f5908f663d36f93afb701c2dc5dcd744f476a50b2bf17fc73ff97f6d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ae5c10683e12cda0c209126d256b6f223d2b4194c85b06be9af9e76c12a710c8fe5d8fe6b3ff646d0b285ff93d0f97a8a0bd0c655474b52746a7c43460fd7925
|
7
|
+
data.tar.gz: a793a4b88d8034f9d3194fd19c07244c4d1083477f9004307208c1b9b23764fc0dde863f6f2a54c0abb264c90f5b2d05360b850fbc074afe9f259d4f51a449cf
|
data/.rubocop.yml
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require:
|
2
|
+
- rubocop-md
|
2
3
|
- rubocop-minitest
|
3
4
|
- rubocop-performance
|
4
5
|
- rubocop-rake
|
@@ -7,18 +8,35 @@ AllCops:
|
|
7
8
|
NewCops: enable
|
8
9
|
Exclude:
|
9
10
|
- .git/**/*
|
11
|
+
- vendor/bundle/**/*
|
12
|
+
|
13
|
+
Gemspec/RequiredRubyVersion:
|
14
|
+
Enabled: false
|
10
15
|
|
11
16
|
Layout/EmptyLineAfterGuardClause:
|
12
17
|
Enabled: false
|
13
18
|
|
19
|
+
Layout/IndentationConsistency:
|
20
|
+
Exclude:
|
21
|
+
- README.md
|
22
|
+
|
23
|
+
Layout/InitialIndentation:
|
24
|
+
Exclude:
|
25
|
+
- README.md
|
26
|
+
|
14
27
|
Layout/LineLength:
|
15
28
|
Exclude:
|
29
|
+
- README.md
|
16
30
|
- fillable-pdf.gemspec
|
17
31
|
Max: 120
|
18
32
|
|
19
33
|
Layout/SpaceInsideHashLiteralBraces:
|
20
34
|
Enabled: false
|
21
35
|
|
36
|
+
Lint/ConstantDefinitionInBlock:
|
37
|
+
Exclude:
|
38
|
+
- lib/fillable-pdf/itext.rb
|
39
|
+
|
22
40
|
Metrics/MethodLength:
|
23
41
|
Max: 12
|
24
42
|
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -2,40 +2,51 @@
|
|
2
2
|
# FillablePDF
|
3
3
|
|
4
4
|
[![Gem Version](https://badge.fury.io/rb/fillable-pdf.svg)](https://rubygems.org/gems/fillable-pdf)
|
5
|
-
[![Build Status](https://
|
5
|
+
[![Build Status](https://app.travis-ci.com/vkononov/fillable-pdf.svg?branch=master)](http://travis-ci.org/vkononov/fillable-pdf)
|
6
|
+
|
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
|
-
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.
|
8
9
|
|
9
10
|
## Known Issues
|
10
11
|
|
11
|
-
|
12
|
+
1. This gem currently does not work with Phusion Passenger's [smart spawning](https://www.phusionpassenger.com/library/indepth/ruby/spawn_methods/#the-smart-spawning-method). Please see [Deployment with Phusion Passenger + Nginx](#deployment-with-phusion-passenger--nginx) for more information.
|
12
13
|
|
13
|
-
|
14
|
-
gem 'spring'
|
15
|
-
gem 'spring-watcher-listen'
|
16
|
-
```
|
14
|
+
2. If the gem hangs in `development`, removing the following gems may fix the issue:
|
17
15
|
|
18
|
-
|
16
|
+
```ruby
|
17
|
+
gem 'spring'
|
18
|
+
gem 'spring-watcher-listen'
|
19
|
+
```
|
20
|
+
|
21
|
+
3. Read-only, write-protected or encrypted PDF files are currently not supported.
|
19
22
|
|
20
23
|
|
21
24
|
## Installation
|
22
25
|
|
23
|
-
**
|
24
|
-
|
25
|
-
|
26
|
-
|
26
|
+
**Prerequisites:** Java SE Development Kit v8, v11
|
27
|
+
|
28
|
+
- Ensure that your `JAVA_HOME` variable is set before installing this gem (see examples below).**
|
29
|
+
|
30
|
+
* OSX: `/Library/Java/JavaVirtualMachines/jdk-11.0.2.jdk/Contents/Home`
|
31
|
+
* Ubuntu/CentOS: `/usr/lib/jvm/java-1.8.0-openjdk`
|
27
32
|
|
28
33
|
Add this line to your application's Gemfile:
|
29
34
|
|
30
|
-
|
35
|
+
```ruby
|
36
|
+
gem 'fillable-pdf'
|
37
|
+
```
|
31
38
|
|
32
39
|
And then execute:
|
33
40
|
|
34
|
-
|
41
|
+
```bash
|
42
|
+
bundle
|
43
|
+
```
|
35
44
|
|
36
45
|
Or install it yourself as:
|
37
46
|
|
38
|
-
|
47
|
+
```bash
|
48
|
+
gem install fillable-pdf
|
49
|
+
```
|
39
50
|
|
40
51
|
If you are using this gem in a script, you need to require it manually:
|
41
52
|
|
@@ -57,127 +68,257 @@ pdf = FillablePDF.new 'input.pdf'
|
|
57
68
|
pdf.close
|
58
69
|
```
|
59
70
|
|
60
|
-
|
71
|
+
### Checking / Unchecking Checkboxes
|
72
|
+
|
73
|
+
Use the values `'Yes'` and `'Off'` to check and uncheck checkboxes, respectively. For example:
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
pdf.set_field(:newsletter, 'Yes')
|
77
|
+
pdf.set_field(:newsletter, 'Off')
|
78
|
+
```
|
79
|
+
|
80
|
+
### Checking / Unchecking Radio Buttons
|
81
|
+
|
82
|
+
Suppose you have the following a radio button field name `language` with the following options:
|
83
|
+
|
84
|
+
- Ruby (`ruby`)
|
85
|
+
- Python (`python`)
|
86
|
+
- Dart (`dart`)
|
87
|
+
- Other (`other`)
|
88
|
+
|
89
|
+
To select one of these options (or change the current option) use:
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
pdf.set_field(:language, 'dart')
|
93
|
+
```
|
94
|
+
|
95
|
+
To unset the radio button use the `'Off'` string:
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
pdf.set_field(:language, 'Off')
|
99
|
+
```
|
100
|
+
|
101
|
+
### Adding Signatures or Images
|
102
|
+
|
103
|
+
Digital signatures are not supported, but you can place an image or a base64 encoded image within the bounds of any form field.
|
104
|
+
|
105
|
+
SVG images are not supported. You will have to convert them to a JPG or PNG first.
|
106
|
+
|
107
|
+
See methods `set_image` and `set_image_base64` below.
|
108
|
+
|
109
|
+
### Instance Methods
|
61
110
|
|
62
111
|
An instance of `FillablePDF` has the following methods at its disposal:
|
63
112
|
|
64
113
|
* `any_fields?`
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
114
|
+
*Determines whether the form has any fields.*
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
pdf.any_fields?
|
118
|
+
# output example: true
|
119
|
+
```
|
70
120
|
|
71
121
|
* `num_fields`
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
122
|
+
*Returns the total number of fillable form fields.*
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
# output example: 10
|
126
|
+
pdf.num_fields
|
127
|
+
```
|
77
128
|
|
78
129
|
* `field`
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
130
|
+
*Retrieves the value of a field given its unique field name.*
|
131
|
+
|
132
|
+
```ruby
|
133
|
+
pdf.field(:full_name)
|
134
|
+
# output example: 'Richard'
|
135
|
+
```
|
84
136
|
|
85
137
|
* `field_type`
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
138
|
+
*Retrieves the numeric type of a field given its unique field name.*
|
139
|
+
|
140
|
+
```ruby
|
141
|
+
pdf.field_type(:football)
|
142
|
+
# output example: '/Btn'
|
143
|
+
|
144
|
+
# list of all field types
|
145
|
+
Field::BUTTON ('/Btn')
|
146
|
+
Field::CHOICE ('/Ch')
|
147
|
+
Field::SIGNATURE ('/Sig')
|
148
|
+
Field::TEXT ('/Tx')
|
149
|
+
```
|
97
150
|
|
98
151
|
* `fields`
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
152
|
+
*Retrieves a hash of all fields and their values.*
|
153
|
+
|
154
|
+
```ruby
|
155
|
+
pdf.fields
|
156
|
+
# output example: {first_name: "Richard", last_name: "Rahl"}
|
157
|
+
```
|
104
158
|
|
105
159
|
* `set_field`
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
160
|
+
*Sets the value of a field given its unique field name and value.*
|
161
|
+
|
162
|
+
```ruby
|
163
|
+
pdf.set_field(:first_name, 'Richard')
|
164
|
+
# result: changes the value of 'first_name' to 'Richard'
|
165
|
+
```
|
111
166
|
|
112
167
|
* `set_fields`
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
168
|
+
*Sets the values of multiple fields given a set of unique field names and values.*
|
169
|
+
|
170
|
+
```ruby
|
171
|
+
pdf.set_fields(first_name: 'Richard', last_name: 'Rahl')
|
172
|
+
# result: changes the values of 'first_name' and 'last_name'
|
173
|
+
```
|
174
|
+
|
175
|
+
* `set_image`
|
176
|
+
*Places an image file within the rectangular bounding box of the given form field.*
|
177
|
+
|
178
|
+
```ruby
|
179
|
+
pdf.set_image(:signature, 'signature.png')
|
180
|
+
# result: the image 'signature.png' is shown in the foreground of the form field
|
181
|
+
```
|
182
|
+
|
183
|
+
* `set_image_base64`
|
184
|
+
*Places a base64 encoded image within the rectangular bounding box of the given form field.*
|
185
|
+
|
186
|
+
```ruby
|
187
|
+
pdf.set_image_base64(:signature, 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==')
|
188
|
+
# result: the base64 encoded image is shown in the foreground of the form field
|
189
|
+
```
|
118
190
|
|
119
191
|
* `rename_field`
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
192
|
+
*Renames a field given its unique field name and the new field name.*
|
193
|
+
|
194
|
+
```ruby
|
195
|
+
pdf.rename_field(:last_name, :surname)
|
196
|
+
# result: renames field name 'last_name' to 'surname'
|
197
|
+
# NOTE: this action does not take effect until the document is saved
|
198
|
+
```
|
126
199
|
|
127
200
|
* `remove_field`
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
201
|
+
*Removes a field from the document given its unique field name.*
|
202
|
+
|
203
|
+
```ruby
|
204
|
+
pdf.remove_field(:last_name)
|
205
|
+
# result: physically removes field 'last_name' from document
|
206
|
+
```
|
133
207
|
|
134
208
|
* `names`
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
209
|
+
*Returns a list of all field keys used in the document.*
|
210
|
+
|
211
|
+
```ruby
|
212
|
+
pdf.names
|
213
|
+
# output example: [:first_name, :last_name]
|
214
|
+
```
|
140
215
|
|
141
216
|
* `values`
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
217
|
+
*Returns a list of all field values used in the document.*
|
218
|
+
|
219
|
+
```ruby
|
220
|
+
pdf.values
|
221
|
+
# output example: ["Rahl", "Richard"]
|
222
|
+
```
|
147
223
|
|
148
224
|
* `save`
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
225
|
+
*Overwrites the previously opened PDF document and flattens it if requested.*
|
226
|
+
|
227
|
+
```ruby
|
228
|
+
pdf.save
|
229
|
+
# result: document is saved without flattening
|
230
|
+
pdf.save_as(flatten: true)
|
231
|
+
# result: document is saved with flattening
|
232
|
+
```
|
156
233
|
|
157
234
|
* `save_as`
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
235
|
+
*Saves the filled out PDF document in a given path and flattens it if requested.*
|
236
|
+
|
237
|
+
```ruby
|
238
|
+
pdf.save_as('output.pdf')
|
239
|
+
# result: document is saved in a given path without flattening
|
240
|
+
pdf.save_as('output.pdf', flatten: true)
|
241
|
+
# result: document is saved in a given path with flattening
|
242
|
+
```
|
165
243
|
|
166
|
-
|
244
|
+
**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.
|
167
245
|
|
168
246
|
* `close`
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
247
|
+
*Closes the PDF document discarding all unsaved changes.*
|
248
|
+
|
249
|
+
```ruby
|
250
|
+
pdf.close
|
251
|
+
# result: document is closed
|
252
|
+
```
|
253
|
+
|
254
|
+
|
255
|
+
## Deployment with Heroku
|
256
|
+
|
257
|
+
When deploying to Heroku, be sure to install the following build packs (in this order):
|
258
|
+
|
259
|
+
```bash
|
260
|
+
heroku buildpacks:add heroku/jvm
|
261
|
+
heroku buildpacks:add heroku/ruby
|
262
|
+
```
|
263
|
+
|
264
|
+
## Deployment with Phusion Passenger + Nginx
|
265
|
+
|
266
|
+
The way the gem is currently built makes it [fundamentally incompatible](https://github.com/phusion/passenger/issues/223#issuecomment-44504029) with Phusion Passenger's [smart spawning](https://www.phusionpassenger.com/library/indepth/ruby/spawn_methods/#the-smart-spawning-method). You must turn off smart spawning, or else your application will freeze as soon Ruby tries to access the Java bridge.
|
267
|
+
|
268
|
+
Below is an example of a simple Nginx virtual host configuration (note the use of `passenger_spawn_method`):
|
269
|
+
|
270
|
+
```nginx
|
271
|
+
server {
|
272
|
+
server_name my-rails-app.com;
|
273
|
+
listen 443 ssl http2;
|
274
|
+
listen [::]:443 ssl http2;
|
275
|
+
passenger_enabled on;
|
276
|
+
passenger_spawn_method direct;
|
277
|
+
root /home/system/my-rails-app/public;
|
278
|
+
}
|
279
|
+
```
|
280
|
+
|
281
|
+
If you absolutely must have smart spawning, I recommend using `fillable-pdf` as a service that runs independently of your Rails application.
|
282
|
+
|
283
|
+
## Deployment with Puma + Nginx
|
284
|
+
|
285
|
+
In order to use Puma in production, you need to configure a reverse proxy in your Nginx virtual host. Here is simple naive example:
|
286
|
+
|
287
|
+
```nginx
|
288
|
+
server {
|
289
|
+
server_name my-rails-app.com;
|
290
|
+
listen 443 ssl http2;
|
291
|
+
listen [::]:443 ssl http2;
|
292
|
+
location / {
|
293
|
+
proxy_pass http://127.0.0.1:8888;
|
294
|
+
proxy_redirect off;
|
295
|
+
proxy_set_header Connection "upgrade";
|
296
|
+
proxy_set_header Host $http_host;
|
297
|
+
proxy_set_header Upgrade $http_upgrade;
|
298
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
299
|
+
proxy_set_header X-Forwarded-Proto https;
|
300
|
+
proxy_set_header X-Real-IP $remote_addr;
|
301
|
+
}
|
302
|
+
}
|
303
|
+
```
|
304
|
+
|
305
|
+
Then you'll have to start Puma in production daemon mode as follows:
|
306
|
+
|
307
|
+
```bash
|
308
|
+
RAILS_ENV=production bin/rails server -p 8888 --daemon
|
309
|
+
```
|
310
|
+
|
311
|
+
Naturally, there are many downsides (in terms of efficiency, scalability, security, etc) to running your application in production in this manner, so please use the above as an example only.
|
312
|
+
|
174
313
|
|
175
314
|
## Example
|
176
315
|
|
177
|
-
The following
|
316
|
+
The following [example.rb](example/run.rb) with [input.pdf](example/input.pdf) is located in the [example](example) 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).
|
178
317
|
|
179
318
|
```ruby
|
180
|
-
|
319
|
+
require_relative '../lib/fillable-pdf'
|
320
|
+
|
321
|
+
BASE64_PHOTO = 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==' # rubocop:disable Layout/LineLength
|
181
322
|
|
182
323
|
# opening a fillable PDF
|
183
324
|
pdf = FillablePDF.new('input.pdf')
|
@@ -193,9 +334,12 @@ puts
|
|
193
334
|
|
194
335
|
# setting form fields
|
195
336
|
pdf.set_fields(first_name: 'Richard', last_name: 'Rahl')
|
196
|
-
pdf.set_fields(football: 'Yes', baseball: 'Yes',
|
197
|
-
basketball: 'Yes', nascar: 'Yes', hockey: 'Yes')
|
337
|
+
pdf.set_fields(football: 'Yes', baseball: 'Yes', basketball: 'Yes', nascar: 'Yes', hockey: 'Yes')
|
198
338
|
pdf.set_field(:date, Time.now.strftime('%B %e, %Y'))
|
339
|
+
pdf.set_field(:newsletter, 'Off') # uncheck the checkbox
|
340
|
+
pdf.set_field(:language, 'dart') # select a radio button option
|
341
|
+
pdf.set_image_base64(:photo, BASE64_PHOTO)
|
342
|
+
pdf.set_image(:signature, 'signature.png')
|
199
343
|
|
200
344
|
# list of fields
|
201
345
|
puts "Fields hash: #{pdf.fields}"
|
@@ -230,10 +374,6 @@ puts
|
|
230
374
|
# Removing field
|
231
375
|
pdf.remove_field :nascar
|
232
376
|
puts "Removed field 'nascar'"
|
233
|
-
puts
|
234
|
-
|
235
|
-
# printing the name of the person used inside the PDF
|
236
|
-
puts "Signatory: #{pdf.field(:first_name)} #{pdf.field(:last_name)}"
|
237
377
|
|
238
378
|
# saving the filled out PDF in another file
|
239
379
|
pdf.save_as('output.pdf')
|
@@ -248,22 +388,20 @@ pdf.close
|
|
248
388
|
|
249
389
|
The example above produces the following output and also generates the output file [output.pdf](example/output.pdf).
|
250
390
|
|
251
|
-
```
|
252
|
-
The form has a total of
|
391
|
+
```text
|
392
|
+
The form has a total of 16 fields.
|
253
393
|
|
254
|
-
Fields hash: {:last_name=>"Rahl", :first_name=>"Richard", :football=>"Yes", :baseball=>"Yes", :basketball=>"Yes", :
|
394
|
+
Fields hash: {:last_name=>"Rahl", :first_name=>"Richard", :football=>"Yes", :baseball=>"Yes", :basketball=>"Yes", :hockey=>"Yes", :date=>"November 16, 2021", :newsletter=>"Off", :nascar=>"Yes", :language=>"dart", :"language.1"=>"dart", :"language.2"=>"dart", :"language.3"=>"dart", :"language.4"=>"dart", :signature=>"", :photo=>""}
|
255
395
|
|
256
|
-
Keys: [:last_name, :first_name, :football, :baseball, :basketball, :nascar, :
|
396
|
+
Keys: [:last_name, :first_name, :football, :baseball, :basketball, :hockey, :date, :newsletter, :nascar, :language, :"language.1", :"language.2", :"language.3", :"language.4", :signature, :photo]
|
257
397
|
|
258
|
-
Values: ["Rahl", "Richard", "Yes", "Yes", "Yes", "Yes", "Yes", "
|
398
|
+
Values: ["Rahl", "Richard", "Yes", "Yes", "Yes", "Yes", "November 16, 2021", "Off", "Yes", "dart", "dart", "dart", "dart", "dart", "", ""]
|
259
399
|
|
260
400
|
Field 'football' is of type BUTTON
|
261
401
|
|
262
402
|
Renamed field 'last_name' to 'surname'
|
263
403
|
|
264
404
|
Removed field 'nascar'
|
265
|
-
|
266
|
-
Signatory: Richard Rahl
|
267
405
|
```
|
268
406
|
|
269
407
|
## Contributing
|
Binary file
|
Binary file
|
data/ext/forms-7.2.3.jar
ADDED
Binary file
|
data/ext/io-7.2.3.jar
ADDED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/fillable-pdf.gemspec
CHANGED
data/lib/field.rb
CHANGED
@@ -1,15 +1,13 @@
|
|
1
1
|
require_relative 'fillable-pdf/itext'
|
2
|
-
require_relative 'kernel'
|
3
2
|
|
4
3
|
class Field
|
5
4
|
# PdfName has a constant "A" and a constant "a". Unfortunately, RJB does not differentiate
|
6
5
|
# between these constants and tries to create the same constant ("A") for both, which causes
|
7
6
|
# an annoying warning "already initialized constant Rjb::Com_itextpdf_kernel_pdf_PdfName::A".
|
8
7
|
# 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') } # rubocop:disable Lint/ConstantDefinitionInBlock
|
10
8
|
|
11
|
-
BUTTON =
|
12
|
-
CHOICE =
|
13
|
-
SIGNATURE =
|
14
|
-
TEXT =
|
9
|
+
BUTTON = ITEXT::PdfName.Btn.toString
|
10
|
+
CHOICE = ITEXT::PdfName.Ch.toString
|
11
|
+
SIGNATURE = ITEXT::PdfName.Sig.toString
|
12
|
+
TEXT = ITEXT::PdfName.Tx.toString
|
15
13
|
end
|
data/lib/fillable-pdf/itext.rb
CHANGED
@@ -1,3 +1,24 @@
|
|
1
|
+
require_relative 'kernel'
|
1
2
|
require 'rjb'
|
2
3
|
|
3
4
|
Rjb.load(Dir.glob(File.expand_path('../../ext/*.jar', __dir__)).join(':'))
|
5
|
+
|
6
|
+
module ITEXT
|
7
|
+
suppress_warnings do
|
8
|
+
ByteArrayOutputStream = Rjb.import 'com.itextpdf.io.source.ByteArrayOutputStream'
|
9
|
+
Canvas = Rjb.import 'com.itextpdf.layout.Canvas'
|
10
|
+
Div = Rjb.import 'com.itextpdf.layout.element.Div'
|
11
|
+
HorizontalAlignment = Rjb.import 'com.itextpdf.layout.properties.HorizontalAlignment'
|
12
|
+
Image = Rjb.import 'com.itextpdf.layout.element.Image'
|
13
|
+
ImageDataFactory = Rjb.import 'com.itextpdf.io.image.ImageDataFactory'
|
14
|
+
PdfAcroForm = Rjb.import 'com.itextpdf.forms.PdfAcroForm'
|
15
|
+
PdfDictionary = Rjb.import 'com.itextpdf.kernel.pdf.PdfDictionary'
|
16
|
+
PdfDocument = Rjb.import 'com.itextpdf.kernel.pdf.PdfDocument'
|
17
|
+
PdfFormXObject = Rjb.import 'com.itextpdf.kernel.pdf.xobject.PdfFormXObject'
|
18
|
+
PdfName = Rjb.import 'com.itextpdf.kernel.pdf.PdfName'
|
19
|
+
PdfReader = Rjb.import 'com.itextpdf.kernel.pdf.PdfReader'
|
20
|
+
PdfWriter = Rjb.import 'com.itextpdf.kernel.pdf.PdfWriter'
|
21
|
+
Rectangle = Rjb.import 'com.itextpdf.kernel.geom.Rectangle'
|
22
|
+
VerticalAlignment = Rjb.import 'com.itextpdf.layout.properties.VerticalAlignment'
|
23
|
+
end
|
24
|
+
end
|
File without changes
|
data/lib/fillable-pdf/version.rb
CHANGED
data/lib/fillable-pdf.rb
CHANGED
@@ -1,34 +1,28 @@
|
|
1
1
|
require_relative 'fillable-pdf/itext'
|
2
2
|
require_relative 'field'
|
3
|
+
require 'base64'
|
3
4
|
require 'fileutils'
|
4
5
|
require 'securerandom'
|
5
6
|
|
6
|
-
class FillablePDF
|
7
|
-
# required Java imports
|
8
|
-
BYTE_STREAM = Rjb.import 'com.itextpdf.io.source.ByteArrayOutputStream'
|
9
|
-
PDF_READER = Rjb.import 'com.itextpdf.kernel.pdf.PdfReader'
|
10
|
-
PDF_WRITER = Rjb.import 'com.itextpdf.kernel.pdf.PdfWriter'
|
11
|
-
PDF_DOCUMENT = Rjb.import 'com.itextpdf.kernel.pdf.PdfDocument'
|
12
|
-
PDF_ACRO_FORM = Rjb.import 'com.itextpdf.forms.PdfAcroForm'
|
13
|
-
PDF_FORM_FIELD = Rjb.import 'com.itextpdf.forms.fields.PdfFormField'
|
14
|
-
|
7
|
+
class FillablePDF # rubocop:disable Metrics/ClassLength
|
15
8
|
##
|
16
9
|
# Opens a given fillable-pdf PDF file and prepares it for modification.
|
17
10
|
#
|
18
11
|
# @param [String|Symbol] file_path the name of the PDF file or file path
|
19
12
|
#
|
20
|
-
def initialize(file_path)
|
21
|
-
raise IOError, "File
|
13
|
+
def initialize(file_path) # rubocop:disable Metrics/MethodLength
|
14
|
+
raise IOError, "File <#{file_path}> is not found" unless File.exist?(file_path)
|
22
15
|
@file_path = file_path
|
23
16
|
begin
|
24
|
-
@byte_stream =
|
25
|
-
@pdf_reader =
|
26
|
-
@pdf_writer =
|
27
|
-
@pdf_doc =
|
28
|
-
@pdf_form =
|
17
|
+
@byte_stream = ITEXT::ByteArrayOutputStream.new
|
18
|
+
@pdf_reader = ITEXT::PdfReader.new @file_path.to_s
|
19
|
+
@pdf_writer = ITEXT::PdfWriter.new @byte_stream
|
20
|
+
@pdf_doc = ITEXT::PdfDocument.new @pdf_reader, @pdf_writer
|
21
|
+
@pdf_form = ITEXT::PdfAcroForm.getAcroForm(@pdf_doc, true)
|
29
22
|
@form_fields = @pdf_form.getFormFields
|
23
|
+
@pdf_form.setGenerateAppearance false
|
30
24
|
rescue StandardError => e
|
31
|
-
raise "#{e.message} (
|
25
|
+
raise "#{e.message} (Input file may be corrupt, incompatible, read-only, write-protected, encrypted, or may not have any form fields)" # rubocop:disable Layout/LineLength
|
32
26
|
end
|
33
27
|
end
|
34
28
|
|
@@ -99,6 +93,64 @@ class FillablePDF
|
|
99
93
|
pdf_field(key).setValue(value.to_s)
|
100
94
|
end
|
101
95
|
|
96
|
+
##
|
97
|
+
# Sets an image within the bounds of the given form field. It doesn't matter
|
98
|
+
# what type of form field it is (signature, image, etc). The image will be scaled
|
99
|
+
# to fill the available space while preserving its aspect ratio. All previous
|
100
|
+
# content will be removed, which means you cannot have both text and image.
|
101
|
+
#
|
102
|
+
# @param [String|Symbol] key the field name
|
103
|
+
# @param [String|Symbol] file_path the name of the image file or image path
|
104
|
+
#
|
105
|
+
def set_image(key, file_path) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
106
|
+
raise IOError, "File <#{file_path}> is not found" unless File.exist?(file_path)
|
107
|
+
field = pdf_field(key)
|
108
|
+
widgets = field.getWidgets
|
109
|
+
widget_dict = suppress_warnings { widgets.isEmpty ? field.getPdfObject : widgets.get(0).getPdfObject }
|
110
|
+
orig_rect = widget_dict.getAsRectangle(ITEXT::PdfName.Rect)
|
111
|
+
border_width = field.getBorderWidth
|
112
|
+
bounding_rectangle = ITEXT::Rectangle.new(
|
113
|
+
orig_rect.getWidth - (border_width * 2),
|
114
|
+
orig_rect.getHeight - (border_width * 2)
|
115
|
+
)
|
116
|
+
|
117
|
+
pdf_form_x_object = ITEXT::PdfFormXObject.new(bounding_rectangle)
|
118
|
+
canvas = ITEXT::Canvas.new(pdf_form_x_object, @pdf_doc)
|
119
|
+
image = ITEXT::Image.new(ITEXT::ImageDataFactory.create(file_path.to_s))
|
120
|
+
.setAutoScale(true)
|
121
|
+
.setHorizontalAlignment(ITEXT::HorizontalAlignment.CENTER)
|
122
|
+
container = ITEXT::Div.new
|
123
|
+
.setMargin(border_width).add(image)
|
124
|
+
.setVerticalAlignment(ITEXT::VerticalAlignment.MIDDLE)
|
125
|
+
.setFillAvailableArea(true)
|
126
|
+
canvas.add(container)
|
127
|
+
canvas.close
|
128
|
+
|
129
|
+
pdf_dict = ITEXT::PdfDictionary.new
|
130
|
+
widget_dict.put(ITEXT::PdfName.AP, pdf_dict)
|
131
|
+
pdf_dict.put(ITEXT::PdfName.N, pdf_form_x_object.getPdfObject)
|
132
|
+
widget_dict.setModified
|
133
|
+
rescue StandardError => e
|
134
|
+
raise "#{e.message} (there may be something wrong with your image)"
|
135
|
+
end
|
136
|
+
|
137
|
+
##
|
138
|
+
# Sets an image within the bounds of the given form field. It doesn't matter
|
139
|
+
# what type of form field it is (signature, image, etc). The image will be scaled
|
140
|
+
# to fill the available space while preserving its aspect ratio. All previous
|
141
|
+
# content will be removed, which means you cannot have both text and image.
|
142
|
+
#
|
143
|
+
# @param [String|Symbol] key the field name
|
144
|
+
# @param [String|Symbol] base64_image_data base64 encoded data image
|
145
|
+
#
|
146
|
+
def set_image_base64(key, base64_image_data)
|
147
|
+
tmp_file = SecureRandom.uuid
|
148
|
+
File.binwrite(tmp_file, Base64.decode64(base64_image_data))
|
149
|
+
set_image(key, tmp_file)
|
150
|
+
ensure
|
151
|
+
FileUtils.rm tmp_file
|
152
|
+
end
|
153
|
+
|
102
154
|
##
|
103
155
|
# Sets the values of multiple fields given a set of unique field names and values.
|
104
156
|
#
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fillable-pdf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.4
|
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: 2022-07-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -154,23 +154,25 @@ files:
|
|
154
154
|
- Rakefile
|
155
155
|
- bin/console
|
156
156
|
- bin/setup
|
157
|
-
- ext/
|
158
|
-
- ext/
|
159
|
-
- ext/
|
160
|
-
- ext/
|
161
|
-
- ext/
|
162
|
-
- ext/
|
163
|
-
- ext/slf4j-
|
157
|
+
- ext/commons-7.2.3.jar
|
158
|
+
- ext/font-asian-7.2.3.jar
|
159
|
+
- ext/forms-7.2.3.jar
|
160
|
+
- ext/io-7.2.3.jar
|
161
|
+
- ext/kernel-7.2.3.jar
|
162
|
+
- ext/layout-7.2.3.jar
|
163
|
+
- ext/slf4j-api-1.7.32.jar
|
164
|
+
- ext/slf4j-simple-1.7.32.jar
|
164
165
|
- fillable-pdf.gemspec
|
165
166
|
- lib/field.rb
|
166
167
|
- lib/fillable-pdf.rb
|
167
168
|
- lib/fillable-pdf/itext.rb
|
169
|
+
- lib/fillable-pdf/kernel.rb
|
168
170
|
- lib/fillable-pdf/version.rb
|
169
|
-
- lib/kernel.rb
|
170
171
|
homepage: https://github.com/vkononov/fillable-pdf
|
171
172
|
licenses:
|
172
173
|
- MIT
|
173
|
-
metadata:
|
174
|
+
metadata:
|
175
|
+
rubygems_mfa_required: 'true'
|
174
176
|
post_install_message:
|
175
177
|
rdoc_options: []
|
176
178
|
require_paths:
|
@@ -186,8 +188,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
186
188
|
- - ">="
|
187
189
|
- !ruby/object:Gem::Version
|
188
190
|
version: '0'
|
189
|
-
requirements:
|
190
|
-
|
191
|
+
requirements:
|
192
|
+
- JDK 8.x - 11.x
|
193
|
+
rubygems_version: 3.3.7
|
191
194
|
signing_key:
|
192
195
|
specification_version: 4
|
193
196
|
summary: Fill out or extract field values from simple fillable PDF forms using iText.
|
data/ext/forms-7.1.12.jar
DELETED
Binary file
|
data/ext/io-7.1.12.jar
DELETED
Binary file
|
data/ext/kernel-7.1.12.jar
DELETED
Binary file
|
data/ext/layout-7.1.12.jar
DELETED
Binary file
|
data/ext/slf4j-api-1.7.29.jar
DELETED
Binary file
|
data/ext/slf4j-simple-1.7.29.jar
DELETED
Binary file
|