Technical Article

Bygga tillgängliga PDF-läsare med talsyntes i Delphi

Tillgänglighet är inte längre en valfri funktion inom modern mjukvaruutveckling. Under regelverk som ADA (Americans with Disabilities Act) och EU:s webbtillgänglighetsdirektiv måste programvara som hanterar dokument tillhandahålla assisterande teknik. För PDF-läsare innebär detta att man implementerar robust talsyntes (Text-to-Speech, TTS) och integration för skärmläsare.

I den här artikeln ska vi titta på hur man extraherar semantiska textströmmar från en PDF med hjälp av PDFium i Delphi, och sedan matar in den texten i Windows Speech API (SAPI) för att bygga en fullt tillgänglig PDF-läsare.

Utmaningen med extrahering av PDF-text

En PDF är i grunden en rityta med målningsinstruktioner. Den vet inte i sig vad ett "stycke" eller en "kolumn" är; den placerar helt enkelt glyfer på specifika X/Y-koordinater. För att läsa ett dokument högt i en logisk ordning måste din tolkare återskapa läsordningen.

PDFium hanterar detta via FPDFText_*-API-familjen, som analyserar glyfernas rumsliga förhållanden för att mata ut sammanhängande textströmmar.

Steg 1: Extrahera text med PDFium

Innan vi kan tala texten måste vi extrahera den. Följande Delphi-kod demonstrerar hur man initierar en textsida och extraherar dess innehåll till en standardsträng.

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;

Steg 2: Integrera Windows Speech API (SAPI)

När vi har den semantiska texten kan vi skicka den till Windows Speech API. SAPI tillhandahåller COM-gränssnittet SpVoice, vilket möjliggör asynkron talsyntes, röstval och kontroll av talhastighet.

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;

Steg 3: Synkronisera tal med markering

En verkligt tillgänglig läsare läser inte bara texten blint; den markerar orden på skärmen allt eftersom de talas. SAPI tillhandahåller händelser (via anslutningspunkter) som utlöses när en ordgräns nås.

Genom att mappa teckenindexet som returneras av SAPIs händelse för ordgräns tillbaka till teckenindexet i PDFium med hjälp av FPDFText_GetCharBox(), kan du hämta den avgränsande rektangeln för det just nu talade ordet och rita en markeringsöverläggning (highlight overlay) på din läsares rityta.

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;

Bygga en inkluderande applikation

Genom att kombinera PDFiums rumsliga textextrahering med SAPIs talmotor kan Delphi-utvecklare skapa kraftfulla verktyg för synskadade användare eller de som föredrar auditivt lärande. Genom att implementera dessa funktioner korrekt säkerställs att din applikation uppfyller strikta tillgänglighetsstandarder för företag och myndigheter.

Obs: Integrerad textextrahering och koordinatmappning stöds fullt ut av PDFium Component.