Эта страница может содержать автоматически переведенный текст.
Как создавать PDF-документы в C# и VB.NET
Эта статья описывает разные способы создавать PDF-документы в .NET с помощью библиотеки Docotic.Pdf. Это высокопроизводительная чистая библиотека на C# для .NET без внешних зависимостей для создания, редактирования, преобразования и обработки PDF-документов.

В следующих разделах я рассматриваю основные подходы к созданию PDF с Docotic.Pdf:
- Использование Core API, которое предоставляет низкоуровневый контроль над текстом, графикой и внутренними механизмами PDF. Этот вариант лучше всего подходит для пользовательских макетов, документов с большим количеством графики и расширенных возможностей.
- Использование высокоуровневого Layout API, которое поддерживает абзацы, таблицы, верхние и нижние колонтитулы, а также автоматическую разбивку на страницы. Это API идеально подходит, когда нужны структурированные документы без ручного вычисления координат.
- Преобразование HTML в PDF с поддержкой SVG и других веб-форматов. Этот подход особенно полезен, когда ваше решение уже формирует HTML-документы, а вам нужны версии этих HTML- и CSS-файлов в PDF.
- Создание PDF из изображений. Этот метод полезен для отсканированных документов, отчетов на основе изображений, квитанций и любых сценариев, которые начинаются с растровых изображений.
- Объединение или разделение PDF. Это хороший выбор для сборки отчетов, обработки пользовательских загрузок, объединения связанных документов и реструктуризации больших PDF.
- Создание PDF из шаблонов. Этот подход хорошо работает, когда для пакетно генерируемых документов, таких как квитанции, налоговые формы, трудовые договоры и другие повторяемые типы документов, требуется единообразное форматирование.
Дополнительные темы, которые рассматриваются в руководстве:
- Интерактивные возможности, такие как ссылки и действия JavaScript
- Подходы к тестированию вывода PDF, чтобы гарантировать ожидаемые результаты
Создание PDF с помощью Core API
Core API — это основа создания PDF в Docotic.Pdf. Он дает полный низкоуровневый контроль над размещением текста, изображений и векторной графики на PDF-холсте через Canvas API. Этот API рисования является подмножеством Core API и предоставляет методы и свойства, которые используются для добавления содержимого на страницы и другие объекты с холстами. Помимо визуализации, Core API также поддерживает аннотации, поля форм, слои, закладки и другие возможности PDF.
Ниже приведен код C#, который создает простой PDF, используя три базовые операции: рисование текста, размещение изображения и вывод векторной графики на холсте страницы.
using var pdf = new PdfDocument();
var canvas = pdf.Pages[0].Canvas;
canvas.Font = pdf.CreateFont(PdfBuiltInFont.HelveticaBold);
canvas.FontSize = 14;
canvas.DrawString(40, 100, "Core API demo: text, images, and vector graphics");
var image = pdf.CreateImage("image.png");
canvas.DrawImage(image, 40, 180, 120, 120, 0);
canvas.Pen.Color = new PdfRgbColor(30, 60, 160);
canvas.Pen.Width = 2;
canvas.Brush.Color = new PdfRgbColor(200, 230, 255);
canvas.DrawRectangle(new PdfRectangle(200, 200, 150, 80), PdfDrawMode.FillAndStroke);
pdf.Save("core-api-demo.pdf");
Этот обзор показывает лишь небольшую часть того, что умеет Core API. В статье о продвинутых темах см. подробный материал о создании PDF с помощью Core API. В статье рассматриваются измерение текста, работа с цветовыми пространствами, применение отсечения, заливка областей узорами, обработка прозрачности и другие возможности.
Генерация PDF с помощью Layout API
Layout API — это высокоуровневый механизм построения документов, который предоставляет самый простой и эффективный способ генерировать сложные, насыщенные содержимым PDF.
При использовании API вы собираете PDF из структурных элементов, таких как страницы, контейнеры, текстовые фрагменты, изображения, таблицы, ссылки, верхние и нижние колонтитулы и т. д. Вместо вычисления координат или ручного управления разбиением на страницы вы описываете структуру документа, а механизм компоновки делает остальное.
Этот пример показывает, как создать PDF с помощью Layout API, используя декларативную компоновку вместо ручного позиционирования.
PdfDocumentBuilder.Create()
.Info(info => info.Title = "Docotic.Pdf Layout API demo")
.Generate("layout-api-demo.pdf", doc => doc.Pages(pages =>
{
pages.Content().Padding(100).Text(text =>
{
text.Span("The Layout API lets you compose PDFs from structural elements ");
text.Line("without manually calculating coordinates or handling pagination.")
.Style(s => s.Strong);
});
}));
Изучите подробное руководство, чтобы узнать, как использовать Layout API в приложениях для генерации PDF в .NET.
Преобразование веб-контента с помощью API HTML to PDF
Docotic.Pdf в сочетании со своим бесплатным дополнением HtmlToPdf предоставляет современный, высококачественный механизм HTML-to-PDF на основе Chrome. Вы можете преобразовывать современный HTML и другой веб-контент, такой как SVG или изображения WebP, в высококачественные PDF-документы с помощью API, предоставляемого дополнением.
API HTML to PDF может создавать PDF из полных HTML-страниц или HTML-фрагментов. Вы можете преобразовывать контент из URL-адресов, строк с «сырым» HTML и локальных HTML-файлов. Два последних варианта позволяют легко генерировать PDF из HTML-шаблонов.
См. пример того, как создать PDF из HTML-шаблона:
public static async Task HelloHtmlTemplate()
{
static string GetUserName()
{
// Замените реальной логикой: ввод формы, вызов API, конфигурация и т. д.
return "World";
}
string html = $@"
<h1>Hello, {GetUserName()}!</h1>
<p>This PDF was generated from an HTML template.</p>";
using var converter = await HtmlConverter.CreateAsync();
using var pdf = await converter.CreatePdfFromStringAsync(html);
pdf.Save("hello-html-template.pdf");
}
Дополнительные сведения и примеры см. в нашем подробном обзоре HTML-to-PDF.
Создание PDF из изображений
Docotic.Pdf предоставляет гибкий и удобный для разработчика способ преобразования изображений в PDF. Библиотека поддерживает форматы JPEG, BMP, GIF, PNG, TIFF и JPEG 2000 через Core API.

Когда это поддерживается форматом PDF, Docotic.Pdf встраивает байты изображения как есть, избегая декодирования и повторного кодирования пикселей, чтобы сохранить исходное сжатие. Библиотека также по возможности сохраняет цветовое пространство.
Кроме того, форматы SVG и WebP поддерживаются через API HTML to PDF. Когда нужно разместить изображения рядом с подписями или описаниями, Layout API помогает выравнивать и компоновать элементы с минимальными усилиями.
Как объединить несколько изображений в один PDF
С помощью Docotic.Pdf вы можете легко преобразовать набор изображений в один PDF, размещая по одному изображению на каждой странице.
В примере ниже изображения загружаются из файлов и каждое изображение рисуется на собственной странице. Каждое изображение масштабируется по размеру страницы и центрируется для аккуратного, единообразного оформления.
public static void ImagesOnToPdf(string[] imagePaths, string outputPath)
{
using var pdf = new PdfDocument();
foreach (string path in imagePaths)
{
var image = pdf.CreateImage(path);
var page = pdf.AddPage();
var pageWidth = page.Width;
var pageHeight = page.Height;
var scale = Math.Min(pageWidth / image.Width, pageHeight / image.Height);
var drawWidth = image.Width * scale;
var drawHeight = image.Height * scale;
var x = (pageWidth - drawWidth) / 2;
var y = (pageHeight - drawHeight) / 2;
page.Canvas.DrawImage(image, x, y, drawWidth, drawHeight, 0);
}
pdf.RemovePage(0);
pdf.Save(outputPath);
}
Работа с многостраничными изображениями TIFF и GIF
Docotic.Pdf полностью поддерживает многостраничные файлы TIFF и GIF. При добавлении изображений в PDF используйте метод OpenImage вместо CreateImage, если какое-либо из изображений может содержать несколько страниц.
Следующий код показывает, как преобразовать TIFF в PDF, и он работает как для одностраничных, так и для многостраничных изображений:
public static void OddFramesToPdf(string[] imagePaths, string outputPath)
{
using var pdf = new PdfDocument();
foreach (string path in imagePaths)
{
var imageFrames = pdf.OpenImage(path);
for (int i = 0; i < imageFrames.Count; i++)
{
if (i % 2 != 0)
continue;
var image = pdf.CreateImage(imageFrames[i]);
var page = pdf.AddPage();
page.Width = image.Width;
page.Height = image.Height;
page.Canvas.DrawImage(image, 0, 0, image.Width, image.Height, 0);
}
}
pdf.RemovePage(0);
pdf.Save(outputPath);
}
Вы можете использовать тот же подход для преобразования GIF в PDF. Он также применим к другим форматам изображений, хотя для форматов, содержащих только один кадр, это более сложно, чем необходимо.
Объединение и разделение PDF
Как полнофункциональная библиотека .NET, Docotic.Pdf может создавать новые PDF, объединяя, извлекая и переупорядочивая страницы из существующих документов.
При объединении PDF библиотека не только добавляет страницы из другого документа, но и добавляет слои, закладки, метки страниц, общий JavaScript, назначения (цели ссылок) и встроенные файлы. Дополнительные сведения и рекомендации по уменьшению размера объединенных PDF см. в статье об объединении PDF.
Цифрово подписанные PDF нельзя объединять, не делая существующие подписи недействительными. Чтобы сохранить подписи, создайте PDF portfolio вместо добавления документов. Другой вариант — сначала объединить PDF, а затем применить новую цифровую подпись к объединенному документу.
Docotic.Pdf также позволяет копировать и извлекать страницы в новые документы. Сохраняется все содержимое, связанное с копируемыми страницами, включая аннотации, элементы форм, структурированное содержимое, слои и другие связанные данные. Практические примеры см. в статье о разделении PDF в .NET. Там же объясняется, как извлекать или удалять страницы.
Работа с шаблонами PDF
Шаблоны PDF — это предварительно подготовленные файлы PDF, которые служат базовой структурой для создания новых документов. Они полезны, когда нужно формировать PDF с единообразной компоновкой, подставляя разные данные. Если вы хотите отделить визуальный дизайн от самих данных, шаблоны PDF — тоже хороший выбор.
Шаблоны могут быть как PDF на основе форм, так и статическими PDF без форм. Оба типа служат одной и той же цели. Кроме того, шаблоны на основе форм включают интерактивные элементы, которые, если их не «сгладить», могут собирать данные от пользователей.
Создание PDF из шаблонов на основе форм
Шаблоны на основе форм обычно содержат AcroForms — стандартный и широко поддерживаемый тип интерактивной PDF-формы. Чтобы создать PDF из такого шаблона, обычно нужно:
- заполнить каждое поле-заполнитель
- сгладить поля, чтобы предотвратить дальнейшее редактирование
- сохранить результат как новый PDF
Ниже приведен код C#, который находит текстовое поле-заполнитель по имени, присваивает ему значение, сглаживает поле и сохраняет результат, создавая PDF из шаблона:
var nameOnCertificate = "Eva Marin";
using var pdf = new PdfDocument("certificate-template.pdf");
if (pdf.TryGetControl("name", out var field))
{
if (field is PdfTextBox nameField)
{
nameField.Text = nameOnCertificate;
nameField.Flatten();
}
}
pdf.Save($"certificate-{nameOnCertificate}.pdf");
Если шаблон содержит много заполнителей, вы можете импортировать данные FDF вместо того, чтобы заполнять каждое поле по отдельности. Также можно использовать PdfDocument.FlattenControls, чтобы сгладить все поля сразу.
Создание PDF из статических шаблонов без форм
Если ваш шаблон не содержит полей формы, вы будете рисовать имена и другие данные непосредственно на холсте страницы. Статические шаблоны PDF обычно содержат фиксированные визуальные заполнители, такие как текст, изображения или пустые области. Чтобы создать PDF из шаблона, нужно заполнить эти пустые области и программно заменить текст и изображения-заполнители.
Пустые области
Используйте Canvas API, чтобы размещать текст и изображения в пустых областях. В простых случаях, когда нужны только небольшие изменения, например добавление имени и фотографии, этот подход работает хорошо. Вам нужно знать координаты и размер областей, а чтобы правильно позиционировать текст, может потребоваться сначала измерить его, а затем выровнять соответствующим образом.
Работа с текстом переменной длины или многострочным текстом сложнее, но все же возможна. Комбинируя DrawText, DrawString и методы измерения текста, вы можете переносить и позиционировать строки по мере необходимости. Если шаблон содержит больше чем несколько таких областей, рассмотрите альтернативный подход, например создание PDF с помощью Layout API.
Замещающий текст
Docotic.Pdf также предоставляет методы для поиска и замены текста. Однако использование поиска текста как механизма шаблонизации обычно не проще, чем работа с пустыми областями-заполнителями. Перед вставкой нового содержимого нужно точно найти нужный фрагмент текста и аккуратно удалить его.
Замещающие изображения
Статические шаблоны могут включать изображения-заполнители для аватаров пользователей или фотографий продуктов. Чтобы найти изображение-заполнитель, перечислите коллекцию изображений, нарисованных на каждой странице. Для каждого нарисованного изображения можно получить его видимый размер и положение. Чтобы заменить заполнитель, используйте PdfImage.ReplaceWith.
using var pdf = new PdfDocument("invoice-template.pdf");
var paintedImages = pdf.Pages[0].GetPaintedImages();
var placeholder = paintedImages.First();
placeholder.Image.ReplaceWith("company-logo.jpg");
pdf.Save($"invoice.pdf");
Другой вариант — нарисовать новое изображение поверх области, занятой изображением-заполнителем, но это обычно без необходимости увеличивает размер получившегося PDF.
Проектирование заполнителей для удобной замены
Для статических шаблонов полезно проектировать компоновку с предсказуемыми, четко определенными областями как для текста, так и для изображений. Оставляйте достаточно отступов вокруг областей, которые будут содержать контент переменной длины, и используйте нейтральные изображения-заполнители, которые соответствуют ожидаемым вами пропорциям вставки.
Если в шаблоне используется текст-заполнитель, который вы планируете заменить, можно упростить рабочий процесс, используя текстовые поля вместо «сырого» текста. Добавьте в шаблон поле только для чтения без границ и поместите в него текст-заполнитель. При генерации итогового PDF откройте шаблон, найдите текстовое поле по имени и присвойте новое значение напрямую через box.Text = "new text";. Затем сгладьте текстовое поле, чтобы предотвратить дальнейшее редактирование.
Добавление интерактивных элементов
Интерактивные возможности превращают статический PDF в динамичный, удобный для навигации документ, обогащенный аннотациями и разметкой. Действия и JavaScript позволяют автоматизировать работу прямо внутри PDF.
Аннотации
Аннотации — это объекты, прикрепленные к странице и представляющие комментарии, выделения, вложения файлов и другие интерактивные элементы интерфейса. Они видны в содержимом страницы и поддерживают рабочие процессы рецензирования и совместную работу.
Следующий пример C# показывает, как добавить текстовые аннотации, также известные как стикеры, на страницу PDF с помощью Docotic.Pdf.
using var pdf = new PdfDocument("example.pdf");
var page = pdf.Pages[0];
var textAnnot = page.AddTextAnnotation(new PdfPoint(50, 100), "Reviewer comment");
textAnnot.Contents = "Please check the figures on this page.";
pdf.Save("text-annotation.pdf");
Следующий пример демонстрирует, как выделить текст и другой контент, чтобы привлечь внимание к ключевым частям документа.
using var pdf = new PdfDocument("example.pdf");
var page = pdf.Pages[0];
var color = new PdfRgbColor(255, 255, 120);
var annotationText = "Please confirm this part.";
var bounds = new PdfRectangle(50, 250, 120, 40);
page.AddHighlightAnnotation(annotationText, bounds, color);
pdf.Save("highlight-annotation.pdf");
Ссылки
Стандарты PDF определяют несколько типов PDF-ссылок. Наиболее важные и широко используемые — внутренние ссылки и гиперссылки.
Внутренние ссылки, также называемые действиями GoTo, позволяют переходить на страницу или именованное назначение внутри того же PDF. Они полезны для перекрестных ссылок и внутренней навигации.
Ниже приведен код C#, который создает ссылку с первой страницы на страницу с индексом 5:
using var pdf = new PdfDocument();
var page = pdf.Pages[0];
int targetPageIndex = 5;
for (int i = 0; i < targetPageIndex; i++)
pdf.AddPage();
var rect = new PdfRectangle(50, 50, 100, 40);
page.Canvas.DrawRectangle(rect);
page.AddLinkToPage(rect, targetPageIndex);
pdf.Pages[targetPageIndex].Canvas.DrawString(50, 50, "Glad to have you here.");
pdf.Save("link-to-page.pdf");
Layout API предоставляет другой способ создавать внутренние ссылки, не требующий абсолютного позиционирования.
Внешние ссылки, также называемые действиями URI, открывают веб-адрес. Вы можете добавить гиперссылку на страницу PDF с помощью метода PdfPage.AddHyperlink. В остальном подход тот же, что и для внутренних ссылок.
Закладки
Закладки, также называемые оглавлением, — это специальные ярлыки или ссылки, которые помогают читателям быстро переходить к конкретным разделам или страницам. Когда читатель нажимает закладку, приложение для просмотра переходит к указанной части документа.
Оглавление отображается на панели закладок просмотрщика и представляет собой иерархическое дерево навигации, похожее на оглавление книги, но интерактивное. Закладки PDF могут включать основные закладки и вложенные закладки, что упрощает структурирование больших документов.
Следующий пример показывает, как создавать закладки в PDF с помощью C# и Docotic.Pdf. Код создает три закладки верхнего уровня. Вторая закладка содержит одну вложенную закладку.
using var pdf = new PdfDocument();
for (int i = 0; i < 5; i++)
{
var page = i == 0 ? pdf.Pages[0] : pdf.AddPage();
var canvas = page.Canvas;
canvas.FontSize = 14;
canvas.DrawString(50, 50, $"Page {i + 1}");
}
var root = pdf.OutlineRoot;
root.AddChild("Getting Started", 1);
var child = root.AddChild("Things You Can Do", 2);
child.AddChild("Making Quick Improvements", 3);
root.AddChild("Keeping Everything Running Smoothly", 4);
pdf.PageMode = PdfPageMode.UseOutlines;
pdf.Save("bookmarks.pdf");
Закладки отличаются от оглавления, которое вы можете видеть напечатанным на страницах физической книги или отображаемым в PDF. Вы можете программно создать оглавление, измеряя заголовки и записывая элементы с номерами страниц.
Чтобы увидеть альтернативный подход к созданию оглавления с использованием Layout API, посмотрите соответствующий код в нашем репозитории примеров.
PDF-скриптинг
Действия JavaScript относятся к наиболее мощным интерактивным возможностям. PDF JavaScript — это подмножество JavaScript, которое предоставляет API документа и просмотрщика. Оно используется для проверки форм, вычислений, диалогов пользовательского интерфейса и небольших задач автоматизации.
Вы можете прикреплять скрипты к аннотациям, закладкам, элементам форм или действиям открытия. С Docotic.Pdf можно внедрять код JavaScript в PDF. Этот код может проверять ввод формы, вычислять значения, показывать или скрывать поля либо выполнять взаимодействия с просмотрщиком.
Коллекция общего JavaScript содержит скрипты, хранящиеся на уровне документа. Эти скрипты можно повторно использовать из нескольких действий. Иными словами, общие скрипты полезны для вспомогательных функций и общей логики. Они помогают уменьшить дублирование и упростить сопровождение.
Ниже приведен код, который определяет общий скрипт, отображающий всплывающее сообщение в просмотрщике PDF, а затем показывает, как вызвать этот скрипт, назначив его действию щелчка кнопки.
using var pdf = new PdfDocument();
pdf.SharedScripts.Add(
pdf.CreateJavaScriptAction("function messageBox(message) { app.alert(message,3); }")
);
var button = pdf.Pages[0].AddButton(50, 50, 100, 40);
button.Text = "Click me";
button.OnMouseUp = pdf.CreateJavaScriptAction("messageBox('Hello, dear!');");
pdf.Save("shared-javascript.pdf");
Скрипт в примере прост, но вы можете создавать действия JavaScript любой сложности. Справочник Adobe JavaScript API содержит множество методов, которые можно использовать. Имейте в виду, что просмотрщики, не относящиеся к Adobe, обычно поддерживают только подмножество API.
Открывающие действия
Открывающее действие — это действие, которое просмотрщик PDF выполняет при открытии документа. Типичные сценарии использования включают открытие на определенной странице, запуск инициализирующей процедуры JavaScript или настройку параметров просмотрщика. Ограничений на тип открывающего действия нет.
Следующий пример показывает, как создать открывающее действие GoTo. Код добавляет текст на вторую страницу и задает открывающее действие, которое автоматически переводит просмотрщик на эту страницу при открытии PDF.
using var pdf = new PdfDocument();
var canvas = pdf.AddPage().Canvas;
canvas.FontSize = 14;
var message =
"If you see this immediately after opening the file, " +
"your PDF viewer supports open actions.";
var options = new PdfTextDrawingOptions(new PdfRectangle(100, 100, 100, 150));
canvas.DrawText(message, options);
pdf.OnOpenDocument = pdf.CreateGoToPageAction(1, 0);
pdf.Save("open-action.pdf");
Обратите внимание, что не все просмотрщики выполняют открывающие действия JavaScript. Некоторые их игнорируют или сначала запрашивают подтверждение пользователя. Некоторые просмотрщики полностью блокируют открывающие действия.
Чтобы проверить, содержит ли PDF открывающее действие, загрузите его в PdfDocument и проверьте свойство OnOpenDocument. Если свойство null, в документе не определено открывающее действие.
Применение шифрования и цифровых подписей
Шифрование и цифровые подписи решают два взаимодополняющих аспекта защиты создаваемых PDF. Шифрование определяет, кто может открыть документ и что можно с ним делать, а подписи подтверждают, кто создал или утвердил файл, и подтверждают, что он не был изменен.
Защита паролем позволяет задавать правила доступа на этапе создания. Вы можете назначить пароль открытия, чтобы ограничить просмотр, и пароль владельца, чтобы определить разрешения, такие как печать, копирование, редактирование или заполнение форм. Шифрование сертификатами обеспечивает более сильную, адресную защиту и хорошо подходит для распространения конфиденциальных PDF нескольким людям без использования общего пароля. Подробнее см. в статье о шифровании PDF с помощью паролей и сертификатов.
Цифровые подписи добавляют подлинность и целостность на этапе создания. Docotic.Pdf может подписывать PDF с использованием сертификатов из файлов, хранилища Windows, аппаратных токенов, HSM или облачных служб ключей. Вы можете включать метки времени и данные для долгосрочной проверки, чтобы подписи оставались проверяемыми спустя долгое время после создания документа. Также поддерживаются внешние сценарии подписи, включая PKCS#11 и облачные KMS.
Настройка метаданных PDF
Метаданные PDF — это описательная информация, встроенная в документ, например заголовок, автор, тема, ключевые слова, даты создания и аналогичные поля. Они помогают программам, поисковым системам и системам управления документами понимать, о чем файл, без его открытия.
PDF-документ может содержать метаданные в двух сосуществующих системах:
- метаданные XMP
- словарь информации документа (
Info)

XMP — это более богатый, структурированный и стандартизированный формат для внедрения описательных метаданных. Словарь Info прост и широко поддерживается, но ограничен; в стандарте PDF 2.0 (ISO 32000‑2) он считается устаревшим в пользу метаданных XMP. Docotic.Pdf может читать и записывать обе системы и предоставляет вспомогательный метод для их синхронизации.
Docotic.Pdf автоматически обновляет некоторые метаданные перед сохранением PDF-файла. Например, библиотека по умолчанию задает значения Producer и Creator. Используйте параметры сохранения, чтобы изменить это поведение и сохранить явно заданные значения метаданных.
Метаданные XMP
Используйте свойство PdfDocument.Metadata, чтобы получить доступ к метаданным XMP в PDF и изменить их. Через это свойство можно работать с известными схемами, такими как XMP Core, Dublin Core и схема PDF, а также управлять собственными пользовательскими метаданными.
using var pdf = new PdfDocument();
var xmp = pdf.Metadata;
xmp.Pdf.Creator = new XmpString("Second-line authoring terminal");
xmp.Pdf.Title = new XmpString("Quarterly Report");
var creators = new XmpArray(XmpArrayType.Ordered);
creators.Values.Add(new XmpString("Second-line authoring terminal"));
creators.Values.Add(new XmpString("Assistive authoring terminal"));
xmp.DublinCore.Creators = creators;
var descriptions = new XmpArray(XmpArrayType.Alternative);
descriptions.Values.Add(new XmpLanguageAlternative("x-default", "Quarterly Report"));
descriptions.Values.Add(new XmpLanguageAlternative("fr", "Rapport trimestriel"));
descriptions.Values.Add(new XmpLanguageAlternative("de", "Quartalsbericht"));
xmp.DublinCore.Descriptions = descriptions;
var author1 = new XmpString("First Author");
author1.Qualifiers.Add("role", "main author");
var author2 = new XmpString("Second Author");
author2.Qualifiers.Add("role", "co-author");
var authors = new XmpArray(XmpArrayType.Unordered);
authors.Values.Add(author1);
authors.Values.Add(author2);
xmp.Custom.Properties.Add("authors", authors);
pdf.Save("with-xmp-metadata.pdf");
XMP поддерживает массивы, структуры и типизированные значения, что делает его хорошим выбором для богатых метаданных. Приведенный выше код также показывает, как хранить свойства, специфичные для приложения, в пользовательской схеме XMP.
Словарь информации документа
Словарь Info в основном хранит строковые текстовые значения. Он компактен и широко поддерживается, но ограничен. Используйте словарь Info для совместимости со старыми инструментами, а в остальных случаях предпочитайте XMP.
Синхронизация метаданных
Хорошей практикой является поддерживать обе системы метаданных в синхронном состоянии, чтобы избежать несоответствий, которые могут запутать читателей и автоматизированные инструменты.
Используйте PdfDocument.SyncMetadata, чтобы выровнять значения XMP и Info, чтобы соответствующие поля совпадали. Метод заполняет отсутствующие свойства Info из XMP и, аналогично, заполняет отсутствующие поля XMP из Info. Установите preferXmp: true, если XMP является вашим авторитетным источником, или false, когда приоритет должен быть у словаря Info.
pdf.SyncMetadata(preferXmp: true);
Дополнительные сведения о том, какие свойства синхронизирует метод, см. в разделе Remarks документации SyncMetadata.
Настройка меток страниц и предпочтений просмотрщика
Недавно созданный PDF может выиграть от явной нумерации страниц, точно настроенных предпочтений просмотрщика и выбранного макета страниц, который лучше представляет содержимое документа. Эти настройки влияют на то, как читатели впервые видят файл и как они в нем перемещаются.
Метки страниц
Метки страниц — это метаданные, которые сообщают просмотрщику PDF, какую метку отображать для каждой страницы. Используйте их, когда видимая нумерация должна отличаться от физического индекса страницы. Например, когда вам нужны i, ii, iii для вводной части и 1, 2, 3 для основного текста в вашем PDF.
Этот код C# показывает, как присвоить страницам PDF метки с римскими цифрами в нижнем регистре для первых трех страниц и арабскую нумерацию, начинающуюся с 1, для остальных.
using var pdf = new PdfDocument();
for (int i = 0; i < 8; i++)
pdf.AddPage();
pdf.PageLabels.AddRange(0, 2, PdfPageNumberingStyle.LowercaseRoman);
pdf.PageLabels.AddRange(3, PdfPageNumberingStyle.DecimalArabic);
pdf.Save("with-page-labels.pdf");
Предпочтения просмотрщика PDF
Предпочтения просмотрщика PDF — это рекомендации, встроенные в документ, которые указывают, как просмотрщик должен отображать его. Например, можно задать, что просмотрщик должен скрывать панели инструментов, центрировать окно или подгонять окно под страницу. Предпочтения просмотрщика дополняют настройки макета страницы и открывающего действия.
Вот как изменить предпочтения просмотра PDF с помощью Docotic.Pdf:
using var pdf = new PdfDocument();
pdf.ViewerPreferences.DisplayTitle = false;
pdf.ViewerPreferences.FitWindow = true;
pdf.ViewerPreferences.HideToolBar = true;
pdf.ViewerPreferences.HideMenuBar = true;
pdf.ViewerPreferences.HideWindowUI = true;
pdf.ViewerPreferences.CenterWindow = true;
pdf.Save("with-viewer-prefs.pdf");
Обратите внимание, что в зависимости от конфигурации Adobe Acrobat и другие просмотрщики могут игнорировать эти предпочтения.
Макет страницы и режим страницы
Макет страницы определяет, как страницы располагаются при открытии документа: по одной странице, непрерывной одноколоночной лентой или разворотами на две страницы. Режим страницы управляет тем, какие панели интерфейса видны при открытии: закладки/оглавление, вложения, миниатюры или ничего.
Вот как задать, чтобы созданный PDF отображался как двухстраничный разворот, с левой страницы первой, и чтобы при открытии была видна панель миниатюр:
using var pdf = new PdfDocument();
for (int i = 0; i < 7; i++)
{
var page = i > 0 ? pdf.AddPage() : pdf.Pages[0];
page.Canvas.FontSize = 36;
page.Canvas.DrawString(100, 100, $"Page {i + 1}");
}
pdf.PageLayout = PdfPageLayout.TwoPageLeft;
pdf.PageMode = PdfPageMode.UseThumbs;
pdf.Save("with-layout-and-mode.pdf");
Сохранение PDF
Docotic.Pdf может создавать разные PDF-файлы или потоки из одного и того же созданного или отредактированного документа. Эти результаты могут соответствовать разным версиям формата PDF, иметь разную длину в байтах и требовать разного объема памяти для генерации.
То, как библиотека формирует байты PDF, зависит от параметров сохранения. Когда параметры сохранения явно не указаны, методы Save, SignAndSave и TimestampAndSave объекта PdfDocument используют настройки по умолчанию. Эти значения по умолчанию тщательно подобраны и хорошо работают в большинстве сценариев, но вам все равно может понадобиться их настроить.
См. документацию по классу PdfSaveOptions для подробной информации о доступных параметрах и их значениях по умолчанию. В разделах ниже выделены некоторые из наиболее важных параметров и приведены практические рекомендации.
Версия PDF
Docotic.Pdf по умолчанию использует объектные потоки, чтобы добиться лучшего сжатия создаваемых файлов. В результате библиотека по умолчанию создает файлы и потоки PDF 1.5.
Для просмотра создаваемых документов PDF 1.5 требует Adobe Reader 6 (выпущенный в 2003 году) или более новую версию. Обычно это не проблема, если только вам не требуется поддержка устаревших инструментов, старых просмотрщиков или встроенных устройств, которые принимают только более старые версии PDF.
Вот как сохранить файл с более старой версией PDF:
using var pdf = new PdfDocument();
var options = new PdfSaveOptions
{
Version = PdfVersion.Pdf14,
UseObjectStreams = false,
};
pdf.Save("version-1.4.pdf", options);
Чтобы сохранить в версии PDF 1.4, объектные потоки также должны быть отключены. Библиотека не будет использовать более старую версию, если документ содержит возможности, появившиеся в более поздних версиях.
Уменьшение размера файла
Несколько параметров сохранения при значении true заставляют Docotic.Pdf создавать файлы меньшего размера (по байтам): RemoveUnusedObjects, OptimizeIndirectObjects, WriteWithoutFormatting и UseObjectStreams.
Вот как создавать PDF без неиспользуемых объектов и лишних пробелов, с данными, плотно упакованными в объектные потоки:
using var pdf = new PdfDocument();
var options = new PdfSaveOptions
{
UseObjectStreams = true,
RemoveUnusedObjects = true,
OptimizeIndirectObjects = true,
WriteWithoutFormatting = true,
};
pdf.Save("optimized.pdf", options);
Эти параметры наиболее эффективны, когда PDF полностью переписывается. Во время инкрементального сохранения они применяются только к новой добавленной ревизии и не могут очистить или оптимизировать ранние части файла.
Инкрементальные обновления
Docotic.Pdf может обновлять PDF инкрементально. Когда WriteIncrementally имеет значение true, библиотека дописывает изменения в существующий файл вместо его полного переписывания. Предыдущие данные перекрестных ссылок и объектов остаются неизменными. Дописываемые данные называются инкрементальным обновлением, а текущее обновление вместе со всеми предыдущими обновлениями составляет новую ревизию файла.
Инкрементальные обновления невозможны для только что созданных документов, потому что нет предыдущей ревизии, к которой можно было бы дописывать. Библиотека игнорирует этот параметр для новых документов и записывает их в неинкрементальном режиме.
Когда требуются инкрементальные обновления
При добавлении новой цифровой подписи к документу, который уже содержит подписи, вы должны сохранять файл инкрементально. То же самое относится к обновлению ранее подписанного файла новыми аннотациями или данными форм. Полная перезапись файла в таких случаях сделала бы существующие подписи недействительными.
В то же время перед применением первой цифровой подписи лучше выполнить неинкрементальное (полное) сохранение, чтобы базовая подписанная версия была чистым, полностью переписанным файлом. Подписание документа, содержащего структурные проблемы в более ранних ревизиях, может привести к неожиданным проблемам с проверкой подписи.
Инкрементальное добавление также требуется в рабочих процессах, которые должны сохранять аудируемую историю ревизий или обеспечивать хранение документов только с дописыванием.
Преимущества использования инкрементальных обновлений
Инкрементальные обновления позволяют создавать несколько подписей в одном и том же файле и допускают ограниченный набор изменений после подписи, например заполнение полей формы, без нарушения существующих подписей.
Кроме того, этот подход обеспечивает более быструю запись небольших изменений, потому что записываются только измененные данные. Он также сохраняет историю ревизий документа, что важно для аудита и других рабочих процессов, ориентированных на соответствие требованиям.
Проблемы и ошибки, которых следует избегать
Инкрементальные обновления не могут применить глобальное сжатие или удалить устаревшие объекты по всему файлу, потому что они дописывают только измененные объекты. В результате обычно получаются более крупные и менее оптимизированные файлы, чем при полной перезаписи.
Размер файла увеличивается с каждой ревизией, даже если неиспользуемые объекты отсутствуют, потому что все предыдущие ревизии остаются встроенными в файл и продолжают занимать место.
Конфиденциальная или некорректная информация из более ранних ревизий остается доступной для восстановления, а существующие проблемы формата PDF или структурные дефекты в предыдущих ревизиях не исправляются добавлением новых данных.
Наконец, некоторые просмотрщики и инструменты обработки испытывают трудности с много-ревизионными PDF. Прежде чем полагаться на инкрементальные обновления, убедитесь, что все потребители ваших документов умеют работать с файлами, содержащими несколько ревизий.
Тестирование вывода PDF
Автоматизированное тестирование PDF защищает релизы от регрессий в содержимом и компоновке, сравнивая сгенерированные PDF с эталонными PDF, хранящимися в вашем репозитории или хранилище артефактов. Эталонные файлы помогают обнаруживать случайные изменения в тексте, шрифтах, изображениях или компоновке и уменьшают необходимость в ручном QA на каждой сборке.
Для наиболее надежных результатов комбинируйте структурные проверки, извлечение текста и визуальные сравнения.
Краткое сравнение подходов
| Метод | Скорость | Чувствительность | Лучше всего подходит для |
|---|---|---|---|
| Структурное сравнение | Быстро | Высокая: обнаруживает изменения на уровне объектов | Регрессионные тесты, где нужно подтвердить, что две версии одного и того же документа структурно идентичны |
| Извлечение текста | Быстро | Средняя: обычно игнорирует изменения компоновки | Проверка семантического содержимого и таблиц |
| Визуальное сравнение | Медленнее | Высокая: обнаруживает и изменения содержимого, и изменения рендеринга/компоновки | Обнаружение визуальных регрессий |
Сравнение структуры документа
Используйте PdfDocument.DocumentsAreEqual, чтобы сравнивать графы объектов PDF, версию PDF и хранилище безопасности документа (DSS), игнорируя зависящие от времени свойства документа. Метод также игнорирует метаданные документа, trailer IDs и другие автоматически создаваемые свойства.
Этот метод идеально подходит для сценариев тестирования PDF-документов, где нужно гарантировать, что не были добавлены или удалены неожиданные объекты. DocumentsAreEqual поддерживает перегрузки для файлов и потоков и может сравнивать зашифрованные PDF.
Полный пример, демонстрирующий эту технику, доступен в примерах Docotic.Pdf. Помимо демонстрации использования метода в обычных приложениях .NET, пример также показывает, как использовать DocumentsAreEqual в Native AOT приложениях.
Проверка PDF по извлеченному тексту
Извлекайте текст из всего документа сразу или со страниц по одной и сравнивайте строки. Можно использовать параметры извлечения текста, чтобы точнее настроить процесс, например исключить прямоугольник с нижним колонтитулом. Для упрощения сравнения извлеченный текст можно разбить на строки или слова.
Для структурных проверок сначала извлеките текст с координатами, шрифтом и другими подробными сведениями о каждом фрагменте, слове или символе. Затем сравнивайте каждый извлеченный элемент с соответствующим эталонным элементом.
Обнаружение визуальных различий
Начните с рендеринга страниц PDF в изображения и сравните каждое изображение с эталонным. Используйте специализированные библиотеки, такие как ImageSharp.Compare или Magick.NET, чтобы обнаруживать различия в изображениях.
Предпочтителен строгий покадровый, пиксель-в-пиксель подход, при котором каждый соответствующий пиксель в обоих изображениях должен совпадать. Если ваши требования допускают небольшие различия при рендеринге, можно скорректировать логику сравнения, чтобы терпеть незначительные отличия, но точное совпадение пикселей дает наиболее надежные результаты.
Рассмотрите использование хеширования как быстрой предварительной проверки, чтобы определить, вероятно ли, что два изображения идентичны, без полного сравнения пикселей. Вычисляйте хеш SHA-256 для каждого отрендеренного изображения, и если хеши совпадают, изображения почти наверняка одинаковы. Если хеши различаются, запускайте полное покадровое сравнение пикселей.
Заключение
Docotic.Pdf предоставляет полноценный многоуровневый набор инструментов для создания и обработки PDF в .NET. Разработчики могут выбирать между низкоуровневым контролем с помощью Core API, высокоуровневой генерацией документов с помощью Layout API или преобразованием HTML-to-PDF для рабочих процессов, уже построенных вокруг веб-технологий.
Библиотека также поддерживает PDF на основе изображений, генерацию на основе шаблонов и богатый набор интерактивных возможностей, таких как аннотации, ссылки, закладки, действия JavaScript и открывающие действия.
Чтобы обеспечить надежность, Docotic.Pdf включает методы для тестирования вывода PDF, чтобы изменения в вашем приложении не приводили к регрессиям или неожиданным различиям.