Skip to content

Recognize text in scans and pictures with Tesseract (OCR, #288) - #429

Merged
KnifeLemon merged 15 commits into
KnifeLemon:mainfrom
cre8ive-marketing:feature/ocr
Oct 23, 2026
Merged

KnifeLemon merged 15 commits into
KnifeLemon:mainfrom
cre8ive-marketing:feature/ocr

Conversation

@cre8ive-marketing

Copy link
Copy Markdown
Collaborator

What does this change?

Adds text recognition (OCR) with Tesseract, as asked in #288 (and #226). Scans and pictures become searchable PDFs, and their text goes into DOCX, TXT, Markdown and HWPX, so a scanned PDF → DOCX gives text you can edit instead of pictures of the pages.

For users

  • A Recognize text (OCR) box in the preset editor (PDF card), for PDF, DOCX, TXT, Markdown and HWPX targets, with a language list.
  • 69 languages, each listed under its own name ("Deutsch", "日本語"), English first. A language that isn't downloaded yet shows its size; it downloads the first time a conversion needs it (0.4–10 MB).
  • A built-in Searchable PDF preset (settings schema 33), after Compress PDF and on no donut, like Compress PDF.
  • PDF pages that already have text are copied as they are. Only pages without text are recognized, so born-digital pages are never turned into pictures. A PDF that has text on every page is copied, with a note.

Engine

  • Tesseract is a new optional package in Settings → Engines. It is offered, not suggested.
  • Windows: UB Mannheim's 5.4.0 build, the one Tesseract's own documentation points to. It is published only as an NSIS installer, which is never run: Filee's bundled 7-Zip unpacks it (new nsis kind), and TrimTesseract removes the training programs, manuals and installer files (~160 MB on disk). It is a MinGW build, so it doesn't need the VC++ runtime.
  • Linux and macOS: the system's Tesseract (apt install tesseract-ocr, brew install tesseract), found like Ghostscript, with the same guidance texts.
  • Languages: tessdata_fast 4.1.0, pinned in Infrastructure/ocr-languages.json (URL, SHA-256, size), installed by EngineInstaller (new traineddata kind) into engines/ocr-languages/<code>.

How it works

  • ConversionEdge.Ocr and RoutePlanner.Plan(ocr: true): a route starts with Tesseract's picture/PDF → PDF edge, then takes the cheapest ordinary route from that PDF. A picture Tesseract can't open (HEIC, PSD, …) becomes a PNG first. OCR edges are never part of an ordinary route. Preset.RecognizesTextOf decides, like SavesFramesOf; it is used in JobQueue (merges too) and PresetAvailability.
  • TesseractConverter renders the pages without text at 300 dpi with PDFium. It recognizes several pages at a time with OMP_THREAD_LIMIT=1, then puts the document back together with PDFsharp (pages and document info; bookmarks and form fields don't come along). It passes the job's own copy of the language data with --tessdata-dir, and -c tessedit_create_pdf=1, because the pdf config file lives in Tesseract's own tessdata folder.
  • PdfDocumentReader.ReadWithOcrLayer: with OCR on, DOCX, HWPX and Markdown read the invisible layer as the page's text, the scan behind it is left out, and Tesseract's GlyphLessFont is dropped. With OCR off nothing changes: an OCR layer stays invisible and the page stays a picture.

Docs: docs/ENGINES.md (engine table, optional engines, a new "Text recognition (OCR)" section), THIRD-PARTY-NOTICES.md (Tesseract, Leptonica, tessdata_fast), and the README privacy policy, which now names the language downloads. Only the English README is changed; I didn't want to guess the other eleven translations of that line.

Settings schema 33, like #351, #393 and #401: this will need renumbering. Happy to do that, or leave it to you.

How was it tested?

  • dotnet format --verify-no-changes
  • dotnet test with Tesseract 5.4, FFmpeg 9.0.2 and rhwp 0.8.7: Platform 48, Core 461, Cli 27, Setup 145, Engines 1469, App 807 pass, none fail.
  • New tests:
    • OcrRouteTests (Core):
      • OCR edges stay out of ordinary routes.
      • Routes with OCR start with Tesseract (also via PNG for HEIC); there's no route without Tesseract.
      • RecognizesTextOf for sources and targets.
      • A job runs Tesseract before the DOCX writer, and merged PDFs are recognized first.
      • A version 32 library gets Searchable PDF after Compress PDF.
    • OcrLanguageListTests: all 69 languages pinned (SHA-256, URL) and named; Tesseract offered but not suggested.
    • RenderTests (App): the Searchable PDF preset shows the box and the language list; German into DOCX is saved; a PNG target hides the box and doesn't keep it on.
    • EngineInstallerTests: a traineddata download lands in its own folder; TrimTesseract keeps tesseract.exe, the DLLs and doc/.
    • OcrTests, with real Tesseract 5.4 (skipped when it isn't installed):
      • picture → searchable PDF;
      • scanned PDF → DOCX with the text and no picture;
      • mixed PDF (the page with text is copied unchanged, only the scan is recognized);
      • an all-text PDF is copied with the note;
      • German downloaded on demand reads "Größe" and "Straße" into TXT.
  • pwsh build/fetch-engines.ps1 -Only 7zip,tesseract sets up the engine for development.

Screenshots (UI changes)

The PDF card of the preset editor gets the "Recognize text (OCR)" box, its hint and, when it's ticked, the language list (from the new render test):

English 한국어
OCR option in English OCR option in Korean

Checklist

  • New UI strings are in all src/Filee.App/Assets/i18n/*.json files
  • New third-party code or binaries are listed in THIRD-PARTY-NOTICES.md

Closes #288.

…ress

Engine package, language downloads, OCR routes, PDF reader OCR layer, tests. Still to do: preset editor UI, translations, Searchable PDF preset, docs.
The preset editor gets Recognize text (OCR) with a language list for PDF, DOCX, TXT, Markdown and HWPX targets, in all 12 UI languages. Settings schema 33 adds the Searchable PDF preset after Compress PDF. ENGINES.md, THIRD-PARTY-NOTICES.md and the README privacy policy mention Tesseract and its language downloads.
@Perricheno

Copy link
Copy Markdown
Contributor

@cre8ive-marketing This is a really thoughtful Tesseract integration, especially the handling of mixed born-digital/scanned PDFs and on-demand language data.

One OCR backend worth considering as a follow-up is Indra OCR (model, announcement). It is CPU-only, uses ONNX Runtime rather than PyTorch, and can return text/Markdown plus line and block bounding boxes, layout labels, confidence, and reading order. That structured JSON could be especially useful for Filee's editable DOCX/Markdown/HWPX routes rather than treating OCR as plain text only.

According to Datalab's current published benchmarks, it reaches about 44 pages/s on 32 CPU cores (~15× Tesseract and ~10× PaddleOCR on their setup), with a 46.7 OmniParseBench text score versus 35.8 for PaddleOCR and 19.3 for Tesseract. The main Latin recognizer is roughly 1.25M parameters; the complete default model set is 7.3M parameters and downloads about 76 MB.

I would probably keep Tesseract as the broad, mature baseline in this PR and consider Indra as an optional selectable engine afterward. There are a few packaging/licensing details to resolve first: it currently requires Python 3.10+ plus ONNX Runtime/OpenCV/pypdfium2, its documented tested platforms do not include Windows yet, and the model weights use a modified OpenRAIL-M license with commercial restrictions (the code itself is Apache-2.0). If those constraints fit Filee, it looks like a very promising local CPU backend.

@Perricheno

Copy link
Copy Markdown
Contributor

@cre8ive-marketing @KnifeLemon One technical reason Indra could be especially interesting for Filee is that it is not only a faster text recognizer: it already produces a structured page model. That could let Filee create genuinely useful .md files from PDFs and scans instead of a flat stream of OCR lines.

Indra output / behavior What Filee could do with it
page.markdown with headings, paragraphs, lists and HTML tables Direct PDF/image → structured Markdown, keeping much more of the document's meaning
Ordered blocks with label, bbox and text Map Section-Header, List-Group, Table, Caption, Footnote, etc. into Markdown, DOCX and HWPX structures
Lines with pixel-space bounding boxes and confidence Build a searchable-PDF text layer, preserve the visual scan, and optionally flag low-confidence regions
source = text / ocr / hybrid Reuse a good PDF text layer, OCR only missing content, and avoid degrading born-digital pages—very close to this PR's current strategy
Detected rotation, skew and vertical text Handle phone scans, sideways pages and CJK vertical layouts before export
Per-page timings and parallel workers Feed Filee's progress UI and process long PDFs page-by-page across CPU cores
Local --model-dir, ONNX Runtime, no GPU Fit the existing optional-engine/download model and remain fully offline after installation

A possible integration boundary could be:

PDF / image
    → Indra CLI (`--format json --mode auto`)
    → Filee OcrDocument { Page, Block, Line, box, confidence }
        ├─ Markdown writer: use semantic blocks / Indra markdown
        ├─ DOCX + HWPX writers: map headings, lists, tables and captions
        └─ Searchable PDF writer: scale line boxes from pixels to PDF points and overlay invisible text

That intermediate OcrDocument would also keep the architecture engine-neutral: Tesseract can remain the mature cross-platform default from this PR, while Indra becomes an optional layout-aware backend where its runtime and model license are acceptable. Filee could then add more OCR engines later without changing every output converter.

One honest limitation to expose in the UI/docs: Indra says simple grid tables work well, but complex tables with merged cells, nested headers or wrapped cell text can still be reconstructed incorrectly. Even with that caveat, its reading order and semantic blocks could make PDF → Markdown one of Filee's strongest conversion paths.

@cre8ive-marketing

Copy link
Copy Markdown
Collaborator Author

@Perricheno Thank you for the detailed write-up. The structured output (blocks, reading order, confidence) is exactly what an editable DOCX needs, so it's a useful pointer.

For Filee, though, I'll keep Tesseract as the only OCR engine, for now and as the default later. Filee's aim is to stay small and to run on every PC, low-end ones included. Indra doesn't fit that yet, for these reasons from your notes:

  • Runtime: it needs Python 3.10+ with ONNX Runtime, OpenCV and pypdfium2. Filee is a self-contained .NET app, and adding a Python stack plus models (~76 MB) to an optional engine would be heavier than the whole Tesseract package.
  • Windows: it isn't tested there yet, and most Filee users are on Windows.
  • License: the model weights use a modified OpenRAIL-M license with commercial restrictions, while Filee and everything it downloads can be used anywhere.
  • Speed on small PCs: the 44 pages/s figure is on 32 cores. On a 2- or 4-core laptop, the gap to Tesseract with tessdata_fast will be much smaller.

This PR is built with low-end machines in mind:

  • Tesseract is an optional download. The installer doesn't grow at all.
  • Each language is 0.4–10 MB (tessdata_fast) and is downloaded only when a preset uses it.
  • Pages are recognized with one thread each, so a 2-core PC isn't overloaded.
  • Only pages without text are rendered and recognized.

If Indra later ships a plain ONNX model with a permissive license that can run from .NET without Python, it would be worth another look as an optional engine.

@KnifeLemon KnifeLemon left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @cre8ive-marketing, this is thorough: OCR is off by default, Tesseract is offered rather than suggested, the NSIS installer is unpacked and never run, every language is pinned with a hash and downloaded only when used, and pages that already have text stay as they are. A few technical points while we settle how this fits with #372:

  1. Memory and disk on big scans. All pages are rendered to 300 dpi PNGs before the first Tesseract starts, so a 300-page scan puts several GB of PNGs in the work folder. Then MaxDegreeOfParallelism = ProcessorCount starts up to 16 or more Tesseract processes on a desktop CPU. Please render and recognize page by page (delete each PNG once its PDF exists) and cap the parallel runs, for example at 4.
  2. Scans with a stamp. A scanned page that carries a little real text (a page number or a Bates stamp added by the scanner software) counts as a page with text and is skipped. A text-coverage threshold would catch those; fine as a follow-up.
  3. The README privacy line is changed in English only. We'll do the other eleven READMEs when merging.
  4. Settings schema 33 is taken by earlier PRs; we'll renumber when merging.

CI for fork runs is waiting for approval; we'll start it.

@KnifeLemon

Copy link
Copy Markdown
Owner

For the record: #372 (@smjrifle) is working on the same feature (Tesseract plus Apple Vision on macOS) after our review there. We're reviewing both and haven't decided which approach goes in; I'll comment on both PRs once we have.

A page is rendered only when one of at most four runs (fewer on PCs with fewer cores) is free, and its picture is deleted once its PDF exists, so a long scan never has more than four 300 dpi pictures in the work folder.
@cre8ive-marketing

Copy link
Copy Markdown
Collaborator Author

@KnifeLemon Thanks for the careful review, and for the note about #372. Point 1 is fixed in 53f7384:

  1. Page by page, capped.
    • A page is rendered only when a Tesseract run is free.
    • At most 4 runs go side by side (TesseractConverter.Runs = Math.Clamp(ProcessorCount, 1, 4), so a 2-core PC runs 2), each still with one thread.
    • Each page's PNG is deleted as soon as its PDF exists, so a 300-page scan never has more than four 300 dpi pictures in the work folder.
    • If a page fails, no more pages are rendered and the error is reported once the running pages end.
    • New test A_long_scan_is_recognized_page_by_page_in_order: a 7-page scan, each page's word lands on its own page in order. docs/ENGINES.md describes the cap.
  2. Scans with a stamp: agreed, I'll leave the text-coverage threshold for a follow-up. A page would count as a scan when a picture covers most of it and it has only a little visible text, and no OCR layer.
  3. and 4. Thanks for taking the other READMEs and the schema number.

dotnet format --verify-no-changes is clean, and the Engines tests pass with Tesseract 5.4. Whichever way you go with #372, I'm happy to adapt this PR or close it.

# Conflicts:
#	docs/ENGINES.md
#	src/Filee.App/Assets/i18n/ar.json
#	src/Filee.App/Assets/i18n/en.json
#	src/Filee.App/Assets/i18n/es.json
#	src/Filee.App/Assets/i18n/fr.json
#	src/Filee.App/Assets/i18n/hi.json
#	src/Filee.App/Assets/i18n/ja.json
#	src/Filee.App/Assets/i18n/ko.json
#	src/Filee.App/Assets/i18n/pl.json
#	src/Filee.App/Assets/i18n/pt-BR.json
#	src/Filee.App/Assets/i18n/ru.json
#	src/Filee.App/Assets/i18n/zh-CN.json
#	src/Filee.App/Assets/i18n/zh-TW.json
#	src/Filee.Core/Presets/Preset.cs
#	src/Filee.Core/Settings/AppSettings.cs
#	src/Filee.Core/Settings/UserDataStore.cs
@cre8ive-marketing

Copy link
Copy Markdown
Collaborator Author

Merged main into this branch (dce4ef5); GitHub shows no conflicts now.

  • Settings: the Searchable PDF step is now v39, after main's 33–38 (CurrentSchemaVersion = 39). Its test upgrades a version 38 library.
  • Language files: each of the 12 existing files keeps main's new strings and the OCR ones. The new Thai and Nepali files have all 12 OCR strings, and every language file has the same keys as en.json.
  • Preset.cs: both RecognizesTextOf and main's JoinsIntoOneMedia are kept.
  • docs/ENGINES.md: main's FFmpeg row, with the Tesseract row before it.

dotnet format --verify-no-changes is clean. Full dotnet test with Tesseract 5.4: Platform 48, Core 508, Cli 27, Setup 149, Engines 1603 pass; App 848 pass and 1 fails, MemoryTrimmerTests.A_new_request_moves_the_trim_on, a timing test under the full run's load, which passes 3/3 alone and isn't touched here.

On the macOS arm64 CI runner the compactor task could start only after the workers had finished, so compactions stayed 0 and the test failed although nothing crashed. The loop now runs at least once.
@cre8ive-marketing

Copy link
Copy Markdown
Collaborator Author

The macOS arm64 check failed in NativeMemoryStressTests on Assert.True(compactions > 0), not in OCR code. On that runner the compactor task could start only after the three workers were done, so it never ran once. The latest commit makes its loop run at least once (do … while); the test's checks are otherwise unchanged and it passes locally. Main has the same test, so other PRs may hit this too.

@KnifeLemon

Copy link
Copy Markdown
Owner

@cre8ive-marketing @smjrifle An update on OCR, since #429 and #372 change the same code and only one approach can go in as it is.

We'd like to take #429 as the base: OCR off by default, Tesseract offered with languages downloaded when needed, pages with text left alone and the Searchable PDF preset. Then #372 adds Apple Vision on macOS on top of it, as the engine used there, so Filee gets the macOS built-in recognizer without a separate pipeline.

@cre8ive-marketing, I'll go through #429 again now. @smjrifle, I'll comment on #372 with what that means for your branch.

@cre8ive-marketing

Copy link
Copy Markdown
Collaborator Author

Thanks, that sounds like a good split. I'll keep #429 up to date with main and pick up your review points as they come. @smjrifle, if it helps your Apple Vision part, the Tesseract-specific code is all in Ocr/TesseractConverter.cs (render, recognize per page, merge). The routing (ConversionEdge.Ocr, Preset.RecognizesTextOf) and the OCR layer that DOCX and Markdown read (PdfDocumentReader.ReadWithOcrLayer) don't depend on which engine made the searchable PDF.

Review point 2 on KnifeLemon#429. A scanned page whose only text is a little visible
text the scanner software added (a page number, a Bates number) counted
as a page with text and was skipped. Now a page counts as a scan when a
picture covers at least half of it and its visible text covers under 1%
of it. An OCR layer (invisible text) always counts as text, so a page
recognized before is never recognized again, and a page drawn with little
text and no picture under it (a cover, a short note) is left alone.
@cre8ive-marketing

Copy link
Copy Markdown
Collaborator Author

@KnifeLemon Point 2 from your review (scans with a stamp) is now in this PR (e77c457, c7e4071):

  • A scan with a stamp is recognized. A page counts as a scan when:
    • a picture covers at least half of it, and
    • its only text is visible and covers under 1% of the page (a page number or Bates number added by the scanner software).
  • An OCR layer always counts as text. Invisible text means the page was recognized before, so it is never recognized again.
  • A drawn page with little text and no picture under it is left alone. Examples: a cover or a short note. It isn't turned into a scan.
  • Tests: they use small hand-written PDFs, so they run without Tesseract. The cases:
    • stamp on a scan → recognized
    • OCR layer → left alone
    • full page of text over a picture → left alone
    • short note without a picture → left alone
  • ENGINES.md explains the rule.

All 83 OCR tests pass locally with Tesseract installed.

main took settings schema 39 for .ps1 (KnifeLemon#474), so the Searchable PDF step
moves to v40 (CurrentSchemaVersion = 40); its test upgrades a version 39
library. README: main's one-line engines entry, with the OCR languages.

@KnifeLemon KnifeLemon left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @cre8ive-marketing. Point 1 from last time is done well: a page is rendered only when a run is free, at most four runs go side by side with one thread each, every PNG is deleted once its PDF exists, and a failed page stops the rendering after the running pages end. The stamp rule in e77c457 is a good answer to point 2 too: an OCR layer always counts as text, and a picture over half the page with under 1 % visible text counts as a scan. The merge with main is clean (schema 39, all 14 language files), and the NativeMemoryStressTests fix is right; main has the same flaky loop.

I built c7e4071 here: Core 507/510 (3 skipped as usual), Engines 1610/1621 on a552a14 (8 skipped; the 3 failures are this PC's LibreOffice/H2Orestart timeout, a calibre e-book PDF and a tracing timing test, none touched here), and on c7e4071 the OCR, installer and stress tests 83/99 (the 16 skipped need Tesseract or FFmpeg live-photo tools). The App tests that cover this (preset editor, availability, localization, renders in every language) pass. CI is green on every job, but the runners have no Tesseract, so the real recognition tests are skipped there; we'll run them once with fetch-engines.ps1 -Only 7zip,tesseract before merging.

Two things before we merge:

  1. The preset's other PDF options are dropped when OCR is on. With "Recognize text" the route to PDF ends at Tesseract (PlanWithOcr adds nothing when the target is PDF), so a PDF → PDF preset that also compresses, writes one file per page or removes metadata silently does none of it. RecognizePdfAsync even copies Title, Author, Subject and Keywords into the new file when "Remove metadata" is ticked, and the "every page already has text" shortcut copies the file as it is. For pictures, the page size and margin are ignored too (Tesseract makes the page the picture's size). The editor shows all of these next to the OCR box. The simplest fix is to make them exclusive: hide compression, one file per page, "Remove metadata", page size and margin while "Recognize text" is ticked, and clear them in Apply when OCR is on (plus: don't copy the document information when RemoveMetadata is set). Running main's PDF → PDF step after the OCR step works too, if the page range is applied in only one of the two steps. A test with OCR + "Remove metadata" and OCR + one file per page would keep it that way.
  2. Paths with non-ASCII characters on Windows. Tesseract gets full paths for the picture, the work folder and --tessdata-dir. The work folder is under %TEMP%, which contains the user name, and pictures are passed from where they are (스캔.jpg in C:\Users\김민수\Documents). Some Windows builds of Tesseract and Leptonica open files through the ANSI code page and fail on such paths. I couldn't check it here (no Tesseract on this PC). Could you try a picture and a scanned PDF with Korean or Cyrillic names, in a folder with such a name? If it fails, running Tesseract with workingDirectory: scratch (ProcessRunner takes it) and relative names (copy the picture into the scratch folder first, --tessdata-dir tessdata) avoids it whatever the user name is.

Smaller, fine as follow-ups:

  • A born-digital page with a full-bleed photo and a short caption (a title slide, a photo page in a brochure) now also counts as a scan, so its real text is rasterized. Counting only text near the top or bottom edge as a stamp (where scanners put page and Bates numbers) would keep those pages as they are.
  • Pictures are recognized one at a time: MaxParallelism => 1 gates the whole engine and each run has one thread, so 50 photos go strictly one after another. One shared SemaphoreSlim(Runs) around every Tesseract process, with MaxParallelism => Runs, would keep the cap at four and let pictures run side by side.
  • When a PDF job is cancelled while pages are being recognized, free.WaitAsync throws and RecognizePdfAsync leaves without waiting for the running pages, so the queue can start deleting the work folder while Tesseract still writes into it. A try/finally that awaits runs (ignoring their errors) closes that.
  • Every preset starts with English as the OCR language. Defaulting it to the UI language where tessdata has one (kor, jpn, …) would save most users a step.

On our side at merge time: the Korean strings engine.tesseract.description, presets.ocr_hint and engines.package.tesseract.description go to 해요체 like the rest of ko.json, the OcrPresets() comment says "settings schema 33" (it's 39), and the privacy line goes into README.fr.md, README.pt-BR.md and README.th.md. A correction to my earlier note: only those three translations have the privacy section, not eleven. This PR goes in first of the open ones, so schema 39 stays as it is.

To get this into the next release, we'll push the remaining changes to your branch ourselves today (maintainer edits are on). Have a look at the commits when they land, and tell us if anything looks off.

@cre8ive-marketing

Copy link
Copy Markdown
Collaborator Author

Merged main into this branch (9993b9a). GitHub shows no conflicts now.

dotnet format --verify-no-changes is clean. Locally, Core (511) and the OCR tests (83) pass.

…#429)

1. With "Recognize text" the editor hides one file per page, compression
   (with removing metadata), page size and margin, and clears them in
   Apply: Tesseract makes the PDF, so none of them would happen. A scanned
   PDF with "Remove metadata" no longer gets the source's title, author,
   subject and keywords.
2. Tesseract runs in the job's scratch folder and sees only plain relative
   names there (the picture is copied in as picture.<ext>, the language
   in tessdata), so a user name or folder in Korean or Cyrillic can't
   trip a build that opens files through the ANSI code page.
- A cancelled or failed PDF waits for the running pages before the work
  folder can be removed.
- The OcrPresets() comment names schema 40.
@cre8ive-marketing

Copy link
Copy Markdown
Collaborator Author

Thanks @KnifeLemon. Both points are in 327224b (and 6dab0c0, format only), so they won't clash with what you push:

  1. Other PDF options with OCR: they are now exclusive, as you suggested.
    • While "Recognize text" is ticked, the editor hides one file per page, compression (and with it "keep metadata"), page size and margin, and Apply clears them.
    • RecognizePdfAsync no longer copies Title, Author, Subject and Keywords when RemoveMetadata is set.
    • Tests: an editor test checks that these options are hidden and cleared, and that they come back when OCR is off. A Tesseract test checks that OCR with "Remove metadata" leaves no title or author but keeps the text.
  2. Non-ASCII paths: I couldn't reproduce it here, because this PC has the "UTF-8 for worldwide language support" code page (ACP 65001). Tesseract 5.4.0 read 김민수 Документы\스캔.png with full paths. So I made the change you described anyway:
    • Tesseract now runs with workingDirectory: scratch and sees only relative names: the picture is copied in as picture.<ext>, the PDF pages are p<n>.png, and the language data is --tessdata-dir tessdata.
    • A new test recognizes a picture and a scanned PDF named in Korean and Cyrillic, in a Korean/Cyrillic folder. It needs Tesseract, so CI skips it.

From the smaller list:

  • Cancel or failure: a cancelled or failed PDF now waits for the running Tesseract pages, in a finally, before it leaves.
  • Comment: OcrPresets() now says the right schema.

The other smaller items are still open: stamps only near the edges, pictures running side by side, and the UI language as the default.

Schema: #474 (.ps1) was merged first and took 39 on main, so after merging main in (9993b9a) the Searchable PDF step is 40 (CurrentSchemaVersion = 40), and its test upgrades a version 39 library.

Tests: all 85 OCR tests pass here with Tesseract installed, along with the preset editor tests. The full suite on the merge commit passed: Core 511, Platform 48, CLI 27, Setup 149, Engines 1619 and App 852, none failed. dotnet format --verify-no-changes is clean.

KnifeLemon and others added 3 commits October 23, 2026 19:06
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…otes

- ko: engine.tesseract.description, presets.ocr_hint and
  engines.package.tesseract.description in the polite style of the rest
  of ko.json.
- README.fr, README.pt-BR and README.th (the translations with the
  privacy section): the OCR languages pinned in ocr-languages.json, as
  README.md has it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cre8ive-marketing cre8ive-marketing mentioned this pull request Oct 23, 2026
@KnifeLemon
KnifeLemon merged commit 8f9a438 into KnifeLemon:main Oct 23, 2026
10 checks passed
KnifeLemon added a commit that referenced this pull request Oct 23, 2026
#429 added the Searchable PDF preset as migration 40. Both migrations stay;
the PNG/JPEG download aliases become 41 and their tests start from 40.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
KnifeLemon added a commit to cre8ive-marketing/Filee that referenced this pull request Oct 23, 2026
ne.json and th.json: keep both the Replace-the-original strings and the OCR
notice from KnifeLemon#429.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cre8ive-marketing added a commit to cre8ive-marketing/Filee that referenced this pull request Oct 23, 2026
main took OCR (KnifeLemon#429), which touches the same PDF options:
- Preset.cs: both PdfOptions groups kept (watermark, page numbers,
  password next to Ocr, OcrLanguage, OcrTargets).
- PresetEditorViewModel: both kept in the constructor, the properties
  and Apply (finishing, then OCR clearing what it doesn't do).
- RenderTests: main's file with the two PDF finishing editor tests
  added back before the OCR one.
KnifeLemon added a commit to smjrifle/Filee that referenced this pull request Oct 23, 2026
KnifeLemon#429 (Tesseract, languages downloaded when used, "Searchable PDF") is the OCR
base now, so this branch keeps only the Apple Vision part and plugs it into
KnifeLemon#429's OCR step. The own OCR layer (IOcrEngine, OcrEngineRegistry,
ImageOcrConverter, TesseractOcrEngine, the Document OCR option, schema 33) is
gone.

- VisionConverter: the same OCR edges as TesseractConverter (pictures and
  PDFs -> searchable PDF), registered before it, so on a Mac the route planner
  takes Vision; unavailable on Windows and Linux. A preset language Vision
  doesn't read goes to Tesseract when it is installed, and is refused with
  error.ocr_needs_tesseract otherwise.
- AppleVision: the Objective-C runtime bridge from this PR, moved into
  Filee.Engines: newest revision, languages asked from the Mac, word boxes
  (boundingBoxForRange), cancel, objc_msgSend_stret on Intel, releases.
- OcrPdfWriter: the page picture with invisible text (render mode 3) in a
  glyphless TrueType font built in code; read like Tesseract's layer.
- PDFs share TesseractConverter.RecognizePdfAsync (pages with text copied).
- Preset editor: no download size for the languages Vision reads, a macOS hint.
- 3 new strings in all 14 languages; docs/ENGINES.md. No settings migration.

Co-authored-by: smjrifle <smjrifle@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New features

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature Request: Implement OCR engine for text recognition in image-based PDFs

3 participants