Tesseract.js: WASM-OCR im Browser für gescannte PDFs

Tesseract ist seit 2005 die de-facto-Standard-OCR-Engine der Open-Source-Welt. HP entwickelte sie ab 1985, gab sie später an Google, das sie als Open-Source-Projekt weiterpflegt. Tesseract.js ist der WebAssembly-Port, der die gesamte Engine im Browser laufen lässt, ohne Server, ohne Plugin. Hier steht, wie pdftxt.de Tesseract.js für gescannte PDFs nutzt, wie das Sprachmodell geladen wird und welche Accuracy man realistisch erwarten kann.

7 Min. Lesezeit 1.248 Wörter
Mateusz Viola

Von Mateusz Viola

Betreiber · PDF.js-Engine, Tesseract.js-OCR & Encoding-Mathematik

Veröffentlicht am 10.06.2026 · Zuletzt geprüft am 10.06.2026

Was Tesseract.js ist

Tesseract wurde von Ray Smith bei Hewlett-Packard ab 1985 entwickelt. Lange Zeit war die Engine proprietär, 2005 gab HP den Code an die UNLV (University of Nevada, Las Vegas) frei, 2006 übernahm Google die Pflege und veröffentlichte den Code als Apache-2.0-Open-Source. Seither ist Tesseract die Open-Source-OCR, an der sich alle Konkurrenten messen lassen müssen.

Tesseract.js (https://github.com/naptha/tesseract.js) ist ein WebAssembly-Port der Tesseract-Engine, gepflegt von Naptha und Kevin Kwok. Der Code wird per Emscripten von C++ zu WASM kompiliert und mit einer JavaScript-API umhüllt. Das Ergebnis: die volle Tesseract-Engine, lauffähig in jedem Browser ohne Plugins, ohne Server.

pdftxt.de nutzt Tesseract.js als Fallback-Pfad: wenn PDF.js bei einer Seite weniger als 10 Zeichen findet, heißt das in der Heuristik gescannt, und der Nutzer bekommt einen Banner-Hinweis: OCR aktivieren? Erst auf Klick wird Tesseract.js geladen, das Sprachmodell heruntergeladen und die Seite OCR-erkannt.

Singleton-Worker

Tesseract.js folgt einem Worker-Pattern: ein Worker wird mit einem Sprachmodell initialisiert, danach kann er beliebig viele Bilder hintereinander erkennen, ohne neu zu initialisieren. Die Initialisierung ist teuer (5 bis 10 Sekunden inkl. Modell-Download), die Recognition pro Seite ist deutlich schneller (1 bis 5 Sekunden).

Damit pro PDF-Konvertierung nicht ein neuer Worker initialisiert wird, hält pdftxt.de den Worker in einem Modul-globalen Singleton:

let workerInstance: Tesseract.Worker | null = null;
let workerLanguages: string | null = null;

async function getOcrWorker(language: string): Promise<Tesseract.Worker> {
  if (workerInstance && workerLanguages === language) {
    return workerInstance;
  }

  // Wenn Sprache wechselt, alten Worker terminieren
  if (workerInstance) {
    await workerInstance.terminate();
    workerInstance = null;
  }

  workerInstance = await Tesseract.createWorker(language);
  workerLanguages = language;
  return workerInstance;
}

Das ist die Standard-Implementierung für Singleton-Pattern in JavaScript. Beim ersten OCR-Aufruf wird der Worker erstellt, beim zweiten wird er wiederverwendet, beim Wechsel der Sprache (von deu auf eng oder deu+eng) wird der alte Worker terminiert und ein neuer erstellt. Memory-Management ist wichtig: ein nicht-terminierter Worker behält rund 100 MB Worker-Memory, das summiert sich bei Tab-Wiederverwendung schnell.

Sprachmodell-Loading

Das Sprachmodell ist eine .traineddata-Datei, die Tesseract intern als Trie speichert, mit Glyph-Templates, n-Gram-Statistiken und LSTM-Network-Gewichten. Für Deutsch ist die Datei deu.traineddata, rund 10 MB komprimiert. Tesseract.js lädt die Datei beim Worker-Init vom Tessdata-CDN:

const worker = await Tesseract.createWorker('deu', 1, {
  langPath: 'https://tessdata.projectnaptha.com/4.0.0_best/',
  cacheMethod: 'write',
});

Das cacheMethod: 'write' weist Tesseract.js an, das Modell im IndexedDB-Cache des Browsers zu speichern, damit der nächste Worker-Start in derselben Domain das Modell nicht erneut laden muss. Erfahrungswerte zeigen, dass der Modell-Load beim ersten Aufruf 3 bis 8 Sekunden dauert (je nach Bandbreite), beim zweiten Aufruf in derselben Session unter einer Sekunde, weil der Cache greift.

Es gibt drei Modell-Versionen pro Sprache:

  • fast (rund 4 MB): schnell, weniger genau, für mobile Geräte
  • best (rund 10 MB): Default in Tesseract.js, ausbalanciert
  • legacy (rund 25 MB): vollständiges Modell der Tesseract-3-Era

pdftxt.de nutzt best, weil das die beste Kombination aus Bandbreite und Accuracy für normalen Standarddruck ist.

Die OCR-Pipeline

Sobald der Worker bereit ist, kann pro Seite die OCR durchgeführt werden. Pro Seite braucht es ein Bild als Eingabe, nicht das Original-PDF. Das ist der Trick: pdftxt.de rendert jede Seite des PDFs mit PDF.js als Canvas in einer hohen Auflösung (300 dpi), übergibt die Canvas an Tesseract.js und bekommt den erkannten Text zurück:

Tesseract.js OCR-Pipeline für eine PDF-Seite
<rect class="box" x="40" y="60" width="120" height="60"/>
<text class="label" x="100" y="84">1. PDF-Seite</text>
<text class="small" x="100" y="102">PDF.js</text>
<text class="small" x="100" y="114">PDFPageProxy</text>

<line stroke="#1e3a8a" stroke-width="2" fill="none" marker-end="url(#arr2)" x1="160" y1="90" x2="200" y2="90"/>

<rect class="box" x="200" y="60" width="120" height="60"/>
<text class="label" x="260" y="84">2. Canvas-Render</text>
<text class="small" x="260" y="102">page.render()</text>
<text class="small" x="260" y="114">300 dpi</text>

<line stroke="#1e3a8a" stroke-width="2" fill="none" marker-end="url(#arr2)" x1="320" y1="90" x2="360" y2="90"/>

<rect class="box-alt" x="360" y="60" width="120" height="60"/>
<text class="label" x="420" y="84">3. Tesseract.js</text>
<text class="small" x="420" y="102">worker.recognize</text>
<text class="small" x="420" y="114">LSTM + Trie</text>

<line stroke="#1e3a8a" stroke-width="2" fill="none" marker-end="url(#arr2)" x1="480" y1="90" x2="520" y2="90"/>

<rect class="box" x="520" y="60" width="120" height="60"/>
<text class="label" x="580" y="84">4. RecognizeResult</text>
<text class="small" x="580" y="102">text + confidence</text>
<text class="small" x="580" y="114">words[]</text>

<line stroke="#1e3a8a" stroke-width="2" fill="none" marker-end="url(#arr2)" x1="580" y1="120" x2="580" y2="170"/>

<rect class="box-alt" x="300" y="170" width="240" height="50"/>
<text class="label" x="420" y="200">5. Per-Seite-Text in pages[]-Array sammeln</text>

<text class="small" x="360" y="255">Tesseract läuft im eigenen WASM-Worker. UI bleibt während OCR reaktiv.</text>
Die 5 Stationen der Tesseract-OCR-Pipeline pro PDF-Seite. PDF.js liefert die Seite als Canvas, Tesseract.js erkennt den Text, pdftxt.de sammelt die Ergebnisse in einem pages-Array.

Im Code:

async function ocrPage(pdfPage: PDFPageProxy, worker: Tesseract.Worker): Promise<string> {
  const viewport = pdfPage.getViewport({ scale: 300 / 72 });  // 300 dpi
  const canvas = new OffscreenCanvas(viewport.width, viewport.height);
  const ctx = canvas.getContext('2d');

  await pdfPage.render({ canvasContext: ctx as unknown as CanvasRenderingContext2D, viewport }).promise;

  const result = await worker.recognize(canvas as unknown as Tesseract.ImageLike);
  return result.data.text;
}

Die scale: 300 / 72 rechnet PDF-Punkte (1/72 inch) in 300-dpi-Pixel um. 300 dpi ist die Sweet-Spot-Auflösung für Tesseract: niedriger und die Glyphen werden zu klein für zuverlässige Erkennung, höher und die OCR-Pipeline wird unnötig langsam ohne Accuracy-Gewinn. Empfehlung der Tesseract-Doku ist 300 dpi für normalen Standarddruck.

Memory-Management

Tesseract.js ist Memory-hungrig. Ein einzelner Worker mit einem geladenen Sprachmodell belegt rund 80 bis 120 MB Browser-Memory. Bei deu+eng (zwei Modelle) entsprechend mehr. Wer den Worker nicht terminiert, behält diese Memory bis zum Tab-Close.

pdftxt.de terminiert den Worker nach Ablauf einer Session-Timeout-Logik (5 Minuten Inaktivität) oder spätestens beim Page-Unload:

window.addEventListener('beforeunload', async () => {
  if (workerInstance) {
    await workerInstance.terminate();
    workerInstance = null;
  }
});

Das ist nicht zwingend (der Browser räumt sowieso auf), aber es ist gute Praxis und verhindert, dass auf langsamen Geräten der Tab-Close hängt.

Accuracy-Realismus

Tesseract.js liefert in der Recognition-Result ein confidence-Feld pro Wort und einen Gesamt-Confidence pro Seite. Die Confidence ist eine Zahl zwischen 0 und 100. Erfahrungswerte:

  • Gescannter Standarddruck (Buchseite, klar, 10 bis 14 pt): Confidence 85 bis 95, Accuracy 95 bis 99 Prozent
  • Schlechter Scan, Schrägstellung 2 bis 5 Grad: Confidence 60 bis 80, Accuracy 80 bis 90 Prozent
  • Fettdruck-Werbedrucke, Magazin-Layout mit bunten Hintergründen: Confidence 40 bis 70, Accuracy 60 bis 85 Prozent
  • Handschrift: Tesseract ist hier praktisch nutzlos, Accuracy oft unter 30 Prozent

pdftxt.de zeigt den Confidence-Wert nicht in der UI, weil er für den Endnutzer mehr verwirrt als hilft. Die Vorschau-Textarea ist das wirksamste Feedback: wenn dort offensichtlich Unsinn steht, ist die Erkennung schlecht, dann hilft ein besserer Scan oder ein Original-PDF mehr als jeder Confidence-Wert.

Was bleibt von Tesseract.js

Tesseract.js ist Open-Source-OCR im Browser, in einer Qualität die vor zehn Jahren nur Server-Lösungen liefern konnten. Die Limitationen (single-threaded, Memory-hungrig, 95-Prozent-Accuracy) sind real, aber für den typischen Anwendungsfall (gescannte Standarddokumente, gelegentliche OCR) gut genug. Die Alternative wäre eine Server-OCR-API mit DPA-Pflicht, Kosten pro Seite und Datenschutz-Risiko, das ist für ein client-only Tool wie pdftxt.de keine echte Alternative.

Was bleibt: Tesseract.js ist die richtige Wahl für den OCR-Fallback. Die Sprachmodelle sind eine externe Abhängigkeit (Tessdata-CDN), die in der Datenschutzerklärung transparent erwähnt werden muss, das machen wir. Und die Performance-Erwartung muss realistisch kommuniziert werden: OCR ist langsam und nie perfekt, das ist ein technisches Limit, kein Tool-Bug.

FAQ

Häufige Fragen

Wie schnell ist Tesseract.js?

Auf moderner Desktop-Hardware (Apple M2, Ryzen 7000, Intel 12. Gen) rund 2 bis 5 Sekunden pro Standardseite mit deutschem Text. Auf Mobile (iPhone 13, mittlere Android-Geräte) eher 5 bis 15 Sekunden pro Seite. Die WASM-Engine ist single-threaded, der Worker trägt also nicht zur Parallelisierung bei. Für ein 10-Seiten-PDF auf einem Laptop sind 30 bis 50 Sekunden realistisch.

Wie gut ist die Accuracy für deutschen Text?

Für scharf gescannten Standarddruck (Bibel-Schrift Antiqua, Serifenlos, 10 bis 14 pt) liegt die Accuracy üblicherweise zwischen 95 und 99 Prozent. Das heißt: pro 100 Zeichen 1 bis 5 Fehler. Schlechte Scans, exotische Schriften (Frakturschrift, italienische Fettschrift), Handschrift oder Tabellen senken die Accuracy deutlich, im Worst-Case unter 80 Prozent. Tesseract ist nicht magisch, sondern eine klassische Computer-Vision-Pipeline.

Wie gross sind die Sprachmodelle?

Das eng-Modell ist rund 10 MB, das deu-Modell rund 10 MB, beide kommen vom Tessdata-CDN (tessdata.projectnaptha.com). Wenn der Nutzer deu+eng aktiviert, werden beide Modelle geladen, in Summe rund 20 MB. Die Modelle werden im Browser-Cache vorgehalten, der erste OCR-Lauf in einer Session ist also langsam, weitere Läufe gehen schneller. Es gibt zusätzlich große Modelle (rund 30 MB pro Sprache) mit höherer Accuracy, die pdftxt.de aus Bandbreiten-Gründen nicht standardmässig lädt.

Warum nutzt pdftxt.de Tesseract.js und nicht eine Server-OCR-API?

Drei Gründe. Erstens: DSGVO. Eine Server-OCR-API würde den Bild-Inhalt zur Verarbeitung übertragen, das ist mit vertraulichen Mandantenakten oder Patientenunterlagen rechtlich heikel und braucht einen Auftragsverarbeitungsvertrag. Zweitens: Kosten. Server-OCR kostet pro Seite oder pro Minute, client-OCR kostet nur die Bandbreite für das Sprachmodell. Drittens: Latenz. Server-OCR braucht Roundtrip plus Server-Compute, client-OCR braucht nur Client-Compute, ist also bei langsamer Internet-Verbindung teilweise schneller.

Wann ist OCR die falsche Lösung?

Wenn das Original-Dokument noch verfügbar ist. OCR ist ein Notfall-Tool für Dokumente, die nur als Scan existieren. Wenn das Dokument ursprünglich als Word-Datei, LaTeX-Source oder native PDF erstellt wurde, lohnt es sich immer, die Original-Datei zu suchen statt OCR auf ein Print-out anzuwenden. Das Original hat 100 Prozent Accuracy, OCR hat 95 Prozent. Bei wissenschaftlichen Texten, juristischen Dokumenten oder Verträgen sind diese 5 Prozent Unterschied gross genug, um Folgefehler zu erzeugen.

Anzeige

Quellen

Weitere Ratgeber

Weiterlesen

Alle Ratgeber

Anzeige
Anzeige
Anzeige
Anzeige