Эта страница может содержать автоматически переведенный текст.
Генератор PDF для .NET
С помощью Docotic.Pdf вы можете создавать PDF-документы, компонуя их из структурных элементов, таких как страницы, контейнеры, текстовые фрагменты, изображения, ссылки, верхние и нижние колонтитулы, таблицы, списки и многое другое. Эти элементы доступны через высокоуровневый Layout API, предоставляемый бесплатной надстройкой Layout для Docotic.Pdf. API также поддерживает повторно используемые пользовательские компоненты.

Layout API позволяет полностью определять документы в коде C# или VB.NET, используя fluent-подход. Согласно этому описанию, генератор PDF, предоставляемый надстройкой, может создавать документы с произвольно сложной разметкой — от простых страниц до строго структурированных PDF-отчетов.
Основы генерации PDF
Чтобы создавать PDF-документы с помощью Layout API, вам нужна бесплатная надстройка Layout. Для использования основной библиотеки и надстроек также требуется лицензионный ключ. Можно использовать бесплатный пробный ключ или приобретенный ключ.
Установка надстройки
Рекомендуемый способ — установить надстройку из NuGet.
Install-Package BitMiracle.Docotic.Pdf.Layout
Диспетчер пакетов автоматически обработает зависимости.
Если вы предпочитаете установить надстройку вручную, начните со скачивания ZIP-архива с двоичными файлами Docotic.Pdf. Распакуйте архив и добавьте ссылки на следующие DLL:
BitMiracle.Docotic.Pdf.dllBitMiracle.Docotic.Pdf.Layout.dllиз подпапкиLayout add-on.
Получение ключа лицензии
Чтобы попробовать библиотеку, запросите бесплатный временный лицензионный ключ, заполнив форму на странице загрузки Docotic.Pdf. Если вы уже приобрели лицензию, используйте код, предоставленный вам после покупки.
Надстройка Layout бесплатна и не требует дополнительной лицензии. Вы можете использовать Layout API с той лицензией Docotic.Pdf, которая у вас уже есть.
Hello, world! с Layout API
Ниже приведен пример кода, использующий API для генерации PDF с классической фразой "Hello, world!":
BitMiracle.Docotic.LicenseManager.AddLicenseData("PUT-LICENSE-HERE");
PdfDocumentBuilder.Create().Generate("hello.pdf", doc => doc.Pages(pages =>
{
pages.Content().Text("Hello, world!");
}));
Этот код создает одностраничный PDF с текстом в левом верхнем углу.
Понимание примера кода
Пример начинается с добавления лицензионного ключа. Без лицензии библиотека Docotic.Pdf ничего не создаст. Код, генерирующий PDF, начинается на следующей строке.
Код создает экземпляр построителя документа, вызывая статический метод PdfDocumentBuilder.Create(). Вызов метода Generate запускает процесс генерации PDF. Этот метод принимает два параметра: имя создаваемого файла и делегат типа Action<Document>. Надстройка создает hello.pdf как результат вызова Generate.
Чтобы понять, какой макет должен иметь PDF, построитель документа вызывает делегат, передавая ему экземпляр Document. Код делегата формирует содержимое документа. В этом примере делегат использует метод Pages, чтобы передать построителю еще один делегат, определяющий макет страниц документа.
Построитель вызывает делегат, переданный методу Pages, с экземпляром PageLayout. Этот экземпляр представляет одну или несколько страниц в документе. Точное число страниц зависит от добавленного в них содержимого.
Делегат страницы вызывает метод Content, чтобы получить доступ к контейнеру макета для основного содержимого страницы(страниц). Последовательный вызов метода Text у контейнера добавляет пример текстового фрагмента на страницу. См. руководство по контейнерам макета, где подробно объясняется их работа.
Построитель документа автоматически распределяет содержимое по страницам, создавая ровно столько страниц, сколько нужно для размещения всех данных, добавленных в контейнер макета основного содержимого. В этом примере достаточно одной страницы, поэтому результат содержит ровно одну страницу.
Общие задачи помимо базового примера
Сначала пример кода создает экземпляр PdfDocumentBuilder, а затем вызывает метод Generate для создания PDF. Вы можете настроить построитель до начала генерации PDF.
Например, можно создать зашифрованный PDF, передав построителю обработчик шифрования. Также можно указать метаданные, которые построитель включит в создаваемый документ. Подробнее о том, как настроить построитель, см. в отдельной статье.
Пример кода использует только контейнер макета слота основного содержимого, но доступны и другие слоты содержимого. Вот полный список методов PageLayout для доступа к слотам содержимого:
Background()- возвращает фоновый слой, который перекрывается другим содержимым.Header()- возвращает общий верхний колонтитул для всех страниц.Content()- возвращает основной слот содержимого страницы.Footer()- возвращает общий нижний колонтитул для всех страниц.Foreground()- возвращает передний слой, который отображается поверх другого содержимого.
Только содержимое в основном слоте влияет на количество страниц в создаваемом PDF. Построитель документа повторяет на каждой странице все слоты, кроме предоставленного Content(). Дополнительные сведения о слотах содержимого см. в статье о макете страницы.
Многие документы используют разные макеты на разных страницах. Например, первая страница может иметь оформление в виде титульного листа, а последующие страницы — более простой макет. Некоторые документы включают специальные страницы для таблиц или используют разные фоны в зависимости от раздела. Чтобы создавать такие документы с Docotic.Pdf и надстройкой Layout, вызывайте метод Document.Pages несколько раз. Рабочий пример можно найти в нашем репозитории примеров.
Организация кода
Для короткого кода, как в примере, вполне нормально объединять вызовы в цепочки и использовать вложенные lambda-выражения. Когда вы создаете более крупное решение, может быть удобнее разделить код на отдельные методы. Это упрощает чтение и поддержку.
Вот как выглядит пример Hello, world!, если разделить его код на методы.
public void GeneratePdf()
{
BitMiracle.Docotic.LicenseManager.AddLicenseData("PUT-LICENSE-HERE");
PdfDocumentBuilder.Create().Generate("hello.pdf", BuildDocument);
}
private void BuildDocument(Document doc)
{
doc.Pages(BuildPages);
}
private void BuildPages(PageLayout pages)
{
pages.Content().Text("Hello, world!");
}
Почему стоит генерировать PDF с помощью Docotic.Pdf Layout API
Layout API — это современный, удобный для разработчика способ создавать PDF из компонуемых строительных блоков без необходимости понимать внутреннее устройство формата PDF. Он раскладывает PDF с высокой производительностью и предсказуемым детерминированным поведением. API можно использовать в сценариях генерации документов с высоким объемом.
API доступен при использовании Docotic.Pdf вместе с бесплатной надстройкой Layout. И Docotic.Pdf, и надстройка Layout — это на 100% управляемые DLL без небезопасных блоков кода. Layout API реализован без каких-либо внешних зависимостей от сторонних компонентов, таких как браузер или двоичные файлы Skia, что делает решение легким, с низкими накладными расходами и простым в развертывании и сопровождении.
Обзор API
Layout API — это fluent API, удобный в использовании. Вы полностью описываете макет документа в коде, используя гибкие элементы макета, а генератор потоково обрабатывает содержимое, автоматически разбивает его на страницы и отображает результат в виде PDF.
Надстройка Layout использует декларативную потоковую систему макета. Ее элементы макета включают списки, колонки, строки, таблицы, изображения, текстовые фрагменты, верхние и нижние колонтитулы, контейнеры и многое другое. Вместо ручного размещения элементов по точным координатам вы описываете, как они должны вести себя. Затем построитель документа вычисляет конечный макет и создает PDF.
Потоковая система макета обеспечивает адаптацию к размеру страницы и содержимому. Благодаря этой системе надстройка особенно хорошо подходит для сложных, структурированных макетов, основанных на правилах. Можно вкладывать разные типы контейнеров и строить сложные структуры, не жертвуя читаемостью.
При работе с Layout API можно объединять в цепочки большинство вызовов. Это дает более компактный и выразительный код, чем традиционные API. Порядок вызовов в цепочке важен. Все строго типизировано, что обеспечивает проверку на этапе компиляции и упрощает рефакторинг. Код, использующий Layout API, также можно покрывать модульными тестами.
Чтобы еще сильнее сократить реализацию макета, вы можете расширить API собственными методами и построить на его основе чистый, выразительный DSL.
Дополнительные сведения о позиционировании и создании DSL см. в статье, объясняющей, как управлять размером, положением, выравниванием и поведением контейнеров при отрисовке.
Версии .NET и поддержка платформ
Вы можете использовать Layout API в проектах, нацеленных на .NET Standard 2.1 и более новые фреймворки. Другими словами, надстройка Layout совместима с .NET 5 по .NET 10 включительно. Кроме того, поддерживается .NET Core 3.0+.
Вы можете генерировать PDF с помощью Layout API в ASP.NET Core, приложениях MAUI, Unity, Xamarin и консольных приложениях. Docotic.Pdf с надстройкой Layout может создавать PDF в Windows, macOS и Linux.
Облачные платформы и образы Docker
Docotic.Pdf с надстройкой Layout может работать в облачных средах Azure и AWS, включая бессерверные конфигурации. Библиотека и надстройка полностью поддерживают динамические изменения аппаратных ресурсов, автоматическое масштабирование и другие облачные возможности среды выполнения.
В большинстве облачных сценариев требуется нелимитированная лицензия. В FAQ по лицензированию объясняется, как выбрать подходящую лицензию для облачных приложений.
Layout API без проблем работает в контейнерах Docker. Для генерации PDF при запуске библиотеки и надстройки Layout внутри контейнера не требуется специальная конфигурация.
Добавление текста в PDF-файлы
Текст — фундаментальная часть любого PDF-документа. Для добавления текста в слот содержимого можно использовать методы Text класса LayoutContainer.

Текстовые фрагменты
В примере Hello, world я использовал перегрузку LayoutContainer.Text(string) для добавления текста в основное содержимое страницы. Теперь рассмотрим другую перегрузку метода Text.
public static void GenerateTextPdf()
{
PdfDocumentBuilder.Create().Generate("text-spans.pdf", doc => doc.Pages(pages =>
{
pages.Content().Text(AddTextSpans);
}));
}
private static void AddTextSpans(TextContainer text)
{
text.Line("About VB.NET")
.Style(t => t.Strong);
text.Span("VB.NET is a multi-paradigm, object-oriented language ");
text.Span("that runs on .NET, Mono, and the ");
text.Hyperlink(
".NET Framework",
new Uri("https://dotnet.microsoft.com/download/dotnet-framework"));
text.Line(".");
text.Span("Released by Microsoft in 2002, ");
text.Line("it continues the lineage of the original Visual Basic language.");
}
Этот код использует методы Span и Line класса TextContainer для добавления текста в текущую строку. Метод Line дополнительно завершает текущую строку. Пример кода также использует метод Hyperlink для привязки внешней ссылки на ресурс к определенному текстовому фрагменту.
Обратите внимание, как пример кода применяет полужирное форматирование к первой строке с помощью метода Style. Давайте подробнее рассмотрим концепцию текстовых стилей.
Текстовые стили
Текстовые стили позволяют настраивать внешний вид текста. Класс TextStyle предоставляет методы для изменения размера шрифта, межбуквенного интервала, цветов и других текстовых свойств. Объекты TextStyle неизменяемы, поэтому каждый вызов метода создает новый экземпляр стиля. Текстовые стили можно применять на разных уровнях макета.
PdfDocumentBuilder.Create().Generate("text-styles.pdf", doc =>
{
doc.Pages(pages =>
{
pages.TextStyle(TextStyle.Parent.FontSize(30));
pages.Content()
.TextStyle(TextStyle.Parent.FontColor(new PdfRgbColor(0, 0, 255)))
.Text(text =>
{
text.Span("Hello,");
text.Span("World!")
.Style(TextStyle.Parent.Underline());
});
});
});
Свойство TextStyle.Parent возвращает специальный стиль, в котором все текстовые свойства не определены. В приведенном выше примере код рисует «Hello, World!» синим цветом, а второе слово — с подчеркиванием, используя шрифт размером 30 пунктов.
Это происходит потому, что код:
- задает размер шрифта 30 пунктов на уровне страницы,
- затем устанавливает синий цвет текста для слота основного содержимого,
- затем применяет стиль подчеркивания к последнему текстовому фрагменту.
Каждый последующий стиль наследует предыдущие через свойство TextStyle.Parent.
Используя методы класса TextStyle, можно, среди прочего, изменить направление текста на справа налево. См. еще один пример использования наследования стиля текста в нашем репозитории примеров.
Типографика
Класс TextStyle позволяет настраивать все текстовые свойства, кроме связанного шрифта. Чтобы изменить шрифт по умолчанию, используйте методы Document.TextStyleWithFont для создания стиля текста на основе конкретного шрифта. Можно использовать шрифт, установленный в операционной системе, или загрузить его из файла или потока.
После создания стиля на основе шрифта вы можете применить дополнительные необязательные свойства, а затем использовать полученный стиль для текстового фрагмента. Этот пример на C# демонстрирует, как использовать системный шрифт.
PdfDocumentBuilder.Create().Generate("text-style-with-font.pdf", doc =>
{
var font = SystemFont.Family("Calibri");
var style = doc.TextStyleWithFont(font).FontSize(30);
doc.Pages(pages =>
{
pages.Content().Text(text =>
{
text.Span("Hello,");
text.Span("World!")
.Style(style);
});
});
});
Метод TextStyleWithFont включает необязательный параметр, который задает способ встраивания шрифта в создаваемый документ. По умолчанию библиотека:
- встраивает используемые глифы для шрифтов TrueType/OpenType,
- встраивает все глифы для шрифтов Type1 и CFF,
- не встраивает глифы для встроенных PDF-шрифтов (Base14 fonts).
Благодаря этим настройкам документы, использующие шрифты TrueType и OpenType, могут оставаться небольшими по размеру даже при использовании крупных шрифтов. Также можно указать пользовательский загрузчик шрифтов, резервные шрифты и обработчик отсутствующих глифов. Подробнее см. в примере кода в нашем репозитории примеров о управлении шрифтами в PDF-документах.
Layout API предоставляет набор предопределенных стилей, к которым можно получить доступ и которые можно изменять через класс Typography.
PdfDocumentBuilder.Create().Generate("typography.pdf", doc =>
{
doc.Typography(t =>
{
var fontsPath = Environment.GetFolderPath(Environment.SpecialFolder.Fonts);
var arialFont = new FileInfo(Path.Combine(fontsPath, "arial.ttf"));
t.Document = doc.TextStyleWithFont(arialFont);
t.Header = t.Parent.FontSize(20).FontColor(new PdfGrayColor(20));
t.Footer = t.Footnote;
});
doc.Pages(pages =>
{
pages.Header().AlignCenter().Text("Header");
pages.Content().Text(t =>
{
t.Line("Title").Style(t => t.Title);
t.Line("Heading 1").Style(t => t.Heading1);
t.Line("Regular");
});
pages.Footer()
.Height(20)
.AlignCenter()
.Text(t => t.CurrentPageNumber());
});
});
Я рекомендую переопределять предопределенные стили, настраивая типографику для всего документа, хотя это и не обязательно: вы по-прежнему можете применять текстовые стили на уровне текстовых фрагментов.
С помощью класса Typography вам не нужно хранить ссылки на текстовые стили в переменных. Вместо этого вы регистрируете необходимые стили с помощью методов Document.Typography, а затем обращаетесь к ним через свойства объекта Typography. См. пример Typography, чтобы увидеть, как использовать предопределенные и пользовательские текстовые стили при создании PDF-документов.
Работа с верхними и нижними колонтитулами
Многие реальные PDF-документы, такие как отчеты или счета, содержат верхние и нижние колонтитулы. В этом разделе показано, как добавить и то и другое в PDF.
public static void GeneratePdfWithHeaderAndFooter()
{
PdfDocumentBuilder.Create()
.Generate("header-footer.pdf", doc => doc.Pages(pages =>
{
pages.Size(PdfPaperSize.A6).Margin(10);
BuildPagesHeader(pages.Header());
BuildPagesFooter(pages.Footer());
pages.Content().Text("Hello, world!");
}));
}
public static void BuildPagesHeader(LayoutContainer header)
{
header.TextStyle(TextStyle.Parent.FontSize(8))
.AlignRight()
.Text(t =>
{
t.Line($"Created by: {Environment.UserName}");
t.Line($"Date: {DateTime.Now}");
});
}
public static void BuildPagesFooter(LayoutContainer footer)
{
footer.AlignRight().Text(text =>
{
text.Style(t => t.Parent.FontColor(new PdfRgbColor(255, 0, 0)));
text.CurrentPageNumber();
text.Span(" / ");
text.PageCount();
});
}
Метод BuildPagesHeader задает меньший размер шрифта для текста верхнего колонтитула. Он использует две строки для содержимого заголовка: одну с именем текущего пользователя и другую с текущей датой. Текст выровнен по правому краю.
Обратите внимание, что код не задает явный размер для верхнего колонтитула. Он занимает всю ширину страницы за вычетом левого и правого полей, а его высота зависит от высоты строк текста.
Метод BuildPagesFooter демонстрирует, как поместить номер текущей страницы в нижний колонтитул PDF. Библиотека автоматически вычисляет номер текущей страницы и общее количество страниц. Эти значения можно получить с помощью методов CurrentPageNumber и PageCount объекта TextContainer.
Layout API также предоставляет способ форматирования номеров страниц. Например, можно вывести номера страниц в шестнадцатеричном виде так:
text.CurrentPageNumber().Format(p => "0x" + p?.ToString("x2"));
В нашем репозитории примеров есть еще один пример добавления верхнего и нижнего колонтитула в PDF. В этом примере номера страниц форматируются как римские цифры.
Вставка изображений
Как говорится, одна картинка стоит тысячи слов. В цитатах или квитанциях часто нужно включить логотип компании или другое важное изображение. В этом примере я использую простое и приятное на вид изображение.
Чтобы использовать изображение, сначала нужно добавить его в документ. Библиотека может загружать изображения из файла или потока. Поддерживаются только растровые форматы: PNG, JPEG, JPEG 2000, BMP, GIF и TIFF.
После того как у вас есть объект Image, вы можете назначить его содержимым одного или нескольких контейнеров макета, вызвав метод Image у контейнера. Можно масштабировать, поворачивать, добавлять отступы и располагать изображение так же, как и любое другое содержимое.
PdfDocumentBuilder.Create().Generate("image-with-text.pdf", doc =>
{
var imageFile = new FileInfo("red-flowers-at-butterfly-world.jpg");
var image = doc.Image(imageFile);
doc.Pages(pages =>
{
pages.Size(PdfPaperSize.A6);
pages.Content().Column(c =>
{
c.Spacing(20);
c.Item()
.AlignCenter()
.Text("Hello, world!")
.FontSize(20);
c.Item()
.AlignCenter()
.MaxWidth(200)
.Image(image);
});
});
});
Пример кода использует и текст, и изображение в слоте основного содержимого. Однако контейнер макета может содержать только текст или только изображение. Чтобы включить и то и другое в основной слот содержимого страницы, вам нужен составной контейнер.
Я использую контейнер Column, чтобы разместить текст и изображение вертикально, одно за другим. Метод Item контейнера колонки предоставляет под-контейнер. Один вызов Item создает контейнер для текста, а другой — для изображения. Составной контейнер со всеми своими под-контейнерами становится основным содержимым.
Чтобы запустить пример кода, скачайте изображение цветка из нашего репозитория примеров и поместите его в рабочую директорию приложения.
Изображения из сети
Если у вас есть только URL изображения, а не файл, загрузите изображение в поток памяти и создайте Image на основе этого потока. Следующий пример показывает, как использовать изображения из сети с Layout API.
public static async Task AddImageWithTextFromUrl()
{
using var http = new HttpClient();
using var stream = await http.GetStreamAsync("url/to/image");
var memoryStream = new MemoryStream();
await stream.CopyToAsync(memoryStream);
memoryStream.Position = 0;
PdfDocumentBuilder.Create().Generate("online-image-with-text.pdf", doc =>
{
var image = doc.Image(memoryStream);
doc.Pages(pages =>
{
pages.Size(PdfPaperSize.A6);
pages.Content().Column(c =>
{
c.Spacing(20);
c.Item()
.AlignCenter()
.Text("Hello, world!")
.FontSize(20);
c.Item()
.AlignCenter()
.MaxWidth(200)
.Image(image);
});
});
});
}
Поскольку метод выполняет асинхронную работу (загрузку изображения по URL), он объявлен как async Task, а не как void. Вызывающему коду нужно await-ить его, чтобы генерация PDF корректно завершилась. В вашем собственном коде похожий метод также может возвращать значение; в этом случае он будет объявлен как async Task<TResult>.
Создание списков
Что такое список? Его можно представить как группу нумерованных элементов, записанных один под другим. Layout API не предоставляет специального типа контейнера для списков, но его легко реализовать с помощью других составных контейнеров.
var dayNames = DateTimeFormatInfo.InvariantInfo.DayNames;
var dayNamesSpain = DateTimeFormatInfo.GetInstance(new CultureInfo("es-ES")).DayNames;
PdfDocumentBuilder.Create().Generate("list.pdf", doc => doc.Pages(pages =>
{
pages.Size(PdfPaperSize.A6);
pages.Content().Column(column =>
{
for (int i = 0; i < dayNames.Length; i++)
{
column.Item().Row(row =>
{
row.Spacing(5);
row.AutoItem().Text($"{i + 1}.");
row.RelativeItem().Text(t =>
{
t.Line(dayNames[i]);
t.Line($"In Spain they call it {dayNamesSpain[i]}");
});
});
}
});
}));
Пример кода создает список как колонку строк. Каждая строка содержит два элемента: первый (слева) содержит номер пункта, а второй (справа) — текст пункта. Код явно задает интервал между элементами в каждой строке.
Для размещения элементов контейнер Row должен либо иметь явно заданный размер каждого элемента, либо вычислять его. В этом примере используются методы AutoItem и RelativeItem. В результате контейнер строки вычисляет ширину, необходимую для первого элемента, а затем использует оставшуюся доступную ширину для второго элемента.
Используя этот подход и при необходимости изменяя внешний вид строк, вы можете создать список, который наилучшим образом соответствует макету и стилю вашего документа.
Создание таблиц
Многие PDF-документы содержат таблицы, что неудивительно, поскольку таблицы повышают наглядность и упорядоченность данных. В этом разделе показано, как создать таблицу в PDF с помощью Layout API.
public static void AddTable()
{
PdfDocumentBuilder.Create().Generate("table.pdf", doc => doc.Pages(pages =>
{
pages.Size(PdfPaperSize.A6);
var color = new PdfGrayColor(75);
pages.Content().Padding(20).Table(t =>
{
t.Columns(c =>
{
c.RelativeColumn(4);
c.RelativeColumn(1);
c.RelativeColumn(4);
});
t.Header(h =>
{
h.Cell().Background(color).Text("Month");
h.Cell().Background(color).Text("Days");
h.Cell().Background(color).Text("First Day");
});
var year = DateTime.Now.Year;
for (int yearDiff = 0; yearDiff < 4; yearDiff++)
{
for (int i = 11; i >= 0; i--)
{
var stats = GetMonthStats(year - yearDiff, i);
t.Cell().Text(stats.Item1);
t.Cell().Text(stats.Item2);
t.Cell().Text(stats.Item3);
}
}
});
}));
}
private static (string, string, string) GetMonthStats(int year, int monthIndex)
{
return (
$"{DateTimeFormatInfo.InvariantInfo.MonthNames[monthIndex]} {year}",
DateTime.DaysInMonth(year, monthIndex + 1).ToString(),
new DateTime(year, monthIndex + 1, 1).DayOfWeek.ToString()
);
}
Пример кода создает простую таблицу, отображающую базовую информацию о месяцах текущего года и трех предыдущих лет. Код определяет три столбца с относительной шириной. Крайний левый и крайний правый столбцы в четыре раза шире среднего столбца.
Код также определяет заголовок таблицы, добавляя ячейки заголовка и указывая текст и цвет фона для каждой ячейки. Когда таблица не помещается на одной странице, заголовок повторяется на каждой странице, которую занимает таблица. Это поведение можно увидеть в PDF, созданном примером кода.
Для построения строк используются два простых цикла. Внешний цикл проходит по годам, а внутренний — по месяцам в обратном порядке. Внутренний цикл получает сведения о каждом месяце, а затем добавляет три ячейки, формируя строку.
Подробнее о возможностях контейнера таблицы можно прочитать в статье, подробно объясняющей его особенности.
Создание внутренних ссылок PDF
PDF-документы поддерживают внутренние ссылки, позволяющие читателю переходить к другому месту в том же файле. В просмотрщике PDF эти ссылки отображаются как кликабельные текстовые или графические элементы. Они работают как гиперссылки, но вместо перехода на внешний сайт перемещают внутри самого документа.

Многие PDF-документы используют внутренние ссылки для закладок или оглавления, помогая читателям быстро перемещаться между разделами. Вот как можно добавить ссылку на раздел документа с помощью Layout API:
PdfDocumentBuilder.Create().Generate("link.pdf", doc =>
{
doc.Pages(pages =>
{
pages.Content().Column(c =>
{
const string SectionName = "Chapter 1";
c.Item().SectionLink(SectionName).Text("Link");
c.Item().PageBreak();
c.Item().Section(SectionName).Text("Target");
});
});
});
Пример кода делает текст на первой странице ссылкой на раздел с указанным именем. Для этого вызывается метод SectionLink у контейнера макета, содержащего текст. Раздел на этом этапе может существовать, а может и нет. Текст становится кликабельным в просмотрщике PDF.
Затем код помечает текст на второй странице как начало раздела с тем же именем. Его внешний вид и поведение не изменяются, но он становится целью для ссылки на первой странице. Это делается путем вызова метода Section у соответствующего контейнера макета.
В этом примере и ссылка, и ее цель представляют собой текстовые фрагменты, но создавать разделы и ссылки можно на любом контейнере макета. Это может быть контейнер с изображением, контейнер таблицы или контейнер, созданный вами самостоятельно.
См. пример того, как создать оглавление PDF в нашем репозитории примеров.
Проектирование сложных макетов PDF
Layout API предоставляет различные контейнеры макета, которые можно комбинировать для создания PDF-документов произвольной сложности. Вы также можете расширить API собственными пользовательскими компонентами.
Примеры на этой странице намеренно просты и предназначены для создания прямолинейных документов, чтобы вы могли сосредоточиться на основных идеях, не теряясь в деталях. Если вы хотите увидеть, как разные контейнеры можно объединять, чтобы создать более сложный PDF, посмотрите соответствующий пример в нашем репозитории примеров на GitHub.
Помимо использования встроенных контейнеров, можно определять и использовать пользовательские компоненты макета. Эти компоненты особенно полезны, когда вы хотите, чтобы один класс инкапсулировал и данные, и логику макета. Хранение всего в одном месте облегчает понимание, изменение и повторное использование компонента, а также дает гибкий способ работы со сложными макетами.
Чтобы создать пользовательский компонент макета, реализуйте в своем классе интерфейс ILayoutComponent. При генерации PDF библиотека вызывает метод Compose интерфейса и передает объект LayoutContext. Ваш код может использовать этот объект для создания элементов макета и доступа к информации о создаваемом документе.
Чтобы добавить пользовательский компонент макета в свой макет, вызовите метод Component класса LayoutContainer. С точки зрения размеров и позиционирования пользовательский компонент ведет себя так же, как текст или изображения.
Пример реализации пользовательского компонента с интерфейсом ILayoutComponent см. в примере компонентов Layout.
Другие способы создания PDF
Docotic.Pdf предлагает несколько способов создания PDF, каждый из которых подходит для разных сценариев. В этом разделе объясняется, когда следует полагаться на Layout API, а когда лучше использовать другие подходы.
Когда стоит предпочесть Layout API
Docotic.Pdf Layout API — мощный способ генерировать PDF из структурированных макетов. Он позволяет строить документы, компонуя текст, изображения, контейнеры и таблицы в произвольно сложные вложенные структуры. Процесс генерации быстрый, использует разумный объем памяти и ведет себя предсказуемо.
Docotic.Pdf и надстройка Layout образуют легкий, полностью автономный комплект. API не требует внешних библиотек или браузеров для генерации PDF. Это делает его надежным выбором для микросервисов .NET, облачных приложений, особенно бессерверных, и других сред, где важен размер.
Поскольку макет документа определяется в коде, можно покрыть модульными тестами любую его часть. Логику макета можно переиспользовать как любой другой код, а данные и поведение макета можно инкапсулировать в пользовательских компонентах.
Альтернативы Layout API
Отдельная статья содержит подробное сравнение всех способов создания PDF с помощью Docotic.Pdf. Ниже приведены некоторые из наиболее часто используемых альтернатив.
-
Преобразование HTML в PDF
Использует существующие шаблоны HTML/CSS. Выбирайте подход HTML-to-PDF, когда ваша команда уже создает документы в HTML/CSS и вам нужны PDF-версии этих документов. -
Низкоуровневая генерация PDF
Предоставляет максимальный контроль над структурой и содержимым PDF, доступный в библиотеке. Выбирайте этот вариант, когда вам нужно позиционирование на уровне пикселей или сложная векторная графика. Этот подход рекомендуется для сценариев, критичных к производительности, или когда требуется минимально возможный размер решения. -
Шаблонная генерация PDF
Предлагает быстрый и предсказуемый способ заполнения документов без проектирования или ручного размещения их элементов. Выбирайте этот вариант, если у вас есть заранее определенная структура PDF, например утвержденные шаблоны или шаблоны под контролем соответствия требованиям, и нужно только изменять текстовые поля, заменять заполнители, прикреплять связанные документы и выполнять похожие задачи. -
Объединение и композиция PDF
Позволяет создать PDF из уже существующих частей вместо того, чтобы собирать его с нуля. Выбирайте этот вариант, когда у вас есть изображения, отсканированные страницы или другие PDF, которые нужно объединить в один файл.
Сравнение с другими решениями для генерации PDF
Этот раздел содержит две сравнительные таблицы: одну с ключевыми выводами и другую с подробной структурированной информацией о том, как Docotic.Pdf с надстройкой Layout сравнивается с другими популярными решениями для генерации PDF.
Ключевые выводы сравнения
Есть сильные варианты для генерации PDF, включая бесплатные. Однако возможности вроде подписания, шифрования или объединения документов различаются, что может ограничивать набор инструментов, действительно подходящих под ваши задачи.
| Решение | Когда использовать | Лучше всего подходит для |
|---|---|---|
| Docotic.Pdf с надстройкой Layout | Когда вам нужен высококачественный, высокопроизводительный движок макета, способный создавать оптимизированные PDF, с продвинутой поддержкой подписей, шифрования и редактирования PDF на разных платформах | Высококачественной генерации счетов, отчетов, выписок и аналогичных документов с отличным опытом для разработчика. Идеально, когда вам нужна обработка PDF корпоративного уровня и профессиональная поддержка |
| PDFsharp + MigraDoc | Когда вам нужна бесплатная библиотека с лицензией MIT для базовой генерации PDF и не требуются цифровые подписи или современные алгоритмы шифрования | Простого создания документов в проектах с открытым исходным кодом или ограниченным бюджетом |
| QuestPDF | Когда вам нужен современный движок макета, предназначенный только для генерации PDF, и не требуется редактирование, подписи или шифрование | Высококачественной генерации PDF с лицензией MIT или недорогой коммерческой лицензией, если все функции, не связанные с генерацией, реализованы в другом месте |
| iText | Когда вам нужен зрелый, богатый функциями набор инструментов PDF как для генерации, так и для обработки PDF, и вы готовы либо открыть свой проект под лицензией AGPL/GPLv3, либо купить дорогую коммерческую лицензию | Командам, уже знакомым с API iText и потому не сталкивающимся с его крутой кривой обучения |
Подробное сравнение
Изучите таблицу, чтобы понять более широкий контекст и сделать собственные выводы.
| Docotic.Pdf с Layout | PDFsharp + MigraDoc | QuestPDF | iText | |
|---|---|---|---|---|
| Возможности PDF | Полнофункциональная библиотека PDF | Генерация PDF и ограниченное редактирование | Только генерация PDF | Широкие возможности работы с PDF |
| Модель рендеринга | Современный декларативный движок макета retained-mode | Блочный движок макета | Современный декларативный движок макета retained-mode | Блочный движок макета + дерево рендеринга |
| Тип API | Fluent API | Императивный API | Fluent API | Императивный API |
| Удобство для разработчика | Отличное. API чистый, современный и интуитивно понятный | Хорошее. Дизайн API традиционный | Отличное. API чистый, современный и интуитивно понятный | Удовлетворительное. API многословный и избыточно сложный |
| Субсеттинг шрифтов | Поддерживается; по умолчанию встраиваются только используемые глифы | Не поддерживается; может приводить к неоправданно большим PDF | Поддерживается; по умолчанию встраиваются только используемые глифы | Поддерживается; по умолчанию встраиваются только используемые глифы |
| Направление содержимого справа налево (RTL) | Поддерживается | Не поддерживается | Поддерживается | Поддерживается |
| Цифровые подписи | Поддерживаются, включая LTV и внешние подписи | Не поддерживаются | Не поддерживаются | Поддерживаются, включая LTV и внешние подписи |
| Шифрование / разрешения | Полностью поддерживаются | Только шифрование RC4, без поддержки AES или сертификатов | Не поддерживаются | Полностью поддерживаются |
| Внешние зависимости | Нет | Нет | Компоненты на базе SkiaSharp / Skia | Нет |
| Поддержка | Профессиональная поддержка для потенциальных и действующих клиентов; приоритетная поддержка для лицензий высшего уровня | Поддержка сообщества; профессиональную поддержку можно приобрести отдельно | Поддержка сообщества через GitHub | Поддержка сообщества для версии AGPL; профессиональная поддержка для владельцев коммерческой лицензии |
| Лицензия | Коммерческая, с бесплатными лицензиями для подходящих сценариев использования | MIT | MIT для частных лиц и небольших компаний; для более крупных организаций требуется коммерческая лицензия | AGPL для проектов с открытым исходным кодом, дорогая коммерческая лицензия для проприетарных проектов |
| Лицензирование для разработчиков | Неограниченное число разработчиков со всеми лицензиями | Неограниченное число разработчиков со всеми лицензиями | Неограниченное число разработчиков с MIT; 10 разработчиков с Professional; неограниченное число разработчиков с Enterprise | Неограниченное число разработчиков с версией AGPL; лицензирование по разработчикам с коммерческой лицензией |
Заключение
Docotic.Pdf с надстройкой Layout предоставляет современный, высокопроизводительный и качественный способ генерировать PDF в C# и VB.NET. Библиотека создает отчеты, выписки, счета и подобные документы. Ее хорошо продуманный fluent API обеспечивает отличный опыт для разработчика. Вы можете рассчитывать на профессиональную поддержку, которую Bit Miracle предоставляет для Docotic.Pdf и его надстроек.
В отличие от некоторых других решений для генерации PDF, Docotic.Pdf — это полнофункциональный PDF API. Библиотека может подписывать создаваемые PDF цифровыми подписями, включая подписи с поддержкой LTV. Docotic.Pdf умеет использовать сертификаты, хранящиеся на защищенном оборудовании, таком как USB-токены и смарт-карты. Также поддерживаются облачные модули аппаратной защиты ключей (HSM), такие как Microsoft Azure Key Vault и AWS Key Management Service (KMS).
С помощью Docotic.Pdf вы можете прикреплять вспомогательные документы, такие как таблицы или голосовые заметки, к создаваемым PDF. Чтобы отображать документы на веб-странице или в похожем интерфейсе, вы можете создавать миниатюры изображений по одной или нескольким их страницам.
Дальнейшие шаги:
- Изучите примеры кода для Layout API.
- Сравните генерацию PDF из компонуемых строительных блоков с другими подходами к созданию PDF.
- Свяжитесь с нами, если у вас есть вопросы, замечания или крайние случаи.