Техническая статья

PDFium: word tracking and speech cursoring в Delphi

Встраивайте workflow PDFium VCL Component в приложения Delphi и C++Builder или workflow PDFium LCL Component в Lazarus/FPC, используя компоненты с исходным кодом для просмотра, рендеринга, форм, печати, preflight-отчетов и проверки по стандартам.

Эта статья предназначена для developers building read-aloud, study, review, or assisted-reading features в Delphi PDF viewers. Она рассматривает word tracking and speech cursoring как промышленную инженерию документов, а не как одиночный вызов компонента.

Практический риск состоит в том, что speech highlighting becomes distracting or wrong when word boxes, ligatures, rotation, hidden text, and timing do not match the spoken stream. Поэтому процессу нужны письменный контракт, наблюдаемая диагностика и реалистичные регрессионные файлы.

Архитектурные решения

Synchronize speech with extracted text, not pixels alone. text extraction source, word segmentation policy, and language assumptions / highlight style, scroll behavior, pause and resume rules, and user controls

  • text extraction source, word segmentation policy, and language assumptions
  • highlight style, scroll behavior, pause and resume rules, and user controls
  • fallback behavior for image-only pages, hidden text, ligatures, and rotated content
  • whether speech timing is driven by the engine, the viewer, or a shared coordinator

Порядок реализации

Track words through a stable text map. The order below keeps the workflow reviewable for Delphi and C++Builder teams.

  1. extract page text and word bounds before speech playback begins
  2. build a word map that links text offsets, page numbers, and viewer coordinates
  3. call the tracking layer as the speech engine advances through words or offsets
  4. scroll the viewport only when the current word leaves the comfortable reading zone
  5. record skipped words, missing boxes, and timing drift for diagnostics

Доказательства проверки

Synchronization evidence for assisted reading. Keep these fields with the output or support record.

  • page number, word text, text offset, bounding box, and speech timestamp
  • tracking method used, including TrackReadingWordAt when the viewer supports it
  • fallback reason for words without reliable geometry
  • latency between speech event and visible cursor update

Word boxes are viewer data

Word-synchronized reading needs a mapping between extracted text, page coordinates, and speech timing. A robust implementation knows when text is unavailable, when a word box is ambiguous, and how to keep the viewport aligned with the current spoken word.

Вопросы для проверки перед выпуском

Перед выпуском в production команда должна уметь ответить на эти вопросы без чтения исходного кода

  • Who owns text extraction source, word segmentation policy, and language assumptions?
  • What evidence proves page number, word text, text offset, bounding box, and speech timestamp?
  • What happens when ligatures can represent multiple characters inside one visual glyph?
  • Which regression file covers record skipped words, missing boxes, and timing drift for diagnostics?

Замечания для инженерного ревью по word tracking and speech cursoring

Используйте эти замечания, чтобы убедиться, что функция вышла за рамки демо и может быть обоснована на релизе, в поддержке и при эскалации клиента

  • Решение: text extraction source, word segmentation policy, and language assumptions. Точка приложения при реализации: build a word map that links text offsets, page numbers, and viewer coordinates. Доказательство приемки: fallback reason for words without reliable geometry. Триггер регрессии: rapid speech rates can require coalescing highlight updates to avoid flicker
  • Решение: highlight style, scroll behavior, pause and resume rules, and user controls. Точка приложения при реализации: call the tracking layer as the speech engine advances through words or offsets. Доказательство приемки: latency between speech event and visible cursor update. Триггер регрессии: ligatures can represent multiple characters inside one visual glyph
  • Решение: fallback behavior for image-only pages, hidden text, ligatures, and rotated content. Точка приложения при реализации: scroll the viewport only when the current word leaves the comfortable reading zone. Доказательство приемки: page number, word text, text offset, bounding box, and speech timestamp. Триггер регрессии: rotated or vertical text needs coordinate handling separate from normal pages

Пограничные случаи

  • ligatures can represent multiple characters inside one visual glyph
  • rotated or vertical text needs coordinate handling separate from normal pages
  • OCR text layers may not align perfectly with scanned images
  • rapid speech rates can require coalescing highlight updates to avoid flicker

Примечания по Delphi / C++Builder

PDFium Component should sit behind a small service boundary that receives files, streams, profiles, and credentials, then returns output paths, warnings, metrics, and validation status. Важные термины включают TrackReadingWordAt, speech cursor, word bounds, text extraction, highlight, reading assistance.

Пример кода Delphi

Следующий эскиз Delphi показывает практическую границу сервиса для этой темы. Оставляйте проверки политики, журналирование и валидацию вне узкого блока вызова продукта, чтобы сценарий было проще тестировать.

procedure TSpeechForm.SpeakWordAtCursor(PageNo, CharIndex: Integer);
var
  UnitInfo: TReadingUnit;
begin
  UnitInfo := LocateWordUnit(PdfView, PageNo, CharIndex);
  HighlightBounds(UnitInfo.PageNo, UnitInfo.Bounds);
  SpeechQueue.Speak(UnitInfo.Text);
  StoreCursorPosition(UnitInfo.PageNo, UnitInfo.EndChar);
end;

Производственный чек-лист

  • Запускайте сценарий на пустом файле, обычном клиентском файле и файле худшего случая
  • Открывайте сгенерированный PDF в целевом просмотрщике, валидаторе, принтере или downstream-приложении
  • Записывайте версию продукта, версию профиля, хэш входа, путь вывода, затраченное время и число предупреждений
  • Храните пароли, сертификаты, временные файлы и данные клиентов по явным правилам хранения
  • Добавляйте регрессионные документы, когда клиентский файл выявляет новый граничный случай

Документация по продукту

PDFium Component

Дополнительные примеры кода

procedure TReaderForm.OnSpeechWordBoundary(StreamPos: Integer);
var
  WordIdx: Integer;
begin
  // Maps the offset to a word box and moves the highlight in one call
  WordIdx := PdfView.TrackReadingWordAt(FPageNo, StreamPos);
  if WordIdx < 0 then
    Exit;                     // boundary fell outside any word: keep last highlight
end;
procedure TReaderForm.StopReading;
begin
  FVoice.Stop;                // halt SAPI playback first
  PdfView.ClearReadingWord;   // then remove the highlight; a stale cursor reads as a bug
end;