Technical Article

بناء عارضات PDF يمكن الوصول إليها مع تحويل النص إلى كلام في Delphi

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

في هذه المقالة، سنلقي نظرة على كيفية استخراج تدفقات نصية دلالية من ملف PDF باستخدام PDFium في Delphi، ثم إرسال هذا النص إلى واجهة برمجة تطبيقات الكلام في Windows (SAPI) لبناء عارض PDF يمكن الوصول إليه بالكامل.

تحدي استخراج النص من PDF

يعد ملف PDF أساسًا لوحة لتعليمات الرسم. إنه لا يعرف بطبيعته ما هي "الفقرة" أو "العمود"؛ فهو يضع ببساطة حروفًا رمزية (glyphs) في إحداثيات X/Y محددة. لقراءة مستند بصوت عالٍ بترتيب منطقي، يجب على المحلل الخاص بك إعادة بناء ترتيب القراءة.

يتعامل PDFium مع هذا عبر عائلة واجهة برمجة التطبيقات FPDFText_*، والتي تحلل العلاقات المكانية للحروف الرمزية لإخراج تدفقات نصية متماسكة.

الخطوة 1: استخراج النص باستخدام PDFium

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

uses
  System.SysUtils, pdfium_lib;

function ExtractPageText(Doc: FPDF_DOCUMENT; PageIndex: Integer): string;
var
  Page: FPDF_PAGE;
  TextPage: FPDF_TEXTPAGE;
  CharCount: Integer;
  Buffer: array of WideChar;
begin
  Result := '';
  Page := FPDF_LoadPage(Doc, PageIndex);
  if Page = nil then Exit;
  
  try
    // Initialize the text extraction engine for this page
    TextPage := FPDFText_LoadPage(Page);
    if TextPage <> nil then
    begin
      try
        CharCount := FPDFText_CountChars(TextPage);
        if CharCount > 0 then
        begin
          SetLength(Buffer, CharCount + 1);
          // Extract the text into the wide string buffer
          FPDFText_GetText(TextPage, 0, CharCount, @Buffer[0]);
          Result := WideCharToString(@Buffer[0]);
        end;
      finally
        FPDFText_ClosePage(TextPage);
      end;
    end;
  finally
    FPDF_ClosePage(Page);
  end;
end;

الخطوة 2: دمج واجهة برمجة تطبيقات الكلام في Windows (SAPI)

بمجرد أن يكون لدينا النص الدلالي، يمكننا تمريره إلى واجهة برمجة تطبيقات الكلام في Windows. يوفر SAPI واجهة SpVoice COM، والتي تسمح بتركيب الكلام غير المتزامن، واختيار الصوت، والتحكم في معدل الكلام.

uses
  System.Win.ComObj, Winapi.ActiveX;

const
  SVSFlagsAsync = 1;

procedure SpeakText(const TextToSpeak: string);
var
  SpVoice: OLEVariant;
begin
  CoInitialize(nil);
  try
    SpVoice := CreateOleObject('SAPI.SpVoice');
    // Speak asynchronously so the UI does not freeze
    SpVoice.Speak(TextToSpeak, SVSFlagsAsync);
  finally
    CoUninitialize;
  end;
end;

الخطوة 3: مزامنة الكلام مع التمييز

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

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

procedure HighlightWord(TextPage: FPDF_TEXTPAGE; CharIndex: Integer; CharCount: Integer);
var
  i: Integer;
  L, T, R, B: Double;
begin
  // Iterate through the characters of the spoken word
  for i := CharIndex to CharIndex + CharCount - 1 do
  begin
    // Get the physical bounding box on the PDF page
    FPDFText_GetCharBox(TextPage, i, @L, @R, @B, @T);
    // Transform PDF coordinates to screen coordinates and draw highlighting rect...
  end;
end;

بناء تطبيق شامل

من خلال الجمع بين الاستخراج المكاني للنص في PDFium ومحرك الكلام في SAPI، يمكن لمطوري Delphi إنشاء أدوات قوية للمستخدمين ضعاف البصر أو أولئك الذين يفضلون التعلم السمعي. يضمن تنفيذ هذه الميزات بشكل صحيح توافق تطبيقك مع معايير إمكانية الوصول الصارمة للمؤسسات والحكومات.

ملاحظة: استخراج النص المدمج وتعيين الإحداثيات مدعومان بالكامل بواسطة مكون PDFium Component VCL.