Руководство по PDFsharp: Создание PDF-файлов с помощью MigraDoc и PdfSharpCore
PDFsharp — это библиотека с открытым исходным кодом для .NET, предназначенная для создания и редактирования PDF-документов из кода C#. Вы рисуете текст, линии и изображения на странице, вызываете функцию «Сохранить», и получаете PDF-файл. Нет браузерного движка, нет нативного исполняемого файла. Проект существует с 2005 года, и многие счета, отчеты и сертификаты, создаваемые с помощью .NET-бэкэндов, до сих пор проходят через него.
Я написал это для разработчиков, которым нужны PDF-файлы на сервере и которые хотят понимать, с чем им предстоит столкнуться. Мы рассмотрим, как PDFsharp и MigraDoc взаимодействуют друг с другом, какую сборку установить, создание первого рабочего файла, проблемы со шрифтами в Linux, недавнее изменение лицензии и момент, когда следует выбрать что-то другое.
Что такое PDFsharp и на что он способен?
За библиотекой PDFsharp стоит компания empira Software GmbH, небольшая немецкая фирма, которая поддерживает её работу уже почти двадцать лет. Большая часть вашего времени уходит на один класс — XGraphics. Если вы когда-либо работали с WinForms, используя System.Drawing.Graphics, вы освоитесь за десять минут: шрифт, кисть, x и y, вперёд!
В комплекте вы получаете:
- Создавайте PDF-документы с нуля, используя текст, векторные фигуры, линии и изображения.
- Откройте существующие PDF-файлы и добавьте на их страницы контент, например, штампы, водяные знаки или номера страниц.
- Объединяйте и разделяйте документы, импортируя страницы из одного файла в другой.
- Внедрите и выберите подмножество шрифтов , чтобы файл выглядел одинаково на всех компьютерах.
- Добавляйте закладки, ссылки и метаданные документа, такие как заголовок, автор и ключевые слова.
- Защитите файлы паролями и флагами прав доступа.
- Подписывать документы в электронном виде (начиная с версии 6.2)
Процесс развертывания скучный, и я говорю это как похвалу. Все реализовано в виде управляемого кода, поэтому вашему специалисту по эксплуатации никогда не придется устанавливать Chrome в безголовом режиме или искать DLL-файл Ghostscript в 2 часа ночи. Вы добавляете ссылку на один пакет NuGet, отправляете изменения — готово.
А теперь подвох. Вы получаете холст и ничего больше. Длинный абзац упирается в нижнее поле? Это ваша проблема. Таблица выходит за пределы первой страницы? Тоже ваша проблема, если только вы не используете MigraDoc.
PDFsharp и MigraDoc: какой слой вам нужен?
Тот же поставщик, тот же график выпуска, но совершенно разные задачи. MigraDoc Foundation находится этажом выше PDFsharp. Вместо того чтобы указывать ему, куда вставлять строку, вы передаете ему разделы, абзацы, таблицы, верхние и нижние колонтитулы, стили и даже диаграммы, и он сам определяет, куда что должно попасть. В результате получается PDF-файл. Или RTF, для коллеги, который настаивает на открытии всего в Word.
Моя сокращенная запись: PDFsharp — это «поместите этот текст по координатам x=40, y=120». MigraDoc — это «вот тридцать строк и повторяющийся заголовок, а страницы сортируйте сами».
| Задача | Наилучший вариант | Почему |
|---|---|---|
| Одностраничный сертификат или билет с указанием местоположения. | PDFsharp | Полный контроль над каждой координатой |
| Многостраничный отчет с таблицами и колонтитулами. | MigraDoc | Автоматическая пагинация и стили |
| Счет-фактура с переменным количеством позиций | MigraDoc | Таблицы увеличиваются и разрываются на страницах. |
| Добавить штамп, водяной знак или номера страниц в существующий PDF-файл. | PDFsharp | MigraDoc только создает новые документы. |
| Объединение или разделение существующих файлов | PDFsharp | Импорт страниц — это функция PDFsharp. |
| Диаграмма бизнес-процесса внутри отчета | MigraDoc | Встроенная поддержка диаграмм |
| Смешанный вариант: сгенерированный отчет плюс обложка, нарисованная на заказ. | Оба | MigraDoc может отображать страницу PDFsharp. |
В реальных проектах обычно используется и то, и другое. Основной текст — через MigraDoc, обложка — нарисованная от руки, или штамп на PDF-файле от стороннего поставщика — через нижний слой. В любом случае, избежать установки PDFsharp невозможно, поскольку пакет MigraDoc автоматически добавляет его в качестве зависимости.
Подробное описание сборок PDFsharp: базовая сборка, GDI+ и WPF.
Новички обычно сталкиваются с проблемой при установке следующих пакетов в NuGet. PDFsharp 6 выпускается в трех сборках, каждая из которых имеет свой аналог в MigraDoc.
| Пакет NuGet | Строить | Платформы | Шрифты и изображения |
|---|---|---|---|
| PDFsharp / PDFsharp-MigraDoc | Основной | Windows, Linux, macOS | Требуется средство разрешения шрифтов; поддерживает изображения форматов BMP, PNG, JPEG. |
| PDFsharp-GDI / PDFsharp-MigraDoc-GDI | ГДИ+ | Только для Windows | Использует установленные шрифты через System.Drawing. |
| PDFsharp-WPF / PDFsharp-MigraDoc-WPF | WPF | Только для Windows | Использует установленные шрифты через WPF. |
Текущие пакеты ориентированы на .NET 8, 9 и 10, а также на .NET Standard 2.0 и .NET Framework 4.6.2. Таким образом, охватывается практически всё, над чем ещё ведётся работа, от устаревшего инструмента WinForms до совершенно нового API ASP.NET Core.
Консольное приложение, веб-API, Docker, Azure Functions, что угодно на Linux? Базовая сборка. GDI+ или WPF имеют смысл только для настольных приложений Windows, где нужны системные шрифты или предварительный просмотр в нативном элементе управления. Кто-то на Stack Overflow однажды спросил, нужна ли его консольному приложению версия WPF. Оказалось, что нет.

Как установить PDFsharp из NuGet в Visual Studio
На форумах до сих пор можно найти сообщения времен WinForms, в которых вам советуют скачать ZIP-архив, найти DLL-файл и добавить ссылку самостоятельно. Игнорируйте их. Установите PDFsharp через NuGet; менеджер пакетов отслеживает версии, так что вам не придется этого делать.
- Откройте ваше решение в Visual Studio и щелкните правой кнопкой мыши по проекту в обозревателе решений.
- Выберите «Управление пакетами NuGet» , перейдите на вкладку «Обзор» и выполните поиск по запросу «PDFsharp».
- Выберите PDFsharp (Core build) или PDFsharp-MigraDoc, если вам также необходима верстка документа. Убедитесь, что издатель — empira Software GmbH.
- Нажмите «Установить» и примите условия лицензионного соглашения.
- Для подтверждения корректного восстановления пакета выполните сборку проекта один раз.
Пользователи терминалов могут обойтись без щелчков мышью:
bash dotnet add package PDFsharp dotnet add package PDFsharp-MigraDoc
В консоли диспетчера пакетов то же самое делается командой Install-Package PDFsharp. И, пожалуйста, не смешивайте сборки. Я видел, как команда потратила целый день на конфликты типов, потому что один проект ссылался на PDFsharp, а соседний — на PDFsharp-GDI.
Ваш первый PDF-документ, созданный с помощью PDFsharp на языке C.
Ниже описана самая маленькая программа, создающая одностраничный PDF-файл. Она работает на базовой сборке любой ОС, при условии, что настроен механизм разрешения шрифтов (следующий раздел).
«csharp»
с использованием PdfSharp.Drawing;
с использованием PdfSharp.Pdf;
// Для использования PDFsharp 6.5+ перед первым применением необходимо выбрать лицензию.
PdfSharpLicense.SetAgplLicense();
var document = new PdfDocument();
document.Info.Title = "Hello PDFsharp";
PdfPage page = document.AddPage();
XGraphics gfx = XGraphics.FromPdfPage(page);
var font = new XFont("Arial", 20, XFontStyleEx.Bold);
gfx.DrawString("Привет, PDFsharp!", font, XBrushes.Black,
new XRect(0, 0, page.Width.Point, page.Height.Point),
XStringFormats.Center);
document.Save("hello.pdf");
```
Каждая программа PDFsharp имеет следующую структуру: документ, страница, XGraphics, рисование, сохранение. Единицы измерения — точки (1/72 дюйма), начало координат находится в верхнем левом углу. В версии 6.2.x удалите строку с лицензией. Этот API появился только в версии 6.5.0.
А вот версия MigraDoc:
«csharp»
using MigraDoc.DocumentObjectModel;
using MigraDoc.Rendering;
var doc = new Document();
Раздел section = doc.AddSection();
section.AddParagraph("Привет, MigraDoc!");
var renderer = новый PdfDocumentRenderer { Document = doc };
renderer.RenderDocument();
renderer.PdfDocument.Save("hello-migradoc.pdf");
```
Координаты нигде не указаны. Добавьте 500 абзацев, и вы получите столько страниц, сколько потребуется, при этом код пагинации с вашей стороны отсутствует.
Шрифты в базовой сборке PDFsharp: проблема с механизмом разрешения шрифтов.
Поспрашивайте у знакомых, и вы чаще всего услышите жалобы на шрифты. Сборки GDI+ и WPF просто считывают установленные шрифты TrueType из Windows. Сборка Core ничего не может предполагать, потому что в облегченном контейнере Linux часто вообще нет пригодных для использования шрифтов. Поэтому первое развертывание Docker обычно заканчивается исключением о том, что подходящий шрифт не найден.
Решение заключается в использовании класса для разрешения шрифтов, реализующего интерфейс IFontResolver. Он имеет два метода:
- Функция ResolveTypeface сопоставляет запрошенное семейство шрифтов и стиль (например, "Arial", жирный) с названием шрифта.
- Функция GetFont возвращает необработанные байты TTF-файла для указанного имени шрифта.
Зарегистрируйте его один раз при запуске системы через GlobalFontSettings.FontResolver, до создания первого шрифта XFont.
«csharp»
public class AppFontResolver : IFontResolver
{
public FontResolverInfo? ResolveTypeface(string family, bool bold, bool italic)
=> new FontResolverInfo(bold ? "Inter-Bold" : "Inter-Regular");
public byte[]? GetFont(string faceName) => File.ReadAllBytes(Path.Combine(AppContext.BaseDirectory, "Fonts", faceName + ".ttf"));
}
GlobalFontSettings.FontResolver = new AppFontResolver();
```
Что стоит знать, прежде чем вы сами в них врежетесь:
- Храните файлы TTF в папке Fonts в проекте и настройте их копирование в выходной каталог, или же встраивайте их в качестве ресурсов, чтобы образ контейнера всегда содержал их.
- В версии 6.2.0 был удалён старый CoreBuildFontResolver. В Windows или WSL2 можно восстановить аналогичное поведение с помощью GlobalFontSettings.UseWindowsFontsUnderWindows, но это не работает в Linux или macOS.
- В официальном репозитории примеров есть класс SubstitutingFontResolver, который можно скопировать в качестве отправной точки.
- Перед внедрением коммерческого шрифта в сгенерированные файлы проверьте лицензию на него. Открытые шрифты, такие как Inter, Roboto или Noto, полностью избавляют от этого вопроса.
При наличии установленного средства разрешения конфликтов выходные данные выглядят одинаково в Windows, Linux и macOS.
Объединение, подписание и защита файлов с помощью PDFsharp 6
Многие команды никогда не создают документы с нуля. Они используют библиотеку для объединения, добавления отметок или блокировки уже существующих файлов. Объединение файлов занимает всего несколько строк: откройте каждый исходный файл в режиме импорта и скопируйте страницы.
csharp var output = new PdfDocument(); foreach (var path in new[] { "part1.pdf", "part2.pdf" }) { using var input = PdfReader.Open(path, PdfDocumentOpenMode.Import); foreach (PdfPage p in input.Pages) output.AddPage(p); } output.Save("merged.pdf");
Разделение выполняется в обратном порядке: один выходной файл на страницу или диапазон. Для защиты document.SecuritySettings принимает пароль пользователя, пароль владельца и флаги разрешений (печать, копирование текста и т. д.).
В линейке 6.2 наконец-то появились две давно ожидаемые функции:
- Цифровые подписи на основе CMS. По умолчанию используется отдельный модуль PDFsharp.Cryptography, а для интеграции можно использовать собственный модуль, реализовав интерфейс IDigitalSigner. Поддержка сервера временных меток работает в современных версиях .NET, но не в сборке .NET Framework.
- Вывод в формате PDF/A для архивирования. В официальной документации указано, что он работает «с некоторыми ограничениями» и находится в стадии разработки, поэтому перед тем, как полагаться на него для соответствия требованиям, проверьте результат с помощью средства проверки PDF/A.
В этом релизе также появились цветные эмодзи-глифы и управляемая реализация MD5, что важно, если вы работаете в соответствии с правилами FIPS или в Blazor.
Репозиторий PDFsharp, форки PdfSharpCore и версии 1.x
Поищите PDFsharp на GitHub, и вы найдете несколько проектов с почти одинаковым названием. Виновата история.
Старая версия 1.x (1.50, 1.51) работала только на .NET Framework. Когда вышел .NET Core, люди не захотели ждать и сами портировали её. Наиболее известна версия PdfSharpCore, созданная Стефаном Штайгером и позже подхваченная другими форками. Она исключила GDI+ и запустила код на Linux за несколько лет до официального релиза.
Затем появился PDFsharp 6: полноценная переработка на современной платформе .NET с официальной кроссплатформенной сборкой Core. Форки потеряли большую часть смысла своего существования.
| Проект | Сопровождающий | Платформы | Статус |
|---|---|---|---|
| PDFsharp 6.x (репозиторий empira/PDFsharp) | empira Software GmbH | .NET 8–10, .NET Standard 2.0, .NET Framework 4.6.2 | Активно поддерживается |
| PDFsharp 1.5x | empira Software GmbH | Только для .NET Framework | Исходный код хранился на GitHub, больше не поддерживается. |
| PdfSharpCore и его форки | Сообщество | .NET Core / .NET Standard 2.0 | Зависит от форка, обновления происходят медленнее. |
| PDFsharp-MigraDoc 6.x | empira Software GmbH | Аналогично PDFsharp 6 | Активно поддерживается |
Итак, тема "PdfSharp против PdfSharpCore", которая постоянно всплывает на Reddit? Новый проект, официальные пакеты. Сохраняйте форк только в том случае, если старый код уже на него опирается, и миграция сейчас не стоит затраченных усилий. А когда документация кажется скудной, загляните в отдельный репозиторий примеров empira. Его папки и файлы содержат работающие примеры, что намного лучше, чем гадать.
PDFsharp — бесплатная программа? Изменения в лицензировании PDFsharp 6.5
Да, на протяжении большей части своего существования. Он распространялся по лицензии MIT, что означает коммерческое использование практически без каких-либо ограничений. Все релизы вплоть до версии 6.2.4 включительно по-прежнему распространяются под этой лицензией.
В версии 6.5.0 это изменилось. Теперь библиотека имеет двойную лицензию:
- Лицензия AGPL (бесплатная). Ее активация осуществляется путем вызова метода PdfSharpLicense.SetAgplLicense() перед использованием библиотеки. Лицензия AGPL требует предоставления исходного кода пользователям, включая пользователей, взаимодействующих с вашим программным обеспечением по сети, поэтому она плохо подходит для SaaS-продуктов с закрытым исходным кодом.
- Коммерческая лицензия. Вы покупаете лицензионный ключ у продавца и загружаете его с помощью PdfSharpLicense.LoadLicense(...). Это снимает обязательства, предусмотренные лицензией AGPL.
Начиная с версии 6.5.0, ваш код должен явно выбирать один из вариантов. Предварительные версии 7.0 работают аналогично.
На практике:
- Проекты с открытым исходным кодом, совместимые с AGPL, могут продолжать использовать новейшую версию бесплатно.
- Разработчики продуктов с закрытым исходным кодом могут либо приобрести коммерческую лицензию, либо остаться на версии 6.2.x, которая по-прежнему находится под управлением MIT. Оставаясь на этой версии, вы рискуете пропустить будущие исправления, поэтому честно оцените эту цену.
- Какой бы вариант вы ни выбрали, внимательно ознакомьтесь с текстом лицензии и получите одобрение вашей юридической команды. Данное руководство не является юридической консультацией.

В чём недостатки PDFsharp и с чем его лучше использовать в паре.
Библиотека хорошо справляется со своей задачей. Просто задача довольно узкая, и одни и те же пробелы возникают в каждой теме форума.
- Преобразование HTML в PDF невозможно. PDFsharp не рендерит HTML или CSS. Существует дополнение от сообщества, HtmlRenderer.PdfSharp, но оно поддерживает только HTML 4.01 и CSS уровня 2, поэтому современные макеты с flexbox или grid не будут работать. Команды, которым нужны HTML-шаблоны, обычно используют рендерер для безголовых браузеров.
- JavaScript не используется. Диаграммы или контент, созданные на стороне клиента, не могут быть перехвачены.
- Преобразование в изображения невозможно. PDFsharp не может преобразовать страницу PDF в PNG для эскизов или предварительного просмотра. Для этого требуется отдельный растеризатор.
- Возможности извлечения текста ограничены. Можно просматривать поток контента, но отсутствует высокоуровневый API, возвращающий чистый текст с указанием позиций. PdfPig, отдельная библиотека с открытым исходным кодом, разработана специально для чтения и извлечения текста.
- Частичная поддержка форм. Простое заполнение форм AcroForm работает; сложные формы со скриптами — это уже совсем другая история.
- Для работы с таблицами необходим MigraDoc. При использовании обычного PDFsharp высота каждой строки рассчитывается самостоятельно.
Это не делает его плохим выбором. Документы, основанные на данных, такие как счета-фактуры, выписки, этикетки и сертификаты, — это именно то, что ему нужно, и он занимает очень мало места. А вот идеально точные копии веб-страниц — нет.
PDFsharp для создания криптосчетов и платежных квитанций.
Вероятно, наиболее распространенный тип чеков, создаваемых с помощью PDFsharp, — это чеки. Криптовалютные чеки немного сложнее, чем чеки по картам. Хорошая новость: как только платежный шлюз отправит запрос через ваш веб-хук (HTTP-запрос, отправляемый при изменении статуса платежа), у вас будут все данные. Ничего лишнего искать не нужно.
Что бы я на ней написал:
- Идентификатор заказа или счета-фактуры и данные продавца.
- Сумма в криптовалюте и ее фиатном эквиваленте на момент платежа.
- Монета и сеть (например, USDT в TRON против USDT в Ethereum)
- Хэш транзакции, позволяющий клиенту проверить её в обозревателе блоков.
- Сокращенный адрес кошелька для получения средств и время подтверждения.
- QR-код, ведущий на страницу транзакции или счета-фактуры.
Моноширинный шрифт для хешей и адресов. Клиенты прищуриваются, рассматривая их по одному символу, и в шрифте Arial ноль и заглавная буква O выглядят как близнецы. Если хеш слишком широкий, перенесите его; 6-пунктный текст никому не поможет. Встраивайте шрифты, сохраняйте файл вместе с заказом и подписывайте его, если ваш бухгалтер когда-нибудь попросит квитанции.
Ничто из вышесказанного не охватывает непосредственно получение денег. Для этого вам понадобится шлюз, например, Plisio . Он принимает BTC, USDT и множество других криптовалют, формирует счет-фактуру и вызывает вашу конечную точку каждый раз при изменении статуса. Ваш обработчик передает данные в MigraDoc, и покупатель получает квитанцию с вашим логотипом, находясь еще на странице благодарности.
Заключение
Я постоянно возвращаюсь к PDFsharp по одной причине: он небольшой и не мешает работе. Базовая сборка работает везде, где работает .NET, а MigraDoc берет на себя работу по верстке, когда холста недостаточно. Три момента, которые нужно решить заранее: какую сборку выбрать, как загружаются шрифты и какую лицензию вы используете теперь, когда версия 6.5 перешла на AGPL. Печатайте данные, а не веб-страницы, и он прослужит вам долгие годы.