Class: Rpdfium::Structure::Element

Inherits:
Object
  • Object
show all
Defined in:
lib/rpdfium/structure/element.rb

Overview

Element di un PDF tagged StructTree.

Un Element rappresenta un nodo della struttura logica del documento: ‘Document`, `P` (paragrafo), `H1`..`H6` (headings), `Table`, `TR`, `TH`, `TD`, `Figure`, `Span`, `Lbl`, `LI`, `Caption`, ecc. Vedi PDF spec §14.8 per la tassonomia completa.

Gli element non hanno una vita autonoma: appartengono al Tree che li ha generati. Quando il Tree viene chiuso, gli element diventano invalidi. Non chiamare metodi su un element dopo ‘tree.close`.

Tutti i metodi sono read-only: PDFium non espone API per modificare il StructTree (è una struttura “di sola lettura” anche nel suo C API pubblico).

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(tree, handle) ⇒ Element

Returns a new instance of Element.



22
23
24
25
# File 'lib/rpdfium/structure/element.rb', line 22

def initialize(tree, handle)
  @tree = tree
  @handle = handle
end

Instance Attribute Details

#handleObject (readonly)

Returns the value of attribute handle.



20
21
22
# File 'lib/rpdfium/structure/element.rb', line 20

def handle
  @handle
end

#treeObject (readonly)

Returns the value of attribute tree.



20
21
22
# File 'lib/rpdfium/structure/element.rb', line 20

def tree
  @tree
end

Instance Method Details

#actual_textObject

ActualText: override del testo “logico” per l’element. Risolve legature (PDF mostra ‘fi` ma actual_text dice “fi”), simboli math (“∫” → “integral”), abbreviazioni. Se presente, ha priorità sul testo grafico per accessibility e ricerca.



63
64
65
# File 'lib/rpdfium/structure/element.rb', line 63

def actual_text
  read_utf16_string(:FPDF_StructElement_GetActualText)
end

#alt_textObject

AltText: testo alternativo per Figure / Formula / immagini. PDF/UA richiede che ogni Figure abbia un alt_text non vuoto.



69
70
71
# File 'lib/rpdfium/structure/element.rb', line 69

def alt_text
  read_utf16_string(:FPDF_StructElement_GetAltText)
end

#attributesObject

Attributi PDF strutturali. Ritorna un Hash { name => value } con tutti gli attributi dichiarati su questo element (RowSpan, ColSpan, Scope, Headers, BBox, ecc.). I valori sono Ruby-native: Integer, Float, String, true/false, o Array per attributi “Headers” che contengono liste di ID.



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/rpdfium/structure/element.rb', line 169

def attributes
  result = {}
  attr_count = Raw.FPDF_StructElement_GetAttributeCount(@handle)
  return result if attr_count <= 0

  (0...attr_count).each do |ai|
    attr = Raw.FPDF_StructElement_GetAttributeAtIndex(@handle, ai)
    next if attr.null?

    key_count = Raw.FPDF_StructElement_Attr_GetCount(attr)
    (0...key_count).each do |ki|
      name = read_attr_name(attr, ki)
      next if name.nil? || name.empty?

      value = read_attr_value(attr, name)
      result[name] = value unless value.nil?
    end
  end
  result
end

#childrenObject

Figli diretti dell’element. Ordinati come dichiarati nel PDF (top-to-bottom, left-to-right per reading order).



108
109
110
111
112
113
114
115
116
# File 'lib/rpdfium/structure/element.rb', line 108

def children
  n = Raw.FPDF_StructElement_CountChildren(@handle)
  return [] if n <= 0

  (0...n).filter_map do |i|
    child_handle = Raw.FPDF_StructElement_GetChildAtIndex(@handle, i)
    child_handle.null? ? nil : Element.new(@tree, child_handle)
  end
end

#expansionObject

Expansion text per abbreviazioni (es. element type “Span” con contenuto “Dr.” e expansion “Doctor”). Usato per text-to-speech.



75
76
77
# File 'lib/rpdfium/structure/element.rb', line 75

def expansion
  read_utf16_string(:FPDF_StructElement_GetExpansion)
end

#idObject

ID univoco dell’element (se dichiarato nel /ID dictionary del StructTreeRoot). Permette riferimenti cross-element (es. Headers attribute di una cella TD che punta a un TH per id).



49
50
51
# File 'lib/rpdfium/structure/element.rb', line 49

def id
  read_utf16_string(:FPDF_StructElement_GetID)
end

#inspectObject



201
202
203
# File 'lib/rpdfium/structure/element.rb', line 201

def inspect
  "#<Rpdfium::Structure::Element #{self}>"
end

#langObject

Lingua dichiarata sull’element (es. “it-IT”, “en-US”). Ereditata dal parent se non sovrascritta. Utile per pipeline language-aware.



55
56
57
# File 'lib/rpdfium/structure/element.rb', line 55

def lang
  read_utf16_string(:FPDF_StructElement_GetLang)
end

#leavesObject

Foglie del sub-tree (element senza figli). Sono i nodi che tipicamente hanno il MCID diretto.



138
139
140
141
142
# File 'lib/rpdfium/structure/element.rb', line 138

def leaves
  return [self] if children.empty?

  children.flat_map(&:leaves)
end

#marked_content_idsObject

Marked Content IDs collegati a questo element. Un element ha tipicamente 1 MCID (es. una ‘<P>` ha tutto il testo del paragrafo dentro un BDC con mcid=N) oppure 0 (element strutturale puro: `<Document>`, `<Table>`, `<TR>` — i loro MCID stanno nei figli foglia).

Per collegare un MCID al testo della pagina: leggi i page object e raggruppa per ‘FPDFPageObj_GetMarkedContentID`. Vedi `Element#text`.



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/rpdfium/structure/element.rb', line 86

def marked_content_ids
  first = Raw.FPDF_StructElement_GetMarkedContentID(@handle)
  count = Raw.FPDF_StructElement_GetMarkedContentIdCount(@handle)
  # Casi: GetMarkedContentIdCount ritorna -1 quando non ci sono MCID
  # diretti (element strutturale). GetMarkedContentID ritorna -1
  # nello stesso caso.
  return [] if count <= 0 && first < 0

  # Quando esiste un solo MCID, GetMarkedContentIdCount può ritornare
  # 0 o -1 mentre GetMarkedContentID dà il valore. Coalescenza:
  if count <= 0
    first >= 0 ? [first] : []
  else
    (0...count).filter_map do |i|
      mcid = Raw.FPDF_StructElement_GetMarkedContentIdAtIndex(@handle, i)
      mcid >= 0 ? mcid : nil
    end
  end
end

#obj_typeObject

Tipo dell’oggetto PDF sottostante: di solito “StructElem”, ma può essere “MCR” (Marked Content Reference) o “OBJR” (Object Reference) per nodi specializzati. La maggior parte degli utenti usa ‘type`.



36
37
38
# File 'lib/rpdfium/structure/element.rb', line 36

def obj_type
  read_utf16_string(:FPDF_StructElement_GetObjType)
end

#parentObject

Parent. Nil per gli element root (figli diretti del StructTree).



119
120
121
122
123
124
# File 'lib/rpdfium/structure/element.rb', line 119

def parent
  h = Raw.FPDF_StructElement_GetParent(@handle)
  return nil if h.null?

  Element.new(@tree, h)
end

#textObject

Testo dell’element, ricostruito dalla pagina via MCID. Risoluzione:

  1. Se ‘actual_text` è presente, lo usa (gestisce legature/abbreviazioni).

  2. Altrimenti raccoglie tutti gli MCID del sub-tree (questo element + ricorsivamente i figli) e concatena il testo dei page objects con quei MCID, in document order.

Per element strutturali puri (‘Table`, `TR`) il testo è la concatenazione di tutti i discendenti — utile come “summary”.



152
153
154
155
156
157
158
159
160
161
162
# File 'lib/rpdfium/structure/element.rb', line 152

def text
  return actual_text if actual_text && !actual_text.empty?

  # Raccoglie MCID di tutto il sub-tree depth-first
  all_mcids = []
  walk { |el| all_mcids.concat(el.marked_content_ids) }
  return "" if all_mcids.empty?

  mcid_map = @tree.send(:mcid_text_map)
  all_mcids.filter_map { |id| mcid_map[id] }.join
end

#titleObject

Title attribute (raro, usato in alcuni documenti per dare un nome parlante all’element, es. “Capitolo 1”).



42
43
44
# File 'lib/rpdfium/structure/element.rb', line 42

def title
  read_utf16_string(:FPDF_StructElement_GetTitle)
end

#to_sObject



190
191
192
193
194
195
196
197
198
199
# File 'lib/rpdfium/structure/element.rb', line 190

def to_s
  parts = ["<#{type || obj_type || '?'}>"]
  mcids = marked_content_ids
  parts << "mcid=#{mcids.first}" if mcids.size == 1
  parts << "mcids=#{mcids.inspect}" if mcids.size > 1
  parts << "lang=#{lang.inspect}" if lang
  parts << "actual_text=#{actual_text.inspect[0, 30]}" if actual_text
  parts << "alt_text=#{alt_text.inspect[0, 30]}" if alt_text
  parts.join(" ")
end

#typeObject

Tipo strutturale dell’element (es. “P”, “H1”, “Table”, “TR”, “TD”). Nil se PDFium non riesce a leggerlo (element placeholder).



29
30
31
# File 'lib/rpdfium/structure/element.rb', line 29

def type
  read_utf16_string(:FPDF_StructElement_GetType)
end

#walk {|_self| ... } ⇒ Object

Walk depth-first dell’intero sub-tree a partire da questo element. Visita prima self, poi ricorsivamente i figli. Senza block ritorna un Enumerator.

Yields:

  • (_self)

Yield Parameters:



129
130
131
132
133
134
# File 'lib/rpdfium/structure/element.rb', line 129

def walk(&block)
  return enum_for(:walk) unless block

  yield self
  children.each { |c| c.walk(&block) }
end