Technical Article

Toegankelijke PDF-viewers bouwen met tekst-naar-spraak in Delphi

Toegankelijkheid is niet langer een optionele functie in moderne softwareontwikkeling. Volgens regelgeving zoals de ADA (Americans with Disabilities Act) en de Europese Richtlijn inzake webtoegankelijkheid moet software die documenten verwerkt, ondersteunende technologieën bieden. Voor PDF-viewers betekent dit het implementeren van robuuste tekst-naar-spraak (TTS) en integratie van schermlezers.

In dit artikel bekijken we hoe u semantische tekststreams uit een PDF kunt extraheren met behulp van PDFium in Delphi, en die tekst vervolgens kunt invoeren in de Windows Speech API (SAPI) om een volledig toegankelijke PDF-viewer te bouwen.

De uitdaging van PDF-tekstextractie

Een PDF is in wezen een canvas met tekeninstructies. Het weet niet van nature wat een "alinea" of een "kolom" is; het plaatst slechts glyphs op specifieke X/Y-coördinaten. Om een document in een logische volgorde hardop voor te lezen, moet uw parser de leesvolgorde reconstrueren.

PDFium handelt dit af via de FPDFText_* API-familie, die de ruimtelijke relaties van glyphs analyseert om coherente tekststreams uit te voeren.

Stap 1: Tekst extraheren met PDFium

Voordat we de tekst kunnen uitspreken, moeten we deze extraheren. De volgende Delphi-code demonstreert hoe u een tekstpagina initialiseert en de inhoud ervan extraheert naar een standaard string.

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;

Stap 2: De Windows Speech API (SAPI) integreren

Zodra we de semantische tekst hebben, kunnen we deze doorgeven aan de Windows Speech API. SAPI biedt de SpVoice COM-interface, die asynchrone spraaksynthese, stemselectie en snelheidsregeling van de spraak mogelijk maakt.

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;

Stap 3: Spraak synchroniseren met markering

Een echt toegankelijke viewer leest de tekst niet alleen blindelings voor; het markeert de woorden op het scherm terwijl ze worden uitgesproken. SAPI biedt gebeurtenissen (via verbindingspunten) die worden geactiveerd wanneer een woordgrens wordt bereikt.

Door de tekenindex die wordt geretourneerd door de SAPI-woordgrensgebeurtenis terug te koppelen naar de tekenindex in PDFium met behulp van FPDFText_GetCharBox(), kunt u de begrenzingsrechthoek (bounding box) van het momenteel gesproken woord ophalen en een markerings-overlay op uw viewer-canvas tekenen.

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;

Een inclusieve applicatie bouwen

Door de ruimtelijke tekstextractie van PDFium te combineren met de spraakengine van SAPI, kunnen Delphi-ontwikkelaars krachtige tools maken voor visueel gehandicapte gebruikers of degenen die de voorkeur geven aan auditief leren. Het correct implementeren van deze functies zorgt ervoor dat uw applicatie voldoet aan strikte toegankelijkheidsnormen voor bedrijven en overheden.

Opmerking: Geïntegreerde tekstextractie en coördinatenmapping worden volledig ondersteund door de PDFium Component.