Class: Acrofill::Form

Inherits:
Object
  • Object
show all
Defined in:
lib/acrofill/form.rb

Overview

The interactive form of a document: field lookup by fully-qualified name, value filling with appearance regeneration, and flattening.

Defined Under Namespace

Classes: Field

Constant Summary collapse

HIDDEN_FLAG =
2
MULTILINE_FLAG =
1 << 12
PUSHBUTTON_FLAG =
1 << 16

Instance Method Summary collapse

Constructor Details

#initialize(doc) ⇒ Form

Returns a new instance of Form.

Raises:



13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/acrofill/form.rb', line 13

def initialize(doc)
  @doc = doc
  @acroform = doc.deref(doc.root[:AcroForm])
  raise Error, 'document has no AcroForm' unless @acroform.is_a?(Hash)

  @appearance = Appearance.new(doc, @acroform)
  # name => array of { node:, widgets: } groups. Several field dicts may
  # share one fully-qualified name (PDF 32000 §12.7.3.2 treats them as a
  # single logical field, e.g. "SSN" repeated on every page) — filling
  # must update all of them.
  @fields = Hash.new { |h, k| h[k] = [] }
  roots = doc.deref(@acroform[:Fields])
  collect_fields(roots.is_a?(Array) ? roots : [])
end

Instance Method Details

#fieldsObject

Metadata for every logical field, in document order.



29
30
31
32
33
34
35
36
37
38
39
# File 'lib/acrofill/form.rb', line 29

def fields
  @fields.map do |name, groups|
    type = field_type(groups.first[:node])
    Field.new(
      name: name,
      type: type,
      value: decode_text_string(@doc.deref(groups.first[:node][:V])),
      states: type == :Btn ? on_states(all_widgets(groups)) : nil
    )
  end
end

#fill(name, value) ⇒ Object

Sets the field value and rebuilds widget appearances. Unknown names are ignored (returns false), matching pdftk's fill_form behaviour.



43
44
45
46
47
48
49
50
51
52
# File 'lib/acrofill/form.rb', line 43

def fill(name, value)
  groups = @fields.fetch(name, [])
  return false if groups.empty?

  case field_type(groups.first[:node])
  when :Btn then fill_button(groups, value)
  when :Tx, :Ch, nil then groups.each { |group| fill_text(group, value) }.any?
  else false # signatures and unknown types are left untouched
  end
end

#flatten!Object

Stamps every visible widget appearance into its page's content and removes the interactive layer, like pdftk's output ... flatten.



56
57
58
59
# File 'lib/acrofill/form.rb', line 56

def flatten!
  @doc.each_page { |page| flatten_page(page) }
  @doc.root.delete(:AcroForm)
end