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