Class: Pdfrb::Document::Structure
- Inherits:
-
Object
- Object
- Pdfrb::Document::Structure
- Defined in:
- lib/pdfrb/document/structure.rb
Overview
Facade for authoring tagged PDF structure trees (PDF/UA §7.9, ISO 32000-2 §14.8).
A tagged PDF has:
* /StructTreeRoot on the Catalog — root of the structure hierarchy.
* /MarkInfo /Marked true on the Catalog — declares the PDF as tagged.
* /ParentTree on StructTreeRoot — maps marked-content BDC/EMC
references (via /MCID on BDC) back to their parent StructElem.
Structure elements form a tree: a document has sections, sections have headings/paragraphs/figures, etc. Each element has a /S (structure type — :H1, :P, :Figure, :Table, ...) and optional /T (title), /Alt (alternate text), /Lang (language).
Instance Attribute Summary collapse
-
#document ⇒ Object
readonly
Returns the value of attribute document.
-
#root ⇒ Object
readonly
Returns the value of attribute root.
Instance Method Summary collapse
-
#add_child(parent, type, **attrs) ⇒ Pdfrb::Model::Cos::Dictionary
Add a child element to a parent element.
-
#add_element(type, page: nil, mcid: nil, **attrs) ⇒ Pdfrb::Model::Cos::Dictionary
Add a top-level child element to the structure tree.
-
#build! ⇒ Object
Build the structure tree, ParentTree, and set up /MarkInfo.
-
#each_element(&block) ⇒ Object
Walk all structure elements depth-first.
-
#enable! ⇒ Pdfrb::Model::Cos::Dictionary
Enable tagged PDF: create /StructTreeRoot, set /MarkInfo.
-
#has_alt_text?(element) ⇒ Boolean
Check if a structure element has alt text (required for /Figure).
-
#initialize(document) ⇒ Structure
constructor
A new instance of Structure.
-
#map_role(custom, standard) ⇒ Object
Define a role mapping: maps a custom structure type name to a standard one.
-
#set_actual_text(element, text) ⇒ Object
Set actual text on a structure element.
-
#set_alt_text(element, text) ⇒ Object
Set alternate text on a structure element for screen readers.
-
#set_language(element, lang) ⇒ Object
Set language on a structure element (overrides document /Lang).
-
#validate_alt_text! ⇒ Array<Hash>
Validate that all /Figure elements have /Alt text per PDF/UA-1.
Constructor Details
#initialize(document) ⇒ Structure
Returns a new instance of Structure.
20 21 22 23 24 |
# File 'lib/pdfrb/document/structure.rb', line 20 def initialize(document) @document = document @elements = [] @current_index = 0 end |
Instance Attribute Details
#document ⇒ Object (readonly)
Returns the value of attribute document.
18 19 20 |
# File 'lib/pdfrb/document/structure.rb', line 18 def document @document end |
#root ⇒ Object (readonly)
Returns the value of attribute root.
18 19 20 |
# File 'lib/pdfrb/document/structure.rb', line 18 def root @root end |
Instance Method Details
#add_child(parent, type, **attrs) ⇒ Pdfrb::Model::Cos::Dictionary
Add a child element to a parent element.
77 78 79 80 81 82 |
# File 'lib/pdfrb/document/structure.rb', line 77 def add_child(parent, type, **attrs) elem = create_element(type, **attrs) append_child(parent, elem) @elements << elem elem end |
#add_element(type, page: nil, mcid: nil, **attrs) ⇒ Pdfrb::Model::Cos::Dictionary
Add a top-level child element to the structure tree.
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/pdfrb/document/structure.rb', line 53 def add_element(type, page: nil, mcid: nil, **attrs) ensure_root elem = create_element(type, **attrs) append_child(@root, elem) if page page_ref = if page.is_a?(Pdfrb::Model::Reference) page else Pdfrb::Model::Reference.new(page.oid, page.gen) end elem.value[:Pg] = page_ref end elem.value[:K] = { MCID: mcid } if mcid @elements << elem elem end |
#build! ⇒ Object
Build the structure tree, ParentTree, and set up /MarkInfo. Idempotent — safe to call multiple times.
234 235 236 237 238 239 |
# File 'lib/pdfrb/document/structure.rb', line 234 def build! enable! if @root.nil? return if @elements.empty? build_parent_tree end |
#each_element(&block) ⇒ Object
Walk all structure elements depth-first.
130 131 132 133 134 |
# File 'lib/pdfrb/document/structure.rb', line 130 def each_element(&block) return enum_for(:each_element) unless block @elements.each(&block) end |
#enable! ⇒ Pdfrb::Model::Cos::Dictionary
Enable tagged PDF: create /StructTreeRoot, set /MarkInfo. Idempotent — returns the existing root if already enabled.
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/pdfrb/document/structure.rb', line 29 def enable! return @root if @root root_elem = document.add( { Type: :StructTreeRoot }, type: Pdfrb::Model::Type::StructTreeRoot ) catalog = document.catalog catalog.value[:StructTreeRoot] = Pdfrb::Model::Reference.new(root_elem.oid, root_elem.gen) mark_info = catalog.value[:MarkInfo] if mark_info.nil? mark_info = document.add({ Marked: true }, type: Pdfrb::Model::Cos::Dictionary) catalog.value[:MarkInfo] = Pdfrb::Model::Reference.new(mark_info.oid, mark_info.gen) end @root = root_elem end |
#has_alt_text?(element) ⇒ Boolean
Check if a structure element has alt text (required for /Figure).
110 111 112 113 |
# File 'lib/pdfrb/document/structure.rb', line 110 def has_alt_text?(element) alt = element.value[:Alt] alt && !alt.to_s.empty? end |
#map_role(custom, standard) ⇒ Object
Define a role mapping: maps a custom structure type name to a standard one. Required for PDF/UA when custom types are used.
140 141 142 143 144 145 146 147 148 149 |
# File 'lib/pdfrb/document/structure.rb', line 140 def map_role(custom, standard) ensure_root role_map = @root.value[:RoleMap] if role_map.nil? role_map = {} @root.value[:RoleMap] = role_map end role_map[custom] = standard role_map end |
#set_actual_text(element, text) ⇒ Object
Set actual text on a structure element. Overrides the visual text for screen readers (e.g., expanding abbreviations).
96 97 98 |
# File 'lib/pdfrb/document/structure.rb', line 96 def set_actual_text(element, text) element.value[:ActualText] = text.to_s end |
#set_alt_text(element, text) ⇒ Object
Set alternate text on a structure element for screen readers. Required for /Figure elements per PDF/UA-1 Tech Note 001.
88 89 90 |
# File 'lib/pdfrb/document/structure.rb', line 88 def set_alt_text(element, text) element.value[:Alt] = text.to_s end |
#set_language(element, lang) ⇒ Object
Set language on a structure element (overrides document /Lang).
103 104 105 |
# File 'lib/pdfrb/document/structure.rb', line 103 def set_language(element, lang) element.value[:Lang] = lang.to_s end |
#validate_alt_text! ⇒ Array<Hash>
Validate that all /Figure elements have /Alt text per PDF/UA-1.
117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/pdfrb/document/structure.rb', line 117 def validate_alt_text! violations = [] each_element do |elem| next unless elem.value[:S]&.to_sym == :Figure unless has_alt_text?(elem) violations << { element: elem, reason: "Figure missing /Alt text" } end end violations end |