辨識使用者(');手寫功能

手寫辨識 API 可讓您辨識手寫輸入內容中的文字,

什麼是手寫辨識 API?

手寫辨識 API 可讓您將使用者的手寫 (手寫) 轉換成文字。某些作業系統一直以來都提供這類 API,而透過這項新功能,您的網頁應用程式最終可以使用這項功能。轉換作業會直接在使用者的裝置上進行,即使在離線模式下也能運作,而且不必新增任何第三方程式庫或服務。

這個 API 實作所謂的「線上」或近乎即時辨識。也就是說,在使用者繪圖時,系統會擷取並分析單一筆劃,藉此辨識手寫輸入。相較於光學字元辨識 (OCR) 這類「離線」程序 (光學字元辨識 (OCR) 通常為已知最終產物),線上演算法可根據額外信號 (例如時空序列和個別墨筆壓力的壓力) 提高準確度。

手寫辨識 API 建議用途

用途範例包括:

  • 一種記事應用程式,可讓使用者擷取手寫筆記並將內容翻譯成文字。
  • 表單應用程式,可讓使用者基於時間限制使用畫筆或手指輸入功能。
  • 需要填入英文字母或數字的遊戲,例如填字、懸吊或數通數。

目前狀態

手寫辨識 API 適用於 (Chromium 99)。

如何使用手寫辨識 API

特徵偵測

檢查導覽器物件上是否存在 createHandwritingRecognizer() 方法,藉此偵測瀏覽器支援:

if ('createHandwritingRecognizer' in navigator) {
  // 🎉 The Handwriting Recognition API is supported!
}

核心概念

無論輸入法 (滑鼠、觸控、筆) 為何,手寫辨識 API 都會將手寫輸入轉換成文字。API 包含四個主要實體:

  1. 代表指標在特定時間的位置。
  2. 「筆劃」由一或多個點組成。當使用者將指標向下移動 (例如點選主要滑鼠按鈕,或使用觸控筆或手指輕觸螢幕),筆劃會開始記錄,並在使用者將指標向上移回時結束。
  3. 「繪圖」包含一或多個筆劃。實際辨識是在這個層級進行。
  4. recognizer 會以預期的輸入語言設定。可用來建立套用辨識工具設定的繪圖執行個體。

這些概念是以特定介面和字典形式實作,我們稍後會探討。

手寫辨識 API 的核心實體:一或多個點會組成筆劃、一或多個筆劃組成繪圖,而辨識器會建立繪圖。實際辨識是在繪圖層級進行。

建立辨識工具

如要辨識手寫輸入內容中的文字,您需要呼叫 navigator.createHandwritingRecognizer() 並傳遞限制,以取得 HandwritingRecognizer 的例項。限制條件會決定應使用的手寫辨識模型。目前,您可以依偏好順序指定語言清單:

const recognizer = await navigator.createHandwritingRecognizer({
  languages: ['en'],
});

當瀏覽器可以執行您的要求時,這個方法會傳回 HandwritingRecognizer 例項解析的承諾。否則,系統會拒絕含有錯誤的承諾,而且無法使用手寫辨識功能。因此,建議您先查詢辨識工具對於特定辨識功能的支援。

查詢辨識工具支援

透過呼叫 navigator.queryHandwritingRecognizerSupport(),您可以檢查目標平台是否支援要使用的手寫辨識功能。在以下範例中,開發人員:

  • 想要偵測英文文字
  • 取得替代字詞,較不可能的預測 (如有)
  • 可存取區隔結果,也就是可辨識的字元,包括構成這些字元的點和筆觸。
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

這個方法會傳回使用結果物件解析的承諾。如果瀏覽器支援開發人員指定的功能,值會設為 true。否則會設為 false。您可以運用這項資訊在應用程式中啟用或停用特定功能,或是調整查詢並傳送新的功能。

開始繪圖

在應用程式中,您應該提供使用者以手寫輸入內容的輸入區域。基於效能考量,建議使用 canvas 物件來實作此程序。這個部分的確切實作方式不在本文的討論範圍,但建議您參閱示範瞭解操作方法。

如要開始新的繪圖,請在辨識器上呼叫 startDrawing() 方法。這個方法會使用包含不同提示的物件來調整辨識演算法。所有提示皆為選填:

  • 輸入的文字類型:文字、電子郵件地址、數字或個別字元 (recognitionType)
  • 輸入裝置類型:滑鼠、觸控或觸控筆輸入 (inputType)
  • 上方文字 (textContext)
  • 應傳回不太可能傳回的替代預測結果數量 (alternatives)
  • 使用者最有可能輸入的可識別字元 (「圖形」) 清單 (graphemeSet)

手寫辨識 API 很適合搭配指標事件使用,這類事件提供抽象介面,可從任何指標裝置取用輸入內容。指標事件引數包含目前使用的指標類型。也就是說,您可以使用指標事件自動判斷輸入類型。在下例中,在手寫區域第一次發生 pointerdown 事件時,系統會自動建立手寫辨識的繪圖。由於 pointerType 可能空白或設為專屬值,我採用了一致性檢查,以確保只針對繪圖的輸入類型設定支援的值。

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);
});

新增筆劃

pointerdown 事件也是開始新的筆觸的正確位置。如要這麼做,請建立新的 HandwritingStroke 例項。除此之外,也建議您儲存目前時間,做為後續新增的點的參考:

function startStroke(event) {
  activeStroke = {
    stroke: new HandwritingStroke(),
    startTime: Date.now(),
  };
  addPoint(event);
}

新增地點

建立筆觸後,應直接新增第一個點。稍後您將新增更多點,因此以個別方法實作點建立邏輯會很合理。在以下範例中,addPoint() 方法會從參考時間戳記計算經過時間。時間資訊不一定要提供,但可以改善辨識品質。接著,它會讀取指標事件中的 X 和 Y 座標,並將該點新增至目前的筆劃。

function addPoint(event) {
  const timeElapsed = Date.now() - activeStroke.startTime;
  activeStroke.stroke.addPoint({
    x: event.offsetX,
    y: event.offsetY,
    t: timeElapsed,
  });
}

指標在畫面上移動時,系統會呼叫 pointermove 事件處理常式。這些點也必須新增至筆劃。如果指標未處於「向下」狀態,也可以引發事件,例如:在沒有按下滑鼠按鈕的情況下將遊標懸停在畫面上時。以下範例的事件處理常式會檢查是否有有效的筆劃,並將新的點加入。

canvas.addEventListener('pointermove', (event) => {
  if (activeStroke) {
    addPoint(event);
  }
});

辨識文字

當使用者再次舉起指標時,您可以呼叫其 addStroke() 方法,在繪圖中加入筆觸。以下範例也會重設 activeStroke,因此 pointermove 處理常式不會將點新增至已完成的筆劃。

接著,請在繪圖上呼叫 getPrediction() 方法,以便識別使用者的輸入內容。辨識通常只需幾百毫秒,因此您可以視需要重複執行預測。下列範例會在您每次完成筆劃後執行新的預測。

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));
});

這個方法會傳回一個承諾,該承諾會依照預測結果陣列的預測結果排序。元素數量取決於您傳遞至 alternatives 提示的值。您可以使用這個陣列,為使用者提供可能相符的選項,讓使用者自行選取選項。或者,您也可以直接使用最有可能的預測結果,也就是我在本範例中進行的操作。

預測物件包含辨識的文字與選用的區隔結果,我將在下一節討論。

透過區隔結果取得詳盡的深入分析

如果目標平台支援,預測結果物件也可能會包含區隔結果。這是所有可辨識的手寫片段、可辨識的字元 (grapheme)、其在辨識文字中的位置 (beginIndexendIndex),以及建立該字元的筆觸和點的組合。

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);
      });
    },
  );
}

您可以使用這項資訊,再次追蹤畫布上辨識出的圖形。

在每個可辨識的石墨色周圍,皆有繪製的方塊

完成辨識

辨識完成後,您可以對 HandwritingDrawing 呼叫 clear() 方法,並在 HandwritingRecognizer 上呼叫 finish() 方法以釋出資源:

drawing.clear();
recognizer.finish();

操作示範

網頁元件 <handwriting-textarea> 實作了漸進式強化功能,讓編輯控制選項能夠辨識手寫辨識功能。按一下編輯控制項右下角的按鈕,即可啟用繪圖模式。完成繪圖後,網頁元件會自動開始辨識,並將辨識的文字加回編輯控制項。如果完全不支援手寫辨識 API,或是平台不支援要求的功能,系統會隱藏編輯按鈕。但基本編輯控制項仍可做為 <textarea> 使用。

網頁元件提供的屬性和屬性可用來定義外部的辨識行為,包括 languagesrecognitiontype。您可以透過 value 屬性設定控制項的內容:

<handwriting-textarea languages="en" recognitiontype="text" value="Hello"></handwriting-textarea>

如要接收值的任何變更通知,您可以監聽 input 事件。

您可以使用這個 Glitch 示範來試用元件。此外,請務必查看原始碼。如要在應用程式中使用控制項,請從 npm 取得

安全性和權限

Chromium 團隊敬上

使用者控制項

使用者無法關閉手寫辨識 API。這項功能僅適用於透過 HTTPS 傳送的網站,而且只能從頂層瀏覽環境呼叫。

透明度

沒有跡象顯示手寫辨識功能是否已啟用。為防止數位指紋採集,瀏覽器會採取對應措施,例如在偵測到可能的濫用情況時,向使用者顯示權限提示。

權限持續性

手寫辨識 API 目前不會顯示任何權限提示。因此,不需要以任何方式保留權限。

意見回饋:

Chromium 團隊想瞭解你的手寫辨識 API 使用體驗。

請與我們分享 API 設計

您覺得這個 API 有什麼不如預期的運作方式?還是你還需要實現想法或屬性呢?對安全性模型有任何疑問或意見嗎?在對應的 GitHub 存放區上提出規格問題,或是將您的想法新增至現有問題。

回報導入問題

您發現 Chromium 實作錯誤嗎?還是採用與規格不同? 前往 new.crbug.com 回報錯誤。此外,請務必盡量提供詳細資料、能重現的簡單操作說明,並在「Components」(元件) 方塊中輸入 Blink>HandwritingGlitch 有便捷的報復工具,

顯示對 API 的支援

你打算使用手寫辨識 API 嗎?您的公開支援服務有助於 Chromium 團隊優先開發特定功能,並向其他瀏覽器廠商說明支援這些功能的重要性。

歡迎前往 WICG Discourse 討論串,說明這項工具的運用方式。使用主題標記 #HandwritingRecognition 將推文傳送至 @ChromiumDev,並告知我們您使用該標記的位置和方式。

特別銘謝

本文評論者為 Joe Medley、Honglin Yu 和 Jiewei Qian。主頁橫幅由 Samir Bouaked 提供,位於 Unsplash 網站上。