Class: HexaPDF::CLI::Form

Inherits:
Command
  • Object
show all
Defined in:
lib/hexapdf/cli/form.rb

Overview

Processes a PDF that contains an interactive form (AcroForm).

Instance Method Summary collapse

Methods included from Command::Extensions

#help, #help_banner

Constructor Details

#initializeForm

:nodoc:



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/hexapdf/cli/form.rb', line 46

def initialize #:nodoc:
  super('form', takes_commands: false)
  short_desc("Show form fields and fill out a form")
  long_desc(<<~EOF)
    Use this command to process interactive PDF forms.

    If the the output file name is not given, all form fields are listed in page order. Use
    the global --verbose option to show additional information like field type and location.

    If the output file name is given, the fields can be filled out interactively, via a
    template or just flattened by using the respective options. Form field flattening can also
    be activated in addition to filling out the form. If neither --fill, --template nor
    --flatten is specified, --fill is implied.
  EOF

  options.on("--password PASSWORD", "-p", String,
             "The password for decryption. Use - for reading from standard input.") do |pwd|
    @password = (pwd == '-' ? read_password : pwd)
  end
  options.on("--fill", "Fill out the form") do
    @fill = true
  end
  options.on("--template TEMPLATE_FILE", "-t TEMPLATE_FILE",
             "Use the template file for the field values (implies --fill)") do |template|
    @template = template
    @fill = true
  end
  options.on('--generate-template', 'Print a template for use with --template') do
    @generate_template = true
  end
  options.on('--flatten', 'Flatten the form fields') do
    @flatten = true
  end
  options.on("--[no-]fill-read-only-fields", "Allow filling in fields that are " \
             "marked as read only. Default: false") do |read_only|
    @fill_read_only_fields = read_only
  end
  options.on("--[no-]viewer-override", "Let the PDF viewer override the visual " \
             "appearance. Default: use setting from input PDF") do |need_appearances|
    @need_appearances = need_appearances
  end
  options.on("--[no-]incremental-save", "Append the changes instead of rewriting the " \
             "whole file. Default: true") do |incremental|
    @incremental = incremental
  end

  @password = nil
  @fill = false
  @flatten = false
  @generate_template = false
  @template = nil
  @fill_read_only_fields = false
  @need_appearances = nil
  @incremental = true
end

Instance Method Details

#execute(in_file, out_file = nil) ⇒ Object

:nodoc:



102
103
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
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/hexapdf/cli/form.rb', line 102

def execute(in_file, out_file = nil) #:nodoc:
  maybe_raise_on_existing_file(out_file) if out_file
  if (@fill || @flatten) && !out_file
    raise Error, "Output file missing"
  end
  with_document(in_file, password: @password, out_file: out_file,
                incremental: @incremental) do |doc|
    if doc.acro_form[:XFA]
      $stderr.puts "Warning: Unsupported XFA form detected, some things may not work correctly"
    end

    if !doc.acro_form
      raise Error, "This PDF doesn't contain an interactive form"
    elsif out_file
      doc.acro_form[:NeedAppearances] = @need_appearances unless @need_appearances.nil?
      if @fill || !@flatten
        if @template
          fill_form_with_template(doc)
        else
          fill_form(doc)
        end
        doc.acro_form.recalculate_fields
      end
      if @flatten && !doc.acro_form.flatten.empty?
        $stderr.puts "Warning: Not all form fields could be flattened"
        doc.catalog.delete(:AcroForm)
        doc.delete(doc.acro_form)
      end
    elsif @generate_template
      unsupported_fields = [:signature_field, :password_field]
      each_field(doc) do |_, _, field, _|
        next if unsupported_fields.include?(field.concrete_field_type)
        name = field.full_field_name.gsub(':', "\\:")
        if field.field_value
          Array(field.field_value).each do |val|
            puts "#{name}: #{val.to_s.gsub(/(\r|\r\n|\n)/, '\1  ')}"
          end
        else
          puts "#{name}: "
        end
      end
    else
      list_form_fields(doc)
    end
  end
end