Class: FillablePDF
- Inherits:
-
Object
- Object
- FillablePDF
- Defined in:
- lib/fillable-pdf.rb,
lib/fillable-pdf/version.rb
Overview
rubocop:disable Metrics/ClassLength
Constant Summary collapse
- VERSION =
'0.9.3'
Instance Method Summary collapse
-
#any_fields? ⇒ Boolean
Determines whether the form has any fields.
-
#close ⇒ Boolean
Closes the PDF document discarding all unsaved changes.
-
#field(key) ⇒ Object
Retrieves the value of a field given its unique field name.
-
#field_type(key) ⇒ Object
Retrieves the numeric type of a field given its unique field name.
-
#fields ⇒ Object
Retrieves a hash of all fields and their values.
-
#initialize(file_path) ⇒ FillablePDF
constructor
Opens a given fillable-pdf PDF file and prepares it for modification.
-
#names ⇒ Object
Returns a list of all field keys used in the document.
-
#num_fields ⇒ Object
Returns the total number of fillable form fields.
-
#remove_field(key) ⇒ Object
Removes a field from the document given its unique field name.
-
#rename_field(old_key, new_key) ⇒ Object
Renames a field given its unique field name and the new field name.
-
#save(flatten: false) ⇒ Object
Overwrites the previously opened PDF document and flattens it if requested.
-
#save_as(file_path, flatten: false) ⇒ Object
Saves the filled out PDF document in a given path and flattens it if requested.
-
#set_field(key, value) ⇒ Object
Sets the value of a field given its unique field name and value.
-
#set_fields(fields) ⇒ Object
Sets the values of multiple fields given a set of unique field names and values.
-
#set_image(key, file_path) ⇒ Object
Sets an image within the bounds of the given form field.
-
#set_image_base64(key, base64_image_data) ⇒ Object
Sets an image within the bounds of the given form field.
-
#values ⇒ Object
Returns a list of all field values used in the document.
Constructor Details
#initialize(file_path) ⇒ FillablePDF
Opens a given fillable-pdf PDF file and prepares it for modification.
@param [String|Symbol] file_path the name of the PDF file or file path
13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
# File 'lib/fillable-pdf.rb', line 13 def initialize(file_path) raise IOError, "File <#{file_path}> is not found" unless File.exist?(file_path) @file_path = file_path begin @byte_stream = ITEXT::ByteArrayOutputStream.new @pdf_reader = ITEXT::PdfReader.new @file_path.to_s @pdf_writer = ITEXT::PdfWriter.new @byte_stream @pdf_doc = ITEXT::PdfDocument.new @pdf_reader, @pdf_writer @pdf_form = ITEXT::PdfAcroForm.getAcroForm(@pdf_doc, true) @form_fields = @pdf_form.getFormFields rescue StandardError => e raise "#{e.} (Input file may be corrupt, incompatible, read-only, write-protected, encrypted, or may not have any form fields)" # rubocop:disable Layout/LineLength end end |
Instance Method Details
#any_fields? ⇒ Boolean
Determines whether the form has any fields.
@return true if form has fields, false otherwise
33 34 35 |
# File 'lib/fillable-pdf.rb', line 33 def any_fields? num_fields.positive? end |
#close ⇒ Boolean
Closes the PDF document discarding all unsaved changes.
235 236 237 238 |
# File 'lib/fillable-pdf.rb', line 235 def close @pdf_doc.close @pdf_doc.isClosed end |
#field(key) ⇒ Object
Retrieves the value of a field given its unique field name.
@param [String|Symbol] key the field name
@return the value of the field
53 54 55 56 57 |
# File 'lib/fillable-pdf.rb', line 53 def field(key) pdf_field(key).getValueAsString rescue NoMethodError raise "unknown key name `#{key}'" end |
#field_type(key) ⇒ Object
Retrieves the numeric type of a field given its unique field name.
@param [String|Symbol] key the field name
@return the type of the field
66 67 68 |
# File 'lib/fillable-pdf.rb', line 66 def field_type(key) pdf_field(key).getFormType.toString end |
#fields ⇒ Object
Retrieves a hash of all fields and their values.
@return the hash of field keys and values
75 76 77 78 79 80 81 82 83 |
# File 'lib/fillable-pdf.rb', line 75 def fields iterator = @form_fields.keySet.iterator map = {} while iterator.hasNext key = iterator.next.toString map[key.to_sym] = field(key) end map end |
#names ⇒ Object
Returns a list of all field keys used in the document.
@return array of field names
186 187 188 189 190 191 |
# File 'lib/fillable-pdf.rb', line 186 def names iterator = @form_fields.keySet.iterator set = [] set << iterator.next.toString.to_sym while iterator.hasNext set end |
#num_fields ⇒ Object
Returns the total number of fillable form fields.
@return the number of fields
42 43 44 |
# File 'lib/fillable-pdf.rb', line 42 def num_fields @form_fields.size end |
#remove_field(key) ⇒ Object
Removes a field from the document given its unique field name.
@param [String|Symbol] key the field name
177 178 179 |
# File 'lib/fillable-pdf.rb', line 177 def remove_field(key) @pdf_form.removeField(key.to_s) end |
#rename_field(old_key, new_key) ⇒ Object
Renames a field given its unique field name and the new field name.
@param [String|Symbol] old_key the field name
@param [String|Symbol] new_key the field name
168 169 170 |
# File 'lib/fillable-pdf.rb', line 168 def rename_field(old_key, new_key) pdf_field(old_key).setFieldName(new_key.to_s) end |
#save(flatten: false) ⇒ Object
Overwrites the previously opened PDF document and flattens it if requested.
@param [bool] flatten true if PDF should be flattened, false otherwise
210 211 212 213 214 |
# File 'lib/fillable-pdf.rb', line 210 def save(flatten: false) tmp_file = SecureRandom.uuid save_as(tmp_file, flatten: flatten) FileUtils.mv tmp_file, @file_path end |
#save_as(file_path, flatten: false) ⇒ Object
Saves the filled out PDF document in a given path and flattens it if requested.
@param [String] file_path the name of the PDF file or file path
@param [Hash] flatten: true if PDF should be flattened, false otherwise
222 223 224 225 226 227 228 |
# File 'lib/fillable-pdf.rb', line 222 def save_as(file_path, flatten: false) if @file_path == file_path save(flatten: flatten) else File.open(file_path, 'wb') { |f| f.write(finalize(flatten: flatten)) && f.close } end end |
#set_field(key, value) ⇒ Object
Sets the value of a field given its unique field name and value.
@param [String|Symbol] key the field name
@param [String|Symbol] value the field value
91 92 93 |
# File 'lib/fillable-pdf.rb', line 91 def set_field(key, value) pdf_field(key).setValue(value.to_s) end |
#set_fields(fields) ⇒ Object
Sets the values of multiple fields given a set of unique field names and values.
@param [Hash] fields the set of field names and values
158 159 160 |
# File 'lib/fillable-pdf.rb', line 158 def set_fields(fields) fields.each { |key, value| set_field key, value } end |
#set_image(key, file_path) ⇒ Object
Sets an image within the bounds of the given form field. It doesn’t matter what type of form field it is (signature, image, etc). The image will be scaled to fill the available space while preserving its aspect ratio. All previous content will be removed, which means you cannot have both text and image.
@param [String|Symbol] key the field name
@param [String|Symbol] file_path the name of the image file or image path
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/fillable-pdf.rb', line 104 def set_image(key, file_path) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength raise IOError, "File <#{file_path}> is not found" unless File.exist?(file_path) field = pdf_field(key) = field.getWidgets = suppress_warnings { .isEmpty ? field.getPdfObject : .get(0).getPdfObject } orig_rect = .getAsRectangle(ITEXT::PdfName.Rect) border_width = field.getBorderWidth bounding_rectangle = ITEXT::Rectangle.new( orig_rect.getWidth - (border_width * 2), orig_rect.getHeight - (border_width * 2) ) pdf_form_x_object = ITEXT::PdfFormXObject.new(bounding_rectangle) canvas = ITEXT::Canvas.new(pdf_form_x_object, @pdf_doc) image = ITEXT::Image.new(ITEXT::ImageDataFactory.create(file_path.to_s)) .setAutoScale(true) .setHorizontalAlignment(ITEXT::HorizontalAlignment.CENTER) container = ITEXT::Div.new .setMargin(border_width).add(image) .setVerticalAlignment(ITEXT::VerticalAlignment.MIDDLE) .setFillAvailableArea(true) canvas.add(container) canvas.close pdf_dict = ITEXT::PdfDictionary.new .put(ITEXT::PdfName.AP, pdf_dict) pdf_dict.put(ITEXT::PdfName.N, pdf_form_x_object.getPdfObject) .setModified rescue StandardError => e raise "#{e.} (there may be something wrong with your image)" end |
#set_image_base64(key, base64_image_data) ⇒ Object
Sets an image within the bounds of the given form field. It doesn’t matter what type of form field it is (signature, image, etc). The image will be scaled to fill the available space while preserving its aspect ratio. All previous content will be removed, which means you cannot have both text and image.
@param [String|Symbol] key the field name
@param [String|Symbol] base64_image_data base64 encoded data image
145 146 147 148 149 150 151 |
# File 'lib/fillable-pdf.rb', line 145 def set_image_base64(key, base64_image_data) tmp_file = SecureRandom.uuid File.open(tmp_file, 'wb') { |f| f.write(Base64.decode64(base64_image_data)) } set_image(key, tmp_file) ensure FileUtils.rm tmp_file end |
#values ⇒ Object
Returns a list of all field values used in the document.
@return array of field values
198 199 200 201 202 203 |
# File 'lib/fillable-pdf.rb', line 198 def values iterator = @form_fields.keySet.iterator set = [] set << field(iterator.next.toString) while iterator.hasNext set end |