Mit der Handschrifterkennungs-API können Sie Text aus handschriftlicher Eingabe in Echtzeit erkennen.
Was ist die Handwriting Recognition 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.
Empfohlene Anwendungsfälle für die Handwriting Recognition 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 bevorzugten Reihenfolge angeben:
const recognizer = await navigator.createHandwritingRecognizer({
languages: ['en'],
});
Die Methode gibt ein Promise zurück, das mit einer Instanz eines HandwritingRecognizer
aufgelöst wird, wenn der Browser die Anfrage erfüllen kann. Andernfalls wird die Zusicherung mit einem Fehler abgelehnt und die Handschrifterkennung ist nicht verfügbar. Aus diesem Grund sollten Sie zuerst die Unterstützung der Erkennungsfunktion für bestimmte Erkennungsfunktionen abfragen.
Unterstützung der Erkennungserkennung wird abgefragt
Wenn Sie navigator.queryHandwritingRecognizerSupport()
aufrufen, können Sie prüfen, ob die Zielplattform die von Ihnen beabsichtigten 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 empfiehlt es sich, dafür ein Canvas-Objekt zu verwenden. 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 starten möchten, rufen Sie die Methode startDrawing()
für die Erkennung auf. Bei dieser Methode wird ein Objekt mit verschiedenen Hinweisen verwendet, um den Erkennungsalgorithmus zu optimieren. Alle Hinweise sind optional:
- Die Art des eingegebenen Textes: 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 unwahrscheinlicher alternativer Vorhersagen, die zurückgegeben werden sollten (
alternatives
) - Eine Liste von Zeichen, die der Nutzer mit hoher Wahrscheinlichkeit eingeben wird
(
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 Zeigerereignissen 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 die Kontur erstellt haben, sollten Sie den ersten Punkt direkt hinzufügen. Da Sie später weitere Punkte hinzufügen, ist es sinnvoll, die Logik zur Punkterstellung 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 Zeiger wieder anhebt, können Sie die Kontur durch Aufrufen der addStroke()
-Methode in Ihre Zeichnung einfügen. Im folgenden Beispiel wird außerdem 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. 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 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 Versprechen zurück, das ein Array von Vorhersagen nach Wahrscheinlichkeit auflöst. Die Anzahl der Elemente hängt vom Wert ab, den Sie an den 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 auf dem Canvas erkannten Graphen 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 verbesserte Bearbeitungssteuerung, die Handschrift erkennen kann. 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 Bearbeitungssteuerelemente können jedoch 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 auf das input
-Ereignis warten.
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 Controlling Access to Powerful Web Platform Features (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, ob die Handschrifterkennung aktiv ist. Um Fingerprinting zu verhindern, implementiert der Browser Gegenmaßnahmen. So wird dem Nutzer beispielsweise eine Berechtigungsaufforderung angezeigt, wenn er einen möglichen Missbrauch erkennt.
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 Handwriting Recognition API wissen.
Informationen zum API-Design
Funktioniert die API nicht wie erwartet? Oder fehlen Methoden oder Eigenschaften, die Sie zur Umsetzung 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 weicht die Implementierung von der Spezifikation ab?
Melden Sie einen Fehler unter new.crbug.com. Geben Sie so viele Details wie möglich und eine einfache Anleitung für die Reproduktion an. Geben Sie dann Blink>Handwriting
in das Feld Komponenten ein.
Glitch eignet sich hervorragend, um schnell und einfach Reproduktionen zu teilen.
Unterstützung für die API anzeigen
Möchten Sie die Handwriting Recognition API verwenden? Ihre öffentliche Unterstützung hilft dem Chromium-Team, Funktionen zu priorisieren, und zeigt anderen Browseranbietern, wie wichtig es ist, sie zu unterstützen.
Im WICG Discourse-Thread können Sie uns mitteilen, wie Sie den Dienst 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
- Entwurf der Spezifikationen
- GitHub-Repository
- ChromeStatus
- Chromium-Fehler
- TAG-Überprüfung
- Intent to Prototype
- WebKit-Dev-Thread
- Position von Mozilla-Standards
Danksagungen
Dieses Dokument wurde von Joe Medley, Honglin Yu und Jiewei Qian geprüft.