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