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

PDFium: render cache and zoom performance в Delphi

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

Эта статья предназначена для 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;