Class: Rpdfium::Structure::Tree
- Inherits:
-
Object
- Object
- Rpdfium::Structure::Tree
- Defined in:
- lib/rpdfium/structure/tree.rb
Overview
StructTree di una pagina PDF tagged.
Per PDF tagged (PDF/UA, esport accessibility-friendly da Word/LibreOffice/InDesign), espone la struttura logica del documento: Document → P, H1, Table, TR, TH, TD, Figure, ecc.
Per PDF NON tagged, ‘Page#struct_tree` ritorna nil. Per PDF “tagged ma vuoti” (es. CR Banca d’Italia, StructTreeRoot presente ma con element placeholder senza type/MCID), ‘Tree#empty?` ritorna true.
Lifecycle: il Tree mantiene un handle PDFium che è “owning” — chiamare ‘FPDF_StructTree_Close` lo dealloca. PDFium dealloca automaticamente lo struct tree alla chiusura del documento, quindi in pratica:
- se non chiudi mai il tree esplicitamente, PDFium lo libera con
`FPDF_CloseDocument` (zero perdita persistente, ma il tree resta
in memoria fino alla chiusura del doc — può essere ~MB)
- per controllo deterministico (rilascia subito), usa il blocco:
page.struct_tree do |tree|
tree.walk { |el| ... }
end
all'uscita dal blocco il tree viene chiuso, anche su eccezione.
Per scelta progettuale NON usiamo ‘ObjectSpace.define_finalizer`: se il GC chiamasse `FPDF_StructTree_Close` dopo che il documento è già stato chiuso, si avrebbe un use-after-free → segfault. La chiusura via Document è sempre sicura; la chiusura via Tree.close (esplicita o tramite blocco) richiede che il documento sia ancora vivo.
Instance Attribute Summary collapse
-
#handle ⇒ Object
readonly
Returns the value of attribute handle.
-
#page ⇒ Object
readonly
Returns the value of attribute page.
Class Method Summary collapse
-
.for_page(page) ⇒ Object
Ritorna nil se la pagina non è tagged.
Instance Method Summary collapse
-
#close ⇒ Object
Chiusura esplicita (idempotente).
- #closed? ⇒ Boolean
-
#empty? ⇒ Boolean
True se il tree è strutturalmente vuoto (nessun element con type leggibile dai root).
-
#find_all(type:) ⇒ Object
Trova tutti gli element del tipo specificato (es. “Table”, “P”, “Figure”).
-
#initialize(page, handle) ⇒ Tree
constructor
A new instance of Tree.
-
#mcid_text_map ⇒ Object
Page objects raggruppati per Marked Content ID, per consentire a Element#text di risolvere il testo dei suoi MCID.
-
#root_count ⇒ Object
Numero di element root (figli diretti del StructTreeRoot per questa pagina).
-
#roots ⇒ Object
Element root (figli diretti del StructTreeRoot).
-
#tables ⇒ Object
Restituisce tutti gli element di tipo “Table”.
- #to_s ⇒ Object (also: #inspect)
-
#walk(&block) ⇒ Object
Walk depth-first di TUTTI gli element del tree.
Constructor Details
#initialize(page, handle) ⇒ Tree
Returns a new instance of Tree.
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/rpdfium/structure/tree.rb', line 45 def initialize(page, handle) @page = page @handle = handle @closed = false @mcid_text_cache = nil # NOTA: niente finalizer. FPDF_StructTree_Close è "owning": chiama # ~CPDF_StructTree() che libera l'oggetto. Se il documento PDF # viene chiuso prima del tree, il finalizer GC chiamerebbe Close # su memoria già liberata → segfault. Lifetime sicuro: # - close esplicito via `tree.close` o via blocco # `page.struct_tree { |tree| ... }` # - se nessuno chiude esplicitamente, PDFium libera il tree # insieme al documento al `FPDF_CloseDocument` (no leak # persistent, solo riserva memoria fino a chiusura doc) end |
Instance Attribute Details
#handle ⇒ Object (readonly)
Returns the value of attribute handle.
35 36 37 |
# File 'lib/rpdfium/structure/tree.rb', line 35 def handle @handle end |
#page ⇒ Object (readonly)
Returns the value of attribute page.
35 36 37 |
# File 'lib/rpdfium/structure/tree.rb', line 35 def page @page end |
Class Method Details
.for_page(page) ⇒ Object
Ritorna nil se la pagina non è tagged. Altrimenti un Tree.
38 39 40 41 42 43 |
# File 'lib/rpdfium/structure/tree.rb', line 38 def self.for_page(page) h = Raw.FPDF_StructTree_GetForPage(page.handle) return nil if h.null? new(page, h) end |
Instance Method Details
#close ⇒ Object
Chiusura esplicita (idempotente). Dopo close, non chiamare metodi su questo Tree né sugli Element che ha generato.
68 69 70 71 72 73 74 |
# File 'lib/rpdfium/structure/tree.rb', line 68 def close return if @closed Raw.FPDF_StructTree_Close(@handle) @closed = true @mcid_text_cache = nil end |
#closed? ⇒ Boolean
62 63 64 |
# File 'lib/rpdfium/structure/tree.rb', line 62 def closed? @closed end |
#empty? ⇒ Boolean
True se il tree è strutturalmente vuoto (nessun element con type leggibile dai root). Caso comune per PDF “fintamente tagged” come CR Banca d’Italia: il StructTreeRoot esiste ma gli element sono placeholder vuoti.
97 98 99 100 101 |
# File 'lib/rpdfium/structure/tree.rb', line 97 def empty? return true if root_count.zero? roots.none? { |r| r.type || r.children.any? } end |
#find_all(type:) ⇒ Object
Trova tutti gli element del tipo specificato (es. “Table”, “P”, “Figure”). Confronto case-sensitive (i tipi PDF sono “Table”, “P”, “H1”, ecc.).
114 115 116 |
# File 'lib/rpdfium/structure/tree.rb', line 114 def find_all(type:) walk.select { |el| el.type == type } end |
#mcid_text_map ⇒ Object
Page objects raggruppati per Marked Content ID, per consentire a Element#text di risolvere il testo dei suoi MCID. La mappa è costruita una sola volta per Tree e cached.
Pubblico ma destinato a uso interno; non parte dell’API stabile.
129 130 131 |
# File 'lib/rpdfium/structure/tree.rb', line 129 def mcid_text_map @mcid_text_cache ||= build_mcid_text_map end |
#root_count ⇒ Object
Numero di element root (figli diretti del StructTreeRoot per questa pagina). Tipicamente 1 (‘<Document>`), ma può essere arbitrariamente alto su PDF strani (es. cu.pdf: 717 placeholder).
79 80 81 82 |
# File 'lib/rpdfium/structure/tree.rb', line 79 def root_count n = Raw.FPDF_StructTree_CountChildren(@handle) [n, 0].max end |
#roots ⇒ Object
Element root (figli diretti del StructTreeRoot). Tipicamente 1 (‘<Document>`).
86 87 88 89 90 91 |
# File 'lib/rpdfium/structure/tree.rb', line 86 def roots (0...root_count).filter_map do |i| h = Raw.FPDF_StructTree_GetChildAtIndex(@handle, i) h.null? ? nil : Element.new(self, h) end end |
#tables ⇒ Object
Restituisce tutti gli element di tipo “Table”. Conveniente per estrazione tabelle semantica.
120 121 122 |
# File 'lib/rpdfium/structure/tree.rb', line 120 def tables find_all(type: "Table") end |
#to_s ⇒ Object Also known as: inspect
133 134 135 |
# File 'lib/rpdfium/structure/tree.rb', line 133 def to_s "#<Rpdfium::Structure::Tree roots=#{root_count}#{empty? ? ' empty' : ''}>" end |
#walk(&block) ⇒ Object
Walk depth-first di TUTTI gli element del tree. Equivalente a ‘roots.flat_map(&:walk)`. Senza block ritorna Enumerator.
105 106 107 108 109 |
# File 'lib/rpdfium/structure/tree.rb', line 105 def walk(&block) return enum_for(:walk) unless block roots.each { |r| r.walk(&block) } end |