التعرف على الكتابة اليدوية للمستخدمين

تتيح لك واجهة برمجة التطبيقات Handwriting Recognition API التعرّف على النص من خلال إدخال مكتوب بخط اليد أثناء كتابته.

ما هي واجهة برمجة تطبيقات التعرُّف على الكتابة بخط اليد؟

تتيح لك واجهة برمجة التطبيقات Handwriting Recognition API تحويل الكتابة بخط اليد (الحبر) من المستخدمين إلى نص. لطالما تضمّنت بعض أنظمة التشغيل واجهات برمجة التطبيقات هذه، ويمكن لتطبيقات الويب من خلال هذه الإمكانية الجديدة استخدام هذه الوظيفة أخيرًا. تحدث عملية الإحالة الناجحة مباشرةً على جهاز المستخدم، وتعمل حتى في وضع عدم الاتّصال بالإنترنت، وكل ذلك بدون إضافة أي مكتبات أو خدمات تابعة لجهات خارجية.

تُنفِّذ واجهة برمجة التطبيقات هذه ما يُعرف بالتعرّف "أثناء التشغيل" أو التعرّف في الوقت الفعلي تقريبًا. وهذا يعني أنّه يتم التعرّف على الإدخال المكتوب بخط اليد أثناء رسمه من قِبل المستخدم من خلال تسجيل الخطوط الفردية وتحليلها. على عكس الإجراءات "غير المتصلة بالإنترنت"، مثل تقنية "التعرّف البصري على الأحرف" (OCR)، حيث يتم معرفة المنتج النهائي فقط، يمكن أن توفّر الخوارزميات "المتصلة بالإنترنت" مستوى أعلى من الدقة بسبب الإشارات الإضافية، مثل التسلسل الزمني وضغط خطوط الحبر الفردية.

حالات الاستخدام المقترَحة لواجهة برمجة التطبيقات Handwriting Recognition API

تشمل أمثلة الاستخدام ما يلي:

  • تطبيقات تدوين الملاحظات التي يريد المستخدمون فيها تدوين ملاحظات مكتوبة بخط اليد وترجمتها إلى نص
  • تطبيقات النماذج التي يمكن للمستخدمين فيها استخدام القلم أو الإدخال باستخدام الإصبع بسبب القيود الزمنية
  • الألعاب التي تتطلّب ملء أحرف أو أرقام، مثل ألعاب الكلمات المتقاطعة أو لعبة "الفار المغلق" أو لعبة سودوكو

الوضع الحالي

تتوفّر واجهة برمجة التطبيقات Handwriting Recognition API من الإصدار (Chromium 99).

طريقة استخدام واجهة برمجة تطبيقات التعرف على الكتابة بخط اليد

رصد الميزات

يمكنك رصد توافق المتصفّح من خلال التحقّق من توفّر طريقة createHandwritingRecognizer() في كائن المتصفّح:

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

المفاهيم الأساسية

تحوِّل واجهة برمجة التطبيقات Handwriting Recognition API النص المكتوب بخط اليد إلى نص، بغض النظر عن طريقة الإدخال (الماوس أو اللمس أو القلم). تتضمّن واجهة برمجة التطبيقات أربعة عناصر رئيسية:

  1. تمثّل النقطة موضع المؤشر في وقت معيّن.
  2. تتألّف الخطوط من نقطة واحدة أو أكثر. يبدأ تسجيل الخطوط عندما يضع المستخدِم المؤشر على الشاشة (أي ينقر على زر الماوس الأساسي أو يلمس الشاشة بالقلم أو بالإصبع)، وينتهي عندما يرفع المؤشر مرة أخرى.
  3. يتكوّن الرسم من خط واحد أو أكثر. ويتم التعرّف الفعلي على هذا المستوى.
  4. تم ضبط أداة التعرّف على لغة الإدخال المتوقّعة. يتم استخدامه لإنشاء مثيل لرسم مع تطبيق إعدادات المعرّف.

يتم تنفيذ هذه المفاهيم كواجهات وقواميس محددة، وسوف أتناولها قريبًا.

العناصر الأساسية لواجهة برمجة التطبيقات Handwriting Recognition API: تتكون الخطوط من نقطة واحدة أو أكثر، وتتكون الرسومات من خط واحد أو أكثر، وهي ما ينشئه معرّف النصوص. ويتم التعرّف الفعلي على مستوى الرسم.

إنشاء معرِّف

للتعرّف على النص من الإدخال المكتوب بخط اليد، عليك الحصول على مثيل من HandwritingRecognizer من خلال استدعاء navigator.createHandwritingRecognizer() وتمرير القيود عليه. تحدِّد القيود نموذج التعرّف على الكتابة اليدوية الذي يجب استخدامه. في الوقت الحالي، يمكنك تحديد قائمة اللغات بترتيب تفضيلك:

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. يمكنك استخدام هذه المعلومات لتفعيل ميزات معيّنة أو إيقافها في تطبيقك، أو لتعديل طلب البحث وإرسال طلب جديد.

بدء رسم

يجب توفير منطقة إدخال حيث يُدخل المستخدم إدخالات مكتوبة بخط اليد. لأسباب متعلقة بالأداء، ننصحك بتنفيذ ذلك باستخدام كائن لوحة. لا يتناول هذا المقال كيفية تنفيذ هذا الجزء بالضبط، ولكن يمكنك الرجوع إلى العرض التجريبي لفهم كيفية تنفيذه.

لبدء رسم جديد، استخدِم طريقة startDrawing() في المعرِّف. تستخدِم هذه الطريقة جسمًا يحتوي على إشارات مختلفة لتحسين خوارزمية التعرّف. جميع التلميحات اختيارية:

  • نوع النص الذي يتم إدخاله: نص أو عناوين بريد إلكتروني أو أرقام أو حرف فردي (recognitionType)
  • نوع جهاز الإدخال: الماوس أو اللمس أو القلم (inputType)
  • النص السابق (textContext)
  • عدد عبارات البحث المقترحة البديلة التي يقل احتمال عرضها (alternatives)
  • قائمة بالأحرف التي يمكن للمستخدم التعرّف عليها ("الرسومات الهجائية") والتي يُرجّح أن يدخلها المستخدم (graphemeSet)

تتوافق واجهة Handwriting Recognition 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. يمكنك استخدام هذه الصفيف لتقديم خيارات للمطابقات المحتمَلة للمستخدم، وطلب تحديد أحد الخيارات. بدلاً من ذلك، يمكنك استخدام التوقع الأكثر ترجيحًا، وهو ما أفعل في المثال التالي.

يحتوي عنصر التوقّع على النص الذي تم التعرّف عليه ونتيجة اختيارية للتقسيم، وسأ discuss في القسم التالي.

إحصاءات تفصيلية مع نتائج التصنيف

يمكن أن يحتوي عنصر التوقّع أيضًا على نتيجة تقسيم إذا كانت المنصة المستهدَفة تتيح ذلك. هذا صفيف يحتوي على جميع أجزاء الكتابة اليدوية التي تم التعرّف عليها، وهي عبارة عن مجموعة من الأحرف التي يتعرّف عليها المستخدم (grapheme) بالإضافة إلى موضعها في النص الذي تم التعرّف عليه (beginIndex وendIndex) والخطوط والنقاط التي تم إنشاؤها.

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

يمكنك استخدام هذه المعلومات لتتبُّع الرموز المرسومة التي تم التعرّف عليها على اللوحة مرة أخرى.

يتم رسم مربّعات حول كل حرف مُعرَّف.

التعرّف الكامل

بعد اكتمال التقدير، يمكنك إخلاء بعض الموارد من خلال استدعاء طريقة clear() في HandwritingDrawing، وطريقة finish() على HandwritingRecognizer:

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

عرض توضيحي

ينفِّذ عنصر الويب <handwriting-textarea> عنصر تحكّم في التعديل محسَّنًا بشكل تدريجي، ويمكنه التعرّف على الكتابة اليدوية. من خلال النقر على الزر في أسفل يسار عنصر التحكّم في التعديل، يمكنك تفعيل وضع الرسم. عند إكمال الرسم، سيبدأ عنصر الويب تلقائيًا عملية التعرّف ويضيف النص الذي تم التعرّف عليه مرة أخرى إلى عنصر التحكّم في التعديل. إذا لم تكن واجهة برمجة تطبيقات التعرف على الكتابة بخط اليد متوافقة على الإطلاق أو إذا كانت المنصة لا تدعم الميزات المطلوبة، فسيكون زر التعديل مخفيًا. يبقى عنصر التحكّم الأساسي في التعديل قابلاً للاستخدام <textarea>.

يقدّم مكوّن الويب سمات وخصائص لتحديد سلوك التعرّف من الخارج، بما في ذلك languages وrecognitiontype. يمكنك ضبط محتوى عنصر التحكّم من خلال سمة value:

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

لمعرفة أي تغييرات تطرأ على القيمة، يمكنك الاستماع إلى الحدث input.

يمكنك تجربة المكوّن باستخدام هذا الإصدار التجريبي على Glitch. احرص أيضًا على إلقاء نظرة على رمز المصدر. لاستخدام عنصر التحكّم في تطبيقك، يمكنك الحصول عليه من npm.

الأمان والأذونات

صمَّم فريق Chromium ونفّذها باستخدام المبادئ الأساسية الموضَّحة في التحكُّم في الوصول إلى ميزات النظام الأساسي الفعّال للويب، بما في ذلك إمكانية تحكُّم المستخدم والشفافية وتسهيل الاستخدام.

التحكّم في المستخدم

لا يمكن للمستخدم إيقاف واجهة برمجة التطبيقات Handwriting Recognition API. ولا يتوفّر إلا للمواقع الإلكترونية التي يتم عرضها من خلال HTTPS، ولا يمكن استدعاؤه إلا من سياق التصفّح على مستوى أعلى.

الشفافية

لا تتوفّر أي إشارة إلى ما إذا كانت ميزة التعرّف على الكتابة اليدوية مفعّلة. لمنع تقنية "البصمة الرقمية"، ينفِّذ المتصفّح إجراءات مضادة، مثل عرض طلب إذن على المستخدم عند رصده إساءة استخدام محتملة.

استمرار الإذن

لا تعرض واجهة برمجة التطبيقات Handwriting Recognition API حاليًا أي طلبات للحصول على أذونات. وبالتالي، لا يلزم الاحتفاظ بالإذن بأي شكل من الأشكال.

ملاحظات

يرغب فريق Chromium في التعرُّف على تجاربك في استخدام واجهة برمجة تطبيقات التعرُّف على الكتابة بخط اليد.

أخبِرنا عن تصميم واجهة برمجة التطبيقات.

هل هناك مشكلة في واجهة برمجة التطبيقات لا تعمل على النحو المتوقّع؟ هل هناك طُرق أو سمات مفقودة تحتاجها لتنفيذ فكرتك؟ هل لديك سؤال أو تعليق حول ملف أمان الحساب؟ يُرجى الإبلاغ عن مشكلة في المواصفات بشأن مستودع GitHub ذي الصلة، أو إضافة أفكارك إلى مشكلة حالية.

الإبلاغ عن مشكلة في التنفيذ

هل عثرت على خطأ في عملية تنفيذ Chromium؟ أم أنّ عملية التنفيذ مختلفة عن المواصفات؟ يمكنك الإبلاغ عن خلل على الرابط new.crbug.com. احرص على تضمين أكبر قدر ممكن من التفاصيل، وتعليمات بسيطة لإعادة إنتاج الخلل، وأدخِل Blink>Handwriting في مربّع المكوّنات. تعمل ميزة الخطأ بشكلٍ رائع لمشاركة النسخ المُعاد إنتاجها بسرعة وسهولة.

إظهار الدعم لواجهة برمجة التطبيقات

هل تخطط لاستخدام واجهة برمجة تطبيقات التعرُّف على الكتابة بخط اليد؟ يساعد دعمك العلني فريق Chromium في تحديد الميزات ذات الأولوية وإظهار مدى أهمية توفيرها لمطوّري المتصفّحات الآخرين.

شارِك الطريقة التي تنوي بها استخدام هذا التقرير في سلسلة محادثات WICG Discourse. أرسِل تغريدة إلى حساب ‎@ChromiumDev باستخدام الهاشتاغ #HandwritingRecognition وأطلِعنا على مكان استخدامك للميزة وطريقة استخدامك لها.

الشكر والتقدير

راجع هذا المستند كلّ من جو ميدلي، هونغلين يو وجيوي تشياو.