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.4'
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 27 |
# File 'lib/fillable-pdf.rb', line 13 def initialize(file_path) # rubocop:disable Metrics/MethodLength 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 @pdf_form.setGenerateAppearance false 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
34 35 36 |
# File 'lib/fillable-pdf.rb', line 34 def any_fields? num_fields.positive? end |
#close ⇒ Boolean
Closes the PDF document discarding all unsaved changes.
236 237 238 239 |
# File 'lib/fillable-pdf.rb', line 236 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
54 55 56 57 58 |
# File 'lib/fillable-pdf.rb', line 54 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
67 68 69 |
# File 'lib/fillable-pdf.rb', line 67 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
76 77 78 79 80 81 82 83 84 |
# File 'lib/fillable-pdf.rb', line 76 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
187 188 189 190 191 192 |
# File 'lib/fillable-pdf.rb', line 187 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
43 44 45 |
# File 'lib/fillable-pdf.rb', line 43 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
178 179 180 |
# File 'lib/fillable-pdf.rb', line 178 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
169 170 171 |
# File 'lib/fillable-pdf.rb', line 169 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
211 212 213 214 215 |
# File 'lib/fillable-pdf.rb', line 211 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
223 224 225 226 227 228 229 |
# File 'lib/fillable-pdf.rb', line 223 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
92 93 94 |
# File 'lib/fillable-pdf.rb', line 92 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
159 160 161 |
# File 'lib/fillable-pdf.rb', line 159 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
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 135 |
# File 'lib/fillable-pdf.rb', line 105 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
146 147 148 149 150 151 152 |
# File 'lib/fillable-pdf.rb', line 146 def set_image_base64(key, base64_image_data) tmp_file = SecureRandom.uuid File.binwrite(tmp_file, 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
199 200 201 202 203 204 |
# File 'lib/fillable-pdf.rb', line 199 def values iterator = @form_fields.keySet.iterator set = [] set << field(iterator.next.toString) while iterator.hasNext set end |