Technical Article

Vytváranie prístupných prehliadačov PDF s prevodom textu na reč v Delphi

Pri vývoji podnikového softvéru na správu dokumentov už prístupnosť nie je len voliteľnou funkciou, v mnohých jurisdikciách, najmä pre vládne a vzdelávacie aplikácie, je to zákonná požiadavka. Vytvorenie prístupného prehliadača PDF pre používateľov so zrakovým postihnutím si vyžaduje viac než len vykresľovanie stránok. Musíte programovo extrahovať text, pochopiť postupnosť čítania a prepojiť tieto údaje so systémovým nástrojom na prevod textu na reč (Text-to-Speech, TTS).

Táto technická poznámka sa zaoberá tým, ako spojiť analýzu textu PDF a rozhranie Microsoft Speech API (SAPI) na vytvorenie prístupného zážitku z čítania pomocou komponentov Delphi.

Výzva extrakcie textu z PDF

Na rozdiel od dokumentov vo formáte Word, ktoré udržiavajú lineárny tok obsahu, sú PDF dokumenty kolekciou nezávislých príkazov na kreslenie textu, ktoré sú viazané na špecifické súradnice X a Y. "Odsek" v PDF neexistuje ako štruktúrovaný prvok (pokiaľ to nie je označené Tagged PDF). Namiesto toho analytický engine zvyčajne vracia zoznam fragmentov textu.

Aby ste získali zmysluplný reťazec, ktorý je možné nahlas prečítať, váš komponent pre prácu s PDF musí implementovať priestorovú heuristiku na zoskupovanie úryvkov znakov do slov, zoraďovanie slov zľava doprava a zoskupovanie riadkov zhora nadol. Pokus o prečítanie surového textového toku PDF bez tohto zoskupenia bude často znieť ako nezmyselný zhluk slabík.

Extrakcia mapovania jednotiek čítania

Pri odosielaní textu do nástroja TTS musíte byť schopní vizuálne zvýrazniť slovo, ktoré sa práve číta, aby ste pomohli používateľom so zvyškami zraku alebo kognitívnymi poruchami. To si vyžaduje mapovanie medzi textovým reťazcom odoslaným do SAPI a ohraničujúcimi obdĺžnikmi na PDF stránke.

Pomocou knižnice, ako je PDFium, môžete získať prístup k obdĺžnikom jednotlivých znakov (Character Rectangles):

procedure TAccessiblePdfViewer.ExtractAndSpeakPage(PageIndex: Integer);
var
  TextPage: FPDF_TEXTPAGE;
  CharCount, I: Integer;
  WordBuffer: string;
  WordRect: TRectF;
  CharRect: DoubleArray4; // left, top, right, bottom
begin
  TextPage := FPDFText_LoadPage(FPDF_LoadPage(FDocument, PageIndex));
  CharCount := FPDFText_CountChars(TextPage);
  
  WordBuffer := '';
  // Simplified extraction logic (in practice, use FPDFText_GetText for properly ordered strings)
  for I := 0 to CharCount - 1 do
  begin
    WordBuffer := WordBuffer + Char(FPDFText_GetUnicode(TextPage, I));
    
    // Determine word boundaries (spaces or punctuation)
    if IsWordBoundary(WordBuffer[Length(WordBuffer)]) then
    begin
      // Retrieve the bounding box for the word's characters
      FPDFText_GetRect(TextPage, I - Length(WordBuffer) + 1, Length(WordBuffer), 
                       @CharRect[0], @CharRect[1], @CharRect[2], @CharRect[3]);
                       
      // Enqueue the word to the TTS engine and store the visual rect for highlighting
      SpeechEngine.Speak(WordBuffer);
      HighlightRectOnScreen(CharRect);
      
      WordBuffer := '';
    end;
  end;
  FPDFText_ClosePage(TextPage);
end;

Integrácia SAPI 5 v Delphi

Systém Windows poskytuje rozhranie Speech API (SAPI), ku ktorému je možné v Delphi ľahko pristupovať prostredníctvom COM.

uses
  ComObj;

var
  SpVoice: OLEVariant;
begin
  SpVoice := CreateOleObject('SAPI.SpVoice');
  // Speak the text asynchronously so the UI thread doesn't freeze
  SpVoice.Speak('Welcome to the accessible PDF reader.', 1); // 1 = SVSFlagsAsync
end;

Pre produkčnú aplikáciu by ste sa mali prihlásiť na odber udalostí SAPI, ako sú WordBoundary, čo vám umožní presne synchronizovať vizuálne zvýraznenie PDF dokumentu so zvukom. Budete tiež musieť zvládnuť ovládacie prvky ako pozastavenie (pause), obnovenie (resume) a zmena rýchlosti čítania.

Poznámka: Plný prístup k textovým fragmentom a k ohraničujúcim obdĺžnikom, ktoré sú nevyhnutné pre nástroje na prevod textu na reč, je poskytovaný komponentom PDFium Component.