class HexaPDF::CLI::Form
Processes a PDF that contains an interactive form (AcroForm).
Private Instance Methods
apply_field_value(field, value)
click to toggle source
Applies the given value to the field.
# File lib/hexapdf/cli/form.rb, line 220 def apply_field_value(field, value) case field.concrete_field_type when :single_line_text_field field.field_value = value when :combo_box, :list_box field.field_value = value when :editable_combo_box field.field_value = value when :check_box unless value.match?(/y(es)?|t(rue)?|f(alse)?|n(o)/) raise HexaPDF::Error, "Invalid input, use one of the possible values" end field.field_value = value.match?(/y(es)?|t(rue)?/) when :radio_button field.field_value = value.intern else raise "Field type not yet supported" end end
each_field(doc) { |page, page_index, field| ... }
click to toggle source
Iterates over all non-push button fields in page order. If a field appears on multiple pages, it is only yielded on the first page.
# File lib/hexapdf/cli/form.rb, line 242 def each_field(doc) # :yields: page, page_index, field seen = {} doc.pages.each_with_index do |page, page_index| page[:Annots]&.each do |annotation| next unless annotation[:Subtype] == :Widget field = annotation.form_field next if field.concrete_field_type == :push_button unless seen[field] yield(page, page_index, field, annotation) seen[field] = true end end end end
fill_form(doc)
click to toggle source
Fills out the form by interactively asking the user for field values.
# File lib/hexapdf/cli/form.rb, line 156 def fill_form(doc) current_page_index = -1 each_field(doc) do |_page, page_index, field, _widget| if current_page_index != page_index puts "Page #{page_index + 1}" current_page_index = page_index end field_name = field.full_field_name + (field.alternate_field_name ? " (#{field.alternate_field_name})" : '') concrete_field_type = field.concrete_field_type puts " #{field_name}" puts " └─ Current value: #{field.field_value.inspect}" if field.field_type == :Ch puts " └─ Possible values: #{field.option_items.map(&:inspect).join(', ')}" elsif concrete_field_type == :radio_button puts " └─ Possible values: #{field.radio_button_values.map(&:inspect).join(', ')}" elsif concrete_field_type == :check_box puts " └─ Possible values: y(es), t(rue); n(o), f(alse)" end begin print " └─ New value: " value = $stdin.readline.chomp next if value.empty? apply_field_value(field, value) rescue HexaPDF::Error => e puts " ⚠ #{e.message}" retry end end end
fill_form_with_template(doc)
click to toggle source
Fills out the form using the data from the provided template file.
# File lib/hexapdf/cli/form.rb, line 192 def fill_form_with_template(doc) data = parse_template form = doc.acro_form data.each do |name, value| field = form.field_by_name(name) raise "Field '#{name}' not found in input PDF" unless field apply_field_value(field, value) end end
list_form_fields(doc)
click to toggle source
Lists all terminal form fields.
# File lib/hexapdf/cli/form.rb, line 126 def list_form_fields(doc) current_page_index = -1 each_field(doc) do |_page, page_index, field, widget| if current_page_index != page_index puts "Page #{page_index + 1}" current_page_index = page_index end field_name = field.full_field_name + (field.alternate_field_name ? " (#{field.alternate_field_name})" : '') concrete_field_type = field.concrete_field_type nice_field_type = concrete_field_type.to_s.split('_').map(&:capitalize).join(' ') position = "(#{widget[:Rect].left}, #{widget[:Rect].bottom})" puts " #{field_name}" if command_parser.verbosity_info? printf(" └─ %-22s | %-20s\n", nice_field_type, position) end puts " └─ #{field.field_value.inspect}" if command_parser.verbosity_info? if field.field_type == :Ch puts " └─ Options: #{field.option_items.map(&:inspect).join(', ')}" elsif concrete_field_type == :radio_button puts " └─ Options: #{field.radio_button_values.map(&:inspect).join(', ')}" end end end end
parse_template()
click to toggle source
Parses the data from the given template file.
# File lib/hexapdf/cli/form.rb, line 203 def parse_template data = {} scanner = StringScanner.new(File.read(@template)) until scanner.eos? field_name = scanner.scan(/(\\:|[^:])*?:/) break unless field_name field_name.gsub!(/\\:/, ':') field_value = scanner.scan(/.*?(?=^\S|\z)/m) data[field_name.chop] = field_value.strip.gsub(/^\s*/, '') if field_value end if !scanner.eos? && command_parser.verbosity_warning? $stderr.puts "Warning: Some template could not be parsed" end data end