Skip to content

Make text in PDF exports extractable - #295

Open
Mythie wants to merge 2 commits into
samizdatco:mainfrom
Mythie:fix/pdf-text-extraction
Open

Make text in PDF exports extractable#295
Mythie wants to merge 2 commits into
samizdatco:mainfrom
Mythie:fix/pdf-text-extraction

Conversation

@Mythie

@Mythie Mythie commented Aug 6, 2026

Copy link
Copy Markdown

Text drawn with fillText() isn't copy/paste-able or searchable in exported PDFs when the shaper substitutes glyphs with no cmap entry (ligatures, stylistic sets):

FontLibrary.use('Caveat', 'Caveat.ttf')
ctx.font = '36px Caveat'
ctx.fillText('Lucas Smithy Bruz', 20, 60)
await canvas.saveAs('out.pdf')  // pdftotext → "Luc  t  Bru"

Paragraph::paint emits bare text blobs, so SkPDF builds /ToUnicode by reverse-cmap lookup and maps substituted glyphs to <0000>.

The fix draws the laid-out runs via drawGlyphs with utf8 & cluster info attached, which SkPDF turns into correct mappings and /ActualText spans.

Rendered output is unchanged. For decorated text, the glyphs are drawn once by the new code path, then Paragraph::paint is still called so skparagraph draws its underline/overline/strike-through lines. Its own glyph drawing is disabled (via a no-op blend mode) so the text isn't painted twice.

The second commit fixes textDecoration ignoring any value without an explicit color (currentColor was treated as invalid). Happy to drop this commit though since it isn't really relevant to what I'm trying to solve.

Both commits add tests that fail on main. Wrapped, RTL, and ligature text verified with pdftotext.

Mythie added 2 commits August 6, 2026 15:05
Glyphs substituted via OpenType features aren't reachable through the
cmap, so SkPDF's /ToUnicode mapped them to <0000> and extraction
dropped them.
`currentColor` was treated as an invalid color, discarding the setting.
@Mythie Mythie changed the title fix/pdf text extraction Make text in PDF exports extractable Aug 6, 2026
@samizdatco samizdatco mentioned this pull request Aug 16, 2026
samizdatco added a commit that referenced this pull request Aug 27, 2026
- continue using Paragraph for text-shaping but switch to a TextBlob-based render path
- includes each run's utf-8 text along with the glyphs so PDF text is now selectable
- implements textDecoration drawing including gaps for descenders (and no longer draws underlines *on top* of the text like Paragraph.paint)
- positions text exactly rather than snapping the baseline to the pixel grid 
- inspired by @Mythie's PR #295
samizdatco added a commit that referenced this pull request Aug 28, 2026
- continue using Paragraph for text-shaping but switch to a TextBlob-based render path
- includes each run's utf-8 text along with the glyphs so PDF text is now selectable
- implements textDecoration drawing including gaps for descenders (and no longer draws underlines *on top* of the text like Paragraph.paint)
- positions text exactly rather than snapping the baseline to the pixel grid 
- inspired by @Mythie's PR #295
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant