Коллекция демо насчитывает 33 темы: 33 проекта Delphi, 32 проекта C++Builder и 33 проекта Lazarus — всего 98 нативных проектов. В основном каталоге каждой платформы собрано 24 полноценных демо рабочих процессов. Девять сфокусированных тем живут внутри Miscellaneous — это 26 нативных проектов на три платформы; XfaLab доступен для Delphi и Lazarus
Начните с рабочего процесса из основного каталога: PDFViewer для тура по функциям, CreatePDF для живого создания документов, ContentExtractionLab для мгновенной инвентаризации, FormFill для редактируемых форм, StandardsLab для валидации и конвертации или IntakeWorkbenchCli для автоматизированного приёма документов. Эти шесть точек входа сразу дают рабочий результат; сфокусированные образцы ниже пригодятся, когда нужно детально разобрать отдельный API
| Демо | Для чего | Чем отличается от родственных демо |
|---|---|---|
PDFViewer | Общий просмотр и оценка возможностей | Основной просмотрщик объединяет навигацию, поиск, миниатюры, режимы отображения, печать и витрину функций |
MultiPageViewer | Непрерывные страницы, развороты и макеты с обложкой | Сфокусированный пример макетов на встроенных API выделения просмотрщика; для более широкого просмотра берите PDFViewer |
SplitView | Сравнение страниц или документов в отдельных панелях | Демонстрирует независимые позиции представлений и адресацию команд активной панели, а не двухстраничный макет в одном представлении |
SearchAndSelect | Результаты поиска и выделение по страницам | Список результатов и параметры поиска раскрывают процесс поиска непосредственнее, чем панель просмотрщика |
PrintPDF | Предпросмотр и обычные задания печати | Диапазоны страниц, масштабирование, прогресс и отмена дают основной процесс печати |
ContentExtractionLab | Совместная инспекция нескольких категорий содержимого | Инвентаризации TXT/JSON описывают объекты и предпросматривают текст; они не заменяют полный экспорт текста или файлов изображений |
ExtractImages | Экспорт встроенных объектов изображений | Извлекает битмапы изображений, а не снимки целых страниц; встроенная фикстура содержит по два настоящих объекта изображения на каждой из двух страниц |
TableExtractionLab | Обнаружение таблиц и экспорт CSV/JSON | Таблицы с линейками и по пробелам, объединённые ячейки, группы продолжения и управление уверенностью не зависят от извлечения простого текста |
Attachment | Чтение, добавление и экспорт встроенных вложений | Операции с полезной нагрузкой вложений выходят за рамки перечисления имён и размеров в ContentExtractionLab |
BatchExport | Экспорт изображений страниц из нескольких документов | Потоковый вывод, статус по файлам и изолированные сбои демонстрируют пакетную обработку, а не одиночную конвертацию |
CreatePDF | Создание содержимого страниц с живым предпросмотром | Все три нативных варианта создают текст, доступный для поиска, векторные фигуры, настоящее растровое изображение, таблицы и аннотацию-заметку; опции перестраивают предпросмотр до явного сохранения |
ImageToPDF | Построение страниц из входных файлов изображений | Компоновка, подгонка, порядок и обработка JPEG дают процесс конвертации документов |
MergePDF | Сборка страниц из нескольких PDF | Демонстрирует импорт документов и упорядоченную композицию; разбиение решает обратную задачу |
SplitPDF | Запись выбранных групп страниц в отдельные PDF | Именование вывода и валидация групп страниц отличаются от слияния или рендеринга изображений страниц |
WatermarkStamp | Наложение повторяющихся слоёв на существующие страницы | Размещение и пакетная штамповка страниц дополняют базовые API создания |
FormFill | Интерактивный ввод AcroForm и уплощение форм | Ввод полей и сохранённые внешние виды отличаются от обмена XFDF и специфического поведения XFA |
AccessibilityReader | Интерактивное чтение и озвучивание | GUI-читалка демонстрирует навигацию по чтению и подсветку, а не аудит соответствия |
AccessibilityWorkbenchCli | Пакетный обзор доступности и генерация отчётов | Находки, сводки и пороги обзора служат автоматизации; находки не заменяют ручной обзор доступности |
StandardsLab | Валидация и конвертация по стандартам | Интерактивная лаборатория раскрывает операции и параметры, а не только генерирует агрегированный отчёт |
PreflightReport | Интерактивные отчёты по стандартам | GUI поддерживает ручную инспекцию и экспорт отчёта |
PreflightReportCli | Автоматизированные отчёты по стандартам | Пакетные входы, форматы отчётов и пороги кода выхода дают автоматизационную пару PreflightReport |
IntakeWorkbenchCli | Пакетный приём, сортировка и маршрутизация | Агрегированные отчёты, пороги сбоев и решения маршрутизации делают это процессом обработки, выходящим за рамки GUI SecurityAudit |
Открывайте эти проекты из Demo\Delphi\Miscellaneous, Demo\CBuilder\Miscellaneous или Demo\Lazarus\Miscellaneous. Они сохраняют полезные рецепты API и узкие задачи экспорта, пока основной каталог сосредоточен на полных сценариях. Базовые проверки записи и повторного чтения Unicode покрываются рабочими процессами создания и извлечения; отдельных демо-проектов для них больше нет
| Демо | Для чего | Чем отличается от родственных демо |
|---|---|---|
SecurityAudit | Интерактивная инспекция состояния безопасности | GUI делает акцент на разрешениях, скриптах, подписях и деталях безопасности, а не на маршрутизации файлов |
XfdfLab | Импорт и экспорт данных XFDF | Обмен и явное сохранение импортированного PDF демонстрируют сохраняемость; одного экспорта XFDF недостаточно для сохранения изменённого PDF |
AccessibilityLab | Обход API чтения в консоли | Компактный исполняемый обход раскрывает единицы чтения, рамки слов, структуру и вывод speech-скриптов |
ExtractText | Экспорт полного текста с выбранных страниц | Вывод текстового слоя, разделители страниц и отмена отличаются от предпросмотров инвентаризации и обнаружения таблиц; OCR не выполняется |
FontProperties | Инспекция метрик шрифтов и символов | Сразу открывается на реальных метриках шрифта и символов первого текстового объекта; выберите другую строку, чтобы сравнить шрифты, не выгружая содержимое документа |
NavigationLab | Закладки, назначения и действия навигации | Компактный обход API дополняет видимые элементы навигации в PDFViewer |
PDFtoJpg | Рендеринг одного документа в изображения страниц | Компактный пример рендеринга одного документа; Delphi раскрывает отдельные диапазоны страниц, тогда как BatchExport сосредоточен на нескольких входных документах |
PrintPreferences | Листы N-up и настройки печати автора PDF | Копии, фильтрация чёт/нечёт и настройки от автора — учебный фокус; это спутник PrintPDF |
ViewerInteractionLab | Диагностика взаимодействия мыши, клавиатуры и координат | Лог взаимодействий и преобразование координат страница/устройство делают его диагностическим инструментом API |
XfaLab | Статические пакеты XFA и возможности runtime | Открывает пакеты template и datasets обычным runtime; интерактивный рендеринг XFA требует runtime с поддержкой XFA, есть варианты для Delphi и Lazarus |
PDFViewer открывает встроенный в комплект PDFiumDemoShowcase.pdf — шестистраничный документ с текстом, доступным для поиска, векторными диаграммами, двумя встроенными изображениями, таблицей, четырьмя полями AcroForm, закладками глав, ссылками, заметкой-рецензией и двумя файловыми вложениями. Панель функций предлагает Restart showcase, Find live text, 2-page spread, Night reading, Inspect this PDF и Explore forms; каждое действие работает с текущим документом
CreatePDF открывает живой двухстраничный предпросмотр отчёта. Отредактируйте заголовок и автора либо переключите фигуры, таблицу и водяной знак, чтобы перестроить реальное содержимое страниц; опция Unicode добавляет третью страницу. Пока вы не сохраните, ничего не записывается, а сохранённый PDF остаётся доступным для поиска
MultiPageViewer, SearchAndSelect, ContentExtractionLab и FormFill открывают тот же документ для своих рабочих процессов, причём результаты поиска, инвентаризация извлечения и редактируемые поля готовы сразу. Miscellaneous\NavigationLab использует собственную локальную копию для обхода API закладок и назначений
Attachment стартует с двумя настоящими встроенными файлами. PrintPreferences открывается на четырёх страницах с настройками автора: две копии, выбранные диапазоны страниц, масштабирование и дуплекс; текущий процесс печати применяет копии и диапазоны страниц, а масштабирование и дуплекс инспектируются и попадают в отчёт. XfaLab стартует с реальных пакетов template и datasets для инспекции статического XFA; интерактивный рендеринг XFA требует подходящего runtime и является отдельной возможностью
Каждый проект просмотра, форм, извлечения и навигации содержит собственный PDFiumDemoShowcase.pdf. Скопируйте каталог проекта и держите этот встроенный входной файл рядом с распространяемым исполняемым файлом; сборки Lazarus подкладывают его автоматически. Тур работает офлайн, а общие просмотрщики и образцы извлечения вдобавок дают сгенерированный резервный контент, когда локальный PDF недоступен
Каждое нативное демо содержит собственную реализацию образца. Точки входа Delphi и Lazarus для AccessibilityLab, AccessibilityWorkbenchCli, IntakeWorkbenchCli и PreflightReportCli несут полный рабочий процесс прямо в каталоге проекта, включая специфичную для компилятора инициализацию и запись JPEG. Примеры вложений, настроек печати и XFA тоже локально строят собственные входные данные под свою функцию. За пределами скопированного проекта нужны только библиотека, соответствующий нативный runtime и обычные зависимости фреймворка компилятора
Выбирайте извлечение объектов изображений, когда нужны встроенные битмапы, рендеринг страниц, когда нужна видимая страница, и извлечение текста, когда у PDF уже есть текстовый слой. Отчёт, перечисляющий эти категории, не выгружает их полные данные. Эти границы удерживают сфокусированные примеры полезными, не раздувая каждое демо до очередного универсального просмотрщика или workbench
Pdf1.FileName := 'C:\MyDocument.pdf';
Pdf1.Active := True;
ShowMessage('Pages: ' + IntToStr(Pdf1.PageCount));
ShowMessage('Title: ' + Pdf1.Title);
ShowMessage('Author: ' + Pdf1.Author);
var
Stream: TMemoryStream;
begin
Stream := TMemoryStream.Create;
try
Stream.LoadFromFile('C:\MyDocument.pdf');
Pdf1.LoadDocument(Stream, True);
Pdf1.Active := True;
ShowMessage('PDF loaded from stream');
finally
Stream.Free;
end;
end;
Pdf1.CreateDocument;
Pdf1.Active := True;
Pdf1.AddPage(0, 612, 792);
Pdf1.PageNumber := 1;
Pdf1.AddText('Hello World!', 'Arial', 12, 100, 700, clBlack, $FF, 0.0);
Pdf1.UpdatePage;
Pdf1.SaveAs('C:\NewDocument.pdf');
Pdf1.Active := False;
var
PageText: WString;
RectText: WString;
begin
Pdf1.PageNumber := 1;
PageText := Pdf1.Text;
Memo1.Text := PageText;
RectText := Pdf1.TextInRectangle(100, 100, 500, 200);
ShowMessage('Text in rectangle: ' + RectText);
end;
var
Position: Integer;
begin
Position := Pdf1.FindFirst('Hello', [seCaseSensitive]);
while Position >= 0 do
begin
ShowMessage('Found at character: ' + IntToStr(Position));
Position := Pdf1.FindNext;
end;
end;
Pdf1.PageNumber := 1;
Pdf1.AddText('Document Title', 'Times New Roman', 16, 100, 750, clBlue);
Pdf1.AddText('This is the document content.', 'Arial', 12, 100, 700, clBlack);
Pdf1.UpdatePage;
var
I: Integer;
MetricSize: Single;
FontBytes: TBytes;
begin
Pdf1.PageNumber := 1;
for I := 0 to Pdf1.ObjectCount - 1 do
if Pdf1.ObjectType[I] = otText then
begin
MetricSize := 12.0;
FontBytes := Pdf1.FontData[I];
Memo1.Lines.Add('Object ' + IntToStr(I));
Memo1.Lines.Add('Base name: ' + Pdf1.FontBaseName[I]);
Memo1.Lines.Add('Family: ' + Pdf1.FontFamilyName[I]);
Memo1.Lines.Add('Embedded: ' + BoolToStr(Pdf1.FontIsEmbedded[I], True));
Memo1.Lines.Add('Weight: ' + IntToStr(Pdf1.FontWeight[I]));
Memo1.Lines.Add('Italic angle: ' + IntToStr(Pdf1.FontItalicAngle[I]));
Memo1.Lines.Add('Ascent: ' + FloatToStr(Pdf1.FontAscent[I, MetricSize]));
Memo1.Lines.Add('Descent: ' + FloatToStr(Pdf1.FontDescent[I, MetricSize]));
Memo1.Lines.Add('Font data bytes: ' + IntToStr(Length(FontBytes)));
end;
if Pdf1.CharacterCount > 0 then
begin
Memo1.Lines.Add('First character size: ' + FloatToStr(Pdf1.CharacterFontSize[0]));
Memo1.Lines.Add('First character weight: ' + IntToStr(Pdf1.CharacterFontWeight[0]));
Memo1.Lines.Add('First character angle: ' + FloatToStr(Pdf1.CharacterAngle[0]));
end;
end;
Проекты Demo\Delphi\Miscellaneous\FontProperties, Demo\CBuilder\Miscellaneous\FontProperties и Demo\Lazarus\Miscellaneous\FontProperties показывают те же метаданные через TPdf и TPdfView
Проекты Demo\Delphi\ContentExtractionLab, Demo\CBuilder\ContentExtractionLab и Demo\Lazarus\ContentExtractionLab превращают извлечение содержимого в единый рабочий процесс. Они открывают или создают PDF, позволяют пользователям выбрать метаданные, текст страниц, объекты страниц, изображения, вложения, ссылки, аннотации, закладки и метрики шрифтов / символов, затем генерируют сводку плюс подробный отчёт TXT или JSON. Лаборатория также включает выбор всех / ни одной категории, копирование отчёта в буфер обмена и действия сохранения исходного PDF, чтобы пользователи могли держать сгенерированный образец PDF рядом с его отчётом извлечения. ExtractImages и Attachment дают рабочие процессы экспорта полезной нагрузки, а Miscellaneous\ExtractText и Miscellaneous\FontProperties остаются сфокусированными примерами API; ExtractText поддерживает параметры диапазона страниц и разделителя страниц для формирования постраничного текстового вывода в Delphi, C++Builder и Lazarus, тогда как ContentExtractionLab представляет собой образец сквозной инвентаризации
Проекты Demo\Delphi\TableExtractionLab, Demo\CBuilder\TableExtractionLab и Demo\Lazarus\TableExtractionLab превращают обнаружение таблиц в единый сценарий. Лаборатория строит образцовый документ с таблицей с линиями разметки и объединёнными ячейками заголовка, таблицей, выровненной по пробелам без линий, и длинной таблицей, разрывающейся на границе страницы, затем запускает ExtractTables для текущей страницы или ExtractDocumentTables для всего документа и сообщает строки, столбцы, значения RowSpan и ColumnSpan, флаги заголовков, режим обнаружения, достоверность и группы продолжений. Опции DetectRuledTables, DetectWhitespaceTables, DetectContinuations, DetectFilledRulings и MinConfidence редактируются в интерфейсе, а выбранная таблица экспортируется через TPdfTable.ToCsv и TPdfTable.ToJson. Лаборатория также обрабатывает пакетом целую папку: Batch folder запускает ExtractDocumentTables для каждого PDF, сообщает количество таблиц по каждому документу, помечает сканы без текстового слоя и повторяет пустые документы с профилем компактных столбцов; Export all CSV записывает каждую найденную таблицу рядом с исходными файлами. Каждый документ открывается в собственном экземпляре TPdf, так что один нечитаемый файл не может задеть остальную часть пакета
var
I: Integer;
FieldInfo: TPdfFormFieldInfo;
begin
Pdf1.FormField[0] := 'John';
for I := 0 to Pdf1.FormFieldCount - 1 do
begin
FieldInfo := Pdf1.FormFieldInfo[I];
ShowMessage(FieldInfo.Name + ': ' + Pdf1.FormField[I]);
end;
end;
// Без сплющивания FormField[i] := value пишет только запись /V —
// видимый внешний вид берётся из потока /AP и может не обновиться.
// GenerateFormAppearances регенерирует /AP для каждого виджета, затем
// FlattenAllPages запекает аннотации и виджеты каждой страницы
// в постоянное, нередактируемое содержимое.
Pdf1.FileName := 'C:\Application.pdf';
Pdf1.Active := True;
Pdf1.FormField[0] := 'John Smith';
Pdf1.FormField[1] := '[email protected]';
Pdf1.GenerateFormAppearances;
if Pdf1.FlattenAllPages then
Pdf1.SaveAs('C:\Application.flat.pdf');
Pdf1.Active := False;
var
I: Integer;
Bitmap: TBitmap;
begin
for I := 0 to Pdf1.BitmapCount - 1 do
begin
Bitmap := Pdf1.Bitmap[I];
try
Bitmap.SaveToFile('C:\ExtractedImage' + IntToStr(I) + '.bmp');
finally
Bitmap.Free;
end;
end;
end;
var
JpegStream: TFileStream;
begin
JpegStream := TFileStream.Create('C:\MyImage.jpg', fmOpenRead or fmShareDenyWrite);
try
Pdf1.AddJpegImage(JpegStream, 100, 500, 200, 150);
finally
JpegStream.Free;
end;
Pdf1.AddPicture(Image1.Picture, 100, 300, 150, 100);
Pdf1.UpdatePage;
end;
var
I: Integer;
Annotation: TPdfAnnotation;
begin
for I := 0 to Pdf1.AnnotationCount - 1 do
begin
Annotation := Pdf1.Annotation[I];
ShowMessage('Annotation ' + IntToStr(I) + ': ' + Annotation.ContentsText);
end;
end;
Pdf1.CreatePath(100, 100, 200, 150, fmAlternate, clYellow, $FF, True, clBlack, $FF, 2.0);
Pdf1.AddPath;
Pdf1.CreatePath(100, 100, fmNone, clBlack, $FF, True, clRed, $FF, 3.0);
Pdf1.LineTo(200, 100);
Pdf1.LineTo(150, 200);
Pdf1.ClosePath;
Pdf1.AddPath;
Pdf1.UpdatePage;
var
I: Integer;
Bookmarks: TBookmarks;
begin
Bookmarks := Pdf1.Bookmarks;
for I := 0 to Length(Bookmarks) - 1 do
ShowMessage(Bookmarks[I].Title + ' -> Page ' + IntToStr(Bookmarks[I].PageNumber));
end;
var
I: Integer;
Destination: TDestination;
begin
for I := 0 to Pdf1.DestinationCount - 1 do
begin
Destination := Pdf1.Destination[I];
if Destination.Name = 'Chapter1' then
begin
Pdf1.PageNumber := Destination.PageNumber;
Break;
end;
end;
end;
var
I: Integer;
AttachmentData: TBytes;
AttachmentName: WString;
FileStream: TFileStream;
begin
for I := 0 to Pdf1.AttachmentCount - 1 do
begin
AttachmentName := Pdf1.AttachmentName[I];
AttachmentData := Pdf1.Attachment[I];
FileStream := TFileStream.Create('C:\Extracted_' + string(AttachmentName), fmCreate);
try
if Length(AttachmentData) > 0 then
FileStream.WriteBuffer(AttachmentData[0], Length(AttachmentData));
finally
FileStream.Free;
end;
end;
if Pdf1.CreateAttachment('MyFile.txt') then
Pdf1.Attachment[Pdf1.AttachmentCount - 1] := TFile.ReadAllBytes('C:\MyFile.txt');
end;
Pdf1.AddPage(Pdf1.PageCount + 1, 612, 792);
Pdf1.AddPage(Pdf1.PageCount + 1, 595, 842);
Pdf1.AddPage(Pdf1.PageCount + 1, 400, 600);
var
SourcePdf: TPdf;
begin
SourcePdf := TPdf.Create(nil);
try
SourcePdf.FileName := 'C:\SourceDocument.pdf';
SourcePdf.Active := True;
Pdf1.ImportPages(SourcePdf, '1', Pdf1.PageCount + 1);
finally
SourcePdf.Free;
end;
end;
if Pdf1.PageCount > 1 then
Pdf1.DeletePage(Pdf1.PageCount);
// Создать сжатый PDF-документ
Pdf1.CreateDocument;
Pdf1.Compressed := True; // гарантировать сжатие всех потоков через FlateDecode (по умолчанию)
Pdf1.Active := True;
Pdf1.AddPage(0, 595, 842); // размер A4
Pdf1.AddText('Hello World!', 'Arial', 24, 100, 700, clBlack, $FF, 0.0);
Pdf1.SaveAs('C:\Compressed.pdf');
Pdf1.Active := False;
// Сохранить с опциями
Pdf1.SaveAs('C:\Output.pdf', saIncremental); // инкрементальное сохранение
Pdf1.SaveAs('C:\NoSecurity.pdf', saRemoveSecurity); // удалить защиту
// Сохранить с целевой версией PDF. Валидатор версии PDF отклоняет
// любую функцию, появившуюся после выбранной цели (JBIG2Decode, MarkInfo,
// шифрование AES, аннотации Polygon / Caret / Watermark / Redact, ...).
if not Pdf1.SaveAs('C:\Legacy15.pdf', saNone, pv15) then
ShowMessage('Save rejected: document contains features newer than PDF 1.5');
// SaveAsPdfA постобрабатывает базовое сохранение инкрементальным
// обновлением, которое внедряет поток метаданных XMP, ICC OutputIntent
// sRGB и обновлённый catalog документа, благодаря чему результат
// соответствует PDF/A-1b. Встроенный профиль sRGB IEC61966-2.1 используется
// автоматически, если пользовательский профиль не передан.
Pdf1.FileName := 'C:\Report.pdf';
Pdf1.Active := True;
if Pdf1.SaveAsPdfA('C:\Report.pdfa.pdf', pac1b) then
ShowMessage('Saved PDF/A-1b archive');
// PDF/A с пользовательским ICC-профилем (например, конвейеры печати CMYK)
var
Opts: TPdfASaveOptions;
begin
Opts := Default(TPdfASaveOptions);
Opts.Conformance := pac1b;
Opts.IccProfileData := TFile.ReadAllBytes('C:\Profiles\Coated_GRACoL_2006.icc');
Pdf1.SaveAsPdfA('C:\Report.cmyk.pdfa.pdf', Opts);
end;
// Вывод PDF/A в память
var
Stream: TMemoryStream;
begin
Stream := TMemoryStream.Create;
try
Opts := Default(TPdfASaveOptions);
Opts.Conformance := pac1b;
if Pdf1.SaveAsPdfAToStream(Stream, Opts) then
UploadToArchive(Stream);
finally
Stream.Free;
end;
end;
var
Validation: TPdfAValidationResult;
Issue: TPdfAValidationIssue;
begin
Pdf1.FileName := 'C:\Incoming\report.pdf';
Pdf1.Active := True;
// Дешёвая проверка стиля «заголовок» — читает соответствие без
// итерации полного валидатора. Результат: pacNone, pac1a, pac1b,
// pac2b, pac3b или pacUnknown.
case Pdf1.PdfAConformance of
pac1b: Status.Caption := 'PDF/A-1b';
pac2b: Status.Caption := 'PDF/A-2b';
pacNone: Status.Caption := 'Not PDF/A';
else
Status.Caption := 'Unknown conformance';
end;
// Полный валидатор с диагностикой по каждой проблеме
Validation := Pdf1.ValidatePdfA;
Memo1.Lines.Add('Conformance: ' + GetEnumName(TypeInfo(TPdfAConformance),
Ord(Validation.Conformance)));
for Issue in Validation.Issues do
Memo1.Lines.Add('- ' + Issue.Description);
end;
Проекты Demo\Delphi\StandardsLab, Demo\CBuilder\StandardsLab и Demo\Lazarus\StandardsLab загружают или создают PDF, запускают ValidatePdfA, ValidatePdfUa, ValidatePdfE, ValidatePdfX, ValidatePdfR и ValidatePdfVT, затем показывают каждый обнаруженный уровень соответствия и количество проблем в одной сетке. Кнопки сохранения вызывают SaveAsPdfA, SaveAsPdfUa, SaveAsPdfE, SaveAsPdfX, SaveAsPdfR и SaveAsPdfVT, благодаря чему рабочий процесс маркерного вывода виден без написания собственной обвязки
Модуль FPdfPreflightReport объединяет ValidatePdfA, ValidatePdfUa, ValidatePdfE, ValidatePdfX, ValidatePdfR и ValidatePdfVT в один объект отчёта, доступный для запросов, со степенями серьёзности Info / Warning / Error, агрегированием статусов и проблем, поиском, фильтрацией и стабильными отпечатками SHA-256. Отчёты можно выгружать в виде текста, HTML, Markdown, JSON, CSV, SARIF 2.1.0, JUnit XML, NDJSON или собственного XML. Проекты Demo\Delphi\PreflightReport, Demo\Lazarus\PreflightReport и Demo\CBuilder\PreflightReport предоставляют интерактивные сценарии выбора и предпросмотра, а Demo\Delphi\PreflightReportCli добавляет программируемые аргументы входа / выхода, фильтрацию по стандартам, опциональное встраивание вложения отчёта, управление кодом выхода для CI, пакетную обработку списков и каталогов, устойчивую к коллизиям маршрутизацию, агрегированные сводки и манифесты CSV. Сгенерированный отчёт указывает, что встроенные валидаторы покрывают проверки маркерного уровня и выбранные проверки уровня файла, поэтому полную препроверку уровня содержимого по-прежнему можно делегировать специализированному движку валидации
// LoadCustomDocument позволяет PDFium забирать блоки из любого
// позиционируемого TStream по требованию. Поток НЕ копируется в память,
// поэтому многогигабайтные PDF, удалённые потоки тел HTTP и БД-источники
// все жизнеспособны без предварительного буфера.
var
FileStream: TFileStream;
begin
// Потоковое чтение из файла (без копии в памяти)
FileStream := TFileStream.Create('C:\Huge.pdf',
fmOpenRead or fmShareDenyWrite);
Pdf1.LoadCustomDocument(FileStream, True{AOwnsStream});
// ^^ передача владения — Pdf1 освобождает FileStream при UnloadDocument.
Pdf1.Active := True;
ShowMessage('Pages: ' + IntToStr(Pdf1.PageCount));
end;
// Внешне-управляемый поток (вызывающий освобождает его после UnloadDocument)
var
Stream: TFileStream;
begin
Stream := TFileStream.Create('C:\Live.pdf',
fmOpenRead or fmShareDenyNone);
try
Pdf1.LoadCustomDocument(Stream, False);
Pdf1.Active := True;
DoWork;
Pdf1.Active := False;
finally
Stream.Free;
end;
end;
// FPdfAsync предоставляет IPdfCancellationToken /
// IPdfCancellationTokenSource для семантики «отмена из интерфейса»,
// которая работает в длительных путях экспорта и рендеринга.
uses FPdfAsync;
var
CancelSource: IPdfCancellationTokenSource;
CancelToken: IPdfCancellationToken;
begin
CancelSource := PdfCancellationTokenSource;
CancelToken := CancelSource.Token;
// ... пользователь нажимает «Отмена» ...
CancelSource.Cancel;
// Worker периодически проверяет CancelToken.IsCancelled, либо путь
// рендеринга опрашивает его через обратный вызов IFSDK_PAUSE PDFium.
if CancelToken.IsCancelled then
Memo1.Lines.Add('Cancelled by user');
end;
// RenderPageProgressive позволяет длительному рендерингу с высоким DPI
// прерваться в середине страницы, когда пользователь нажимает «Отмена»,
// вместо блокировки вызывающего до завершения.
var
Status: TPdfProgressiveStatus;
Bitmap: TBitmap;
begin
Bitmap := TBitmap.Create;
try
Bitmap.PixelFormat := pf32bit;
Bitmap.SetSize(2480, 3508); // A4 @ 300 DPI
Status := Pdf1.RenderPageProgressive(Bitmap, 0, 0, Bitmap.Width,
Bitmap.Height, CancelToken, ro0, [reAnnotations], clWhite);
case Status of
prsDone: SaveBitmap(Bitmap);
prsCancelled: Memo1.Lines.Add('Render cancelled — partial result available');
prsFailed: Memo1.Lines.Add('PDFium reported FPDF_RENDER_FAILED');
end;
finally
Bitmap.Free;
end;
end;
// TPdfFuture<T> запускает worker в фоновом потоке и отправляет конверт
// TPdfFutureResult<T> обратно в главный поток.
//
// Важно: TPdf сериализует вызовы рендеринга для каждого экземпляра, но
// worker всё ещё владеет диспетчеризацией и временем жизни документа.
// Не мутируйте TPdf во время выполняющегося рендеринга; пакетный экспорт
// обычно держит по одному TPdf на файл.
type
TRenderResult = record
Bitmap : TBitmap;
PageNo : Integer;
end;
var
Future: TPdfFuture<TRenderResult>;
begin
Future := TPdfFuture<TRenderResult>.Create(
function (const ACancelToken: IPdfCancellationToken): TRenderResult
var
LocalPdf: TPdf;
begin
LocalPdf := TPdf.Create(nil);
try
LocalPdf.FileName := 'C:\Huge.pdf';
LocalPdf.Active := True;
LocalPdf.PageNumber := 1;
Result.Bitmap := LocalPdf.RenderPage(0, 0, 2480, 3508);
Result.PageNo := 1;
finally
LocalPdf.Free;
end;
end,
procedure (const AResult: TPdfFutureResult<TRenderResult>)
begin
case AResult.State of
pfsSuccess: PaintBitmapToView(AResult.Value.Bitmap);
pfsCancelled: Log.Add('Cancelled');
pfsFailed: Log.Add('Worker failed: ' + AResult.ErrorMessage);
end;
end);
end;
// FPdfMatrix оборачивает FS_MATRIX из PDFium, чтобы вызывающие могли
// декларативно построить преобразование и передать его в
// FPDFPageObj_SetMatrix.
uses FPdfMatrix, FPdfView;
var
M: TPdfMatrix;
RawMatrix: FS_MATRIX;
PageObj: FPDF_PAGEOBJECT;
begin
M := TPdfMatrix.Create;
try
M.Translate(72, 200); // сдвинуть на 1 дюйм вправо, ~2.8 дюйма вверх
M.Scale(0.5, 0.5); // штамп половинного размера
M.Rotate(15); // поворот на 15° против часовой
// M.HorizontalFlip;
// M.VerticalFlip;
// M.CentralFlip;
// M.Skew(10, 5);
// M.Multiply(Other); // постумножение на другую матрицу
// Применить к любому объекту страницы PDFium (текст / путь / изображение / Form XObject)
RawMatrix := M.Handle;
FPDFPageObj_SetMatrix(PageObj, RawMatrix);
finally
M.Free;
end;
end;
// ImportPagesByIndex копирует явный массив нулевых индексов из исходного
// PDF в этот документ. InsertAt = 0 вставляет перед страницей 1;
// PageCount добавляет в конец.
var
Source: TPdf;
begin
Source := TPdf.Create(nil);
try
Source.FileName := 'C:\Report.pdf';
Source.Active := True;
// Импортировать страницы 0, 2, 4 (от единицы: страницы 1, 3, 5) из Source
// и добавить их в конец Pdf1.
Pdf1.ImportPagesByIndex(Source, [0, 2, 4], Pdf1.PageCount);
// Пустой массив импортирует все страницы источника
// Pdf1.ImportPagesByIndex(Source, [], 0);
finally
Source.Free;
end;
end;
// ImportNPagesToOne возвращает совершенно новый TPdf, страницы которого
// являются композициями NumX*NumY ЭТОГО документа. OutputWidth/Height —
// это пользовательские единицы PDF (1 единица = 1/72 дюйма).
var
Composite: TPdf;
begin
Pdf1.FileName := 'C:\Slides.pdf';
Pdf1.Active := True;
// 4-up A4 альбомная: 842 x 595 pt, 2 столбца x 2 строки
Composite := Pdf1.ImportNPagesToOne(842, 595, 2, 2);
try
if Composite <> nil then
Composite.SaveAs('C:\Slides_4up.pdf');
finally
Composite.Free;
end;
end;
// MovePages принимает нулевые индексы перемещаемых страниц плюс индекс
// назначения для первой перемещённой страницы после завершения перемещения.
// Другие страницы сдвигаются вокруг перемещаемого блока, благодаря чему
// длина документа остаётся прежней.
//
// Пример: в 5-страничном документе со страницами [0,1,2,3,4],
// MovePages([2, 3], 0) переупорядочивает в [2, 3, 0, 1, 4].
if not Pdf1.MovePages([2, 3], 0) then
ShowMessage('Invalid indices passed to MovePages');
// CreateXObjectFromPage создаёт переиспользуемый дескриптор Form XObject
// из любой страницы любого другого TPdf. Штампуйте этот дескриптор на
// столько страниц ЭТОГО документа, сколько нужно — каждый штамп
// представляет собой один объект страницы PDFium, который можно
// позиционировать, масштабировать и поворачивать через матричный API.
uses FPdfMatrix, FPdfView;
var
WatermarkSource: TPdf;
XObj: TPdfXObject;
PageObj: FPDF_PAGEOBJECT;
M: TPdfMatrix;
RawMatrix: FS_MATRIX;
I: Integer;
begin
WatermarkSource := TPdf.Create(nil);
try
WatermarkSource.FileName := 'C:\Watermarks\Confidential.pdf';
WatermarkSource.Active := True;
// Обернуть страницу 0 из WatermarkSource как переиспользуемый XObject
XObj := Pdf1.CreateXObjectFromPage(WatermarkSource, 0);
try
for I := 1 to Pdf1.PageCount do
begin
Pdf1.PageNumber := I;
PageObj := Pdf1.InsertFormObjectFromXObject(XObj);
if PageObj = nil then Continue;
// Центрировать водяной знак на странице
M := TPdfMatrix.Create;
try
M.Scale(0.5, 0.5);
M.Translate(0.25 * Pdf1.PageWidth, 0.5 * Pdf1.PageHeight);
RawMatrix := M.Handle;
FPDFPageObj_SetMatrix(PageObj, RawMatrix);
finally
M.Free;
end;
Pdf1.UpdatePage;
end;
finally
XObj.Free; // закрывает дескриптор FPDF_XOBJECT
end;
Pdf1.SaveAs('C:\Watermarked.pdf');
finally
WatermarkSource.Free;
end;
end;
Проекты Demo\Delphi\WatermarkStamp, Demo\Lazarus\WatermarkStamp и Demo\CBuilder\WatermarkStamp превращают этот шаблон в работающий процесс: они создают целевой PDF и переиспользуемый PDF штампа, оборачивают страницу штампа через CreateXObjectFromPage, вставляют один и тот же Form XObject на каждую целевую страницу, применяют преобразования TPdfMatrix для центрированных водяных знаков и штампов в правом верхнем углу и добавляют опциональные метки номеров страниц перед сохранением результата
// AddImage(FileName) принимает любой формат, зарегистрированный в
// графических модулях VCL или LCL (BMP, PNG через PngImage, JPG, ...).
Pdf1.AddImage('C:\Photo.png', 100, 500, 200, 150);
// AddImage(TBitmap) пропускает промежуточный TPicture, что идеально,
// когда растровое изображение уже получено из рендеринга или пакетной
// генерации.
var
Bitmap: TBitmap;
begin
Bitmap := Pdf1.RenderPage(0, 0, 595, 842);
try
Pdf1.PageNumber := 2;
Pdf1.AddImage(Bitmap, 50, 50, 250, 350);
Pdf1.UpdatePage;
finally
Bitmap.Free;
end;
end;
Проекты Demo\Delphi\ImageToPDF, Demo\CBuilder\ImageToPDF и Demo\Lazarus\ImageToPDF превращают это в полный пакетный рабочий процесс: выбрать несколько файлов изображений, предпросмотреть выбранный элемент, создать одну страницу PDF на каждое изображение, масштабировать каждое изображение в страницу A4 в портретной или альбомной ориентации, сохранить результат и открыть сгенерированный PDF
var
MatchCount: Integer;
begin
// Нарисовать маску clYellow поверх каждого совпадения на текущей странице просмотра.
// Переход на другую страницу автоматически очищает подсветку.
PdfView1.HighlightColor := clYellow;
MatchCount := PdfView1.HighlightSearchText('invoice', False{Case}, True{Word});
Status.Caption := Format('%d match(es) on this page', [MatchCount]);
// Программно убрать наложение перед сменой страницы
PdfView1.ClearHighlight;
end;
// FitMode удерживает длинные документы в кадре при изменении размера
// или смене страницы. Прямая установка Zoom отменяет FitMode (он
// возвращается к pfmNone).
PdfView1.FitMode := pfmFitPage; // вся страница в области просмотра
// PdfView1.FitMode := pfmFitWidth; // ширина страницы совпадает с шириной области просмотра
// PdfView1.FitMode := pfmActualSize; // 100%
// PageColor отделяет отрисованную страницу PDF от Color управляющего хоста
// — типичная настройка просмотрщика тёмной темы оставляет область прокрутки
// тёмной, а сама страница PDF остаётся белой как бумага.
PdfView1.Color := clBlack; // область прокрутки
PdfView1.PageColor := clWhite; // фон страницы PDF
// Опциональная отбрасываемая тень и рамка страницы, чтобы приподнять
// страницу над тёмным фоном
PdfView1.PageShadowSize := 6;
PdfView1.PageShadowColor := $00404040;
PdfView1.PageBorderColor := clGray;
Проекты Demo\Delphi\Miscellaneous\ViewerInteractionLab, Demo\CBuilder\Miscellaneous\ViewerInteractionLab и Demo\Lazarus\Miscellaneous\ViewerInteractionLab держат современную поверхность взаимодействия TPdfView в одной компактной форме: открыть или создать образец PDF, переключить DisplayMode, применить FitMode, изменить PageColor, повернуть страницы, подсветить совпадения поиска на текущей странице через HighlightSearchText, включить или выключить пользовательское выделение текста, изучить SelectedText, вызвать SelectAll, CopySelectionToClipboard и ClearSelection и наблюдать обновление координат DeviceToPage в строке состояния при движении мыши над страницей
Проекты Demo\Delphi\SearchAndSelect, Demo\CBuilder\SearchAndSelect и Demo\Lazarus\SearchAndSelect превращают рабочий процесс поиска и выделения в просмотрщике в самостоятельные образцы. Они открывают или создают PDF, перечисляют результаты поиска по всем страницам с номером страницы, индексом символа и предпросмотром текста, поддерживают навигацию «Предыдущее / Следующее» и переход к результату по двойному клику, подсвечивают совпадения текущей страницы через HighlightSearchText, предоставляют опции учёта регистра и целого слова, переключают AllowUserTextSelection, показывают предпросмотр SelectedText, управляют SelectAll, CopySelectionToClipboard и ClearSelection с кнопок и позволяют пользователям переключаться между одиночными и развёрнутыми режимами отображения
Проекты Demo\Delphi\Miscellaneous\PrintPreferences, Demo\CBuilder\Miscellaneous\PrintPreferences и Demo\Lazarus\Miscellaneous\PrintPreferences читают настройки печати автора перед печатью. Они отображают PrintCopies, PrintPageRanges, PrintScaling и PrintPaperHandling, могут копировать предоставленные автором копии и диапазоны во входные параметры печати и показывают, как SetPdfPrintPaperHandlingDevMode отображает намерение дуплекса PDF в Windows DEVMODE
Проекты Demo\Delphi\PrintPDF, Demo\CBuilder\PrintPDF и Demo\Lazarus\PrintPDF показывают стандартный процесс печати: открыть PDF, предпросмотреть страницы, выбрать диапазоны страниц и копии в платформенном диалоге печати, учитывать режим разборки копий, рендерить каждую страницу через TPdf.RenderPage и предоставлять прогресс печати с отменой. Образец Delphi также принимает PDF-файлы, перетащенные мышью, для быстрой загрузки
Проекты Demo\Delphi\MultiPageViewer, Demo\CBuilder\MultiPageViewer и Demo\Lazarus\MultiPageViewer используют непрерывный, развёрнутый и учитывающий обложку просмотр со штатными рабочими процессами навигации по страницам и масштабирования. Они также полезны для тестирования скорости открытия первой страницы и отзывчивости рендеринга на очень больших PDF: в тестах с большими файлами документы размером 2.x ГБ, на которые Acrobat или Foxit могут тратить 20–30 секунд до первого просмотра, могут стать пригодными к использованию практически мгновенно через путь просмотрщика PDFium Delphi Component
Проекты Demo\Delphi\SplitView, Demo\CBuilder\SplitView и Demo\Lazarus\SplitView показывают параллельный обзор PDF. Образцы C++Builder и Lazarus посвящены сравнению двух или трёх панелей, выбору активного представления, опциональным синхронизированным командам навигации, общим пресетам масштабирования и повороту для выбранного представления или всех загруженных представлений. Используйте эти образцы для сравнения больших документов, сохраняя при этом отзывчивость первого пригодного просмотра и последующего рендеринга страниц; те же PDF-файлы размером 2.x ГБ, на открытие которых Acrobat или Foxit могут тратить 20–30 секунд, могут стать пригодными к использованию практически мгновенно через путь просмотрщика PDFium Delphi Component
Проекты Demo\Delphi\SecurityAudit, Demo\CBuilder\SecurityAudit и Demo\Lazarus\SecurityAudit открывают PDF только для чтения и перечисляют состояние разрешений, встроенные вложения, действия JavaScript документа, аннотации-ссылки URI и Launch, веб-ссылки, сводки подписей, состояние XFA, доступность помощников V8 и обратные вызовы неподдерживаемых функций. Те же строки сводки и находок можно сохранить или скопировать как аудиторский отчёт TXT или сохранить как структурированный JSON. Они предназначены как панели рисков приложения-хоста, а не как обнаружение вредоносных программ
// LinkOptions управляет автоматической обработкой четырёх типов
// действий PDF-ссылок. По умолчанию включены только goto и URI; запуск
// программы (loAutoLaunch) и встроенный GotoR (переход к другому файлу)
// остаются ВЫКЛ, чтобы случайный клик не мог запустить произвольный код.
PdfView1.LinkOptions :=
[loAutoGoto, loAutoOpenURI]; // безопасные значения по умолчанию
// OnAnnotationLinkClick срабатывает для адресов назначения внутри
// документа (переходы по страницам, именованные адреса, цепочки действий).
// Установите Handled := True, чтобы запретить автоследование по ссылке.
procedure TForm1.PdfView1AnnotationLinkClick(Sender: TObject;
LinkIndex: Integer; const Action: TPdfAction;
var Handled: Boolean);
begin
if Action.Kind = paUri then
begin
if MessageDlg('Open ' + Action.Uri + '?', mtConfirmation, [mbYes, mbNo], 0)
<> mrYes then
Handled := True; // подавить автообработку
end;
end;
// OnWebLinkClick срабатывает для строк URI, обнаруженных сканером
// веб-ссылок PDFium (автообнаруженные URL в текстовом потоке, даже без
// аннотации /A <</S/URI...>>).
procedure TForm1.PdfView1WebLinkClick(Sender: TObject;
WebLinkIndex: Integer; const Url: WString;
var Handled: Boolean);
begin
Log.Add('Web link clicked: ' + string(Url));
end;
// На сфокусированном виджете AcroForm шесть новых методов управляют
// историей редактирования формы PDFium. Все шесть безопасно завершают
// работу, если ни один виджет не сфокусирован или документ не несёт
// AcroForm.
procedure TForm1.btnSelectAllClick(Sender: TObject);
begin
PdfView1.SelectAllFormText;
EditMenuCopy.Caption := 'Copy: ' + string(PdfView1.GetSelectedFormText);
end;
procedure TForm1.btnUndoClick(Sender: TObject);
begin
btnUndo.Enabled := PdfView1.FormCanUndo;
btnRedo.Enabled := PdfView1.FormCanRedo;
if PdfView1.FormCanUndo then
PdfView1.FormUndo;
end;
procedure TForm1.btnRedoClick(Sender: TObject);
begin
if PdfView1.FormCanRedo then
PdfView1.FormRedo;
end;
// Все три по умолчанию равны True, поэтому существующие приложения
// обновляются без изменения поведения. Установите их в False для
// киосков, панелей предпросмотра или встраиваний только для чтения
// без наследования TPdfView.
PdfView1.AllowUserPageChange := False; // PgUp/PgDn/Ctrl+Home/End
PdfView1.ChangePageOnMouseScrolling := False; // переходы колесом вверх/вниз
PdfView1.AllowUserTextSelection := False; // выделение текста мышью/клавиатурой
// Ctrl+колесо зарезервировано для масштабирования и пропускается
// обработчиком навигации независимо от ChangePageOnMouseScrolling.
// TPdfThumbnailView (модуль FPdfThumbnail) рендерит одну миниатюру
// страницы в строку в прокручиваемой боковой панели.
uses FPdfThumbnail;
procedure TForm1.FormCreate(Sender: TObject);
begin
ThumbView.Pdf := Pdf1;
ThumbView.ThumbnailWidth := 120;
ThumbView.ThumbnailHeight := 160;
ThumbView.SelectionColor := $00CFA85F; // тёплая подсветка
ThumbView.OnPageClick := ThumbViewPageClick;
end;
procedure TForm1.ThumbViewPageClick(Sender: TObject; PageIndex: Integer);
begin
PdfView1.PageNumber := PageIndex + 1; // PageIndex отсчитывается от нуля
end;
procedure TForm1.PdfView1PageNumberChanged(Sender: TObject);
begin
ThumbView.CurrentPageIndex := PdfView1.PageNumber - 1;
end;
// Шаблон, используемый Demo\Delphi\BatchExport, Demo\CBuilder\BatchExport
// и Demo\Lazarus\BatchExport. Один TPdf на файл, IPdfCancellationToken
// для «отмены из интерфейса», TPdfStreamAdapter для буферизованной
// загрузки файла.
uses FPdfAsync;
procedure ExportBatch(const Files: TArray<string>;
const OutDir: string; DPI: Integer; Quality: Integer;
const ACancelToken: IPdfCancellationToken);
var
I, J: Integer;
Job: TPdf;
Bmp: TBitmap;
Jpeg: TJPEGImage;
begin
for I := 0 to High(Files) do
begin
if ACancelToken.IsCancelled then Break;
OverallProgress.Position := I;
Job := TPdf.Create(nil);
try
Job.FileName := Files[I];
Job.Active := True;
PageProgress.Max := Job.PageCount;
for J := 1 to Job.PageCount do
begin
if ACancelToken.IsCancelled then Break;
PageProgress.Position := J;
Job.PageNumber := J;
Bmp := Job.RenderPage(
0, 0,
Round(Job.PageWidth * DPI / 72),
Round(Job.PageHeight * DPI / 72));
try
Jpeg := TJPEGImage.Create;
try
Jpeg.CompressionQuality := Quality;
Jpeg.Assign(Bmp);
Jpeg.SaveToFile(Format('%s\%s.p%.3d.jpg',
[OutDir, ExtractFileName(Files[I]), J]));
finally
Jpeg.Free;
end;
finally
Bmp.Free;
end;
end;
finally
Job.Free;
end;
end;
end;
procedure FitCurrentPage;
begin
PdfView1.Zoom := PdfView1.PageZoom[PdfView1.PageNumber];
end;
procedure InspectViewerPoint(X, Y: Integer);
var
PageNo: Integer;
PageX, PageY: Double;
CharIndex: Integer;
Ch: WString;
begin
PageNo := PdfView1.PageNumber;
if not PdfView1.DeviceToPage(X, Y, PageNo, PageX, PageY) then
Exit;
CharIndex := PdfView1.CharacterIndexAtPos(X, Y, 8, 8);
if CharIndex >= 0 then
begin
Ch := PdfView1.Text(CharIndex, 1);
ShowMessage(Format('Page %d, X %.2f, Y %.2f, character %s',
[PageNo, PageX, PageY, string(Ch)]));
end;
end;
function LoadPdfSafely(const FileName: string): Boolean;
begin
Result := False;
if not FileExists(FileName) then
Exit;
try
Pdf1.FileName := FileName;
Pdf1.Active := True;
Result := Pdf1.Active;
except
Result := False;
end;
end;
function ExtractTextSafely(PageNo: Integer): WString;
begin
Result := '';
if not Pdf1.Active then
Exit;
if (PageNo < 1) or (PageNo > Pdf1.PageCount) then
Exit;
Pdf1.PageNumber := PageNo;
Result := Pdf1.Text;
end;
// IsTagged — дешёвая проверка каталога — True, когда существует
// /StructTreeRoot. StructureElements материализует дерево в плоский
// массив записей TPdfStructureElement с типом, заголовком,
// альтернативным текстом, фактическим текстом, расширительным текстом,
// языком, уровнем, индексом родителя и счётчиками потомков /
// маркированного содержимого / атрибутов.
var
Elements: TPdfStructureElements;
I: Integer;
begin
if not Pdf1.IsTagged then
begin
Log.Add('Document is NOT tagged — accessibility tools may struggle.');
Exit;
end;
if Pdf1.Language = '' then
Log.Add('Tagged PDF without /Lang — fails PDF/UA.');
Elements := Pdf1.StructureElements;
for I := 0 to High(Elements) do
Log.Add(StringOfChar(' ', Elements[I].Level * 2)
+ Elements[I].StructType + ' "' + Elements[I].Title + '"');
end;
// SetPdfPrintMode — глобальная функция, которая отображается в
// FPDF_SetPrintMode PDFium. Используйте подходящее значение TPdfPrintMode
// для используемого драйвера принтера.
SetPdfPrintMode(pmEmf); // GDI EMF (по умолчанию)
// SetPdfPrintMode(pmTextOnly); // рендеринг только текста
// SetPdfPrintMode(pmPostScript2); // PostScript Level 2
// SetPdfPrintMode(pmPostScript3); // PostScript Level 3
// SetPdfPrintMode(pmPostScript2PassThrough);
// SetPdfPrintMode(pmPostScript3PassThrough);
// SetPdfPrintMode(pmEmfImageMasks); // EMF + маски изображений
// SetPdfPrintMode(pmPostScript3Type42); // PostScript 3 + шрифты Type 42
// PrintCopies, PrintPageRanges, PrintScaling и PrintPaperHandling —
// это записи словаря настроек просмотрщика. Они кодируют то, что автор
// документа хотел использовать как значения по умолчанию для читателей PDF.
var
Ranges: TPrintPageRanges;
Range: TPrintPageRange;
begin
ShowMessage('Suggested copies: ' + IntToStr(Pdf1.PrintCopies));
ShowMessage('Print scaling: ' + GetEnumName(TypeInfo(TPrintScaling),
Ord(Pdf1.PrintScaling)));
Ranges := Pdf1.PrintPageRanges; // диапазоны от единицы
for Range in Ranges do
Log.Add(Format('Pages %d..%d', [Range.First, Range.Last]));
if SetPdfPrintPaperHandlingDevMode(PrinterDevMode, Pdf1.PrintPaperHandling) then
ApplyPrinterDevMode(PrinterDevMode);
end;
// JavaScript уровня документа хранится в дереве имён /Names /JavaScript.
// JavaScriptAction[i] возвращает одну запись; JavaScriptActions
// возвращает полный массив.
var
I: Integer;
Action: TPdfJavaScriptAction;
begin
for I := 0 to Pdf1.JavaScriptActionCount - 1 do
begin
Action := Pdf1.JavaScriptAction[I];
Memo1.Lines.Add('Name: ' + string(Action.Name));
Memo1.Lines.Add('Script: ' + string(Action.Script));
Memo1.Lines.Add('---');
end;
end;
procedure ProcessMultiplePages;
var
I: Integer;
PageText: WString;
begin
for I := 1 to Pdf1.PageCount do
begin
Pdf1.PageNumber := I;
PageText := Pdf1.Text;
ProcessPageText(PageText);
end;
end;
procedure SetOptimalRenderOptions;
begin
PdfView1.Options := [reAnnotations, reLcd];
end;
// Путь рендеринга без копирования (по умолчанию с v1.21.0): RenderPage
// пишет напрямую в буфер DIB назначения TBitmap, когда вызывающие
// передают предварительно выделенное растровое изображение, избегая
// одной копии размером ширина * высота * 4 байта.
procedure RenderIntoCallerBitmap(Bitmap: TBitmap);
begin
Bitmap.PixelFormat := pf32bit;
Bitmap.SetSize(2480, 3508); // A4 @ 300 DPI
Pdf1.RenderPage(Bitmap, 0, 0, Bitmap.Width, Bitmap.Height);
end;