Technical Article

Construirea de vizualizatoare PDF accesibile cu Text-to-Speech în Delphi

Accesibilitatea nu mai este o caracteristică opțională în dezvoltarea modernă de software. Conform reglementărilor precum ADA (Americans with Disabilities Act) și Directivei UE privind accesibilitatea site-urilor web, software-ul care gestionează documente trebuie să ofere tehnologii de asistență. Pentru vizualizatoarele PDF, acest lucru înseamnă implementarea unei integrări robuste Text-to-Speech (TTS) și a cititoarelor de ecran.

În acest articol, vom analiza modul de extragere a fluxurilor de text semantic dintr-un PDF folosind PDFium în Delphi, și apoi transmiterea acelui text către Windows Speech API (SAPI) pentru a construi un vizualizator PDF complet accesibil.

Provocarea extragerii textului din PDF

Un PDF este în esență o pânză cu instrucțiuni de desenare. Nu știe inerent ce este un „paragraf” sau o „coloană”; pur și simplu plasează glife la coordonate X/Y specifice. Pentru a citi un document cu voce tare într-o ordine logică, parserul dumneavoastră trebuie să reconstruiască ordinea de citire.

PDFium gestionează acest lucru prin familia de API-uri FPDFText_*, care analizează relațiile spațiale ale glifelor pentru a produce fluxuri de text coerente.

Pasul 1: Extragerea textului cu PDFium

Înainte de a putea vorbi textul, trebuie să îl extragem. Următorul cod Delphi demonstrează modul de inițializare a unei pagini de text și extragerea conținutului său într-un șir de caractere standard.

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;

Pasul 2: Integrarea Windows Speech API (SAPI)

Odată ce avem textul semantic, îl putem transmite către Windows Speech API. SAPI oferă interfața COM SpVoice, care permite sinteza asincronă a vorbirii, selectarea vocii și controlul vitezei de vorbire.

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;

Pasul 3: Sincronizarea vorbirii cu evidențierea

Un vizualizator cu adevărat accesibil nu doar citește textul orbește; el evidențiază cuvintele pe ecran pe măsură ce sunt rostite. SAPI oferă evenimente (prin connection points) care se declanșează atunci când este atinsă o limită de cuvânt.

Mapând indexul caracterului returnat de evenimentul SAPI de limită de cuvânt înapoi la indexul caracterului din PDFium utilizând FPDFText_GetCharBox(), puteți prelua dreptunghiul de încadrare al cuvântului rostit curent și puteți desena o suprapunere de evidențiere (highlight) pe pânza vizualizatorului dumneavoastră.

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;

Construirea unei aplicații incluzive

Combinând extragerea textului spațial a PDFium cu motorul de vorbire SAPI, dezvoltatorii Delphi pot crea instrumente puternice pentru utilizatorii cu deficiențe de vedere sau pentru cei care preferă învățarea auditivă. Implementarea corectă a acestor caracteristici asigură faptul că aplicația dumneavoastră respectă standardele stricte de accesibilitate pentru companii și guvern.

Notă: Extragerea integrată a textului și maparea coordonatelor sunt pe deplin suportate de PDFium Component.