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

Layout API позволяет определять документы полностью на языке C# или VB.NET, используя гибкий подход. Исходя из описания в коде, генератор 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.
Привет, мир! с помощью 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 несколько раз. Вы можете найти рабочий
пример в нашем репозитории примеров.
Организация кода
Для коротких фрагментов кода, как в примере, допустимо использовать цепочки вызовов и вложенные лямбда-выражения. При создании чего-то более масштабного может быть удобнее разделить код на отдельные методы. Это упрощает чтение и сопровождение кода.
Вот как выглядит пример «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
API Layout — это удобный для разработчиков современный способ генерации PDF-файлов из составных блоков без необходимости разбираться во внутренней структуре формата PDF. Он обеспечивает высокопроизводительную компоновку PDF-файлов с детерминированным, предсказуемым поведением. Вы можете использовать API в сценариях генерации большого объема документов.
API доступен при использовании Docotic.Pdf вместе с бесплатным дополнением Layout. И Docotic.Pdf, и дополнение Layout представляют собой DLL-файлы с полностью управляемым кодом, без небезопасных (unsafe) блоков кода. API макета реализован без каких-либо внешних зависимостей от сторонних сервисов, таких как браузер или исполняемые файлы Skia, что обеспечивает легковесное решение с низкими накладными расходами, простое в развертывании и обслуживании.
Обзор API
Layout API — это удобный и интуитивно понятный API. Вы описываете макет документа полностью в коде, используя гибкие элементы макета, а генератор автоматически распределяет контент по страницам и отображает результат в формате PDF.
Дополнение Layout использует декларативную, основанную на потоках систему компоновки. Его элементы макета включают списки, столбцы, строки, таблицы, изображения, текстовые блоки, верхние и нижние колонтитулы, контейнеры и многое другое. Вместо ручного размещения элементов по точным координатам, вы описываете, как должны вести себя элементы. Затем конструктор документа вычисляет окончательный макет и создает PDF-файл.
Система компоновки, основанная на потоках, гарантирует, что макет адаптируется к размеру страницы и содержимому. Благодаря этой системе дополнение отлично подходит для сложных, структурированных, основанных на правилах макетов. Вы можете вкладывать различные типы контейнеров и создавать сложные структуры без ущерба для читаемости.
При работе с Layout API вы можете объединять большинство вызовов в цепочки. Это приводит к более компактному и выразительному коду, чем при использовании традиционных API. Порядок вызовов в цепочке важен. Все строго типизировано, что обеспечивает безопасность на этапе компиляции и делает код удобным для рефакторинга. Вы также можете тестировать модульным методом код, использующий Layout API.
Чтобы сделать вашу реализацию компоновки еще более лаконичной, вы можете расширить API собственными методами и создать на его основе чистый, выразительный DSL.
Для получения дополнительной информации о позиционировании и создании DSL обратитесь к статье, объясняющей, как управлять размером, положением, выравниванием и поведением рендеринга контейнеров.
Поддержка версий .NET и платформ
API Layout можно использовать в проектах, ориентированных на .NET Standard 2.1 и более новые платформы. Другими словами, дополнение Layout совместимо с .NET 5–.NET 10. Кроме того, поддерживается .NET Core 3.0+.
С помощью Layout API можно создавать PDF-файлы в ASP.NET Core, приложениях MAUI, Unity, Xamarin и консольных приложениях. Docotic.Pdf с дополнением Layout может создавать PDF-файлы в Windows, macOS и Linux.
Облачные платформы и Docker
Библиотека Docotic.Pdf с надстройкой Layout может работать в облачных средах Azure и AWS, включая бессерверные конфигурации. Библиотека и надстройка полностью поддерживают динамические изменения оборудования, автомасштабирование и другие функции облачной среды выполнения.
В большинстве облачных сценариев требуется неограниченная лицензия. В разделе «Часто задаваемые вопросы о лицензиях» объясняется, как выбрать подходящую лицензию для облачных приложений.
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).
Из-за этих настроек по умолчанию документы, использующие шрифты 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 контейнера Column предоставляет подконтейнер. Один вызов 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-документах используются внутренние ссылки для закладок или оглавления, помогающие читателям быстро перемещаться между разделами. Вот как можно добавить ссылку на раздел документа с помощью 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 см. в
примере Компоненты макета.
Другие способы создания 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 в PDF, если ваша команда уже создает документы в формате HTML/CSS, и вам нужны PDF-версии этих документов. -
Низкоуровневая генерация PDF-файлов
Обеспечивает максимальный контроль над структурой и содержимым PDF-файлов, доступный в библиотеке. Выбирайте этот вариант, если вам требуется позиционирование на уровне пикселей или сложная векторная графика. Этот подход рекомендуется для сценариев, критически важных с точки зрения производительности, или когда требуется минимальное потребление ресурсов. -
Генерация PDF-файлов на основе шаблонов
Предлагает быстрый и предсказуемый способ заполнения документов без необходимости проектирования или упорядочивания их элементов. Выбирайте этот вариант, если у вас есть предопределенная структура PDF-файла, например, утвержденные или соответствующие требованиям шаблоны, и вам нужно только изменить текстовые поля, заменить заполнители, прикрепить связанные документы и выполнить подобные задачи. -
Объединение и композиция PDF-файлов
Позволяет создать PDF-файл из существующих фрагментов вместо создания его с нуля. Выберите этот вариант, если у вас есть изображения, отсканированные страницы или другие PDF-файлы, которые необходимо объединить в один файл.
Сравнение с другими решениями для генерации PDF
В этом разделе представлены две сравнительные таблицы: одна с основными выводами, а другая — с подробной структурированной информацией о том, как Docotic.Pdf с надстройкой Layout соотносится с другими популярными решениями для генерации PDF.
Основные выводы сравнения
Существует множество отличных инструментов для создания PDF-файлов, в том числе и бесплатных. Однако возможности, такие как подписание, шифрование или объединение документов, различаются, что может ограничивать выбор действительно подходящих инструментов.
| Решение | Когда использовать | Лучше всего подходит для |
|---|---|---|
| Docotic.Pdf с дополнением Layout | Если вам нужен высококачественный и высокопроизводительный механизм верстки, способный создавать оптимизированные PDF-файлы с расширенной поддержкой подписей, шифрования и редактирования PDF-файлов на разных платформах | Высококачественное создание счетов-фактур, отчетов, выписок и аналогичных документов с превосходным API для разработчиков. Идеально подходит, когда вам необходима обработка 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-возможности |
| Модель рендеринга | Современный декларативный механизм компоновки с сохранением состояния | Механизм компоновки на основе блоков | Современный декларативный механизм компоновки с сохранением состояния | Механизм компоновки на основе блоков + дерево рендеринга |
| Тип 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. Библиотека позволяет создавать отчеты, выписки, счета-фактуры и аналогичные документы. Ее хорошо продуманный, гибкий API обеспечивает превосходный опыт разработки. Вы можете рассчитывать на профессиональную поддержку, которую Bit Miracle предоставляет для Docotic.Pdf и его дополнений.
В отличие от некоторых других решений для генерации PDF-файлов, Docotic.Pdf — это полнофункциональный API для работы с PDF. Библиотека может подписывать сгенерированные PDF-файлы цифровыми подписями, включая подписи с поддержкой LTV. Docotic.Pdf способен использовать сертификаты, хранящиеся на защищенном оборудовании, такие как USB-токены и смарт-карты. Также поддерживаются облачные аппаратные модули безопасности (HSM), такие как Microsoft Azure Key Vault и AWS Key Management Service (KMS).
С помощью Docotic.Pdf вы можете прикреплять вспомогательные документы, такие как электронные таблицы или голосовые заметки, к сгенерированным PDF-файлам. Для отображения документов на веб-странице или в аналогичном интерфейсе вы можете создавать миниатюрные изображения одной или нескольких страниц.
Следующие шаги:
- Изучите примеры кода для API Layout.
- Сравните генерацию PDF-файлов из составных строительных блоков с другими подходами к созданию PDF-файлов.
- Свяжитесь с нами с вопросами, отзывами или особыми случаями.