rpdfium 0.4.1 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rpdfium
4
- # Ricerca testuale interna alla pagina, basata su FPDFText_Find*.
5
- # Mantiene lo stato (cursor) e supporta forward/backward.
4
+ # Text search within the page, based on FPDFText_Find*.
5
+ # Keeps the state (cursor) and supports forward/backward.
6
6
  #
7
- # Esempio:
7
+ # Example:
8
8
  # page.search("totale").each_match { |m| p m[:bbox], m[:text] }
9
9
  class Search
10
10
  include Enumerable
@@ -43,8 +43,8 @@ module Rpdfium
43
43
  @state[:handle]
44
44
  end
45
45
 
46
- # Itera tutte le occorrenze in avanti. Ritorna hash con :char_index, :length,
47
- # :text, :rects (array di bbox top-down: una per riga di testo).
46
+ # Iterates over all forward occurrences. Returns a hash with :char_index, :length,
47
+ # :text, :rects (an array of top-down bboxes: one per text line).
48
48
  def each_match
49
49
  return enum_for(:each_match) unless block_given?
50
50
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rpdfium
4
- # File embedded nel PDF (allegati). PDFium li espone via FPDFDoc_GetAttachment.
4
+ # Files embedded in the PDF (attachments). PDFium exposes them via FPDFDoc_GetAttachment.
5
5
  class Attachment
6
6
  attr_reader :document, :index, :handle
7
7
 
@@ -16,7 +16,7 @@ module Rpdfium
16
16
  Raw.read_utf16_string(:FPDFAttachment_GetName, @handle)
17
17
  end
18
18
 
19
- # Ritorna i bytes del file allegato. Pattern probe-then-fetch.
19
+ # Returns the bytes of the attached file. Probe-then-fetch pattern.
20
20
  def bytes
21
21
  out_size = FFI::MemoryPointer.new(:ulong)
22
22
  Raw.FPDFAttachment_GetFile(@handle, FFI::Pointer::NULL, 0, out_size)
@@ -25,10 +25,10 @@ module Rpdfium
25
25
 
26
26
  buf = FFI::MemoryPointer.new(:uchar, n)
27
27
  Raw.FPDFAttachment_GetFile(@handle, buf, n, out_size)
28
- # Leggo n byte (la dimensione del MIO buffer), non out_size.read_ulong:
29
- # PDFium può aggiornare out_size con un valore diverso da n (es. dim
30
- # totale necessaria) che leggerebbe oltre il buffer → IndexError.
31
- # Se la write effettiva è < n, riempie il resto con NUL.
28
+ # Read n bytes (the size of OUR buffer), not out_size.read_ulong:
29
+ # PDFium may update out_size with a value different from n (e.g. the
30
+ # total size required), which would read past the buffer → IndexError.
31
+ # If the actual write is < n, the remainder is filled with NUL.
32
32
  buf.read_bytes(n)
33
33
  end
34
34
 
@@ -2,20 +2,20 @@
2
2
 
3
3
  module Rpdfium
4
4
  module Structure
5
- # Element di un PDF tagged StructTree.
5
+ # Element of a tagged PDF StructTree.
6
6
  #
7
- # Un Element rappresenta un nodo della struttura logica del documento:
8
- # `Document`, `P` (paragrafo), `H1`..`H6` (headings), `Table`, `TR`,
9
- # `TH`, `TD`, `Figure`, `Span`, `Lbl`, `LI`, `Caption`, ecc. Vedi
10
- # PDF spec §14.8 per la tassonomia completa.
7
+ # An Element represents a node of the document's logical structure:
8
+ # `Document`, `P` (paragraph), `H1`..`H6` (headings), `Table`, `TR`,
9
+ # `TH`, `TD`, `Figure`, `Span`, `Lbl`, `LI`, `Caption`, etc. See
10
+ # PDF spec §14.8 for the complete taxonomy.
11
11
  #
12
- # Gli element non hanno una vita autonoma: appartengono al Tree che li
13
- # ha generati. Quando il Tree viene chiuso, gli element diventano
14
- # invalidi. Non chiamare metodi su un element dopo `tree.close`.
12
+ # Elements have no independent lifetime: they belong to the Tree that
13
+ # produced them. When the Tree is closed, the elements become
14
+ # invalid. Do not call methods on an element after `tree.close`.
15
15
  #
16
- # Tutti i metodi sono read-only: PDFium non espone API per modificare
17
- # il StructTree (è una struttura "di sola lettura" anche nel suo C API
18
- # pubblico).
16
+ # All methods are read-only: PDFium exposes no API to modify the
17
+ # StructTree (it is a "read-only" structure even in its public C
18
+ # API).
19
19
  class Element
20
20
  attr_reader :handle, :tree
21
21
 
@@ -24,75 +24,75 @@ module Rpdfium
24
24
  @handle = handle
25
25
  end
26
26
 
27
- # Tipo strutturale dell'element (es. "P", "H1", "Table", "TR", "TD").
28
- # Nil se PDFium non riesce a leggerlo (element placeholder).
27
+ # Structural type of the element (e.g. "P", "H1", "Table", "TR", "TD").
28
+ # Nil if PDFium cannot read it (placeholder element).
29
29
  def type
30
30
  read_utf16_string(:FPDF_StructElement_GetType)
31
31
  end
32
32
 
33
- # Tipo dell'oggetto PDF sottostante: di solito "StructElem", ma può
34
- # essere "MCR" (Marked Content Reference) o "OBJR" (Object Reference)
35
- # per nodi specializzati. La maggior parte degli utenti usa `type`.
33
+ # Type of the underlying PDF object: usually "StructElem", but may
34
+ # be "MCR" (Marked Content Reference) or "OBJR" (Object Reference)
35
+ # for specialized nodes. Most users use `type`.
36
36
  def obj_type
37
37
  read_utf16_string(:FPDF_StructElement_GetObjType)
38
38
  end
39
39
 
40
- # Title attribute (raro, usato in alcuni documenti per dare un nome
41
- # parlante all'element, es. "Capitolo 1").
40
+ # Title attribute (rare, used in some documents to give the element
41
+ # a descriptive name, e.g. "Capitolo 1").
42
42
  def title
43
43
  read_utf16_string(:FPDF_StructElement_GetTitle)
44
44
  end
45
45
 
46
- # ID univoco dell'element (se dichiarato nel /ID dictionary del
47
- # StructTreeRoot). Permette riferimenti cross-element (es. Headers
48
- # attribute di una cella TD che punta a un TH per id).
46
+ # Unique ID of the element (if declared in the /ID dictionary of
47
+ # the StructTreeRoot). Enables cross-element references (e.g. the
48
+ # Headers attribute of a TD cell pointing to a TH by id).
49
49
  def id
50
50
  read_utf16_string(:FPDF_StructElement_GetID)
51
51
  end
52
52
 
53
- # Lingua dichiarata sull'element (es. "it-IT", "en-US"). Ereditata
54
- # dal parent se non sovrascritta. Utile per pipeline language-aware.
53
+ # Language declared on the element (e.g. "it-IT", "en-US"). Inherited
54
+ # from the parent if not overridden. Useful for language-aware pipelines.
55
55
  def lang
56
56
  read_utf16_string(:FPDF_StructElement_GetLang)
57
57
  end
58
58
 
59
- # ActualText: override del testo "logico" per l'element. Risolve
60
- # legature (PDF mostra `fi` ma actual_text dice "fi"), simboli math
61
- # ("∫" → "integral"), abbreviazioni. Se presente, ha priorità sul
62
- # testo grafico per accessibility e ricerca.
59
+ # ActualText: override of the "logical" text for the element. Resolves
60
+ # ligatures (the PDF shows `fi` but actual_text says "fi"), math symbols
61
+ # ("∫" → "integral"), abbreviations. When present, it takes precedence
62
+ # over the graphical text for accessibility and search.
63
63
  def actual_text
64
64
  read_utf16_string(:FPDF_StructElement_GetActualText)
65
65
  end
66
66
 
67
- # AltText: testo alternativo per Figure / Formula / immagini. PDF/UA
68
- # richiede che ogni Figure abbia un alt_text non vuoto.
67
+ # AltText: alternative text for Figure / Formula / images. PDF/UA
68
+ # requires every Figure to have a non-empty alt_text.
69
69
  def alt_text
70
70
  read_utf16_string(:FPDF_StructElement_GetAltText)
71
71
  end
72
72
 
73
- # Expansion text per abbreviazioni (es. element type "Span" con
74
- # contenuto "Dr." e expansion "Doctor"). Usato per text-to-speech.
73
+ # Expansion text for abbreviations (e.g. an element of type "Span"
74
+ # with content "Dr." and expansion "Doctor"). Used for text-to-speech.
75
75
  def expansion
76
76
  read_utf16_string(:FPDF_StructElement_GetExpansion)
77
77
  end
78
78
 
79
- # Marked Content IDs collegati a questo element. Un element ha tipicamente
80
- # 1 MCID (es. una `<P>` ha tutto il testo del paragrafo dentro un BDC con
81
- # mcid=N) oppure 0 (element strutturale puro: `<Document>`, `<Table>`,
82
- # `<TR>` — i loro MCID stanno nei figli foglia).
79
+ # Marked Content IDs linked to this element. An element typically has
80
+ # 1 MCID (e.g. a `<P>` holds all the paragraph text inside a BDC with
81
+ # mcid=N) or 0 (a pure structural element: `<Document>`, `<Table>`,
82
+ # `<TR>` — their MCIDs reside in the leaf children).
83
83
  #
84
- # Per collegare un MCID al testo della pagina: leggi i page object e
85
- # raggruppa per `FPDFPageObj_GetMarkedContentID`. Vedi `Element#text`.
84
+ # To link an MCID to the page text: read the page objects and group
85
+ # by `FPDFPageObj_GetMarkedContentID`. See `Element#text`.
86
86
  def marked_content_ids
87
87
  first = Raw.FPDF_StructElement_GetMarkedContentID(@handle)
88
88
  count = Raw.FPDF_StructElement_GetMarkedContentIdCount(@handle)
89
- # Casi: GetMarkedContentIdCount ritorna -1 quando non ci sono MCID
90
- # diretti (element strutturale). GetMarkedContentID ritorna -1
91
- # nello stesso caso.
89
+ # Cases: GetMarkedContentIdCount returns -1 when there are no direct
90
+ # MCIDs (structural element). GetMarkedContentID returns -1 in the
91
+ # same case.
92
92
  return [] if count <= 0 && first < 0
93
93
 
94
- # Quando esiste un solo MCID, GetMarkedContentIdCount può ritornare
95
- # 0 o -1 mentre GetMarkedContentID il valore. Coalescenza:
94
+ # When a single MCID exists, GetMarkedContentIdCount may return
95
+ # 0 or -1 while GetMarkedContentID provides the value. Coalesce:
96
96
  if count <= 0
97
97
  first >= 0 ? [first] : []
98
98
  else
@@ -103,8 +103,8 @@ module Rpdfium
103
103
  end
104
104
  end
105
105
 
106
- # Figli diretti dell'element. Ordinati come dichiarati nel PDF
107
- # (top-to-bottom, left-to-right per reading order).
106
+ # Direct children of the element. Ordered as declared in the PDF
107
+ # (top-to-bottom, left-to-right for reading order).
108
108
  def children
109
109
  n = Raw.FPDF_StructElement_CountChildren(@handle)
110
110
  return [] if n <= 0
@@ -115,7 +115,7 @@ module Rpdfium
115
115
  end
116
116
  end
117
117
 
118
- # Parent. Nil per gli element root (figli diretti del StructTree).
118
+ # Parent. Nil for root elements (direct children of the StructTree).
119
119
  def parent
120
120
  h = Raw.FPDF_StructElement_GetParent(@handle)
121
121
  return nil if h.null?
@@ -123,9 +123,9 @@ module Rpdfium
123
123
  Element.new(@tree, h)
124
124
  end
125
125
 
126
- # Walk depth-first dell'intero sub-tree a partire da questo element.
127
- # Visita prima self, poi ricorsivamente i figli.
128
- # Senza block ritorna un Enumerator.
126
+ # Depth-first walk of the entire sub-tree starting from this element.
127
+ # Visits self first, then recursively the children.
128
+ # Without a block returns an Enumerator.
129
129
  def walk(&block)
130
130
  return enum_for(:walk) unless block
131
131
 
@@ -133,26 +133,26 @@ module Rpdfium
133
133
  children.each { |c| c.walk(&block) }
134
134
  end
135
135
 
136
- # Foglie del sub-tree (element senza figli). Sono i nodi che
137
- # tipicamente hanno il MCID diretto.
136
+ # Leaves of the sub-tree (elements without children). These are the
137
+ # nodes that typically hold the direct MCID.
138
138
  def leaves
139
139
  return [self] if children.empty?
140
140
 
141
141
  children.flat_map(&:leaves)
142
142
  end
143
143
 
144
- # Testo dell'element, ricostruito dalla pagina via MCID. Risoluzione:
145
- # 1. Se `actual_text` è presente, lo usa (gestisce legature/abbreviazioni).
146
- # 2. Altrimenti raccoglie tutti gli MCID del sub-tree (questo element
147
- # + ricorsivamente i figli) e concatena il testo dei page objects
148
- # con quei MCID, in document order.
144
+ # Text of the element, reconstructed from the page via MCID. Resolution:
145
+ # 1. If `actual_text` is present, use it (handles ligatures/abbreviations).
146
+ # 2. Otherwise collect all MCIDs of the sub-tree (this element
147
+ # + recursively the children) and concatenate the text of the page
148
+ # objects with those MCIDs, in document order.
149
149
  #
150
- # Per element strutturali puri (`Table`, `TR`) il testo è la
151
- # concatenazione di tutti i discendenti utile come "summary".
150
+ # For pure structural elements (`Table`, `TR`) the text is the
151
+ # concatenation of all descendantsuseful as a "summary".
152
152
  def text
153
153
  return actual_text if actual_text && !actual_text.empty?
154
154
 
155
- # Raccoglie MCID di tutto il sub-tree depth-first
155
+ # Collect MCIDs of the entire sub-tree depth-first
156
156
  all_mcids = []
157
157
  walk { |el| all_mcids.concat(el.marked_content_ids) }
158
158
  return "" if all_mcids.empty?
@@ -161,11 +161,11 @@ module Rpdfium
161
161
  all_mcids.filter_map { |id| mcid_map[id] }.join
162
162
  end
163
163
 
164
- # Attributi PDF strutturali. Ritorna un Hash { name => value } con
165
- # tutti gli attributi dichiarati su questo element (RowSpan, ColSpan,
166
- # Scope, Headers, BBox, ecc.). I valori sono Ruby-native: Integer,
167
- # Float, String, true/false, o Array per attributi "Headers" che
168
- # contengono liste di ID.
164
+ # Structural PDF attributes. Returns a Hash { name => value } with
165
+ # all attributes declared on this element (RowSpan, ColSpan,
166
+ # Scope, Headers, BBox, etc.). Values are Ruby-native: Integer,
167
+ # Float, String, true/false, or Array for "Headers" attributes that
168
+ # contain lists of IDs.
169
169
  def attributes
170
170
  result = {}
171
171
  attr_count = Raw.FPDF_StructElement_GetAttributeCount(@handle)
@@ -204,9 +204,9 @@ module Rpdfium
204
204
 
205
205
  private
206
206
 
207
- # Helper UTF-16 string read con probe-then-fetch corretto. PDFium
208
- # restituisce il numero di byte necessari (incluso null terminator),
209
- # anche se il buffer è troppo piccolo.
207
+ # UTF-16 string read helper with proper probe-then-fetch. PDFium
208
+ # returns the number of bytes required (including the null
209
+ # terminator), even when the buffer is too small.
210
210
  def read_utf16_string(fn_name)
211
211
  needed = Raw.send(fn_name, @handle, FFI::Pointer::NULL, 0)
212
212
  return nil if needed < 2
@@ -215,7 +215,7 @@ module Rpdfium
215
215
  written = Raw.send(fn_name, @handle, buf, needed)
216
216
  return nil if written < 2
217
217
 
218
- # Clamp: leggi al massimo il buffer allocato meno il null terminator.
218
+ # Clamp: read at most the allocated buffer minus the null terminator.
219
219
  payload = [written - 2, needed - 2].min
220
220
  return nil if payload <= 0
221
221
 
@@ -235,7 +235,7 @@ module Rpdfium
235
235
  n = len_buf.read_ulong
236
236
  return nil if n.zero?
237
237
 
238
- # GetName ritorna ASCII (latin-1), non UTF-16
238
+ # GetName returns ASCII (latin-1), not UTF-16
239
239
  name_buf.read_bytes(n).force_encoding("UTF-8").delete("\u0000")
240
240
  end
241
241
 
@@ -244,7 +244,7 @@ module Rpdfium
244
244
  return nil if val_handle.null?
245
245
 
246
246
  type = Raw.FPDF_StructElement_Attr_GetType(val_handle)
247
- # Type codes da fpdf_structtree.h:
247
+ # Type codes from fpdf_structtree.h:
248
248
  # 1 = Boolean, 2 = Number, 3 = String, 4 = Blob,
249
249
  # 5 = Name, 6 = Array, 7 = Dictionary
250
250
  case type
@@ -258,15 +258,15 @@ module Rpdfium
258
258
  read_attr_string_value(val_handle)
259
259
  when 4 # Blob (raw bytes)
260
260
  read_attr_blob_value(val_handle)
261
- when 6 # Array → ricorsivamente raccolgo i figli
261
+ when 6 # Array → recursively collect the children
262
262
  n = Raw.FPDF_StructElement_Attr_CountChildren(val_handle)
263
263
  (0...n).filter_map do |i|
264
264
  child = Raw.FPDF_StructElement_Attr_GetChildAtIndex(val_handle, i)
265
265
  next nil if child.null?
266
266
 
267
- # Per ogni child applico la stessa lettura via type. Ma non ho
268
- # un "name" per accedere a Attr_GetValue su un child; il child
269
- # È già una FPDF_STRUCTELEMENT_ATTR_VALUE. Leggi direttamente.
267
+ # For each child apply the same read via type. But there is no
268
+ # "name" to access Attr_GetValue on a child; the child is
269
+ # already an FPDF_STRUCTELEMENT_ATTR_VALUE. Read it directly.
270
270
  read_attr_value_handle(child)
271
271
  end
272
272
  else
@@ -294,7 +294,7 @@ module Rpdfium
294
294
 
295
295
  def read_attr_string_value(val_handle)
296
296
  len_buf = FFI::MemoryPointer.new(:ulong)
297
- # Probe size
297
+ # Probe the size
298
298
  Raw.FPDF_StructElement_Attr_GetStringValue(val_handle,
299
299
  FFI::Pointer::NULL, 0, len_buf)
300
300
  n = len_buf.read_ulong
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rpdfium
4
- # Albero di bookmark (outline) del documento. Costruito ricorsivamente.
4
+ # Document bookmark (outline) tree. Built recursively.
5
5
  class Outline
6
6
  attr_reader :title, :page_index, :children
7
7
 
@@ -32,7 +32,7 @@ module Rpdfium
32
32
  result
33
33
  end
34
34
 
35
- # Iteratore flat preorder: utile per generare un sommario lineare.
35
+ # Flat preorder iterator: useful for generating a linear table of contents.
36
36
  def self.flatten(outline_tree, depth = 0, &block)
37
37
  outline_tree.each do |item|
38
38
  block.call(item, depth)
@@ -2,39 +2,40 @@
2
2
 
3
3
  module Rpdfium
4
4
  module Structure
5
- # StructTree di una pagina PDF tagged.
5
+ # StructTree of a tagged PDF page.
6
6
  #
7
- # Per PDF tagged (PDF/UA, esport accessibility-friendly da
8
- # Word/LibreOffice/InDesign), espone la struttura logica del documento:
9
- # Document → P, H1, Table, TR, TH, TD, Figure, ecc.
7
+ # For tagged PDFs (PDF/UA, accessibility-friendly exports from
8
+ # Word/LibreOffice/InDesign), it exposes the logical structure of the
9
+ # document: Document → P, H1, Table, TR, TH, TD, Figure, etc.
10
10
  #
11
- # Per PDF NON tagged, `Page#struct_tree` ritorna nil. Per PDF "tagged
12
- # ma vuoti" (es. CR Banca d'Italia, StructTreeRoot presente ma con
13
- # element placeholder senza type/MCID), `Tree#empty?` ritorna true.
11
+ # For NON-tagged PDFs, `Page#struct_tree` returns nil. For "tagged but
12
+ # empty" PDFs (e.g. CR Banca d'Italia, StructTreeRoot present but with
13
+ # placeholder elements without type/MCID), `Tree#empty?` returns true.
14
14
  #
15
- # Lifecycle: il Tree mantiene un handle PDFium che è "owning" — chiamare
16
- # `FPDF_StructTree_Close` lo dealloca. PDFium dealloca automaticamente
17
- # lo struct tree alla chiusura del documento, quindi in pratica:
15
+ # Lifecycle: the Tree holds a PDFium handle that is "owning" — calling
16
+ # `FPDF_StructTree_Close` deallocates it. PDFium automatically
17
+ # deallocates the struct tree when the document is closed, so in
18
+ # practice:
18
19
  #
19
- # - se non chiudi mai il tree esplicitamente, PDFium lo libera con
20
- # `FPDF_CloseDocument` (zero perdita persistente, ma il tree resta
21
- # in memoria fino alla chiusura del docpuò essere ~MB)
22
- # - per controllo deterministico (rilascia subito), usa il blocco:
20
+ # - if you never close the tree explicitly, PDFium frees it with
21
+ # `FPDF_CloseDocument` (zero persistent leak, but the tree stays
22
+ # in memory until the doc is closedit may be ~MB)
23
+ # - for deterministic control (release immediately), use the block:
23
24
  #
24
25
  # page.struct_tree do |tree|
25
26
  # tree.walk { |el| ... }
26
27
  # end
27
- # all'uscita dal blocco il tree viene chiuso, anche su eccezione.
28
+ # on exit from the block the tree is closed, even on exception.
28
29
  #
29
- # Per scelta progettuale NON usiamo `ObjectSpace.define_finalizer`: se
30
- # il GC chiamasse `FPDF_StructTree_Close` dopo che il documento è già
31
- # stato chiuso, si avrebbe un use-after-free → segfault. La chiusura
32
- # via Document è sempre sicura; la chiusura via Tree.close (esplicita
33
- # o tramite blocco) richiede che il documento sia ancora vivo.
30
+ # As a design choice we do NOT use `ObjectSpace.define_finalizer`: if
31
+ # the GC were to call `FPDF_StructTree_Close` after the document had
32
+ # already been closed, this would cause a use-after-free → segfault.
33
+ # Closing via Document is always safe; closing via Tree.close (explicit
34
+ # or through a block) requires the document to still be alive.
34
35
  class Tree
35
36
  attr_reader :handle, :page
36
37
 
37
- # Ritorna nil se la pagina non è tagged. Altrimenti un Tree.
38
+ # Returns nil if the page is not tagged. Otherwise a Tree.
38
39
  def self.for_page(page)
39
40
  h = Raw.FPDF_StructTree_GetForPage(page.handle)
40
41
  return nil if h.null?
@@ -48,23 +49,23 @@ module Rpdfium
48
49
  @closed = false
49
50
  @mcid_text_cache = nil
50
51
 
51
- # NOTA: niente finalizer. FPDF_StructTree_Close è "owning": chiama
52
- # ~CPDF_StructTree() che libera l'oggetto. Se il documento PDF
53
- # viene chiuso prima del tree, il finalizer GC chiamerebbe Close
54
- # su memoria già liberata → segfault. Lifetime sicuro:
55
- # - close esplicito via `tree.close` o via blocco
52
+ # NOTE: no finalizer. FPDF_StructTree_Close is "owning": it calls
53
+ # ~CPDF_StructTree() which frees the object. If the PDF document
54
+ # is closed before the tree, the GC finalizer would call Close on
55
+ # already-freed memory → segfault. Safe lifetime:
56
+ # - explicit close via `tree.close` or via the block
56
57
  # `page.struct_tree { |tree| ... }`
57
- # - se nessuno chiude esplicitamente, PDFium libera il tree
58
- # insieme al documento al `FPDF_CloseDocument` (no leak
59
- # persistent, solo riserva memoria fino a chiusura doc)
58
+ # - if nobody closes it explicitly, PDFium frees the tree
59
+ # together with the document at `FPDF_CloseDocument` (no
60
+ # persistent leak, only memory held until the doc is closed)
60
61
  end
61
62
 
62
63
  def closed?
63
64
  @closed
64
65
  end
65
66
 
66
- # Chiusura esplicita (idempotente). Dopo close, non chiamare metodi
67
- # su questo Tree sugli Element che ha generato.
67
+ # Explicit close (idempotent). After close, do not call methods on
68
+ # this Tree nor on the Elements it generated.
68
69
  def close
69
70
  return if @closed
70
71
 
@@ -73,15 +74,15 @@ module Rpdfium
73
74
  @mcid_text_cache = nil
74
75
  end
75
76
 
76
- # Numero di element root (figli diretti del StructTreeRoot per
77
- # questa pagina). Tipicamente 1 (`<Document>`), ma può essere
78
- # arbitrariamente alto su PDF strani (es. cu.pdf: 717 placeholder).
77
+ # Number of root elements (direct children of the StructTreeRoot for
78
+ # this page). Typically 1 (`<Document>`), but it can be arbitrarily
79
+ # high on odd PDFs (e.g. cu.pdf: 717 placeholders).
79
80
  def root_count
80
81
  n = Raw.FPDF_StructTree_CountChildren(@handle)
81
82
  [n, 0].max
82
83
  end
83
84
 
84
- # Element root (figli diretti del StructTreeRoot). Tipicamente 1
85
+ # Root elements (direct children of the StructTreeRoot). Typically 1
85
86
  # (`<Document>`).
86
87
  def roots
87
88
  (0...root_count).filter_map do |i|
@@ -90,42 +91,42 @@ module Rpdfium
90
91
  end
91
92
  end
92
93
 
93
- # True se il tree è strutturalmente vuoto (nessun element con type
94
- # leggibile dai root). Caso comune per PDF "fintamente tagged" come
95
- # CR Banca d'Italia: il StructTreeRoot esiste ma gli element sono
96
- # placeholder vuoti.
94
+ # True if the tree is structurally empty (no element with a readable
95
+ # type among the roots). A common case for "fake-tagged" PDFs such as
96
+ # CR Banca d'Italia: the StructTreeRoot exists but the elements are
97
+ # empty placeholders.
97
98
  def empty?
98
99
  return true if root_count.zero?
99
100
 
100
101
  roots.none? { |r| r.type || r.children.any? }
101
102
  end
102
103
 
103
- # Walk depth-first di TUTTI gli element del tree. Equivalente a
104
- # `roots.flat_map(&:walk)`. Senza block ritorna Enumerator.
104
+ # Depth-first walk of ALL the elements of the tree. Equivalent to
105
+ # `roots.flat_map(&:walk)`. Without a block it returns an Enumerator.
105
106
  def walk(&block)
106
107
  return enum_for(:walk) unless block
107
108
 
108
109
  roots.each { |r| r.walk(&block) }
109
110
  end
110
111
 
111
- # Trova tutti gli element del tipo specificato (es. "Table", "P",
112
- # "Figure"). Confronto case-sensitive (i tipi PDF sono "Table",
113
- # "P", "H1", ecc.).
112
+ # Finds all the elements of the specified type (e.g. "Table", "P",
113
+ # "Figure"). Case-sensitive comparison (PDF types are "Table",
114
+ # "P", "H1", etc.).
114
115
  def find_all(type:)
115
116
  walk.select { |el| el.type == type }
116
117
  end
117
118
 
118
- # Restituisce tutti gli element di tipo "Table". Conveniente per
119
- # estrazione tabelle semantica.
119
+ # Returns all the elements of type "Table". Convenient for semantic
120
+ # table extraction.
120
121
  def tables
121
122
  find_all(type: "Table")
122
123
  end
123
124
 
124
- # Page objects raggruppati per Marked Content ID, per consentire a
125
- # Element#text di risolvere il testo dei suoi MCID. La mappa è
126
- # costruita una sola volta per Tree e cached.
125
+ # Page objects grouped by Marked Content ID, to allow Element#text
126
+ # to resolve the text of its MCIDs. The map is built only once per
127
+ # Tree and cached.
127
128
  #
128
- # Pubblico ma destinato a uso interno; non parte dell'API stabile.
129
+ # Public but intended for internal use; not part of the stable API.
129
130
  def mcid_text_map
130
131
  @mcid_text_cache ||= build_mcid_text_map
131
132
  end
@@ -137,9 +138,9 @@ module Rpdfium
137
138
 
138
139
  private
139
140
 
140
- # Itera tutti i page objects (incl. Form XObject) e raggruppa il loro
141
- # testo per MCID. Il pattern probe-then-fetch su FPDFTextObj_GetText
142
- # è già rodato (vedi Page#read_text_obj_text_fast).
141
+ # Iterates all the page objects (incl. Form XObject) and groups their
142
+ # text by MCID. The probe-then-fetch pattern on FPDFTextObj_GetText
143
+ # is well-established (see Page#read_text_obj_text_fast).
143
144
  def build_mcid_text_map
144
145
  map = Hash.new { |h, k| h[k] = +"" }
145
146
  tp = @page.text_page
@@ -170,8 +171,8 @@ module Rpdfium
170
171
  end
171
172
 
172
173
  def read_text_obj_text(obj, tp, buf)
173
- # Probe con buffer 1024 byte (sufficiente per il 99% dei marked
174
- # content runs, che tipicamente sono parole singole o frasi brevi).
174
+ # Probe with a 1024-byte buffer (sufficient for 99% of marked
175
+ # content runs, which are typically single words or short phrases).
175
176
  needed = Raw.FPDFTextObj_GetText(obj, tp.handle, buf, 1024)
176
177
  return nil if needed < 2
177
178