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

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

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

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

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

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

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

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

الوضع الحالي

تتوفّر واجهة برمجة تطبيقات التعرف على الكتابة بخط اليد من (Chromium 99).

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

رصد الميزات

اكتشِف توافق المتصفّح من خلال التحقق من توفُّر طريقة createHandwritingRecognizer() في عنصر أداة التنقّل:

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

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

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

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

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

الكيانات الأساسية لواجهة برمجة تطبيقات التعرف على الكتابة بخط اليد: تؤدي نقطة واحدة أو أكثر إلى إنشاء سُمك خط ، وضغطة واحدة أو أكثر تؤلف رسمًا، تنشئها أداة التعرف. يحدث التعرف الفعلي على مستوى الرسم.

إنشاء أداة التعرّف

للتعرّف على النص من الإدخال المكتوب بخط اليد، عليك الحصول على مثيل من 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)

تعمل واجهة برمجة تطبيقات التعرف على الكتابة بخط اليد بشكل جيد مع أحداث المؤشر التي توفّر واجهة مجردة لاستهلاك المدخلات من أي جهاز تأشير. تتضمن وسيطات أحداث المؤشر نوع المؤشر المستخدَم. وهذا يعني أنّه يمكنك استخدام أحداث المؤشر لتحديد نوع الإدخال تلقائيًا. في المثال التالي، يتم إنشاء الرسم للتعرّف على الكتابة بخط اليد تلقائيًا عند الورود الأول لحدث 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) بالإضافة إلى موضعها في النص الذي تم التعرّف عليه (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 ونفّذها باستخدام المبادئ الأساسية الموضَّحة في التحكُّم في الوصول إلى ميزات النظام الأساسي الفعّال للويب، بما في ذلك إمكانية تحكُّم المستخدم والشفافية وتسهيل العمل.

تحكم المستخدم

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

الشفافية

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

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

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

ملاحظات

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

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

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

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

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

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

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

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

شكر وتقدير

تمت مراجعة هذه المقالة بواسطة جو ميدلي وهونغلين يو وجيوي تشيان. صورة رئيسية من تأليف سمير بوكيد على Unسباش