Dostępność (accessibility) nie jest już opcjonalną funkcją w nowoczesnym tworzeniu oprogramowania. Zgodnie z przepisami, takimi jak ADA (Americans with Disabilities Act) oraz unijną dyrektywą w sprawie dostępności stron internetowych, oprogramowanie obsługujące dokumenty musi zapewniać wsparcie dla technologii asystujących. W przypadku przeglądarek PDF oznacza to wdrożenie solidnej integracji z funkcją Text-to-Speech (TTS) oraz czytnikami ekranu.
W tym artykule przyjrzymy się, jak wyodrębnić semantyczne strumienie tekstu z pliku PDF przy użyciu PDFium w Delphi, a następnie przekazać ten tekst do interfejsu Windows Speech API (SAPI), aby zbudować w pełni dostępny czytnik PDF.
Wyzwanie ekstrakcji tekstu z PDF
Zasadniczo PDF to po prostu obszar roboczy wypełniony instrukcjami rysowania. Format ten z natury nie "wie", czym jest "akapit" czy "kolumna"; po prostu umieszcza glify w określonych współrzędnych X i Y. Aby móc odczytać dokument na głos w logicznej kolejności, parser musi najpierw zrekonstruować odpowiednią kolejność czytania.
W PDFium zadanie to realizuje rodzina interfejsów API FPDFText_*, która analizuje relacje przestrzenne glifów, wyprowadzając z nich spójne strumienie tekstowe.
Krok 1: Ekstrakcja tekstu przy użyciu PDFium
Zanim będziemy mogli wypowiedzieć tekst na głos, musimy go wyodrębnić. Poniższy kod Delphi demonstruje, jak zainicjować stronę tekstową i wyodrębnić jej zawartość do standardowego ciągu znaków.
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;
Krok 2: Integracja Windows Speech API (SAPI)
Kiedy mamy już tekst semantyczny, możemy przekazać go do interfejsu Windows Speech API. SAPI udostępnia interfejs COM SpVoice, który umożliwia asynchroniczną syntezę mowy, wybór głosu oraz kontrolę tempa czytania.
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;
Krok 3: Synchronizacja mowy z podświetlaniem
Naprawdę dostępny czytnik nie tylko "na ślepo" odczytuje tekst; on również podświetla słowa na ekranie w miarę ich wypowiadania. SAPI dostarcza zdarzenia (za pośrednictwem punktów połączeń), które są wyzwalane po osiągnięciu granicy słowa.
Mapując indeks znaku zwrócony przez zdarzenie granicy słowa SAPI z powrotem na indeks znaku w PDFium za pomocą funkcji FPDFText_GetCharBox(), możesz pobrać prostokąt ograniczający (bounding rectangle) aktualnie wypowiadanego słowa i narysować podświetlenie na płótnie swojego czytnika.
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;
Budowanie aplikacji inkluzywnej
Łącząc przestrzenną ekstrakcję tekstu z PDFium oraz silnik mowy SAPI, programiści Delphi mogą tworzyć potężne narzędzia dla użytkowników niedowidzących lub preferujących naukę ze słuchu. Prawidłowe wdrożenie tych funkcji gwarantuje, że Twoja aplikacja jest zgodna z surowymi korporacyjnymi i rządowymi standardami dostępności.
Uwaga: Zintegrowana ekstrakcja tekstu i mapowanie współrzędnych są w pełni obsługiwane przez PDFium Component.