Class: Acrofill::Form
- Inherits:
-
Object
- Object
- Acrofill::Form
- 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
- MULTILINE_FLAG =
1 << 12
- PUSHBUTTON_FLAG =
1 << 16
- COMB_FLAG =
1 << 24
- OFF_VALUES =
Values that uncheck a button, compared case-insensitively: "Off" unchecking while "off" ticked the box was a silent data error. A state the template actually names is matched first, so a checkbox whose on state is literally called "no" stays checkable.
['', 'off', 'false', 'no', '0'].freeze
Instance Method Summary collapse
-
#fields ⇒ Object
Metadata for every logical field, in document order.
-
#fill(name, value) ⇒ Object
Sets the field value and rebuilds widget appearances.
-
#flatten! ⇒ Object
Stamps every visible widget appearance into its page's content and removes the interactive layer, like pdftk's `output ...
-
#initialize(doc) ⇒ Form
constructor
A new instance of Form.
Constructor Details
#initialize(doc) ⇒ Form
Returns a new instance of Form.
18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'lib/acrofill/form.rb', line 18 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
#fields ⇒ Object
Metadata for every logical field, in document order.
34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/acrofill/form.rb', line 34 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((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.
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/acrofill/form.rb', line 48 def fill(name, value) groups = @fields.fetch(name, []) return false if groups.empty? # Several field dicts may share one name without sharing one /FT. # Dispatching on the first one's type would push a checkbox through # the text path, overwriting its /AP state dictionary with a text # appearance, so each type is handled with its own groups. groups.group_by { |group| field_type(group[:node]) }.map do |type, typed| case type when :Btn then (typed, value) when :Tx, :Ch, nil then fill_text_groups(typed, value) else false # signatures and unknown types are left untouched end end.any? end |