{"id":1908,"date":"2026-09-16T03:49:13","date_gmt":"2026-09-15T18:49:13","guid":{"rendered":"https:\/\/www.weschkalnies.de\/blog\/?p=1908"},"modified":"2026-09-16T20:50:59","modified_gmt":"2026-09-16T11:50:59","slug":"chrome-erweiterung-um-text-direkt-aus-bildern-zu-extrahieren","status":"publish","type":"post","link":"https:\/\/www.weschkalnies.de\/blog\/chrome-erweiterung-um-text-direkt-aus-bildern-zu-extrahieren\/","title":{"rendered":"Chrome-Erweiterung um Text direkt aus Bildern zu extrahieren"},"content":{"rendered":"<p>Manchmal entstehen kleine Tools aus einem ziemlich simplen Problem. Ab und zu kommt es vor, dass ich den Text gerne direkt aus einer Grafik zur Verf\u00fcgung h\u00e4tte. Nat\u00fcrlich gibt es daf\u00fcr OCR-Dienste und diverse Online-Tools. F\u00fcr ein paar W\u00f6rter einen Screenshot zu erstellen, diesen irgendwo hochzuladen und anschlie\u00dfend den erkannten Text wieder herauszukopieren, erschien mir allerdings unn\u00f6tig umst\u00e4ndlich.<\/p>\n<p>Also habe ich mir daf\u00fcr eine eigene Chrome-Erweiterung gebaut: <a href=\"https:\/\/github.com\/weschkalnies\/chrome-image-to-text\" target=\"_blank\" rel=\"noopener\">chrome-image-to-text<\/a><\/p>\n<h3>Bereich ausw\u00e4hlen, Text kopieren<\/h3>\n<p>Die Idee hinter der Erweiterung ist bewusst einfach gehalten.<\/p>\n<p>Nach dem Start der Erweiterung kann ich mit der Maus einen beliebigen Bereich der aktuellen Browseransicht markieren. Die Erweiterung erstellt daraus intern einen Bildausschnitt und versucht anschlie\u00dfend, den darin enthaltenen Text zu erkennen.<\/p>\n<p>Der erkannte Text erscheint in einem kleinen Dialog, kann dort noch bearbeitet und korrigiert werden und l\u00e4sst sich anschlie\u00dfend direkt in die Zwischenablage kopieren.<\/p>\n<p>Der Ablauf besteht damit im Grunde nur aus vier Schritten:<\/p>\n<p>1. Erweiterung anklicken<br \/>\n2. Bereich auf dem Bildschirm markieren<br \/>\n3. erkannten Text pr\u00fcfen oder bearbeiten<br \/>\n4. Text kopieren<\/p>\n<p>Mit Escape l\u00e4sst sich der Vorgang jederzeit abbrechen.<\/p>\n<h3>OCR komplett lokal im Browser<\/h3>\n<p>Ein Punkt war mir bei der Entwicklung besonders wichtig: **F\u00fcr die Texterkennung sollen keine Screenshots an irgendeinen externen Dienst geschickt werden.**<\/p>\n<p>Meine Erweiterung verwendet deshalb Tesseract.js f\u00fcr die OCR und f\u00fchrt die Erkennung vollst\u00e4ndig lokal aus. Aktuell sind Sprachmodelle f\u00fcr Deutsch und Englisch integriert. Eine Erweiterung um weitere Sprachen ist aber keine gro\u00dfe Aufgabe.<\/p>\n<p>Das bedeutet auch: Die f\u00fcr die OCR erzeugten Bilddaten und der erkannte Text verlassen den eigenen Rechner nicht.<\/p>\n<p>Gerade bei Screenshots finde ich das relevant. Schlie\u00dflich k\u00f6nnen auf dem Bildschirm schnell personenbezogene Daten, Kundendaten, interne Informationen oder andere Inhalte sichtbar sein, die ich nicht f\u00fcr eine einfache Texterkennung an einen Cloud-Dienst \u00fcbertragen m\u00f6chte.<\/p>\n<p>Deshalb verzichtet die Erweiterung auch auf Telemetrie und externe OCR-Anfragen.<\/p>\n<h3>M\u00f6glichst wenige Chrome-Berechtigungen<\/h3>\n<p>Chrome-Erweiterungen k\u00f6nnen theoretisch ziemlich weitreichende Berechtigungen erhalten. Auch das wollte ich m\u00f6glichst restriktiv integrieren.<\/p>\n<p>Die Erweiterung ben\u00f6tigt keine dauerhafte Berechtigung f\u00fcr s\u00e4mtliche besuchten Webseiten. Stattdessen arbeitet sie im Wesentlichen mit `activeTab` und `scripting` und wird damit gezielt f\u00fcr den aktuellen Tab aktiv.<\/p>\n<p>Auch der Dialog mit dem erkannten Text ist bewusst vom Inhalt der eigentlichen Webseite getrennt. Er l\u00e4uft in einem geschlossenen Shadow DOM, damit Skripte der ge\u00f6ffneten Webseite nicht einfach auf das OCR-Ergebnis zugreifen k\u00f6nnen.<\/p>\n<p>Das ist f\u00fcr ein so kleines Tool vielleicht mehr technischer Aufwand als unbedingt notwendig \u2013 aber gerade bei Browser-Erweiterungen halte ich einen m\u00f6glichst kleinen Berechtigungsumfang f\u00fcr sinnvoll.<\/p>\n<h3>Ein kleines Projekt mit einigen interessanten Details<\/h3>\n<p>Was zun\u00e4chst nach einer recht einfachen Erweiterung klingt, hat bei der Umsetzung dann doch einige interessante technische Details mitgebracht.<\/p>\n<p>Beispielsweise muss der auf dem Bildschirm markierte Bereich korrekt auf den tats\u00e4chlichen Screenshot \u00fcbertragen werden. Dabei spielen Display-Skalierung und High-DPI-Monitore eine Rolle. Die Koordinaten des sichtbaren Browserfensters entsprechen nicht zwangsl\u00e4ufig 1:1 den Pixeln des erzeugten Screenshots.<\/p>\n<p>Dazu kommen die Besonderheiten von Chrome Manifest V3, Service Workern und der dynamischen Injection des Content Scripts.<\/p>\n<p>Auch die OCR selbst l\u00e4uft nicht einfach einmalig als Funktion durch. Tesseract arbeitet mit einem Worker, dessen Lebenszyklus innerhalb einer Browser-Erweiterung sauber verwaltet werden muss.<\/p>\n<p>Aus dem urspr\u00fcnglich kleinen \u201eIch m\u00f6chte Text aus einem Bild kopieren\u201c-Projekt wurde dadurch nebenbei ein ganz interessantes Experiment mit der Architektur moderner Chrome-Erweiterungen.<\/p>\n<h3>Installation<\/h3>\n<p>Zur Installation, einfach das Release auf Github herunterladen, Archiv in ein Verzeichnis entpacken, in Chrome chrome:\/\/extensions\/ aufrufen und dort auf &#8222;Entpackte Erweiterung&#8220; laden das Verzeichnis &#8218;\/deploy&#8216; ausw\u00e4hlen und schon ist die Erweiterung geladen und kann eingesetzt werden.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Manchmal entstehen kleine Tools aus einem ziemlich simplen Problem. Ab und zu kommt es vor, dass ich den Text gerne direkt aus einer Grafik zur Verf\u00fcgung h\u00e4tte. Nat\u00fcrlich&#8230;<\/p>\n","protected":false},"author":4,"featured_media":1909,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[142,10],"tags":[154],"class_list":["post-1908","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-apps","category-releases","tag-chrome-erweiterung"],"_links":{"self":[{"href":"https:\/\/www.weschkalnies.de\/blog\/wp-json\/wp\/v2\/posts\/1908","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.weschkalnies.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.weschkalnies.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.weschkalnies.de\/blog\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/www.weschkalnies.de\/blog\/wp-json\/wp\/v2\/comments?post=1908"}],"version-history":[{"count":6,"href":"https:\/\/www.weschkalnies.de\/blog\/wp-json\/wp\/v2\/posts\/1908\/revisions"}],"predecessor-version":[{"id":1915,"href":"https:\/\/www.weschkalnies.de\/blog\/wp-json\/wp\/v2\/posts\/1908\/revisions\/1915"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.weschkalnies.de\/blog\/wp-json\/wp\/v2\/media\/1909"}],"wp:attachment":[{"href":"https:\/\/www.weschkalnies.de\/blog\/wp-json\/wp\/v2\/media?parent=1908"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.weschkalnies.de\/blog\/wp-json\/wp\/v2\/categories?post=1908"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.weschkalnies.de\/blog\/wp-json\/wp\/v2\/tags?post=1908"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}