Class: Pdfrb::Document::Form
- Inherits:
-
Object
- Object
- Pdfrb::Document::Form
- Defined in:
- lib/pdfrb/document/form.rb
Overview
Facade for AcroForm interactive forms (ISO 32000-2 §12.7).
Creates the /AcroForm dictionary on the Catalog and manages form fields. Each field is a /Type /Annot /Subtype /Widget indirect object linked to a page via /P and positioned via /Rect.
Supported field types (FT):
:Btn — button (checkbox, radio, pushbutton)
:Tx — text input
:Ch — choice (list, combo)
:Sig — digital signature
Appearance streams are generated by the viewer when /NeedAppearances is true on the /AcroForm dict.
Instance Attribute Summary collapse
-
#document ⇒ Object
readonly
Returns the value of attribute document.
Instance Method Summary collapse
-
#add_checkbox(name, page:, rect:, checked: false) ⇒ Object
Add a checkbox field.
-
#add_combo(name, page:, rect:, options:, value: nil) ⇒ Pdfrb::Model::Cos::Dictionary
Add a combo box (dropdown) field.
-
#add_text_field(name, page:, rect:, value: nil, multiline: false) ⇒ Object
Add a text field.
-
#count ⇒ Object
Total field count.
- #delete_acroform_key(acroform, key) ⇒ Object
-
#each_field(&block) ⇒ Object
Enumerate all top-level fields.
-
#enable! ⇒ Object
Enable AcroForm by creating the /AcroForm dict on the Catalog.
-
#field_names ⇒ Object
List of fully qualified field names (T values).
-
#find(name) ⇒ Object
Find a field by fully qualified name.
-
#flatten! ⇒ Object
Flatten all form fields: stamp their appearance streams into page content, then remove the field from /AcroForm /Fields.
-
#get_value(name) ⇒ Object?
Get a field value by name.
-
#initialize(document) ⇒ Form
constructor
A new instance of Form.
-
#remove_field(field) ⇒ Object
Remove a single field from /AcroForm /Fields and its widget from the page's /Annots array.
-
#set_value(name, value) ⇒ Pdfrb::Model::Cos::Dictionary?
Set a field value by name.
Constructor Details
#initialize(document) ⇒ Form
Returns a new instance of Form.
22 23 24 |
# File 'lib/pdfrb/document/form.rb', line 22 def initialize(document) @document = document end |
Instance Attribute Details
#document ⇒ Object (readonly)
Returns the value of attribute document.
20 21 22 |
# File 'lib/pdfrb/document/form.rb', line 20 def document @document end |
Instance Method Details
#add_checkbox(name, page:, rect:, checked: false) ⇒ Object
Add a checkbox field. @return [Pdfrb::Model::Cos::Dictionary] the field.
56 57 58 59 60 61 62 63 |
# File 'lib/pdfrb/document/form.rb', line 56 def add_checkbox(name, page:, rect:, checked: false) enable! field = (name, page: page, rect: rect) field.value[:FT] = :Btn field.value[:V] = checked ? :Yes : :Off register_field(field) field end |
#add_combo(name, page:, rect:, options:, value: nil) ⇒ Pdfrb::Model::Cos::Dictionary
Add a combo box (dropdown) field.
67 68 69 70 71 72 73 74 75 76 |
# File 'lib/pdfrb/document/form.rb', line 67 def add_combo(name, page:, rect:, options:, value: nil) enable! field = (name, page: page, rect: rect) field.value[:FT] = :Ch field.value[:Ff] = 0x20000 # bit 18 = Combo field.value[:Opt] = field.value[:V] = value if value register_field(field) field end |
#add_text_field(name, page:, rect:, value: nil, multiline: false) ⇒ Object
Add a text field. @return [Pdfrb::Model::Cos::Dictionary] the field.
42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/pdfrb/document/form.rb', line 42 def add_text_field(name, page:, rect:, value: nil, multiline: false) enable! flags = 0 flags |= 0x1000 if multiline # bit 13 = multiline field = (name, page: page, rect: rect) field.value[:FT] = :Tx field.value[:Ff] = flags if flags.positive? field.value[:V] = value if value register_field(field) field end |
#count ⇒ Object
Total field count.
79 80 81 82 83 84 85 |
# File 'lib/pdfrb/document/form.rb', line 79 def count acroform = document.catalog.value[:AcroForm] return 0 unless acroform fields = acroform[:Fields] fields ? fields.length : 0 end |
#delete_acroform_key(acroform, key) ⇒ Object
149 150 151 152 153 154 155 156 157 |
# File 'lib/pdfrb/document/form.rb', line 149 def delete_acroform_key(acroform, key) return unless acroform if acroform.is_a?(Pdfrb::Model::Cos::Dictionary) acroform.value.delete(key) else acroform.delete(key) end end |
#each_field(&block) ⇒ Object
Enumerate all top-level fields.
93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/pdfrb/document/form.rb', line 93 def each_field(&block) acroform = document.catalog.value[:AcroForm] return enum_for(:each_field) unless block return unless acroform fields = acroform[:Fields] || [] fields.each do |ref| obj = ref.is_a?(Pdfrb::Model::Reference) ? document.object(ref) : ref yield obj if obj end end |
#enable! ⇒ Object
Enable AcroForm by creating the /AcroForm dict on the Catalog. Idempotent. @return [Hash] the AcroForm dict value.
28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/pdfrb/document/form.rb', line 28 def enable! catalog = document.catalog return catalog.value[:AcroForm] if catalog.value[:AcroForm] acroform = { Fields: [], NeedAppearances: true, DA: "/Helv 0 Tf 0 g", } catalog.value[:AcroForm] = acroform acroform end |
#field_names ⇒ Object
List of fully qualified field names (T values).
107 108 109 |
# File 'lib/pdfrb/document/form.rb', line 107 def field_names each_field.filter_map { |f| f.value[:T] } end |
#find(name) ⇒ Object
Find a field by fully qualified name.
88 89 90 |
# File 'lib/pdfrb/document/form.rb', line 88 def find(name) each_field.find { |f| f.value[:T] == name } end |
#flatten! ⇒ Object
Flatten all form fields: stamp their appearance streams into page content, then remove the field from /AcroForm /Fields. After flattening, the form is read-only.
138 139 140 141 142 143 144 145 146 147 |
# File 'lib/pdfrb/document/form.rb', line 138 def flatten! each_field.to_a.each do |field| stamp_field_appearance(field) remove_field(field) end acroform = document.catalog.value[:AcroForm] delete_acroform_key(acroform, :Fields) delete_acroform_key(acroform, :NeedAppearances) document end |
#get_value(name) ⇒ Object?
Get a field value by name.
128 129 130 131 132 133 |
# File 'lib/pdfrb/document/form.rb', line 128 def get_value(name) field = find(name) return nil unless field field.value[:V] end |
#remove_field(field) ⇒ Object
Remove a single field from /AcroForm /Fields and its widget from the page's /Annots array.
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/pdfrb/document/form.rb', line 161 def remove_field(field) acroform = document.catalog.value[:AcroForm] return nil unless acroform fields = acroform[:Fields] return nil unless fields field_ref = Pdfrb::Model::Reference.new(field.oid, field.gen) fields.delete_if { |r| r == field_ref || (r.is_a?(Pdfrb::Model::Reference) && r.oid == field.oid) } # Remove widget annotation from page /Annots page_ref = field.value[:P] if page_ref page = page_ref.is_a?(Pdfrb::Model::Reference) ? document.object(page_ref) : page_ref annots = page&.value&.[](:Annots) annots&.delete_if { |r| r == field_ref || (r.is_a?(Pdfrb::Model::Reference) && r.oid == field.oid) } end field end |
#set_value(name, value) ⇒ Pdfrb::Model::Cos::Dictionary?
Set a field value by name. Auto-regenerates the appearance stream for text/checkbox fields. For unsupported types, sets /V only.
116 117 118 119 120 121 122 123 |
# File 'lib/pdfrb/document/form.rb', line 116 def set_value(name, value) field = find(name) return nil unless field field.value[:V] = normalize_value(field, value) regenerate_appearance(field) field end |