Skip to content

fix(ocr): detect Homebrew tessdata on Apple Silicon and custom prefixes - #146

Merged
nelsonduarte merged 2 commits into
mainfrom
fix/tessdata-apple-silicon
Aug 3, 2026
Merged

fix(ocr): detect Homebrew tessdata on Apple Silicon and custom prefixes#146
nelsonduarte merged 2 commits into
mainfrom
fix/tessdata-apple-silicon

Conversation

@nelsonduarte

Copy link
Copy Markdown
Owner

Problem

On a macOS Apple Silicon Mac (a user's MacBook Air M5), extra OCR language
packs such as Hebrew never appeared. Root cause: _find_tessdata in
app/tools/ocr.py could not locate the tessdata directory on Homebrew
Apple Silicon.

Homebrew keeps the binary under <prefix>/bin but the language data under
<prefix>/share/tessdata:

  • Intel: /usr/local/bin/tesseract + /usr/local/share/tessdata
  • Apple Silicon: /opt/homebrew/bin/tesseract + /opt/homebrew/share/tessdata

The old function only probed:

  1. a tessdata folder adjacent to the binary (<dir>/tessdata) — which
    does not exist on Homebrew, and
  2. a fixed fallback list containing /usr/local/share/tessdata (Intel only),
    plus the Linux /usr/share/... paths and snap.

/opt/homebrew/share/tessdata was in neither, so on Apple Silicon the
function returned None, the app never set TESSDATA_PREFIX, and any
non-baked-in language pack was invisible.

Fix (additive, no existing behaviour changed)

  1. Prefix-relative derivation. Right after the adjacent bin/tessdata
    probe, derive <prefix>/share/tessdata from the binary
    (os.path.dirname(os.path.dirname(tess_exe)) + share/tessdata). This
    covers Intel, Apple Silicon and non-standard install prefixes in one
    generic step.
  2. Explicit fallback. Add /opt/homebrew/share/tessdata to the fixed
    linux/darwin fallback list (next to the existing
    /usr/local/share/tessdata) for the case where the binary is resolved via
    PATH and the derived prefix does not match.

Windows-adjacent lookup and the Linux
/usr/share/tesseract-ocr/<version>/tessdata reverse-sorted preference are
untouched.

Tests

New tests/test_ocr_tessdata.py (10 tests). All monkeypatch
os.path.isdir / glob.glob / sys.platform with a fictitious tess_exe,
so they run identically on the Windows and Linux CI runners (no macOS
runner, no dependency on real system paths):

  • Apple Silicon Homebrew -> /opt/homebrew/share/tessdata (was None)
  • Intel Homebrew regression -> /usr/local/share/tessdata
  • Custom prefix -> /opt/custom/share/tessdata (proves generic derivation)
  • Explicit /opt/homebrew/share/tessdata fallback when derived prefix misses
  • Adjacent bin/tessdata takes precedence (Windows layout)
  • Real Windows install path
  • Linux versioned tessdata + reverse-sort prefers latest (5 over 4.00)
  • Nothing found -> None; tess_exe=None -> None

The four Apple-Silicon / Intel / custom-prefix / fallback tests fail against
the pre-fix code (verified), confirming they are discriminative.

Full suite: 508 passed, 3 skipped, 0 failed. ruff check --select F,E9 app/tools/ocr.py: clean.

🤖 Generated with Claude Code

nelsonduarte and others added 2 commits August 3, 2026 15:24
_find_tessdata only probed a tessdata folder adjacent to the binary and,
as a fixed fallback, /usr/local/share/tessdata (Intel Homebrew). On an
Apple Silicon Mac the binary is /opt/homebrew/bin/tesseract but the data
lives in /opt/homebrew/share/tessdata, so the function returned None and
the app never set TESSDATA_PREFIX. Extra language packs such as Hebrew
were therefore invisible on a MacBook Air M5.

Fix (additive, no existing behaviour changed):
- Derive <prefix>/share/tessdata relative to the binary
  (<prefix>/bin/tesseract -> <prefix>/share/tessdata), checked right
  after the adjacent bin/tessdata probe. Covers Intel, Apple Silicon and
  non-standard install prefixes generically.
- Add /opt/homebrew/share/tessdata to the fixed linux/darwin fallback
  list for when the binary is resolved via PATH and the derived prefix
  does not match.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The prefix-relative derivation <prefix>/share/tessdata ran before the
versioned Linux lookup /usr/share/tesseract-ocr/<version>/tessdata. For
/usr/bin/tesseract the derivation yields the flat /usr/share/tessdata,
so on a system where both that stale dir and a newer versioned dir
exist, the stale one shadowed the versioned one - inverting the issue
#27 invariant (Ubuntu 24.04 ships v5 but the baked-in default points at
4.00).

Reorder _find_tessdata precedence: (1) adjacent bin/tessdata, (2)
reverse-sorted versioned /usr/share/tesseract-ocr/*/tessdata, (3)
relative <prefix>/share/tessdata derivation (still resolves Apple
Silicon /opt/homebrew, Intel /usr/local and custom prefixes since the
versioned glob finds nothing there), (4) fixed fallbacks. The relative
derivation keeps its `if tess_exe:` guard.

Add a discriminative Linux conflict test that fails against the old
ordering and passes after the reorder.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying pdfapps with  Cloudflare Pages  Cloudflare Pages

Latest commit: cc3311a
Status: ✅  Deploy successful!
Preview URL: https://0e58539f.pdfapps.pages.dev
Branch Preview URL: https://fix-tessdata-apple-silicon.pdfapps.pages.dev

View logs

@nelsonduarte
nelsonduarte merged commit ba9d15d into main Aug 3, 2026
4 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