Technical Article

Construindo Visualizadores de PDF Acessíveis com Text-to-Speech no Delphi

A acessibilidade não é mais um recurso opcional no desenvolvimento de software moderno. Sob regulamentações como a ADA (Lei dos Americanos com Deficiências) e a Diretiva de Acessibilidade da Web da UE, os softwares que lidam com documentos devem fornecer tecnologias assistivas. Para visualizadores de PDF, isso significa implementar recursos robustos de Text-to-Speech (TTS) e integração de leitores de tela.

Neste artigo, veremos como extrair fluxos de texto semânticos de um PDF usando o PDFium no Delphi e, em seguida, alimentar esse texto na API de Fala do Windows (SAPI) para construir um visualizador de PDF totalmente acessível.

O Desafio da Extração de Texto de PDF

Um PDF é fundamentalmente uma tela de instruções de pintura. Ele não sabe inerentemente o que é um "parágrafo" ou uma "coluna"; ele meramente posiciona glifos em coordenadas X/Y específicas. Para ler um documento em voz alta em uma ordem lógica, seu analisador deve reconstruir a ordem de leitura.

O PDFium lida com isso através da família de APIs FPDFText_*, que analisa as relações espaciais dos glifos para gerar fluxos de texto coerentes.

Etapa 1: Extraindo Texto com o PDFium

Antes de podermos falar o texto, devemos extraí-lo. O código Delphi a seguir demonstra como inicializar uma página de texto e extrair seu conteúdo para uma string padrão.

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;

Etapa 2: Integrando a API de Fala do Windows (SAPI)

Assim que tivermos o texto semântico, podemos passá-lo para a API de Fala do Windows. A SAPI fornece a interface COM SpVoice, que permite síntese de fala assíncrona, seleção de voz e controle da taxa de fala.

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;

Etapa 3: Sincronizando a Fala com o Realce

Um visualizador verdadeiramente acessível não apenas lê o texto cegamente; ele realça as palavras na tela conforme são faladas. A SAPI fornece eventos (por meio de pontos de conexão) que são acionados quando um limite de palavra é alcançado.

Ao mapear o índice de caractere retornado pelo evento de limite de palavra da SAPI de volta para o índice de caractere no PDFium usando FPDFText_GetCharBox(), você pode recuperar o retângulo delimitador da palavra falada no momento e desenhar uma sobreposição de realce na tela do visualizador.

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;

Construindo um Aplicativo Inclusivo

Ao combinar a extração de texto espacial do PDFium com o mecanismo de fala da SAPI, os desenvolvedores do Delphi podem criar ferramentas poderosas para usuários com deficiência visual ou aqueles que preferem o aprendizado auditivo. Implementar adequadamente esses recursos garante que seu aplicativo esteja em conformidade com rigorosos padrões de acessibilidade corporativos e governamentais.

Nota: A extração de texto integrada e o mapeamento de coordenadas são totalmente suportados pelo PDFium Component.