Technical Article

Erstellen von barrierefreien PDF-Viewern mit Text-to-Speech in Delphi

Barrierefreiheit ist in der modernen Softwareentwicklung kein optionales Feature mehr. Nach Vorschriften wie dem ADA (Americans with Disabilities Act) und der EU-Richtlinie über den barrierefreien Zugang zum Web muss Software, die Dokumente verarbeitet, unterstützende Technologien bereitstellen. Für PDF-Viewer bedeutet dies die Implementierung einer robusten Text-to-Speech (TTS)- und Screenreader-Integration.

In diesem Artikel sehen wir uns an, wie man mithilfe von PDFium in Delphi semantische Text-Streams aus einem PDF extrahiert und diesen Text dann in die Windows Speech API (SAPI) einspeist, um einen vollständig barrierefreien PDF-Viewer zu erstellen.

Die Herausforderung der PDF-Textextraktion

Ein PDF ist im Grunde eine Leinwand mit Malanweisungen. Es weiß von Natur aus nicht, was ein „Absatz“ oder eine „Spalte“ ist; es platziert lediglich Glyphen an bestimmten X/Y-Koordinaten. Um ein Dokument in einer logischen Reihenfolge laut vorzulesen, muss Ihr Parser die Lesereihenfolge rekonstruieren.

PDFium handhabt dies über die FPDFText_*-API-Familie, die die räumlichen Beziehungen von Glyphen analysiert, um kohärente Text-Streams auszugeben.

Schritt 1: Textextraktion mit PDFium

Bevor wir den Text sprechen können, müssen wir ihn extrahieren. Der folgende Delphi-Code zeigt, wie eine Textseite initialisiert und ihr Inhalt in einen Standard-String extrahiert wird.

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;

Schritt 2: Integration der Windows Speech API (SAPI)

Sobald wir den semantischen Text haben, können wir ihn an die Windows Speech API übergeben. SAPI stellt die COM-Schnittstelle SpVoice zur Verfügung, die eine asynchrone Sprachsynthese, die Auswahl der Stimme und die Steuerung der Sprechgeschwindigkeit ermöglicht.

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;

Schritt 3: Synchronisierung der Sprache mit Hervorhebungen

Ein wirklich barrierefreier Viewer liest den Text nicht nur blind vor; er hebt die Wörter auf dem Bildschirm hervor, während sie gesprochen werden. SAPI bietet Ereignisse (über Verbindungspunkte), die ausgelöst werden, wenn eine Wortgrenze erreicht ist.

Indem Sie den vom SAPI-Wortgrenzen-Ereignis zurückgegebenen Zeichenindex mithilfe von FPDFText_GetCharBox() wieder dem Zeichenindex in PDFium zuordnen, können Sie das Begrenzungsrechteck des aktuell gesprochenen Wortes abrufen und ein Hervorhebungs-Overlay auf dem Viewer-Canvas zeichnen.

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;

Aufbau einer inklusiven Anwendung

Durch die Kombination der räumlichen Textextraktion von PDFium mit der Sprach-Engine von SAPI können Delphi-Entwickler leistungsstarke Tools für sehbehinderte Benutzer oder für diejenigen erstellen, die auditives Lernen bevorzugen. Die ordnungsgemäße Implementierung dieser Funktionen stellt sicher, dass Ihre Anwendung strengen Barrierefreiheitsstandards von Unternehmen und Behörden entspricht.

Hinweis: Integrierte Textextraktion und Koordinatenzuordnung werden von der PDFium Component VCL-Komponente vollständig unterstützt.