Bug
Text extracted from some native-text Form XObjects is decoded correctly but is emitted with overlapping origin-based geometry because the text extractor does not compose the page cm, Form /Matrix, and nested glyph cm transformations.
This pattern is produced by PDF generators that render unit-sized glyphs at the text-space origin and supply their actual position through transformation matrices.
Reproduction
With gxpdf v0.9.4, a synthetic one-page PDF containing a positioned financial table produces readable characters through the text extractor, but the glyph coordinates overlap and all four table modes return no tables:
MethodAuto: 0 tables
MethodStream: 0 tables
MethodLattice: 0 tables
MethodHybrid: 0 tables
The reproduction composes:
- a page-level scale through
cm;
- a Form XObject
/Matrix translation; and
- a separate scale/translation
cm for each unit-sized glyph.
It also includes direct-page text after the Form to verify that graphics state is restored.
Expected behavior
ExtractTextElements() should return finite page-space positions after composing those matrices, without leaking Form graphics state into the caller. Because ExtractTables() consumes the same text elements, table detection should receive the corrected geometry as well.
Proposed fix
- track
q, Q, and cm in the text extractor;
- apply Form
/Matrix while processing Form XObjects;
- isolate each Form's graphics-state stack from its caller;
- use embedded simple/composite font widths for individually positioned glyph advances;
- bound composite
/W ranges to the valid unsigned 16-bit CID space.
The initial coordinate path is deliberately limited to unit-sized text inside Form XObjects to avoid silently changing the established coordinate space of larger Form text. Removing that compatibility threshold requires coordinated re-baselining of text geometry and table-coordinate normalization.
Scope note
Corrected geometry makes the synthetic table detectable, but existing Stream column-boundary behavior can still omit a far-right financial column. That is a separate table-reconstruction issue and should not be presented as solved by this geometry change.
Environment
- gxpdf: v0.9.4
- Go: 1.26.6
- macOS arm64; the reproduction is deterministic and platform-independent
Bug
Text extracted from some native-text Form XObjects is decoded correctly but is emitted with overlapping origin-based geometry because the text extractor does not compose the page
cm, Form/Matrix, and nested glyphcmtransformations.This pattern is produced by PDF generators that render unit-sized glyphs at the text-space origin and supply their actual position through transformation matrices.
Reproduction
With gxpdf v0.9.4, a synthetic one-page PDF containing a positioned financial table produces readable characters through the text extractor, but the glyph coordinates overlap and all four table modes return no tables:
The reproduction composes:
cm;/Matrixtranslation; andcmfor each unit-sized glyph.It also includes direct-page text after the Form to verify that graphics state is restored.
Expected behavior
ExtractTextElements()should return finite page-space positions after composing those matrices, without leaking Form graphics state into the caller. BecauseExtractTables()consumes the same text elements, table detection should receive the corrected geometry as well.Proposed fix
q,Q, andcmin the text extractor;/Matrixwhile processing Form XObjects;/Wranges to the valid unsigned 16-bit CID space.The initial coordinate path is deliberately limited to unit-sized text inside Form XObjects to avoid silently changing the established coordinate space of larger Form text. Removing that compatibility threshold requires coordinated re-baselining of text geometry and table-coordinate normalization.
Scope note
Corrected geometry makes the synthetic table detectable, but existing Stream column-boundary behavior can still omit a far-right financial column. That is a separate table-reconstruction issue and should not be presented as solved by this geometry change.
Environment