Skip to content

fix(ocr): find the snap's bundled tessdata under its tesseract prefix - #192

Merged
nelsonduarte merged 1 commit into
mainfrom
fix/snap-ocr-tessdata
Oct 9, 2026
Merged

nelsonduarte merged 1 commit into
mainfrom
fix/snap-ocr-tessdata

Conversation

@nelsonduarte

Copy link
Copy Markdown
Owner

Summary

OCR is broken in the published snap (rev 43, 1.15.0): _find_tessdata()
returns None, TESSDATA_PREFIX is never set, and tesseract falls back to
its compiled-in /usr/share/tesseract-ocr/4.00/tessdata, which inside the
snap resolves against the core22 base, where no Tesseract data is installed.
OCR fails with "Error opening data file".

The snap stages Ubuntu 22.04's tesseract-ocr debs, so the data lives at
$SNAP/usr/share/tesseract-ocr/4.00/tessdata. This PR adds a versioned
lookup under the binary's own prefix,
<prefix>/share/tesseract-ocr/<version>/tessdata (newest first, Linux and
macOS only), right after the adjacent-tessdata probe.

  • _find_tesseract / _find_tessdata move to app/tools/_ocr_paths.py
    (no Qt or app.* imports of its own); app.tools.ocr keeps both names
    bound.
  • tests/test_ocr_tessdata.py: 34 tests, including a pattern-aware fake
    glob and an import allowlist for the new module.

Behaviour change

/usr/bin/tesseract gets the same lookup as before, and Windows is
unchanged. A tesseract under another prefix that carries its own versioned
tessdata (e.g. /usr/local/bin/tesseract with
/usr/local/share/tesseract-ocr/<v>/tessdata) now gets that directory
ahead of /usr/share, even when it holds fewer languages.

Verification

  • Published snap rev 43 extracted and run over the core22 rootfs (rev 2955)
    in a container, with the snap's environment and Python 3.10: current
    main returns None and fails; this branch finds
    $SNAP/usr/share/tesseract-ocr/4.00/tessdata, OCRs to .txt and .pdf
    with the right text, and lists deu, eng, fra, osd, por, spa.
  • Parity, old vs new _find_tessdata, over 638,976 layout/binary/platform
    combinations: differences only where the binary sits under /usr/local,
    /opt/homebrew or the snap with a versioned tree under its own prefix.
  • Mutation testing on Windows, Linux without Tesseract and Linux with
    Tesseract: every behavioural mutant is killed.
  • Full suite: Windows 809 passed / 2 skipped; Linux 808 passed / 3 skipped
    (with and without Tesseract installed).
  • PyInstaller build: app.tools._ocr_paths is in the bundle.

Not exercised: real snapd confinement (AppArmor/seccomp), a core24 snap,
macOS.

Known issues, not addressed here

  • The OCR language combo is rebuilt inside the run and resets to its first
    entry, so with this fix the first OCR in the snap runs in German whatever
    was selected. Pre-existing; separate fix to follow before the release.
  • Ghostscript in the snap cannot find gs_init.ps (needs GS_LIB), so
    Compress silently skips its Ghostscript pass. Same class of defect;
    separate fix.

🤖 Generated with Claude Code

The snap (base core22) stages Ubuntu 22.04's tesseract-ocr debs, so the
binary is $SNAP/usr/bin/tesseract and the language data is
$SNAP/usr/share/tesseract-ocr/4.00/tessdata. _find_tessdata never looked
there: the versioned lookup was hard-wired to /usr/share and the prefix
derivation only tried the flat <prefix>/share/tessdata. It returned
None, TESSDATA_PREFIX was never set, and tesseract fell back to its
compiled-in /usr/share/tesseract-ocr/4.00/tessdata, which inside the
snap resolves against the core22 base, where no Tesseract data is
installed. OCR in the published snap (rev 43, 1.15.0) fails with
"Error opening data file".

Add a versioned lookup under the binary's own prefix,
<prefix>/share/tesseract-ocr/<version>/tessdata, newest first, on Linux
and macOS, right after the adjacent tessdata probe. Deriving it from the
binary instead of pinning $SNAP or 4.00 also finds the
tesseract-ocr/5/tessdata layout of the Tesseract 5 debs, and does not
send a tesseract outside the snap to the snap's data when SNAP leaks
into its environment. For /usr/bin/tesseract it is the same lookup as
before, and the Windows lookup is unchanged. A tesseract under another
prefix that carries its own versioned tessdata, such as /usr/local, now
gets that directory ahead of /usr/share, even when it holds fewer
languages.

Move _find_tesseract and _find_tessdata to app/tools/_ocr_paths.py,
which imports neither Qt nor app.*; app.tools.ocr keeps both names
bound.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying pdfapps with  Cloudflare Pages  Cloudflare Pages

Latest commit: fde39cb
Status: ✅  Deploy successful!
Preview URL: https://17212479.pdfapps.pages.dev
Branch Preview URL: https://fix-snap-ocr-tessdata.pdfapps.pages.dev

View logs

@nelsonduarte
nelsonduarte merged commit 674bef3 into main Oct 9, 2026
5 checks passed
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