Mit der Handwriting Recognition API können Sie Text aus handschriftlichen Eingaben in Echtzeit erkennen.
Was ist die Handwriting Recognition API?
Mit der Handwriting Recognition API können Sie die Handschrift (Tinte) Ihrer Nutzer in Text umwandeln. Einige Betriebssysteme enthalten solche APIs schon seit Langem. Mit dieser neuen Funktion können Ihre Web-Apps diese Funktion endlich nutzen. Die Konvertierung erfolgt direkt auf dem Gerät des Nutzers, funktioniert auch im Offlinemodus und es müssen keine Drittanbieterbibliotheken oder ‑dienste hinzugefügt werden.
Diese API implementiert die sogenannte „Online“- oder Near-Realtime-Erkennung. Das bedeutet, dass die handschriftliche Eingabe erkannt wird, während der Nutzer sie zeichnet. Dazu werden die einzelnen Striche erfasst und analysiert. Im Gegensatz zu „Offline“-Verfahren wie der optischen Zeichenerkennung (Optical Character Recognition, OCR), bei denen nur das Endprodukt bekannt ist, können Online-Algorithmen aufgrund zusätzlicher Signale wie der zeitlichen Abfolge und des Drucks einzelner Tintenstriche eine höhere Genauigkeit erzielen.
Vorgeschlagene Anwendungsfälle für die Handwriting Recognition API
Beispiele für die Verwendung:
- Notiz-Apps, in denen Nutzer handschriftliche Notizen erfassen und in Text übersetzen lassen möchten.
- Formularanwendungen, in denen Nutzer aufgrund von Zeitbeschränkungen einen Stift oder Finger zur Eingabe verwenden können.
- Spiele, bei denen Buchstaben oder Zahlen eingegeben werden müssen, z. B. Kreuzworträtsel, Galgenmännchen oder Sudoku.
Aktueller Status
Die Handwriting Recognition API ist ab Chromium 99 verfügbar.
Verwendung der Handwriting Recognition API
Funktionserkennung
Sie können die Browserunterstützung erkennen, indem Sie prüfen, ob die Methode createHandwritingRecognizer()
für das Navigator-Objekt vorhanden ist:
if ('createHandwritingRecognizer' in navigator) {
// 🎉 The Handwriting Recognition API is supported!
}
Wichtige Konzepte
Die Handwriting Recognition API wandelt handschriftliche Eingaben in Text um, unabhängig von der Eingabemethode (Maus, Touch, Eingabestift). Die API hat vier Hauptentitäten:
- Ein Punkt gibt an, wo sich der Mauszeiger zu einem bestimmten Zeitpunkt befand.
- Ein Strich besteht aus einem oder mehreren Punkten. Die Aufzeichnung eines Strichs beginnt, wenn der Nutzer den Mauszeiger absetzt (d.h. auf die primäre Maustaste klickt oder den Bildschirm mit dem Stift oder Finger berührt), und endet, wenn er den Mauszeiger wieder anhebt.
- Eine Zeichnung besteht aus einem oder mehreren Strichen. Die eigentliche Erkennung erfolgt auf dieser Ebene.
- Der Recognizer ist mit der erwarteten Eingabesprache konfiguriert. Damit wird eine Instanz einer Zeichnung mit der angewendeten Konfiguration des Erkenners erstellt.
Diese Konzepte werden als spezifische Schnittstellen und Wörterbücher implementiert, auf die ich gleich eingehen werde.
Erkennungssystem erstellen
Wenn Sie Text aus handschriftlichen Eingaben erkennen möchten, müssen Sie eine Instanz von HandwritingRecognizer
abrufen, indem Sie navigator.createHandwritingRecognizer()
aufrufen und Einschränkungen übergeben. Einschränkungen bestimmen das zu verwendende Handschrifterkennungsmodell. Derzeit können Sie eine Liste von Sprachen in der Reihenfolge ihrer Priorität angeben:
const recognizer = await navigator.createHandwritingRecognizer({
languages: ['en'],
});
Die Methode gibt ein Promise zurück, das mit einer Instanz von HandwritingRecognizer
aufgelöst wird, wenn der Browser Ihre Anfrage erfüllen kann. Andernfalls wird das Promise mit einem Fehler abgelehnt und die Handschrifterkennung ist nicht verfügbar. Aus diesem Grund sollten Sie zuerst abfragen, ob das Erkennungsmodul bestimmte Erkennungsfunktionen unterstützt.
Unterstützung für Erkennung abfragen
Mit dem Aufruf von navigator.queryHandwritingRecognizer()
können Sie prüfen, ob die Zielplattform die Handschrifterkennungsfunktionen unterstützt, die Sie verwenden möchten. Diese Methode verwendet dasselbe Constraint-Objekt wie die navigator.createHandwritingRecognizer()
-Methode, das die Liste der angeforderten Sprachen enthält. Die Methode gibt ein Promise zurück, das mit einem Ergebnisobjekt aufgelöst wird, wenn ein kompatibler Erkennungsdienst gefunden wird. Andernfalls wird das Promise mit null
aufgelöst.
Im folgenden Beispiel gilt:
- möchte Texte auf Englisch erkennen
- alternative, weniger wahrscheinliche Vorhersagen erhalten, sofern verfügbar
- Zugriff auf das Segmentierungsergebnis erhalten, d.h. auf die erkannten Zeichen, einschließlich der Punkte und Striche, aus denen sie bestehen
const result =
await navigator.queryHandwritingRecognizerSupport({
languages: ['en']
});
console.log(result?.textAlternatives); // true if alternatives are supported
console.log(result?.textSegmentation); // true if segmentation is supported
Wenn der Browser die vom Entwickler benötigte Funktion unterstützt, wird ihr Wert im Ergebnisobjekt auf true
gesetzt. Andernfalls wird er auf false
gesetzt.
Anhand dieser Informationen können Sie bestimmte Funktionen in Ihrer Anwendung aktivieren oder deaktivieren oder eine neue Anfrage für eine andere Gruppe von Sprachen senden.
Zeichnung beginnen
In Ihrer Anwendung sollten Sie einen Eingabebereich anbieten, in dem der Nutzer seine handschriftlichen Einträge vornehmen kann. Aus Leistungsgründen wird empfohlen, dies mithilfe eines Canvas-Objekts zu implementieren. Die genaue Implementierung dieses Teils geht über den Rahmen dieses Artikels hinaus. Sie können sich jedoch in der Demo ansehen, wie das funktioniert.
Rufen Sie die Methode startDrawing()
für die Erkennung auf, um eine neue Zeichnung zu starten. Diese Methode verwendet ein Objekt mit verschiedenen Hinweisen, um den Erkennungsalgorithmus zu optimieren. Alle Hinweise sind optional:
- Die Art des eingegebenen Texts: Text, E‑Mail-Adressen, Zahlen oder ein einzelnes Zeichen (
recognitionType
) - Art des Eingabegeräts: Maus, Touch oder Stift (
inputType
) - Der vorherige Text (
textContext
) - Die Anzahl der weniger wahrscheinlichen alternativen Vorhersagen, die zurückgegeben werden sollen (
alternatives
) - Eine Liste der für den Nutzer identifizierbaren Zeichen („Grapheme“), die der Nutzer höchstwahrscheinlich eingeben wird (
graphemeSet
)
Die Handwriting Recognition API ist gut mit Pointer Events kompatibel, die eine abstrakte Schnittstelle für die Verarbeitung von Eingaben von beliebigen Zeigegeräten bieten. Die Argumente des Zeigerereignisses enthalten den Typ des verwendeten Zeigers. Das bedeutet, dass Sie mit Zeigerereignissen den Eingabetyp automatisch ermitteln können. Im folgenden Beispiel wird die Zeichnung für die Handschrifterkennung automatisch erstellt, wenn das Ereignis pointerdown
zum ersten Mal im Handschriftbereich auftritt. Da pointerType
leer oder auf einen proprietären Wert festgelegt sein kann, habe ich eine Konsistenzprüfung eingeführt, um sicherzustellen, dass nur unterstützte Werte für den Eingabetyp der Zeichnung festgelegt werden.
let drawing;
let activeStroke;
canvas.addEventListener('pointerdown', (event) => {
if (!drawing) {
drawing = recognizer.startDrawing({
recognitionType: 'text', // email, number, per-character
inputType: ['mouse', 'touch', 'stylus'].find((type) => type === event.pointerType),
textContext: 'Hello, ',
alternatives: 2,
graphemeSet: ['f', 'i', 'z', 'b', 'u'], // for a fizz buzz entry form
});
}
startStroke(event);
});
Strich hinzufügen
Das pointerdown
-Ereignis ist auch der richtige Ort, um einen neuen Strich zu beginnen. Erstellen Sie dazu eine neue Instanz von HandwritingStroke
. Außerdem sollten Sie die aktuelle Zeit als Referenzpunkt für die nachfolgenden Punkte speichern, die hinzugefügt werden:
function startStroke(event) {
activeStroke = {
stroke: new HandwritingStroke(),
startTime: Date.now(),
};
addPoint(event);
}
Punkt hinzufügen
Nachdem Sie den Strich erstellt haben, sollten Sie ihm direkt den ersten Punkt hinzufügen. Da Sie später weitere Punkte hinzufügen werden, ist es sinnvoll, die Logik zum Erstellen von Punkten in einer separaten Methode zu implementieren. Im folgenden Beispiel wird mit der Methode addPoint()
die seit dem Referenzzeitstempel vergangene Zeit berechnet.
Die Zeitinformationen sind optional, können aber die Erkennungsqualität verbessern. Anschließend werden die X- und Y-Koordinaten aus dem Zeigerereignis gelesen und der Punkt wird dem aktuellen Strich hinzugefügt.
function addPoint(event) {
const timeElapsed = Date.now() - activeStroke.startTime;
activeStroke.stroke.addPoint({
x: event.offsetX,
y: event.offsetY,
t: timeElapsed,
});
}
Der pointermove
-Ereignis-Handler wird aufgerufen, wenn der Mauszeiger über den Bildschirm bewegt wird. Diese Punkte müssen auch dem Strich hinzugefügt werden. Das Ereignis kann auch ausgelöst werden, wenn sich der Zeiger nicht in einem „Down“-Zustand befindet, z. B. wenn der Cursor über den Bildschirm bewegt wird, ohne dass die Maustaste gedrückt wird. Der Event-Handler im folgenden Beispiel prüft, ob ein aktiver Strich vorhanden ist, und fügt den neuen Punkt hinzu.
canvas.addEventListener('pointermove', (event) => {
if (activeStroke) {
addPoint(event);
}
});
Text erkennen
Wenn der Nutzer den Zeiger wieder anhebt, können Sie den Strich der Zeichnung hinzufügen, indem Sie die addStroke()
-Methode aufrufen. Im folgenden Beispiel wird auch activeStroke
zurückgesetzt, sodass der pointermove
-Handler dem abgeschlossenen Strich keine Punkte hinzufügt.
Als Nächstes müssen Sie die Eingabe des Nutzers erkennen, indem Sie die Methode getPrediction()
für die Zeichnung aufrufen. Die Erkennung dauert in der Regel weniger als einige Hundert Millisekunden. Sie können also bei Bedarf wiederholt Vorhersagen ausführen. Im folgenden Beispiel wird nach jedem abgeschlossenen Strich eine neue Vorhersage ausgeführt.
canvas.addEventListener('pointerup', async (event) => {
drawing.addStroke(activeStroke.stroke);
activeStroke = null;
const [mostLikelyPrediction, ...lessLikelyAlternatives] = await drawing.getPrediction();
if (mostLikelyPrediction) {
console.log(mostLikelyPrediction.text);
}
lessLikelyAlternatives?.forEach((alternative) => console.log(alternative.text));
});
Diese Methode gibt ein Promise zurück, das mit einem Array von Vorhersagen aufgelöst wird, die nach Wahrscheinlichkeit sortiert sind. Die Anzahl der Elemente hängt vom Wert ab, den Sie an den Hinweis alternatives
übergeben haben. Sie können dieses Array verwenden, um dem Nutzer eine Auswahl möglicher Übereinstimmungen zu präsentieren und ihn eine Option auswählen zu lassen. Alternativ können Sie auch einfach die wahrscheinlichste Vorhersage verwenden, wie ich es im Beispiel tue.
Das Vorhersageobjekt enthält den erkannten Text und ein optionales Segmentierungsergebnis, das ich im nächsten Abschnitt erläutern werde.
Detaillierte Statistiken mit Segmentierungsergebnissen
Wenn die Zielplattform dies unterstützt, kann das Vorhersageobjekt auch ein Segmentierungsergebnis enthalten.
Dies ist ein Array, das alle erkannten Handschriftsegmente enthält. Ein Segment besteht aus dem erkannten, nutzeridentifizierbaren Zeichen (grapheme
), seiner Position im erkannten Text (beginIndex
, endIndex
) und den Strichen und Punkten, aus denen es besteht.
if (mostLikelyPrediction.segmentationResult) {
mostLikelyPrediction.segmentationResult.forEach(
({ grapheme, beginIndex, endIndex, drawingSegments }) => {
console.log(grapheme, beginIndex, endIndex);
drawingSegments.forEach(({ strokeIndex, beginPointIndex, endPointIndex }) => {
console.log(strokeIndex, beginPointIndex, endPointIndex);
});
},
);
}
Anhand dieser Informationen können Sie die erkannten Grapheme auf dem Canvas wiederfinden.
Vollständige Erkennung
Nachdem die Spracherkennung abgeschlossen ist, können Sie Ressourcen freigeben, indem Sie die Methode clear()
für HandwritingDrawing
und die Methode finish()
für HandwritingRecognizer
aufrufen:
drawing.clear();
recognizer.finish();
Demo
Die Webkomponente <handwriting-textarea>
implementiert ein progressiv erweitertes Bearbeitungselement mit Handschrifterkennung. Wenn Sie auf die Schaltfläche rechts unten im Bearbeitungsfeld klicken, wird der Zeichenmodus aktiviert. Wenn Sie die Zeichnung fertiggestellt haben, startet die Webkomponente automatisch die Texterkennung und fügt den erkannten Text wieder in das Bearbeitungselement ein. Wenn die Handwriting Recognition API überhaupt nicht unterstützt wird oder die Plattform die angeforderten Funktionen nicht unterstützt, wird die Schaltfläche „Bearbeiten“ ausgeblendet. Die grundlegende Bearbeitungssteuerung bleibt jedoch als <textarea>
verfügbar.
Die Webkomponente bietet Properties und Attribute, um das Erkennungsverhalten von außen zu definieren, darunter languages
und recognitiontype
. Sie können den Inhalt des Steuerelements über das Attribut value
festlegen:
<handwriting-textarea languages="en" recognitiontype="text" value="Hello"></handwriting-textarea>
Wenn Sie über Änderungen am Wert informiert werden möchten, können Sie auf das input
-Ereignis warten.
Hier finden Sie eine Demo auf Glitch. Sehen Sie sich auch den Quellcode an. Wenn Sie das Steuerelement in Ihrer Anwendung verwenden möchten, rufen Sie es von npm ab.
Sicherheit und Berechtigungen
Das Chromium-Team hat die Handwriting Recognition API gemäß den in Controlling Access to Powerful Web Platform Features definierten Grundsätzen entwickelt und implementiert, darunter Nutzerkontrolle, Transparenz und Ergonomie.
Kontrolle durch Nutzer
Die Handwriting Recognition API kann vom Nutzer nicht deaktiviert werden. Sie ist nur für Websites verfügbar, die über HTTPS bereitgestellt werden, und darf nur über den Browsing-Kontext der obersten Ebene aufgerufen werden.
Transparenz
Es gibt keine Anzeige dafür, ob die Handschrifterkennung aktiv ist. Um Fingerprinting zu verhindern, ergreift der Browser Gegenmaßnahmen, z. B. wird dem Nutzer eine Berechtigungsaufforderung angezeigt, wenn er möglichen Missbrauch erkennt.
Beibehalten von Berechtigungen
Für die Handwriting Recognition API werden derzeit keine Berechtigungsaufforderungen angezeigt. Daher muss die Berechtigung nicht auf irgendeine Weise gespeichert werden.
Feedback
Das Chromium-Team möchte mehr über Ihre Erfahrungen mit der Handwriting Recognition API erfahren.
Informationen zum API-Design
Funktioniert etwas an der API nicht wie erwartet? Oder fehlen Methoden oder Eigenschaften, die Sie für die Umsetzung Ihrer Idee benötigen? Haben Sie Fragen oder Anmerkungen zum Sicherheitsmodell? Melden Sie ein Spezifikationsproblem im entsprechenden GitHub-Repository oder fügen Sie Ihre Gedanken zu einem bestehenden Problem hinzu.
Problem mit der Implementierung melden
Haben Sie einen Fehler in der Chromium-Implementierung gefunden? Oder weicht die Implementierung von der Spezifikation ab?
Melden Sie einen Fehler unter new.crbug.com. Geben Sie dabei so viele Details wie möglich an, fügen Sie eine einfache Anleitung zur Reproduktion hinzu und geben Sie Blink>Handwriting
in das Feld Components (Komponenten) ein.
API-Support zeigen
Möchten Sie die Handwriting Recognition API verwenden? Ihr öffentlicher Support hilft dem Chromium-Team, Funktionen zu priorisieren, und zeigt anderen Browseranbietern, wie wichtig es ist, sie zu unterstützen.
Teilen Sie im WICG-Discourse-Thread mit, wie Sie die API verwenden möchten. Senden Sie einen Tweet an @ChromiumDev mit dem Hashtag #HandwritingRecognition
und teilen Sie uns mit, wo und wie Sie die Funktion verwenden.
Hilfreiche Links
- Erläuterung
- Spezifikationsentwurf
- GitHub-Repository
- ChromeStatus
- Chromium-Fehler
- TAG-Überprüfung
- Absicht, einen Prototyp zu erstellen
- WebKit-Dev-Thread
- Mozilla-Standards
Danksagungen
Dieses Dokument wurde von Joe Medley, Honglin Yu und Jiewei Qian geprüft.