Technical Article

Akadálymentesített PDF megjelenítők építése Text-to-Speech támogatással Delphiben

Az akadálymentesítés már nem opcionális funkció a modern szoftverfejlesztésben. Olyan szabályozások értelmében, mint az ADA (Americans with Disabilities Act) és az EU Web-akadálymentesítési irányelve (EU Web Accessibility Directive), a dokumentumokat kezelő szoftvereknek kisegítő technológiákat kell biztosítaniuk. A PDF megjelenítők esetében ez robusztus Text-to-Speech (TTS) és képernyőolvasó integrációt jelent.

Ebben a cikkben megvizsgáljuk, hogyan lehet szemantikai szövegstreameket kinyerni egy PDF-ből a PDFium használatával Delphiben, majd ezt a szöveget betáplálni a Windows Speech API-ba (SAPI) egy teljesen akadálymentesített PDF megjelenítő felépítéséhez.

A PDF szövegkinyerés kihívása

A PDF alapvetően festési utasítások vászna. Eredendően nem tudja, mi az a "bekezdés" vagy "oszlop"; csupán karakterjeleket (glyph) helyez el meghatározott X/Y koordinátákon. A dokumentum logikai sorrendben történő felolvasásához az elemzőnek (parser) rekonstruálnia kell az olvasási sorrendet.

A PDFium ezt az FPDFText_* API családon keresztül kezeli, amely elemzi a karakterjelek térbeli viszonyait, hogy koherens szövegstreameket hozzon létre.

1. lépés: Szöveg kinyerése a PDFiummal

Mielőtt kimondanánk a szöveget, ki kell nyernünk azt. A következő Delphi kód bemutatja, hogyan kell inicializálni egy szöveges oldalt, és hogyan lehet annak tartalmát egy szabványos karakterláncba (string) kinyerni.

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. lépés: A Windows Speech API (SAPI) integrálása

Miután megvan a szemantikai szöveg, átadhatjuk azt a Windows Speech API-nak. A SAPI biztosítja az SpVoice COM interfészt, amely lehetővé teszi az aszinkron beszédszintézist, a hang kiválasztását és a beszédsebesség szabályozását.

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. lépés: A beszéd szinkronizálása a kiemeléssel

Egy igazán akadálymentesített megjelenítő nem csak vakon olvassa a szöveget; ki is emeli a szavakat a képernyőn, amint elhangzanak. A SAPI eseményeket biztosít (kapcsolódási pontokon - connection points keresztül), amelyek akkor sülnek el, amikor egy szó határához érünk.

Azáltal, hogy a SAPI szóhatár (word boundary) esemény által visszaadott karakterindexet visszarendeli a PDFiumban lévő karakterindexhez az FPDFText_GetCharBox() használatával, lekérheti az éppen kimondott szó befoglaló téglalapját (bounding rectangle), és rajzolhat egy kiemelő rátétet (highlight overlay) a megjelenítő vásznára.

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;

Egy inkluzív alkalmazás felépítése

A PDFium térbeli szövegkinyerésének és a SAPI beszédmotorjának kombinálásával a Delphi fejlesztők hatékony eszközöket hozhatnak létre látássérült felhasználók vagy olyanok számára, akik a hallás utáni tanulást részesítik előnyben. Ezeknek a funkcióknak a megfelelő megvalósítása biztosítja, hogy alkalmazása megfeleljen a szigorú vállalati és kormányzati akadálymentesítési szabványoknak.

Megjegyzés: Az integrált szövegkinyerést és koordináta-leképezést teljes mértékben támogatja a PDFium Component.