Skip to content

fix(text): patch @libpdf/core pour extraire le texte des form XObjects#4

Open
Xusifob wants to merge 1 commit into
stagingfrom
fix/libpdf-xobject-text-extraction
Open

fix(text): patch @libpdf/core pour extraire le texte des form XObjects#4
Xusifob wants to merge 1 commit into
stagingfrom
fix/libpdf-xobject-text-extraction

Conversation

@Xusifob

@Xusifob Xusifob commented Jul 24, 2026

Copy link
Copy Markdown
Member

Problème

Le placement de champ par placeholder (POST /envelope/field/create-many) repose sur findText() pour localiser le marqueur dans le PDF. Les documents médicaux Instamed sont scellés via TCPDF/FPDI, qui importe toute la page dans un form XObject. Or @libpdf/core 0.3.3 ne suit pas l'opérateur Do pendant l'extraction de texte : il ne voit rien du contenu réel.

Mesuré sur un document réel scellé :

0.3.3 actuel avec ce patch
Texte extrait 32 car. — « Powered by TCPDF » 312 car. — tout le contenu
findText("{POSITION_SIGNATURE}") 0 match 1 match (X≈39,7 % Y≈34,2 %)

Conséquence côté Instamed : create-many renvoyait 400 « Placeholder not found », le repli en coordonnées s'appliquait, et le champ de signature atterrissait toujours au même endroit arbitraire au lieu de la zone déclarée dans le document.

Solution

Backport du correctif amont — LibPDF-js/core#85, commit f391d90 « feat(text): extract text from form XObjects » — sur le 0.3.3 épinglé, via patch-package (déjà en place dans ce dépôt, et patches/ est explicitement copié dans les deux stages du Dockerfile).

TextExtractor descend désormais dans les form XObjects en utilisant leurs propres /Resources, avec la /Matrix du form concaténée à la CTM.

Le cherry-pick sur v0.3.3 s'applique sans conflit : la PR amont ne touche que 3 fichiers du sous-système d'extraction de texte (text-extractor.ts, text-state.ts, pdf-page.ts), aucun dans la signature. Le code de signature/scellement — utilisé par packages/signing, seal-document, generate-certificate-pdf, normalize-pdf — reste identique au bit près au 0.3.3 déployé. C'est délibéré : vendorer le build 0.4.2 de la PR aurait fait sauter deux versions mineures sur le chemin cryptographique.

Vérification

  • Round-trip : sur une installation @libpdf/core@0.3.3 vierge, patch-package applique le patch (@libpdf/core@0.3.3 ✔) et le marqueur est retrouvé.
  • Build d'image local : patch appliqué dans les deux stages (installer + runner), dist patché présent dans l'image finale.
  • Bout en bout contre cette image locale : create-many avec placeholder renvoie 200 (au lieu de 400) et crée le champ à X=39,7 % / Y=34,2 % — la position du marqueur.

Retrait

Ce patch est temporaire. Le supprimer dès que @libpdf/core publie le correctif dans une version releasée et que la dépendance est bumpée (la PR amont n'est pas encore mergée).

Lien

Nécessaire au bon fonctionnement de instamedsolutions/Instamed#2692. Sans cette PR déployée, le repli en coordonnées s'applique — pas de régression, mais pas de gain.

🤖 Generated with Claude Code

https://claude.ai/code/session_01CSpvLGq8AdWLwXEVEUBF5a

Documenso's placeholder-based field positioning (POST /envelope/field/create-many
with a "placeholder") relies on findText() locating the marker in the PDF. Our
medical documents are sealed via TCPDF/FPDI, which wraps the whole page inside a
form XObject. @libpdf/core 0.3.3 does not follow the `Do` operator during text
extraction, so findText() returns nothing and field placement silently falls back
to default coordinates.

This backports the upstream fix (LibPDF-js/core PR #85, commit f391d90 "feat(text):
extract text from form XObjects") onto the pinned 0.3.3 build via patch-package:
TextExtractor now recurses into form XObjects using their own /Resources with the
form's /Matrix concatenated onto the CTM. Only the text-extraction subsystem is
touched; signing/sealing code is byte-identical to 0.3.3.

Remove this patch once @libpdf/core ships the fix in a released version and the
dependency is bumped.
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