Fixed contextName stack exception for context-less PDFs when using PdfTextLocator - #1538
Fixed contextName stack exception for context-less PDFs when using PdfTextLocator#1538ConvoluteHumanBot wants to merge 12 commits into
Conversation
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 47 |
| Duplication | -143 |
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
|
|
This PR might actually be a good idea, I think it could be interesting to improve this and get it included. Do you have more information? @ConvoluteHumanBot |
|
Hi Andreas,
About the DocumentFont problem: CMapAwareDocumentFont is properly parsing the CID map to decode the chars, but the widths are stored sequentially as they appear in the PdfName.TOUNICODE stream. The char width is then retrieved using the unicode integer, and was causing a mismatch. I'm trying to figure out if it is better to add a map from UNICODE to CID and leave the widths initialization as is (currently done locally and working), or if it is better reworking the widths association altogether and use an IntHashmap as for CJK fonts. Thanks for your time @andreasrosdal |
…mentFonts. Widths calculation now properly working. TODO: maybe change the widths structure to match the more precise CJK fonts.
DocumentFont.getWidth(int) is keyed by Unicode character, but a content stream yields character codes, so the parser was measuring codes against a Unicode-keyed table. For Identity-H fonts this silently returned 0, or a wrong width when a code collided with an unrelated Unicode value. Keep the CID-keyed table that readWidths(/W) already builds instead of discarding it after inverting it into metrics, and add DocumentFont.getWidthOfCode(int) alongside the Unicode-keyed getWidth. The parser and the text locator now measure through it, so the reverse unicodeToCid map and CMap.getLookup() are no longer needed. Also fixes the text matrix advance in parsePdfString, which used a user-space width where a text-space width is required, and restores code-point iteration in getAsPartialWords so two-byte codes are no longer split. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The constructor javadoc listed @PARAM llx twice, documented no leftX or rightX, and ordered its parameters differently from the signature. It also described endIndex as the last index of the match, where it is one past it. toString opened "Text: [" and closed it with "}", printing Text: [foo} - {3::8}]. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The bounds of startIndex and endIndex were checked independently, so a pair that was individually in range but crossed reached substring and threw StringIndexOutOfBoundsException. Fold the checks into the one condition that substring actually requires, 0 <= start <= end <= length. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Text locator: matched-substring coordinates, and a fix to glyph width lookupFollow-up to the coordinate-based text extraction that landed earlier The width fix
For a WinAnsi font this goes unnoticed, because code == Unicode across ASCII. Bridging this with a reverse Unicode→CID map is lossy: several codes can share The fix goes the other way, which is how a PDF actually stores widths. public int getWidthOfCode(int code)
Before / afterLocating patterns in an Identity-H document, via
Before, only spaces had a width, via a fallback; every real glyph measured 0, so Also fixed in the parser
New public API
Testing
Added Known limitations
|
SonarCloud reported two S2259 null dereferences in DocumentFont, both on pre-existing lines that this branch brought into the analysed set. Assert the font dictionary resolves, and return early from processType0 when a malformed Type0 font has no descendant font, rather than turning it into an ExceptionConverter(NullPointerException). getMatchedPatterns had a cognitive complexity of 33 (S3776) and carried the line assembly switch twice; locatePdfString had an NPath complexity of 648 with two copies of the same binary search. Move the line accumulation into a LineBuffer, and extract inspectLine, isOutsideSearchBox, nearestOffsetAtOrBefore and lineBox. Coordinates are unchanged, verified against an Identity-H document. The MatchedPattern constructor took 10 parameters (S107, ExcessiveParameterList); the four line coordinates become one float[], matching how a bounding box is already passed to PdfTextLocator. Also removes a commented-out line of code (S125). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
@andreasrosdal Hi, the code is now clean and the width conversion for glyphs is tested using the proper CID map. Claude spotted another possible failure on a restricted set of fonts, i should address it on a next PR. |





Bugfix
Fixed emptystack exception in PdfContentTextLocator.java, contextNames stack was not tracked on pushContext function call, causing context-less documents to throw exception.
Changed internal mode matching strategy from int to enum for better readability.
Your real name
Alessandro Ragusi (ConvoluteHumanBot)