Mit der Handschrifterkennungs-API können Sie Text aus handschriftlicher Eingabe in Echtzeit erkennen.
Was ist die Handschrifterkennung API?
Mit der Handschrifterkennungs-API können Sie die Handschrift (Tinte) Ihrer Nutzer in Text umwandeln. Einige Betriebssysteme haben solche APIs schon lange. Mit dieser neuen Funktion können Ihre Web-Apps diese Funktion endlich nutzen. Die Conversion erfolgt direkt auf dem Gerät des Nutzers und funktioniert auch im Offlinemodus – ganz ohne Bibliotheken oder Dienste von Drittanbietern.
Diese API implementiert die sogenannte „Onlineerkennung“ oder die Erkennung in nahezu Echtzeit. Das bedeutet, dass die handschriftliche Eingabe erkannt wird, während der Nutzer sie schreibt, indem die einzelnen Striche erfasst und analysiert werden. 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 dem Druck einzelner Tintenstriche eine höhere Genauigkeit bieten.
Vorgeschlagene Anwendungsfälle für die Handschrifterkennungs-API
Beispiele:
- Notiz-Apps, in denen Nutzer handschriftliche Notizen erstellen und in Text umwandeln lassen möchten
- Formulare, in denen Nutzer aufgrund von Zeitdruck Eingaben per Stift oder Finger machen können
- Spiele, bei denen Buchstaben oder Zahlen eingegeben werden müssen, z. B. Kreuzworträtsel, Galgenmännchen oder Sudoku.
Aktueller Status
Die Handschrifterkennungs-API ist ab Chromium 99 verfügbar.
Verwendung der Handschrifterkennung API
Funktionserkennung
Prüfe, ob der Browser unterstützt wird, indem du prüfst, ob die Methode createHandwritingRecognizer()
im Navigator-Objekt vorhanden ist:
if ('createHandwritingRecognizer' in navigator) {
// 🎉 The Handwriting Recognition API is supported!
}
Wichtige Konzepte
Die Handschrifterkennungs-API wandelt handschriftliche Eingaben in Text um, unabhängig von der Eingabemethode (Maus, Touch, Stift). Die API umfasst vier Hauptentitäten:
- Ein Punkt gibt an, wo sich der Cursor zu einem bestimmten Zeitpunkt befand.
- Ein Strich besteht aus einem oder mehreren Punkten. Die Aufzeichnung eines Strichs beginnt, wenn der Nutzer den Zeiger auf das Display setzt (d.h., auf die primäre Maustaste klickt oder den Bildschirm mit dem Stift oder Finger berührt) und endet, wenn er den Zeiger wieder anhebt.
- Eine Zeichnung besteht aus einem oder mehreren Strichen. Die eigentliche Erkennung erfolgt auf dieser Ebene.
- Der Erknerner ist für die erwartete Eingabesprache konfiguriert. Damit wird eine Instanz einer Zeichnung mit der angewendeten Erkennerkonfiguration erstellt.
Diese Konzepte werden als bestimmte Schnittstellen und Wörterbücher implementiert, auf die ich gleich näher eingehe.
Erkennungssystem erstellen
Wenn Sie Text aus handschriftlicher Eingabe erkennen möchten, müssen Sie eine Instanz von HandwritingRecognizer
abrufen. Rufen Sie dazu navigator.createHandwritingRecognizer()
auf und übergeben Sie ihm Einschränkungen. Mit Einschränkungen wird das zu verwendende Modell für die Handschrifterkennung festgelegt. Derzeit können Sie eine Liste von Sprachen in der Reihenfolge angeben, in der sie bevorzugt werden sollen:
const recognizer = await navigator.createHandwritingRecognizer({
languages: ['en'],
});
Die Methode gibt ein Versprechen zurück, das mit einer Instanz eines HandwritingRecognizer
aufgelöst wird, wenn der Browser Ihre Anfrage erfüllen kann. Andernfalls wird die Zusicherung mit einem Fehler abgelehnt und die Handschrifterkennung ist nicht verfügbar. Daher sollten Sie sich zuerst über die Unterstützung bestimmter Erkennungsfunktionen durch den Recognizer informieren.
Support für Erkennungssysteme anfragen
Wenn Sie navigator.queryHandwritingRecognizerSupport()
aufrufen, können Sie prüfen, ob die Zielplattform die von Ihnen vorgesehenen Funktionen zur Handschrifterkennung unterstützt. Im folgenden Beispiel hat der Entwickler Folgendes getan:
- möchte Text 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 { languages, alternatives, segmentationResults } =
await navigator.queryHandwritingRecognizerSupport({
languages: ['en'],
alternatives: true,
segmentationResult: true,
});
console.log(languages); // true or false
console.log(alternatives); // true or false
console.log(segmentationResult); // true or false
Die Methode gibt ein Versprechen zurück, das mit einem Ergebnisobjekt aufgelöst wird. Wenn der Browser die vom Entwickler angegebene Funktion unterstützt, wird der Wert auf true
gesetzt. Andernfalls wird er auf false
gesetzt.
Anhand dieser Informationen können Sie bestimmte Funktionen in Ihrer Anwendung aktivieren oder deaktivieren oder Ihre Abfrage anpassen und eine neue senden.
Zeichnen starten
In Ihrer App sollte ein Eingabebereich vorhanden sein, in dem Nutzer ihre handschriftlichen Einträge machen können. Aus Leistungsgründen wird empfohlen, dies mithilfe eines Canvas-Objekts zu implementieren. Die genaue Implementierung dieses Teils geht über den Rahmen dieses Artikels hinaus. In der Demo sehen Sie, wie das geht.
Wenn Sie eine neue Zeichnung beginnen möchten, rufen Sie die Methode startDrawing()
auf dem Erkennungsmodul auf. Bei dieser Methode wird ein Objekt mit verschiedenen Hinweisen verwendet, 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, Touchbedienung oder Eingabe per Stift (
inputType
) - Der vorherige Text (
textContext
) - Die Anzahl der weniger wahrscheinlichen alternativen Vorhersagen, die zurückgegeben werden sollen (
alternatives
) - Eine Liste der von Nutzern erkennbaren Zeichen („Grapheme“), die der Nutzer am wahrscheinlichsten eingibt (
graphemeSet
)
Die Handschrifterkennungs-API funktioniert gut mit Maus-Ereignissen, die eine abstrakte Schnittstelle zum Verbrauchen von Eingaben von beliebigen Eingabegeräten bieten. Die Argumente für das Zeigerereignis enthalten den verwendeten Zeigertyp. Sie können also den Eingabetyp automatisch anhand von Zeiger-Ereignissen bestimmen. Im folgenden Beispiel wird die Zeichnung für die Handschrifterkennung automatisch beim ersten Auftreten eines pointerdown
-Ereignisses im Handschriftbereich erstellt. Da pointerType
leer sein 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 sind.
let drawing;
let activeStroke;
canvas.addEventListener('pointerdown', (event) => {
if (!drawing) {
drawing = recognizer.startDrawing({
recognitionType: 'text', // email, number, per-character
inputType: ['mouse', 'touch', 'pen'].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 Ereignis pointerdown
ist auch der richtige Ort, um einen neuen Strich zu beginnen. Dazu erstellen Sie eine neue Instanz von HandwritingStroke
. Außerdem sollten Sie die aktuelle Uhrzeit als Referenzpunkt für die nachfolgenden Punkte speichern:
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 verstrichene Zeit ab dem Referenzzeitstempel berechnet.
Die Zeitangaben sind optional, können aber die Erkennungsqualität verbessern. Anschließend werden die X- und Y-Koordinaten aus dem Zeigerereignis gelesen und der Punkt 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 Ereignis-Handler pointermove
wird aufgerufen, wenn der Cursor über den Bildschirm bewegt wird. Diese Punkte müssen dem Strich ebenfalls hinzugefügt werden. Das Ereignis kann auch ausgelöst werden, wenn sich der Cursor nicht im Status „gedrückt“ befindet, z. B. wenn Sie den Cursor über den Bildschirm bewegen, ohne die Maustaste zu drücken. Der Event-Handler im folgenden Beispiel prüft, ob ein aktiver Stroke vorhanden ist, und fügt ihm den neuen Punkt hinzu.
canvas.addEventListener('pointermove', (event) => {
if (activeStroke) {
addPoint(event);
}
});
Text erkennen
Wenn der Nutzer den Mauszeiger wieder hebt, können Sie den Strich Ihrer Zeichnung hinzufügen, indem Sie die Methode addStroke()
aufrufen. Im folgenden Beispiel wird auch activeStroke
zurückgesetzt, sodass der pointermove
-Handler dem fertigen Strich keine Punkte hinzufügt.
Als Nächstes müssen Sie die Eingabe des Nutzers erkennen. Rufen Sie dazu die Methode getPrediction()
für die Zeichnung auf. Die Erkennung dauert in der Regel weniger als ein paar hundert Millisekunden. Sie können also bei Bedarf wiederholt Vorhersagen ausführen. Im folgenden Beispiel wird nach jedem vollständigen 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 Versprechen zurück, das ein Array von Vorhersagen nach Wahrscheinlichkeit auflöst. Die Anzahl der Elemente hängt vom Wert ab, den Sie dem alternatives
-Hinweis übergeben haben. Sie können dieses Array verwenden, um dem Nutzer eine Auswahl möglicher Übereinstimmungen anzubieten und ihn eine Option auswählen zu lassen. Alternativ können Sie sich einfach für die wahrscheinlichste Vorhersage entscheiden. Das habe ich in diesem Beispiel getan.
Das Vorhersageobjekt enthält den erkannten Text und ein optionales Segmentierungsergebnis, das ich im folgenden Abschnitt erläutern werde.
Detaillierte Statistiken mit Segmentierungsergebnissen
Wenn von der Zielplattform unterstützt, kann das Vorhersageobjekt auch ein Segmentierungsergebnis enthalten.
Dies ist ein Array, das alle erkannten Handschriftensegmente enthält, eine Kombination aus dem erkannten, vom Nutzer identifizierbaren Zeichen (grapheme
) zusammen mit 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
Nach Abschluss der Erkennung können Sie Ressourcen freigeben, indem Sie die Methode clear()
für die HandwritingDrawing
und die Methode finish()
für die HandwritingRecognizer
aufrufen:
drawing.clear();
recognizer.finish();
Demo
Die Webkomponente <handwriting-textarea>
implementiert eine schrittweise erweiterte Bearbeitungssteuerung mit Handschrifterkennung. Klicken Sie auf die Schaltfläche rechts unten im Bearbeitungskontrollelement, um den Zeichenmodus zu aktivieren. Sobald Sie die Zeichnung fertiggestellt haben, startet die Webkomponente automatisch die Erkennung und fügt den erkannten Text wieder dem Bearbeitungskontrollelement hinzu. Wenn die Handschrifterkennungs-API nicht unterstützt wird oder die Plattform die angeforderten Funktionen nicht unterstützt, wird die Schaltfläche „Bearbeiten“ ausgeblendet. Die grundlegenden Bearbeitungsoptionen können aber weiterhin als <textarea>
verwendet werden.
Die Webkomponente bietet Eigenschaften und Attribute, mit denen das Erkennungsverhalten von außen definiert werden kann, einschließlich 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 das Ereignis input
beobachten.
Sie können die Komponente mit dieser Demo auf Glitch ausprobieren. Sehen Sie sich auch den Quellcode an. Wenn Sie das Steuerelement in Ihrer Anwendung verwenden möchten, laden Sie es von npm herunter.
Sicherheit und Berechtigungen
Das Chromium-Team hat die Handschrifterkennungs-API unter Berücksichtigung der in Zugriff auf leistungsstarke Funktionen der Webplattform steuern definierten Grundprinzipien entwickelt und implementiert, einschließlich Nutzersteuerung, Transparenz und Ergonomie.
Nutzersteuerung
Die Handschrifterkennungs-API kann vom Nutzer nicht deaktiviert werden. Sie ist nur für Websites verfügbar, die über HTTPS ausgeliefert werden, und kann nur vom Browserkontext der obersten Ebene aufgerufen werden.
Transparenz
Es gibt keine Anzeige dafür, ob die Handschrifterkennung aktiv ist. Um das Fingerprinting zu verhindern, implementiert der Browser Gegenmaßnahmen, z. B. wird dem Nutzer eine Berechtigungsanfrage angezeigt, wenn ein möglicher Missbrauch erkannt wird.
Berechtigungsspeicherung
Die Handschrifterkennungs-API zeigt derzeit keine Berechtigungsaufforderungen an. Die Berechtigung muss also nicht auf irgendeine Weise beibehalten werden.
Feedback
Das Chromium-Team möchte mehr über Ihre Erfahrungen mit der Handschrifterkennungs-API erfahren.
Informationen zum API-Design
Funktioniert die API nicht wie erwartet? Oder fehlen Methoden oder Eigenschaften, die Sie zur Implementierung Ihrer Idee benötigen? Haben Sie Fragen oder Kommentare zum Sicherheitsmodell? Reichen Sie ein Problem mit der Spezifikation im entsprechenden GitHub-Repository ein oder fügen Sie Ihre Gedanken zu einem vorhandenen Problem hinzu.
Problem mit der Implementierung melden
Haben Sie einen Fehler in der Chromium-Implementierung gefunden? Oder unterscheidet sich die Implementierung von der Spezifikation?
Melden Sie den Fehler unter new.crbug.com. Geben Sie dabei so viele Details wie möglich an, eine einfache Anleitung zur Reproduktion und geben Sie Blink>Handwriting
in das Feld Components ein.
Glitch eignet sich hervorragend, um schnell und einfach Reproduktionen zu teilen.
Unterstützung für die API anzeigen
Planen Sie die Verwendung der Handschrifterkennungs-API? Ihre öffentliche Unterstützung 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 es verwenden möchten. Senden Sie einen Tweet an @ChromiumDev mit dem Hashtag #HandwritingRecognition
und teilen Sie uns mit, wo und wie Sie ihn verwenden.
Hilfreiche Links
- Erläuterung
- Spezifikationsentwurf
- GitHub-Repository
- ChromeStatus
- Chromium-Fehler
- TAG-Überprüfung
- Intent to Prototype
- WebKit-Entwickler-Thread
- Mozilla-Standpunkt zu Standards
Danksagungen
Dieses Dokument wurde von Joe Medley, Honglin Yu und Jiewei Qian geprüft.