技術記事

PDFium Component: Delphi での word tracking and speech cursoring

Delphi/C++Builder には PDFium VCL Component のワークフローを、Lazarus/FPC には PDFium LCL Component のワークフローを組み込み、表示、レンダリング、フォーム、印刷、プリフライトレポート、標準対応の検証をソースコード付きコンポーネントで実装できます。

この記事は 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.

リリース前の確認事項

本番に出す前に、チームはソースコードを読まずにこれらの質問に答えられる必要があります

  • 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;