Technical Article

Xây dựng trình xem PDF có thể truy cập bằng văn bản thành giọng nói trong Delphi

Khả năng truy cập không còn là một tính năng tùy chọn trong phát triển phần mềm hiện đại. Theo các quy định như ADA (Đạo luật Người khuyết tật Hoa Kỳ) và Chỉ thị về Khả năng truy cập Web của EU, phần mềm xử lý tài liệu phải cung cấp các công nghệ hỗ trợ. Đối với trình xem PDF, điều này có nghĩa là triển khai sự tích hợp mạnh mẽ với công cụ Chuyển văn bản thành giọng nói (Text-to-Speech - TTS) và trình đọc màn hình.

Trong bài viết này, chúng ta sẽ xem xét cách trích xuất các luồng văn bản ngữ nghĩa từ tệp PDF bằng PDFium trong Delphi, sau đó đưa văn bản đó vào Windows Speech API (SAPI) để xây dựng một trình xem PDF hoàn toàn có thể truy cập được.

Thách thức của việc trích xuất văn bản PDF

Về cơ bản, một tệp PDF là một khung vẽ (canvas) của các lệnh đồ họa. Bản thân nó không biết "đoạn văn" hoặc "cột" là gì; nó chỉ đơn thuần đặt các ký tự (glyphs) tại các tọa độ X/Y cụ thể. Để đọc to một tài liệu theo một thứ tự hợp lý, trình phân tích cú pháp của bạn phải xây dựng lại thứ tự đọc.

PDFium xử lý điều này thông qua họ API FPDFText_*, phân tích các mối quan hệ không gian của các ký tự để xuất ra các luồng văn bản mạch lạc.

Bước 1: Trích xuất văn bản với PDFium

Trước khi chúng ta có thể nói văn bản, chúng ta phải trích xuất nó. Mã Delphi sau đây thể hiện cách khởi tạo một trang văn bản và trích xuất nội dung của nó vào một chuỗi chuẩn.

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;

Bước 2: Tích hợp Windows Speech API (SAPI)

Khi chúng ta có văn bản ngữ nghĩa, chúng ta có thể chuyển nó đến Windows Speech API. SAPI cung cấp giao diện COM SpVoice, cho phép tổng hợp giọng nói không đồng bộ, chọn giọng nói và kiểm soát tốc độ nói.

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;

Bước 3: Đồng bộ hóa giọng nói với tính năng làm nổi bật (Highlighting)

Một trình xem thực sự có thể truy cập không chỉ đọc văn bản một cách mù quáng; nó làm nổi bật các từ trên màn hình khi chúng được nói. SAPI cung cấp các sự kiện (thông qua các điểm kết nối) sẽ kích hoạt khi đạt đến ranh giới từ.

Bằng cách ánh xạ chỉ số ký tự được trả về bởi sự kiện ranh giới từ của SAPI trở lại chỉ số ký tự trong PDFium bằng cách sử dụng FPDFText_GetCharBox(), bạn có thể lấy hình chữ nhật bao quanh (bounding rectangle) của từ đang được nói và vẽ một lớp phủ làm nổi bật trên khung xem (viewer canvas) của mình.

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;

Xây dựng một ứng dụng hòa nhập

Bằng cách kết hợp việc trích xuất văn bản không gian của PDFium với công cụ giọng nói của SAPI, các nhà phát triển Delphi có thể tạo ra các công cụ mạnh mẽ cho người dùng khiếm thị hoặc những người thích học qua thính giác. Việc triển khai đúng đắn các tính năng này đảm bảo ứng dụng của bạn tuân thủ các tiêu chuẩn về khả năng truy cập nghiêm ngặt của doanh nghiệp và chính phủ.

Lưu ý: Khả năng trích xuất văn bản và ánh xạ tọa độ tích hợp được hỗ trợ đầy đủ bởi PDFium Component.