L'API Handwriting Recognition ti consente di riconoscere il testo inserito a mano libera in tempo reale.
Che cos'è l'API Handwriting Recognition?
L'API Handwriting Recognition consente di convertire la scrittura a mano libera (inchiostro) degli utenti in testo. Alcuni sistemi operativi includono da tempo queste API e, con questa nuova funzionalità, le tue app web possono finalmente utilizzarle. La conversione avviene direttamente sul dispositivo dell'utente, funziona anche in modalità offline, il tutto senza aggiungere librerie o servizi di terze parti.
Questa API implementa il cosiddetto riconoscimento "online" o quasi in tempo reale. Ciò significa che l'input scritto a mano viene riconosciuto mentre l'utente lo disegna acquisendo e analizzando i singoli tratti. A differenza delle procedure "offline" come il riconoscimento ottico dei caratteri (OCR), in cui è noto solo il prodotto finale, gli algoritmi online possono fornire un livello di precisione superiore grazie a indicatori aggiuntivi come la sequenza temporale e la pressione dei singoli tratti di inchiostro.
Casi d'uso suggeriti per l'API Riconoscimento della scrittura a mano libera
Ecco alcuni esempi di utilizzo:
- Applicazioni per prendere appunti in cui gli utenti vogliono acquisire note scritte a mano e farle tradurre in testo.
- Applicazioni di moduli in cui gli utenti possono utilizzare l'input con stilo o dito a causa di limiti di tempo.
- Giochi che richiedono di inserire lettere o numeri, come cruciverba, impiccato o sudoku.
Stato attuale
L'API Handwriting Recognition è disponibile a partire da Chromium 99.
Come utilizzare l'API Handwriting Recognition
Rilevamento delle funzionalità
Rileva il supporto del browser controllando l'esistenza del metodo createHandwritingRecognizer()
nell'oggetto navigator:
if ('createHandwritingRecognizer' in navigator) {
// 🎉 The Handwriting Recognition API is supported!
}
Concetti principali
L'API Handwriting Recognition converte l'input scritto a mano in testo, indipendentemente dal metodo di input (mouse, tocco, stilo). L'API ha quattro entità principali:
- Un punto rappresenta la posizione del puntatore in un determinato momento.
- Un tratto è composto da uno o più punti. La registrazione di un tratto inizia quando l'utente posiziona il puntatore verso il basso (ovvero fa clic sul pulsante principale del mouse o tocca lo schermo con lo stilo o il dito) e termina quando solleva di nuovo il puntatore.
- Un disegno è composto da uno o più tratti. Il riconoscimento effettivo avviene a questo livello.
- Il riconoscitore è configurato con la lingua di input prevista. Viene utilizzato per creare un'istanza di un disegno con la configurazione del riconoscimento applicata.
Questi concetti vengono implementati come interfacce e dizionari specifici, che tratterò a breve.
Creare un riconoscimento
Per riconoscere il testo dall'input scritto a mano, devi ottenere un'istanza di un
HandwritingRecognizer
chiamando navigator.createHandwritingRecognizer()
e passando i vincoli. I vincoli determinano il modello di riconoscimento della scrittura a mano libera da utilizzare. Al momento, puoi specificare un elenco di lingue in ordine di preferenza:
const recognizer = await navigator.createHandwritingRecognizer({
languages: ['en'],
});
Il metodo restituisce una promessa che si risolve con un'istanza di HandwritingRecognizer
quando il browser può soddisfare la tua richiesta. In caso contrario, rifiuterà la promessa con un errore e
il riconoscimento della scrittura a mano non sarà disponibile. Per questo motivo, ti consigliamo di eseguire una query per verificare
il supporto del sistema di riconoscimento per determinate funzionalità di riconoscimento.
Query di supporto del riconoscitore
Chiamando navigator.queryHandwritingRecognizer()
, puoi verificare se la piattaforma di destinazione
supporta le funzionalità di riconoscimento della scrittura che intendi utilizzare. Questo metodo accetta
lo stesso oggetto vincolo del metodo navigator.createHandwritingRecognizer()
,
contenente l'elenco delle lingue richieste. Il metodo restituisce una promessa che si risolve
con un oggetto risultato se viene trovato un riconoscitore compatibile. In caso contrario, la promessa restituisce null
.
Nel seguente esempio, lo sviluppatore:
- vuole rilevare i testi in inglese
- ricevere previsioni alternative meno probabili, se disponibili
- accedere al risultato della segmentazione, ovvero i caratteri riconosciuti, inclusi i punti e i tratti che li compongono
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
Se il browser supporta la funzionalità
necessaria allo sviluppatore, il suo valore verrà impostato su true
nell'oggetto risultato. In caso contrario, verrà impostato su false
.
Puoi utilizzare queste informazioni per attivare o disattivare determinate funzionalità all'interno dell'applicazione o per inviare una nuova query per un diverso insieme di lingue.
Iniziare un disegno
All'interno dell'applicazione, devi offrire un'area di input in cui l'utente inserisce le voci scritte a mano. Per motivi di rendimento, è consigliabile implementare questa funzionalità con l'aiuto di un oggetto canvas. L'implementazione esatta di questa parte non rientra nell'ambito di questo articolo, ma puoi fare riferimento alla demo per vedere come può essere eseguita.
Per iniziare un nuovo disegno, chiama il metodo startDrawing()
sul riconoscitore. Questo metodo accetta un
oggetto contenente diversi suggerimenti per perfezionare l'algoritmo di riconoscimento. Tutti i suggerimenti sono facoltativi:
- Il tipo di testo inserito: testo, indirizzi email, numeri o un singolo carattere
(
recognitionType
) - Il tipo di dispositivo di input: mouse, tocco o stilo (
inputType
) - Il testo precedente (
textContext
) - Il numero di previsioni alternative meno probabili da restituire (
alternatives
) - Un elenco di caratteri identificabili dall'utente ("grafemi") che l'utente inserirà più probabilmente
(
graphemeSet
)
L'API Handwriting Recognition funziona bene con
Pointer Events, che forniscono un'interfaccia
astratta per utilizzare l'input di qualsiasi dispositivo di puntamento. Gli argomenti dell'evento puntatore contengono
il tipo di puntatore utilizzato. Ciò significa che puoi utilizzare gli eventi puntatore per determinare automaticamente il tipo di input. Nell'esempio seguente, il disegno per il riconoscimento della scrittura a mano libera viene creato automaticamente
alla prima occorrenza di un evento pointerdown
nell'area di scrittura a mano libera. Poiché
pointerType
potrebbe essere vuoto o impostato su un valore proprietario, ho introdotto un controllo di coerenza per assicurarmi
che per il tipo di input del disegno siano impostati solo valori supportati.
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);
});
Aggiungere un tratto
L'evento pointerdown
è anche il punto giusto per iniziare una nuova bracciata. Per farlo, crea una nuova
istanza di HandwritingStroke
. Inoltre, devi memorizzare l'ora corrente come punto di riferimento per
i punti successivi aggiunti:
function startStroke(event) {
activeStroke = {
stroke: new HandwritingStroke(),
startTime: Date.now(),
};
addPoint(event);
}
Aggiunge un punto
Dopo aver creato il tratto, devi aggiungervi direttamente il primo punto. Poiché in seguito aggiungerai altri punti, è consigliabile implementare la logica di creazione dei punti in un metodo separato. Nell'esempio
seguente, il metodo addPoint()
calcola il tempo trascorso dal timestamp di riferimento.
Le informazioni temporali sono facoltative, ma possono migliorare la qualità del riconoscimento. Quindi, legge le coordinate X e Y dall'evento puntatore e aggiunge il punto al tratto corrente.
function addPoint(event) {
const timeElapsed = Date.now() - activeStroke.startTime;
activeStroke.stroke.addPoint({
x: event.offsetX,
y: event.offsetY,
t: timeElapsed,
});
}
Il gestore eventi pointermove
viene chiamato quando il puntatore viene spostato sullo schermo. Questi punti
devono essere aggiunti anche al tratto. L'evento può essere generato anche se il puntatore non è in stato
"giù", ad esempio quando si sposta il cursore sullo schermo senza premere il pulsante del mouse. Il gestore di eventi dell'esempio seguente verifica se esiste un tratto attivo e aggiunge il nuovo punto.
canvas.addEventListener('pointermove', (event) => {
if (activeStroke) {
addPoint(event);
}
});
Riconoscimento del testo
Quando l'utente solleva di nuovo il puntatore, puoi aggiungere il tratto al disegno chiamando il metodo
addStroke()
. L'esempio seguente reimposta anche activeStroke
, quindi il gestore pointermove
non aggiungerà punti al tratto completato.
Il passaggio successivo consiste nel riconoscere l'input dell'utente chiamando il metodo getPrediction()
sul
disegno. Il riconoscimento di solito richiede meno di qualche centinaio di millisecondi, quindi puoi eseguire ripetutamente
le previsioni, se necessario. L'esempio seguente esegue una nuova previsione dopo ogni tratto completato.
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));
});
Questo metodo restituisce una promessa che si risolve con un array di previsioni ordinate in base alla loro
probabilità. Il numero di elementi dipende dal valore che hai passato al suggerimento alternatives
. Puoi utilizzare questo array per presentare all'utente una scelta di possibili corrispondenze e fargli selezionare un'opzione. In alternativa, puoi semplicemente scegliere la previsione più probabile, come faccio nell'esempio.
L'oggetto di previsione contiene il testo riconosciuto e un risultato di segmentazione facoltativo, che tratterò nella sezione seguente.
Informazioni dettagliate con i risultati della segmentazione
Se supportato dalla piattaforma di destinazione, l'oggetto di previsione può contenere anche un risultato di segmentazione.
Si tratta di un array contenente tutti i segmenti di scrittura a mano libera riconosciuti, una combinazione del carattere riconoscibile
identificabile dall'utente (grapheme
) insieme alla sua posizione nel testo riconosciuto
(beginIndex
, endIndex
) e ai tratti e ai punti che lo hanno creato.
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);
});
},
);
}
Puoi utilizzare queste informazioni per rintracciare nuovamente i grafemi riconosciuti sul canvas.
Riconoscimento completo
Al termine del riconoscimento, puoi liberare le risorse chiamando il metodo clear()
su
HandwritingDrawing
e il metodo finish()
su HandwritingRecognizer
:
drawing.clear();
recognizer.finish();
Demo
Il componente web <handwriting-textarea>
implementa un controllo di modifica migliorato progressivamente in grado di riconoscere la scrittura a mano. Se fai clic sul pulsante nell'angolo in basso a destra del controllo di modifica, attivi
la modalità di disegno. Quando completi il disegno, il componente web avvia automaticamente il
riconoscimento e aggiunge il testo riconosciuto al controllo di modifica. Se l'API Handwriting Recognition
non è supportata o se la piattaforma non supporta le funzionalità richieste, il pulsante di modifica
sarà nascosto. Tuttavia, il controllo di modifica di base rimane utilizzabile come <textarea>
.
Il componente web offre proprietà e attributi per definire il comportamento di riconoscimento dall'esterno, inclusi languages
e recognitiontype
. Puoi impostare i contenuti del controllo tramite l'attributo
value
:
<handwriting-textarea languages="en" recognitiontype="text" value="Hello"></handwriting-textarea>
Per essere informato di eventuali modifiche al valore, puoi ascoltare l'evento input
.
Puoi provare il componente utilizzando questa demo su GitHub. Assicurati inoltre di dare un'occhiata al codice sorgente. Per utilizzare il controllo nella tua applicazione, scaricalo da npm.
Sicurezza e autorizzazioni
Il team di Chromium ha progettato e implementato l'API Handwriting Recognition utilizzando i principi fondamentali definiti in Controlling Access to Powerful Web Platform Features, tra cui controllo utente, trasparenza ed ergonomia.
Controllo utente
L'API Riconoscimento scrittura non può essere disattivata dall'utente. È disponibile solo per i siti web forniti tramite HTTPS e può essere chiamato solo dal contesto di navigazione di primo livello.
Trasparenza
Non è presente alcuna indicazione che indichi se il riconoscimento della scrittura è attivo. Per impedire il fingerprinting, il browser implementa contromisure, ad esempio mostrando all'utente una richiesta di autorizzazione quando rileva un possibile abuso.
Persistenza delle autorizzazioni
L'API Handwriting Recognition al momento non mostra richieste di autorizzazione. Pertanto, l'autorizzazione non deve essere mantenuta in alcun modo.
Feedback
Il team di Chromium vuole conoscere la tua esperienza con l'API Handwriting Recognition.
Descrivi la progettazione dell'API
C'è qualcosa nell'API che non funziona come previsto? Oppure mancano metodi o proprietà che ti servono per implementare la tua idea? Hai una domanda o un commento sul modello di sicurezza? Segnala un problema relativo alle specifiche nel repository GitHub corrispondente o aggiungi i tuoi commenti a un problema esistente.
Segnalare un problema relativo all'implementazione
Hai trovato un bug nell'implementazione di Chromium? L'implementazione è diversa dalla specifica?
Segnala un bug all'indirizzo new.crbug.com. Assicurati di includere il maggior numero possibile di dettagli,
istruzioni semplici per la riproduzione e inserisci Blink>Handwriting
nella casella Componenti.
Mostra il tuo sostegno all'API
Intendi utilizzare l'API Handwriting Recognition? Il tuo supporto pubblico aiuta il team di Chromium a dare la priorità alle funzionalità e mostra ad altri fornitori di browser quanto sia fondamentale supportarle.
Condividi il modo in cui prevedi di utilizzarlo nel thread di discussione WICG. Invia un tweet a
@ChromiumDev utilizzando l'hashtag
#HandwritingRecognition
e facci sapere dove e come lo utilizzi.
Link utili
- Explainer
- Spec draft
- Repository GitHub
- ChromeStatus
- Bug di Chromium
- TAG review
- Intent to Prototype
- WebKit-Dev thread
- Posizione di Mozilla sugli standard
Ringraziamenti
Questo documento è stato rivisto da Joe Medley, Honglin Yu e Jiewei Qian.