技術記事

PDFium Component: Delphi での render cache and zoom performance

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

この記事は developers building document viewers that must feel responsive on large PDFs and high-DPI displays 向けです。render cache and zoom performance を単なるコンポーネント呼び出しではなく、本番向けのドキュメントエンジニアリングとして扱います。

実務上のリスクは zooming can appear fast in a sample but stutter under large pages, thumbnails, annotations, continuous scrolling, or memory pressure です。そのため、明確な契約、観測可能な診断、実際の顧客ファイルに近い回帰サンプルが必要です。

アーキテクチャ上の判断

Define cache policy as viewer behavior. cache key fields such as page, zoom, rotation, DPI, color mode, and annotation state / memory budget, eviction strategy, thumbnail sharing, and prefetch distance

  • cache key fields such as page, zoom, rotation, DPI, color mode, and annotation state
  • memory budget, eviction strategy, thumbnail sharing, and prefetch distance
  • progressive rendering behavior for fast preview versus final-quality output
  • cancellation rules when users scroll, resize, search, or change zoom quickly

実装フロー

Measure the interaction path, not only render time. The order below keeps the workflow reviewable for Delphi and C++Builder teams.

  1. record render requests through one queue instead of direct control event handlers
  2. reuse cached bitmaps only when the key fully matches the visible state
  3. render low-latency placeholders before high-quality pages when appropriate
  4. cancel stale jobs and evict pages outside the viewport and prefetch window
  5. measure frame latency and memory during realistic scroll and zoom sequences

検証エビデンス

Performance evidence users can feel. Keep these fields with the output or support record.

  • cache hit rate, render latency, queue depth, cancellation count, and memory peak
  • viewport size, zoom level, DPI, page dimensions, and color-filter state
  • time to first preview and time to final-quality render
  • eviction and prefetch behavior during continuous scrolling

Caching is a user-experience feature

A render cache should balance page quality, memory budget, cancellation, invalidation, and perceived latency. The viewer needs to cancel stale work when the user scrolls or zooms rather than finishing irrelevant renders.

Profile ownership and versioning

A named, versioned profile is easier to review than options scattered across forms, scripts, and batch parameters. It also makes support reports readable when customers use older templates or policies.

  • cache key fields such as page, zoom, rotation, DPI, color mode, and annotation state
  • memory budget, eviction strategy, thumbnail sharing, and prefetch distance
  • progressive rendering behavior for fast preview versus final-quality output
  • cancellation rules when users scroll, resize, search, or change zoom quickly
  • cache hit rate, render latency, queue depth, cancellation count, and memory peak
  • viewport size, zoom level, DPI, page dimensions, and color-filter state

render cache and zoom performance に関する技術レビューの注意点

これらのレビュー項目を使って、機能がデモ段階を超え、リリース、サポート、顧客エスカレーションの場で説明できることを確認します

  • 判断: cache key fields such as page, zoom, rotation, DPI, color mode, and annotation state. 実装上の焦点: reuse cached bitmaps only when the key fully matches the visible state. 受け入れ証拠: time to first preview and time to final-quality render. 回帰の引き金: rendering thumbnails and pages through separate caches wastes memory
  • 判断: memory budget, eviction strategy, thumbnail sharing, and prefetch distance. 実装上の焦点: render low-latency placeholders before high-quality pages when appropriate. 受け入れ証拠: eviction and prefetch behavior during continuous scrolling. 回帰の引き金: large engineering drawings can exceed cache assumptions made for letters or invoices
  • 判断: progressive rendering behavior for fast preview versus final-quality output. 実装上の焦点: cancel stale jobs and evict pages outside the viewport and prefetch window. 受け入れ証拠: cache hit rate, render latency, queue depth, cancellation count, and memory peak. 回帰の引き金: annotation overlays invalidate cached pages when review state changes
  • 判断: cancellation rules when users scroll, resize, search, or change zoom quickly. 実装上の焦点: measure frame latency and memory during realistic scroll and zoom sequences. 受け入れ証拠: viewport size, zoom level, DPI, page dimensions, and color-filter state. 回帰の引き金: high-DPI displays multiply bitmap memory even when page count is small
  • 判断: cache key fields such as page, zoom, rotation, DPI, color mode, and annotation state. 実装上の焦点: record render requests through one queue instead of direct control event handlers. 受け入れ証拠: time to first preview and time to final-quality render. 回帰の引き金: rendering thumbnails and pages through separate caches wastes memory
  • 判断: memory budget, eviction strategy, thumbnail sharing, and prefetch distance. 実装上の焦点: reuse cached bitmaps only when the key fully matches the visible state. 受け入れ証拠: eviction and prefetch behavior during continuous scrolling. 回帰の引き金: large engineering drawings can exceed cache assumptions made for letters or invoices
  • 判断: progressive rendering behavior for fast preview versus final-quality output. 実装上の焦点: render low-latency placeholders before high-quality pages when appropriate. 受け入れ証拠: cache hit rate, render latency, queue depth, cancellation count, and memory peak. 回帰の引き金: annotation overlays invalidate cached pages when review state changes

境界ケース

  • large engineering drawings can exceed cache assumptions made for letters or invoices
  • annotation overlays invalidate cached pages when review state changes
  • high-DPI displays multiply bitmap memory even when page count is small
  • rendering thumbnails and pages through separate caches wastes memory

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. 重要な用語には render cache, zoom, DPI, progressive rendering, eviction, prefetch.

Delphi コード例

次の Delphi スケッチは、このテーマに対する実用的なサービス境界を示します。ポリシー確認、ログ記録、検証を製品呼び出しの狭い部分の外側に置くと、ワークフローをテストしやすくなります。

procedure TPreviewForm.RenderCachedPage(PageIndex: Integer; Zoom: Double);
var
  CacheKey: string;
begin
  CacheKey := Format('%d:%.2f', [PageIndex, Zoom]);
  if not FRenderCache.TryGetValue(CacheKey, FPageBitmap) then
  begin
    FPageBitmap := PdfView.RenderPage(PageIndex, 0, Round(850 * Zoom), Round(1100 * Zoom), ro0, []);
    FRenderCache.Add(CacheKey, FPageBitmap);
  end;
  PaintBitmap(FPageBitmap);
end;

本番チェックリスト

  • ワークフローは、空のファイル、通常の顧客ファイル、最悪ケースのファイルで実行します
  • 生成された PDF は、対象のビューアー、検証ツール、プリンター、または downstream アプリケーションで開きます
  • 製品バージョン、プロファイルバージョン、入力ハッシュ、出力パス、経過時間、警告数を記録します
  • パスワード、証明書、一時ファイル、顧客データは明確な保持ルールの下で管理します
  • 顧客ファイルが新しい境界ケースを示したら、回帰用ドキュメントを追加します

製品ドキュメント

PDFium Component

追加のコード例

procedure TViewerForm.RequestRender(TargetZoom: Single);
var
  Status: TPdfProgressiveStatus;
begin
  if FTokenSource <> nil then
    FTokenSource.Cancel;           // abandon the previous in-flight render
  FTokenSource := TPdfCancellationTokenSource.New;  // FPdfAsync unit

  Status := Pdf.RenderPageProgressive(FBackBuffer, 0, 0,
    FBackBuffer.Width, FBackBuffer.Height, FTokenSource.Token,
    ro0, [reAnnotations]);

  case Status of
    prsDone:      PresentBackBuffer;
    prsCancelled: ;                // superseded by a newer request: drop silently
    prsFailed:    ShowRenderFailure;
  end;
end;