Прогрессивный рендеринг и отмена
HotPDF умеет рендерить загруженную страницу за несколько ограниченных вызовов и останавливать долгие операции с документом через общий cancellation token, принадлежащий вызывающей стороне
Прогрессивный рендеринг страниц
Для линеаризованных сетевых источников THPDFLinearizedPageRedrawScheduler отделяет диапазоны первого отображения от опциональных зависимостей shared-object и запрашивает перерисовку только когда прибывшая зависимость способна изменить страницу
Session := PDF.BeginLoadedPageProgressiveRender(0, 144);
try
repeat
Status := Session.ContinueRender(8, 128);
Preview.Assign(Session.Bitmap);
until Status in [prsCompleted, prsCancelled];
if Status = prsCompleted then
FinalBitmap := Session.TakeBitmap;
finally
Session.Free;
end;
ContinueRender принимает максимальное прошедшее время в миллисекундах, максимальное число операторов верхнего уровня в содержимом страницы — или и то и другое; ноль означает отсутствие ограничения по этому бюджету
Вызов завершает хотя бы один оператор до применения ненулевого временного бюджета, поэтому graphics state всегда ставится на паузу на границе оператора
Bitmap открывает живой частичный bitmap, доступный вызывающей стороне только для чтения, а TakeBitmap после достижения сессией prsCompleted или prsCancelled передаёт владение без копирования
ObjectsProcessed и TotalObjects считают операторы верхнего уровня из каждого stream'а /Contents страницы в порядке источника
Прогрессивный рендеринг области
Session := PDF.BeginLoadedPageProgressiveRegionRender(
0, 72, 144, 360, 432, 144);
try
repeat
Status := Session.ContinueRender(6, 96);
until Status in [prsCompleted, prsCancelled];
finally
Session.Free;
end;
Четыре координаты области задаются в пользовательских координатах PDF с началом в левом нижнем углу, а выходной bitmap покрывает ровно это окно при запрошенном DPI
Сессия переиспользует кешированную display list, сохраняет graphics и text state между вызовами и подавляет дорогие отрисовки path, текста, изображений, Form и shadings, чьи консервативные границы не пересекают ROI
Операторы состояния и продвижение текста всё равно выполняются в порядке источника, поэтому отсечение более раннего знака не может сдвинуть или перекрасить более поздний видимый знак
RegionVisiblePaintObjects и RegionCulledPaintObjects открывают отбор display list, а резерв пиковой памяти считается по размерам области, а не полной страницы
Прогрессивные JPEG scan'ы
Когда THotPDF.ProgressiveJPEGScanDecoding включён, подходящее прогрессивное изображение DCTDecode продвигается на один JPEG scan за ограниченный вызов ContinueRender, так что живой bitmap может показать грубый ранний предпросмотр до финального scan'а
THotPDF.ProgressiveJPEGMaxScans ограничивает каждое изображение диапазоном 1–4096 scan'ов, а байтовый бюджет декодирования документа покрывает и выровненный выходной bitmap
THPDFLoadedPageRenderSession.ProgressiveJPEGScansDecoded и THPDFLoadedPageRenderSession.ProgressiveJPEGImagesDecoded сообщают числа завершённых scan'ов и изображений; THPDFLoadedPageRenderSession.OnProgressiveJPEGScan получает THPDFProgressiveJPEGScanEvent после каждого видимого scan'а и может отменить сессию
Модуль HPDFJpeg также открывает THPDFJpegScanDecoder для сырых входов THPDFJpegByteArray — с результатами THPDFJpegScanDecodeStatus и опциональным callback'ом THPDFJpegCancellationCheck для отмены на уровне строк
Инкрементальный путь принимает отрисовку JPEG-изображений на всю целевую область в DeviceRGB или DeviceGray с непрозрачностью по умолчанию и без mask, transfer functions, halftones, overprint или состояния transparency-group; все прочие отрисовки идут через декодер полного изображения, чтобы не менять семантику рендеринга
Выключенная опция, требование изоляции codec, превышение лимита или повреждённый ввод тоже переключают на путь полного изображения — без показа частично неудачного декодирования
Callback'и прогресса
THPDFProgressiveRenderProgressEvent срабатывает после каждого завершённого оператора и получает счётчики обработанных и всех операторов плюс время выполнения рендеринга
Установите параметр Cancel callback'а в true, чтобы завершить сессию в prsCancelled, не отменяя общий token
Form XObject, pattern, декодирование изображения и другие вложенные операции принадлежат объемлющему оператору верхнего уровня и могут выйти за маленький временной бюджет до возврата управления
Отмена на уровне операции
Token := THPDFCancellationToken.Create;
try
PDF.OperationCancellationToken := Token;
Worker.Start;
// Call Token.Cancel from another thread when the operation should stop
finally
PDF.OperationCancellationToken := nil;
Token.Free;
end;
THPDFCancellationToken потокобезопасен, одноразовый и принадлежит вызывающей стороне; Cancel перманентно запрашивает отмену, а IsCancellationRequested открывает состояние
ThrowIfCancellationRequested возбуждает EHPDFOperationCancelled и сохраняет имя операции в OperationName
THotPDF.OperationCancellationToken действует на загрузку, синхронный рендеринг, прогрессивный рендеринг без явного token, OptimizeLoadedStreams, CreatePreflightReport и ValidatePDFVT
SignPDFWithPFX и SignPDFWithSystemCertificate имеют перегрузки, принимающие token напрямую
Владение и правила частичных результатов
- Документ и token должны жить дольше каждой ссылающейся на них
THPDFLoadedPageRenderSession - За отменённой загрузкой может последовать новая загрузка на том же экземпляре документа
- Оптимизация stream'ов кооперативная, а не транзакционная: stream'ы, завершённые до отмены, остаются оптимизированными
- Назначение подписания после отмены может содержать частичный вывод; если нужна атомарная доставка, его следует выбросить
- Вызов Windows-провайдера приватного ключа нельзя безопасно прервать, поэтому отмена проверяется непосредственно до и после этого вызова