FillablePDF
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.
Known Issues
If the gem hangs in development
, removing the following gems may fix the issue:
gem 'spring'
gem 'spring-watcher-listen'
If the gem hangs in production
, you could try to use puma
with a reverse proxy to host the application.
Installation
Ensure that your JAVA_HOME
variable is set before installing this gem (see examples below).
- OSX:
/Library/Java/JavaVirtualMachines/jdk-12.0.2.jdk/Contents/Home
- Ubuntu/CentOS:
/usr/lib/jvm/java-1.8.0-openjdk
Add this line to your application's Gemfile:
gem 'fillable-pdf'
And then execute:
bundle
Or install it yourself as:
gem install fillable-pdf
If you are using this gem in a script, you need to require it manually:
require 'fillable-pdf'
Usage
First of all, you should open a fillable PDF file:
pdf = FillablePDF.new 'input.pdf'
Always remember to close your document once you're finished working with it in order to avoid memory leaks:
pdf.close
Instance Methods
An instance of FillablePDF
has the following methods at its disposal:
-
any_fields?
Determines whether the form has any fields.pdf.any_fields? # output example: true
-
num_fields
Returns the total number of fillable form fields.# output example: 10 pdf.num_fields
-
field
Retrieves the value of a field given its unique field name.pdf.field(:full_name) # output example: 'Richard'
-
field_type
Retrieves the numeric type of a field given its unique field name.pdf.field_type(:football) # output example: 4 # list of all field types Field::BUTTON Field::CHOICE Field::SIGNATURE Field::TEXT
-
fields
Retrieves a hash of all fields and their values.pdf.fields # output example: {first_name: "Richard", last_name: "Rahl"}
-
set_field
Sets the value of a field given its unique field name and value.pdf.set_field(:first_name, 'Richard') # result: changes the value of 'first_name' to 'Richard'
-
set_fields
Sets the values of multiple fields given a set of unique field names and values.pdf.set_fields(first_name: 'Richard', last_name: 'Rahl') # result: changes the values of 'first_name' and 'last_name'
-
rename_field
Renames a field given its unique field name and the new field name.pdf.rename_field(:last_name, :surname) # result: renames field name 'last_name' to 'surname' # NOTE: this action does not take effect until the document is saved
-
remove_field
Removes a field from the document given its unique field name.pdf.remove_field(:last_name) # result: physically removes field 'last_name' from document
-
names
Returns a list of all field keys used in the document.pdf.names # output example: [:first_name, :last_name]
-
values
Returns a list of all field values used in the document.pdf.values # output example: ["Rahl", "Richard"]
-
save
Overwrites the previously opened PDF document and flattens it if requested.pdf.save # result: document is saved without flatenning pdf.save_as(flatten: true) # result: document is saved with flatenning
-
save_as
Saves the filled out PDF document in a given path and flattens it if requested.pdf.save_as('output.pdf') # result: document is saved in a given path without flatenning pdf.save_as('output.pdf', flatten: true) # result: document is saved in a given path with flatenning
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. -
close
Closes the PDF document discarding all unsaved changes.pdf.close # result: document is closed
Example
The following example example.rb and the input file 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 and output.flat.pdf.
require 'fillable-pdf'
# opening a fillable PDF
pdf = FillablePDF.new('input.pdf')
# total number of fields
if pdf.any_fields?
puts "The form has a total of #{pdf.num_fields} fields."
else
puts 'The form is not fillable.'
end
puts
# setting form fields
pdf.set_fields(first_name: 'Richard', last_name: 'Rahl')
pdf.set_fields(football: 'Yes', baseball: 'Yes',
basketball: 'Yes', nascar: 'Yes', hockey: 'Yes')
pdf.set_field(:date, Time.now.strftime('%B %e, %Y'))
# list of fields
puts "Fields hash: #{pdf.fields}"
puts
# list of field names
puts "Keys: #{pdf.names}"
puts
# list of field values
puts "Values: #{pdf.values}"
puts
# Checking field type
if pdf.field_type(:football) == Field::BUTTON
puts "Field 'football' is of type BUTTON"
else
puts "Field 'football' is not of type BUTTON"
end
puts
# Renaming field
pdf.rename_field :last_name, :surname
puts "Renamed field 'last_name' to 'surname'"
puts
# Removing field
pdf.remove_field :nascar
puts "Removed field 'nascar'"
puts
# printing the name of the person used inside the PDF
puts "Signatory: #{pdf.field(:first_name)} #{pdf.field(:last_name)}"
# saving the filled out PDF in another file
pdf.save_as('output.pdf')
# saving another copy of the filled out PDF in another file and making it non-editable
pdf = FillablePDF.new('output.pdf')
pdf.save_as 'output.flat.pdf', flatten: true
# closing the document
pdf.close
The example above produces the following output and also generates the output file output.pdf.
The form has a total of 8 fields.
Fields hash: {:last_name=>"Rahl", :first_name=>"Richard", :football=>"Yes", :baseball=>"Yes", :basketball=>"Yes", :nascar=>"Yes", :hockey=>"Yes", :date=>"August 30, 2019"}
Keys: [:last_name, :first_name, :football, :baseball, :basketball, :nascar, :hockey, :date]
Values: ["Rahl", "Richard", "Yes", "Yes", "Yes", "Yes", "Yes", "August 30, 2019"]
Field 'football' is of type BUTTON
Renamed field 'last_name' to 'surname'
Removed field 'nascar'
Signatory: Richard Rahl
Contributing
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request
License
The gem is available as open source under the terms of the MIT License.
However, you must also adhere to the iText License when using this gem in your project.