MigraDoc: гайд от гика, структура документов, рендеринг, форматы и ограничения

MigraDoc — не настольный редактор и не веб-сервис, а библиотека для .NET-приложений, которая строит документ из объектов высокого уровня и затем рендерит его в PDF или RTF. Разработчик описывает разделы, абзацы, стили, таблицы, изображения, диаграммы, колонтитулы, поля и ссылки в коде, а движок сам рассчитывает перенос текста и разбиение на страницы для PDF. Это делает MigraDoc уместным для счетов, актов, отчётов, ведомостей, договорных форм и других документов, которые формируются из данных приложения. В обзоре разбирается актуальная стабильная ветка 6.2.4; предварительная 7.0.0 Preview 1 упоминается отдельно и не смешивается со стабильным выпуском.

Что такое MigraDoc и какой продукт рассматривается

MigraDoc входит в проект PDFsharp & MigraDoc, который поддерживает empira Software GmbH. Исходный код размещён в общем репозитории PDFsharp, а библиотека распространяется как набор NuGet-пакетов. Назначение MigraDoc отличается от PDFsharp: PDFsharp даёт более низкоуровневые средства создания и обработки PDF, тогда как MigraDoc предлагает объектную модель документа с автоматическим потоком текста, стилями и разметкой. Если приложению нужен документ, похожий по структуре на текстовый процессор, MigraDoc обычно избавляет от ручного вычисления координат каждой строки и каждого переноса страницы.

На 4 сентября 2026 года последняя стабильная версия семейства 6 — 6.2.4 от 6 января 2026 года. В официальном репозитории одновременно развивается MigraDoc 7 как часть PDFsharp & MigraDoc 7; доступен выпуск 7.0.0 Preview 1 от 24 марта 2026 года. Для производственного обзора разумно отделять эти ветки: 6.2.4 является стабильным релизом, а 7.0.0 Preview 1 — предварительным вариантом для оценки будущего поколения.

Параметр Состояние
Тип продукта Встраиваемая .NET-библиотека генерации документов
Разработчик и поддержка empira Software GmbH, команда PDFsharp
Актуальная стабильная версия 6.2.4, опубликована 6 января 2026 года
Предварительная ветка 7.0.0 Preview 1, опубликована 24 марта 2026 года
Основной способ распространения NuGet-пакеты PDFsharp-MigraDoc, PDFsharp-MigraDoc-GDI и PDFsharp-MigraDoc-WPF
Платформы Core-сборка — платформы, совместимые с .NET; GDI и WPF — Windows
Целевые платформы стабильной 6.2.4 Core: net8.0, net9.0, net10.0 и netstandard2.0; Windows-сборки также имеют Windows-цели и net462
Прямой вывод MigraDoc PDF и RTF
Сериализация модели MDDDL через DdlWriter
Лицензия MIT
Регистрация и облачный аккаунт Для работы библиотеки не требуются
Мобильное приложение и веб-интерфейс Отсутствуют; MigraDoc встраивается в код приложения
Язык интерфейса Не применим: постоянного GUI нет; публичный API и основная документация используют английские идентификаторы и термины
Облачная и ИИ-обработка В состав MigraDoc не входят

Название MigraDoc встречается в старых материалах о версии 1.5, но текущий проект — не отдельный архивный репозиторий MigraDoc-1.5. Современная ветка развивается внутри PDFsharp. Это важно при поиске примеров: код и рекомендации для 1.5 могут опираться на другие пакеты, старые пространства имён и прежнее поведение шрифтов, тогда как версия 6.2 использует современную схему Core/GDI/WPF и другую модель разрешения шрифтов.

Жизненный цикл и текущий статус

Современная линия началась с PDFsharp & MigraDoc 6.0 в ноябре 2023 года и устранила принципиальное ограничение прежней Core-сборки: Core в 6.x стал независим от Windows-специфичных GDI/WPF-компонентов. Версия 6.1.1 вышла в июле 2024 года, ветка 6.2 получила финальный релиз в мае 2025 года, а 6.2.4 стала актуальным стабильным выпуском в январе 2026 года. В 6.2 команда также вернула компонент предварительного просмотра для GDI-сборки, исправила бесконечный цикл рендерера и изменила поведение, связанное с ориентацией и размером страницы.

В марте 2026 года появился PDFsharp & MigraDoc 7.0.0 Preview 1. Репозиторий прямо маркирует его как preview и связывает с обновлением кодовой базы под C# 12 и современные .NET 8, 9 и 10. Поэтому переход на 7.0 в рабочем проекте требует обычной для предварительных релизов оценки совместимости и регрессионного тестирования; само наличие preview не отменяет стабильную 6.2.4.

Проект активно поддерживается: официальный репозиторий помечен как maintained, документация обновлена до веток 6.2.4 и 7.0 Preview 1, а NuGet содержит актуальные пакеты. Для пользователя это означает, что MigraDoc нельзя относить к заброшенным библиотекам, несмотря на долгую историю продукта и существование отдельных старых репозиториев версии 1.5.

Интерфейс и архитектура: почему здесь нет обычного окна программы

У MigraDoc нет постоянного пользовательского интерфейса с меню «Файл», лентой, панелью слоёв или редактором страниц. Основной интерфейс — программный API. Рабочее пространство разработчика состоит из проекта .NET, объектной модели MigraDoc и выбранного рендерера. Поэтому качество интеграции зависит не от расположения кнопок, а от того, как приложение строит объект Document, создаёт Section, наполняет разделы содержимым и передаёт модель в PdfDocumentRenderer или RtfDocumentRenderer.

Логически работу можно разделить на четыре слоя. Первый — структура документа: Document, Section и элементы содержимого. Второй — форматирование: стили, ParagraphFormat, Font, границы, заливки, отступы и параметры страницы. Третий — ресурсы: шрифты и изображения, пути к ним и правила разрешения. Четвёртый — рендеринг, где динамическая модель преобразуется в фиксированный PDF либо в RTF с динамической пагинацией на стороне программы, которая затем откроет файл.

Для Windows существуют GDI- и WPF-сборки, а в 6.2 восстановлен компонент MigraDoc Preview для GDI; в примерах есть варианты предварительного просмотра для GDI и WPF. Это вспомогательный контрол для приложения, а не обязательная оболочка MigraDoc. Если проект — консольная служба, ASP.NET-приложение, Linux-сервис или фоновой генератор отчётов, никакого визуального окна у библиотеки обычно нет.

Разработчикам, которые впервые сталкиваются с NuGet и средой разработки, может пригодиться материал GeekHow о Microsoft Visual Studio. Сам MigraDoc не привязан к конкретной IDE: важны совместимый .NET-проект и корректно выбранный пакет.

Основные функции MigraDoc

Структура документа и автоматический поток текста

Документ строится из секций, а секции содержат абзацы, таблицы, изображения, диаграммы и другие объекты. Страницы при создании модели ещё не существуют. Они появляются при PDF-рендеринге, когда движок вычисляет, сколько содержимого помещается на текущей странице, и вставляет новые страницы. Именно это отличает MigraDoc от низкоуровневого рисования PDF, где разработчик сам рассчитывает координаты и часто вручную управляет переходами между страницами.

Секции позволяют менять настройки страницы и управлять началом нового логического блока. Поддерживаются явные разрывы страниц, начало секции со следующей, нечётной или чётной страницы, а для абзацев — свойства PageBreakBefore, KeepWithNext, KeepTogether и WidowControl. Эти механизмы важны для заголовков, коротких блоков, актов и отчётов, в которых заголовок не должен оставаться последней строкой страницы.

Текст, стили и наследование форматирования

Текст добавляется через Paragraph, FormattedText и обычные текстовые элементы. Абзац может получать стиль либо прямое форматирование. Стили уменьшают количество повторяющегося кода: изменение базового стиля влияет на связанные элементы при последующем рендеринге. Форматы также наследуются от родительских объектов и базовых стилей. Важное следствие: до стадии flattening не все фактические значения форматирования записаны непосредственно в конкретный объект, поэтому чтение свойства может вернуть незаданное значение даже тогда, когда итоговый вид будет унаследован.

Поддерживаются выравнивание, интервалы до и после абзаца, отступы, межстрочные интервалы, размеры и цвет шрифта, жирное и курсивное начертание, подчёркивание, верхний и нижний индекс. Маркированные и нумерованные списки реализованы как абзацы с ListInfo и типом списка, поэтому их оформление также удобно выносить в стили. Для структурных заголовков предусмотрены предопределённые стили Heading1–Heading9; уровень OutlineLevel позволяет получить структуру документа в PDF-навигации.

Таблицы

Таблица создаётся из колонок и строк, а ячейки доступны внутри строк. MigraDoc поддерживает ширину колонок, высоту строк, границы, заливку, выравнивание, объединение ячеек и повторяемые строки заголовка. Свойство HeadingFormat у верхних строк позволяет повторять шапку на новых страницах, если таблица длинная. Свойство KeepWith у строки объединяет её с заданным количеством следующих строк в неразрываемую группу и помогает контролировать перенос логически связанных частей.

Табличная модель подходит для счетов и ведомостей, но не превращает MigraDoc в электронную таблицу: здесь нет формул Excel, ячеечного калькулятора и интерактивной сортировки. Данные и вычисления выполняет приложение, а MigraDoc отвечает за представление результата.

Изображения

Изображения можно добавлять в секции, ячейки таблиц, колонтитулы, текстовые фреймы и даже внутрь абзаца. Для файлов с относительными путями важны Document.ImagePath и WorkingDirectory рендерера. Core-сборка PDFsharp, от которой зависит PDF-вывод MigraDoc, поддерживает JPEG, PNG и BMP; Windows-сборки GDI/WPF имеют более широкие возможности, зависящие от соответствующих Windows API.

Изображение можно масштабировать и позиционировать, а для растровых файлов доступен параметр интерполяции. Встроенное в строку изображение ведёт себя как элемент текста: его позиционные свойства не работают так же, как у плавающей фигуры. Это стоит учитывать для пиктограмм, маркеров и небольших значков внутри абзаца.

Диаграммы, текстовые фреймы и смешивание с PDFsharp

MigraDoc включает бизнес-диаграммы, серии данных, подписи, легенды и области диаграммы. Текстовые фреймы позволяют размещать содержимое вне основного потока. Когда возможностей объектной модели недостаточно, PDF-рендерер создаёт объект PdfDocument из PDFsharp, после чего приложение может добавить низкоуровневое содержимое PDFsharp перед сохранением. Такой гибридный подход полезен для водяных знаков, нестандартной графики и элементов, которым удобнее задавать точные координаты.

Поля, закладки, ссылки и колонтитулы

Поля автоматически вставляют номер страницы, номер секции, дату и сведения о документе. Закладки помечают позиции, а гиперссылки могут вести на закладку внутри PDF, другой файл, веб-адрес или почтовый адрес. Заголовки и нижние колонтитулы привязаны к секции; можно задавать основной вариант, отдельное оформление первой страницы и чётных страниц. Содержимое колонтитула не ограничено текстом: туда можно помещать таблицы, изображения и другие поддерживаемые элементы.

Рендеринг PDF и RTF

PdfDocumentRenderer выполняет flattening, вычисляет итоговый поток, позиции объектов и страницы, затем формирует PdfDocument. PDF получается фиксированным документом, пригодным для печати и предсказуемого просмотра. RtfDocumentRenderer работает иначе: он применяет наследуемое форматирование, но не фиксирует пагинацию. Разрывы строк и страниц в RTF окончательно рассчитывает приложение, которое откроет RTF, поэтому совпадение страниц с PDF не является гарантированной целью.

RTF полезен, когда итог должен оставаться редактируемым в совместимом текстовом процессоре. Если после генерации требуется ручная правка PDF, это уже отдельный сценарий; обзор соответствующего ПО есть в материале GeekHow о программах для редактирования PDF.

MDDDL как сериализация объектной модели

MDDDL — MigraDoc Document Description Language, текстовое представление документа. DdlWriter может сохранить объект Document в файл MDDDL. Исторически язык был важной частью подхода MigraDoc; современная документация делает акцент на создании документов из C#-кода, но MDDDL сохраняется как средство сериализации и обучения. Это не аналог DOCX и не универсальный обменный формат для офисных редакторов.

Задача → инструмент → результат → что проверить

Задача Инструмент MigraDoc Результат Что проверить
Сформировать многостраничный отчёт Document, Section, Paragraph, стили и PdfDocumentRenderer PDF с автоматическим переносом текста Поля страницы, заголовки, переносы и доступность шрифтов
Вывести табличные данные Table, Column, Row, Cell, HeadingFormat, KeepWith Таблица с повторяемой шапкой и контролем разрывов Ширину колонок, высоту строк и перенос длинного текста
Добавить фирменные изображения AddImage, ImagePath, WorkingDirectory Растровая графика внутри документа Формат файла, относительные пути и масштаб
Сделать содержание и навигацию Heading1–Heading9, OutlineLevel, Bookmark, Hyperlink, поля Структурированный PDF с навигацией Уникальность закладок и корректность целевых ссылок
Получить редактируемый результат RtfDocumentRenderer RTF Отличия пагинации от PDF и наличие используемых шрифтов у получателя
Защитить готовый PDF паролем PdfDocumentRenderer и SecuritySettings из PDFsharp Зашифрованный PDF Открытие нужным паролем и заданные разрешения
Добавить нестандартную графику после верстки Результирующий PdfDocument и API PDFsharp PDF с дополнительным низкоуровневым содержимым Координаты на каждой странице и отсутствие перекрытий
Сохранить модель документа в текстовом виде DdlWriter Файл MDDDL Что все внешние ресурсы, особенно изображения, остаются доступными

Карта форматов и совместимости

Формат или объект Направление Редактируемость Ограничения и переносимость
PDF Основной экспорт через PdfDocumentRenderer Фиксированный результат; дальнейшее изменение выполняется уже средствами PDFsharp или стороннего PDF-ПО Пагинация рассчитывается MigraDoc; шрифты должны корректно разрешаться
RTF Экспорт через RtfDocumentRenderer Редактируется совместимыми текстовыми процессорами Пагинация определяется приложением просмотра, поэтому страницы могут отличаться от PDF
MDDDL Сериализация модели через DdlWriter Текстовое представление структуры MigraDoc Не является офисным форматом; актуальная документация Grammar by Example отмечает, что MDDDL по-прежнему использует ANSI-кодировку
JPEG, PNG, BMP Вставка изображений в Core-сборке при PDF-рендеринге Растровый ресурс Путь и доступность файла контролирует приложение; Windows-сборки имеют более широкую поддержку изображений
DOCX Нет прямого импорта или экспорта MigraDoc Не применяется Для DOCX нужен другой инструмент, например Open XML SDK или коммерческий документный движок
HTML Нет штатного преобразователя HTML → MigraDoc DOM Не применяется HTML требуется разбирать и отображать на объекты MigraDoc в коде либо выбирать специализированный HTML-to-PDF движок
Существующий PDF MigraDoc не является импортёром PDF в собственную объектную модель Не применяется Операции с готовым PDF относятся к PDFsharp; документ MigraDoc строится как новая модель

Эта карта помогает не приписывать библиотеке функции текстового редактора. MigraDoc не открывает произвольный DOCX, чтобы продолжить его редактирование, и не преобразует существующий PDF обратно в абзацы и таблицы DOM. Основной поток начинается с данных приложения или заранее созданной объектной модели и заканчивается рендерингом. Если конечная цель — передать текст в Google Docs для дальнейшей ручной работы, отдельный этап конвертации PDF разобран в статье GeekHow о преобразовании PDF в Google Docs; это уже внешний по отношению к MigraDoc процесс.

Как пользоваться программой — советы гика

Выбрать пакет и подключить MigraDoc к проекту

Цель. Подключить стабильную 6.2.4 в приложение без смешивания Core, GDI и WPF. Подготовка. Нужен .NET-проект с целевой платформой, совместимой с выбранным NuGet-пакетом. Для кроссплатформенного сервиса используется PDFsharp-MigraDoc; для Windows-приложения, которое опирается на System.Drawing или WinForms, подходит PDFsharp-MigraDoc-GDI; для WPF — PDFsharp-MigraDoc-WPF.

  1. Откройте файл проекта или менеджер NuGet в IDE.
  2. Добавьте пакет PDFsharp-MigraDoc версии 6.2.4 для Core-сценария либо соответствующий пакет с суффиксом GDI/WPF для Windows.
  3. Убедитесь, что в проект не попали одновременно разные flavor-пакеты одной и той же библиотеки.
  4. В исходном файле подключите пространства имён MigraDoc.DocumentObjectModel и MigraDoc.Rendering; для настроек PDF потребуется пространство имён PDFsharp.

Параметры. У 6.2.4 Core-пакет включает цели net8.0, net9.0, net10.0 и netstandard2.0. GDI/WPF предназначены для Windows и добавляют Windows-специфичные цели. Проверка. Проект должен восстановить зависимости и компилироваться без конфликта одинаковых типов из разных сборок. Типичная ошибка. Выбор GDI/WPF для Linux-контейнера или, наоборот, переход со старого Windows-проекта на Core без настройки шрифтов. Безопасный откат. Верните предыдущий PackageReference и очистите артефакты сборки; модель документов при смене пакета не нужно переписывать до тех пор, пока код не использует flavor-специфичные API.

Создать Document и логическую структуру секций

Цель. Получить минимальную объектную модель, которую можно рендерить. Подготовка. Пакет подключён, пространства имён доступны.

  1. Создайте объект Document.
  2. Добавьте первую секцию методом document.AddSection().
  3. Добавляйте содержимое в Section, а новую Section используйте тогда, когда нужен новый логический блок с отдельными параметрами страницы, колонтитулами или обязательным началом на новой странице.
  4. Для явного разрыва внутри секции используйте section.AddPageBreak(), а не пустые абзацы.

Параметры. Section.PageSetup управляет размером страницы, полями и правилами начала секции. Проверка. Перед рендерингом Document должен содержать хотя бы одну Section с содержимым. Типичная ошибка. Попытка заранее считать номера страниц во время построения DOM. В MigraDoc страницы ещё не существуют до PDF-рендеринга. Безопасный откат. Удалите добавленную секцию или разрыв из кода; исходные бизнес-данные при этом не меняются.

Настроить стили, шрифты и параметры страницы

Цель. Задать единое оформление до наполнения документа. Подготовка. Определите набор реально доступных шрифтов и формат страницы.

  1. Получите базовый стиль через document.Styles[StyleNames.Normal] и задайте Font.Name, Font.Size и параметры ParagraphFormat.
  2. Измените предопределённые Heading1–Heading9 для заголовков вместо ручного форматирования каждого абзаца.
  3. В Section.PageSetup задайте поля и ориентацию. Если PageSetup получен как Clone и затем меняются формат или ориентация в ветке 6.2, сначала примените ResetPageSize(), чтобы не наследовать конфликтующие ширину и высоту.
  4. Для Core-сборки зарегистрируйте собственный IFontResolver через GlobalFontSettings.FontResolver либо используйте документированный Windows-режим только там, где приложение действительно ограничено Windows.
  5. Проверьте, что шрифт для сообщений об ошибках, задаваемый PredefinedFontsAndChars.ErrorFontName, также разрешается вашим FontResolver.

Параметры. Для абзацев доступны выравнивание, интервалы, отступы, межстрочный интервал, KeepWithNext, KeepTogether и WidowControl. Проверка. Отрендерите короткий документ с обычным текстом, заголовком и маркерованным списком, чтобы выявить отсутствующие regular/bold/italic faces до генерации большого отчёта. Типичная ошибка. Core-приложение в Linux предполагает наличие Arial или Courier New только потому, что эти шрифты установлены на рабочем Windows-ПК. Безопасный откат. Верните стиль к стандартному и временно используйте один гарантированно поставляемый приложением шрифт.

Добавить текст, заголовки и локальное форматирование

Цель. Сформировать обычный текстовый поток. Подготовка. Стили настроены до рендеринга.

  1. Добавьте абзац методом section.AddParagraph().
  2. Назначьте paragraph.Style равным StyleNames.Heading1, Heading2 или другому стилю для структурного заголовка.
  3. Для части строки используйте paragraph.AddFormattedText() и меняйте свойства возвращённого FormattedText, если выделение не должно затрагивать весь абзац.
  4. Для связанных заголовка и следующего абзаца включите KeepWithNext в стиле заголовка.
  5. Не фиксируйте всё прямым форматированием: общие свойства храните в стилях, чтобы будущие изменения не требовали обхода сотен элементов.

Параметры. Шрифт, размер, цвет, Bold, Italic, Underline, Superscript и Subscript задаются через Font. Проверка. В PDF заголовки с OutlineLevel выше BodyText должны появиться в структуре документа, которую показывают многие PDF-просмотрщики. Типичная ошибка. Ожидание, что унаследованное свойство уже записано в конкретный Paragraph до flattening. Безопасный откат. Уберите прямое форматирование с проблемного элемента и верните управление стилю.

Собрать таблицу с повторяемой шапкой

Цель. Вывести структурированные строки данных на несколько страниц. Подготовка. Определите ширину печатной области и набор колонок.

  1. Создайте таблицу через section.AddTable().
  2. Добавьте колонки методами table.AddColumn(Unit.FromCentimeter(…)); суммарную ширину согласуйте с шириной тела страницы.
  3. Добавьте первую строку методом table.AddRow() и установите HeadingFormat = true, если шапка должна повторяться на следующих страницах.
  4. Заполняйте ячейки через row.Cells[index] или индексатор строки и добавляйте в ячейки Paragraph.
  5. Для групп строк, которые нельзя разрывать, задайте KeepWith у первой строки группы.
  6. Не используйте HeightRule.Exactly для строк с неизвестным объёмом текста без проверки: при недостаточной высоте текст может выйти за нижнюю границу ячейки.

Параметры. Доступны MergeDown, MergeRight, границы, заливка, выравнивание и формат текста. Проверка. Сгенерируйте таблицу минимум на две страницы и убедитесь, что HeadingFormat повторяет нужные строки, а длинные значения не перекрывают границы. Типичная ошибка. Слишком широкие колонки создаются без учёта полей страницы. Безопасный откат. Верните предыдущие значения ширины и снимите Exactly у проблемных строк.

Добавить изображения и правильно настроить пути

Цель. Вставить логотип, иллюстрацию или схему без жёстко прошитых абсолютных путей. Подготовка. Для Core используйте поддерживаемый JPEG, PNG или BMP и заранее решите, где приложение хранит ресурсы.

  1. Установите document.ImagePath, если все изображения лежат в общей папке относительно рабочего каталога.
  2. У PdfDocumentRenderer или RtfDocumentRenderer задайте WorkingDirectory, чтобы относительные пути разрешались одинаково в локальной среде и на сервере.
  3. Добавьте изображение через section.AddImage(«имя-файла») или AddImage у ячейки, колонтитула либо абзаца.
  4. Ограничьте Width или Height, если исходное изображение больше доступной области.
  5. Для пиксельной графики отключайте Interpolate только осознанно; по умолчанию интерполяция включена.

Параметры. Встроенное в Paragraph изображение считается inline-элементом и не подчиняется обычным позиционным свойствам плавающих фигур. Проверка. Запустите генерацию из того же рабочего каталога, который будет использовать production-процесс или контейнер. Типичная ошибка. Ресурс существует рядом с проектом разработчика, но отсутствует рядом с опубликованным приложением. Безопасный откат. Уберите ссылку на картинку либо верните предыдущий WorkingDirectory; MigraDoc не изменяет исходный файл изображения.

Добавить диаграмму и подписи данных

Цель. Отобразить рассчитанные приложением значения в виде бизнес-диаграммы. Подготовка. Числовые данные должны быть очищены и подготовлены до передачи MigraDoc.

  1. Добавьте Chart к секции или другому поддерживаемому контейнеру и выберите тип диаграммы.
  2. Создайте Series через коллекцию серий и добавьте числовые значения.
  3. Добавьте XSeries с подписями категорий, если они нужны выбранному типу.
  4. Настройте DataLabel, легенду, размеры и формат шрифта.
  5. Оставляйте расчёты процентов, агрегирование и сортировку в бизнес-логике приложения, а не в слое документа.

Параметры. Размеры и отступы задаются типом Unit, цвета — Color. Проверка. Сопоставьте количество категорий и значений и визуально проверьте читаемость подписей в итоговом PDF. Типичная ошибка. Передача строковых данных как готовой «таблицы для анализа» с ожиданием, что MigraDoc сам вычислит серии. Безопасный откат. Удалите Chart из DOM и оставьте таблицу с исходными значениями — данные приложения не теряются.

Настроить колонтитулы, номера страниц, закладки и ссылки

Цель. Сделать документ навигационным и пригодным для многостраничной выдачи. Подготовка. Решите, где начинаются логические разделы и какие страницы требуют особого колонтитула.

  1. Получите section.Headers.Primary или section.Footers.Primary и добавьте в них Paragraph, таблицу либо изображение.
  2. Для номера страницы добавьте поле методом AddPageField() в нужный Paragraph.
  3. Если первая страница должна отличаться, включите DifferentFirstPageHeaderFooter в PageSetup и заполните Headers.FirstPage/Footers.FirstPage.
  4. Для чётных страниц включите соответствующий режим PageSetup и задайте EvenPage.
  5. Добавьте закладку методом paragraph.AddBookmark(«имя»), а ссылку на неё — через AddHyperlink с тем же именем.

Параметры. Имена закладок должны быть уникальными в документе. Проверка. Откройте PDF в просмотрщике, который показывает структуру и активные ссылки, и проверьте переходы. Типичная ошибка. Новый Section неожиданно наследует колонтитул предыдущей секции. MigraDoc копирует предыдущий Header/Footer, если новый не задан. Безопасный откат. Присвойте текущей секции новые пустые HeaderFooter для Primary, FirstPage и EvenPage там, где наследование нужно прекратить.

Сохранить PDF и проверить фиксированную верстку

Цель. Получить основной конечный формат MigraDoc. Подготовка. DOM завершён, шрифты и ресурсы доступны.

  1. Создайте PdfDocumentRenderer.
  2. Присвойте его свойству Document подготовленный объект Document.
  3. При необходимости задайте WorkingDirectory.
  4. Вызовите RenderDocument(); на этом этапе выполняются flattening, расчёт потока и создание страниц.
  5. Сохраните результат методом Save(filename) либо через PdfDocument.Save.

Параметры. После RenderDocument доступен PdfDocument из PDFsharp, поэтому перед Save можно применить PDF-специфичные настройки. Проверка. Убедитесь, что файл открывается, число страниц разумно для исходных данных, заголовки не отрываются от следующего текста, таблицы и изображения не выходят за область страницы. Типичная ошибка. Изменение стилей после PrepareRenderPages или RenderDocument с ожиданием, что уже flattened-объекты автоматически пересчитаются. Безопасный откат. Стройте новый Document или новый renderer из исходных данных и выполняйте рендеринг заново.

Сохранить RTF и учитывать отличия пагинации

Цель. Получить редактируемый документ для совместимого текстового процессора. Подготовка. Убедитесь, что потребителю действительно нужен RTF, а не точное совпадение страниц с PDF.

  1. Создайте RtfDocumentRenderer.
  2. Вызовите Render(document, filename, workingDirectory), передав документ, имя файла и рабочий каталог.
  3. Откройте RTF в целевом редакторе и проверьте шрифты, таблицы, колонтитулы и переносы.
  4. Не сравнивайте номера страниц с PDF как критерий правильности: RTF не получает фиксированную пагинацию от MigraDoc.

Параметры. Для RTF не требуется встраивание шрифтов через PDFsharp font resolver, но внешний редактор должен иметь подходящие шрифты для ожидаемого отображения. Проверка. Правильность оценивайте по структуре и содержанию в реальном целевом редакторе. Типичная ошибка. Использование RTF как точной копии печатной формы PDF. Безопасный откат. Для фиксированной разметки оставьте PDF основным результатом, а RTF выдавайте только как редактируемую версию.

Зашифровать PDF после рендеринга

Цель. Применить парольную защиту к итоговому PDF. Подготовка. Документ уже отрендерен в PdfDocumentRenderer.

  1. Вызовите RenderDocument и получите pdfRenderer.PdfDocument.
  2. Задайте SecuritySettings.UserPassword и/или OwnerPassword на PdfDocument.
  3. При необходимости выберите поддерживаемый PDFsharp метод шифрования через SecurityHandler; по умолчанию PDFsharp использует AES-128 в схеме версии 4.
  4. Настройте разрешения SecuritySettings, если они нужны вашему сценарию.
  5. После настройки сохраните PDF.

Параметры. Шифрование относится к PDFsharp и применяется к уже созданному PdfDocument. Проверка. Откройте копию файла в отдельном PDF-просмотрщике с пользовательским паролем и, при необходимости, с владельческим паролем. Типичная ошибка. Настройка SecuritySettings на ещё не созданном итоговом PdfDocument или потеря пароля без резервной процедуры. Безопасный откат. Перерендерите исходный Document без паролей; не пытайтесь «исправлять» единственный защищённый файл вручную.

Сквозной сценарий: отчёт из данных приложения до PDF, RTF и MDDDL

Цель. Собрать воспроизводимый конвейер без ручной верстки. Подготовка. Приложение имеет список записей, заголовок отчёта, логотип и каталог вывода.

  1. Создайте Document и настройте Normal и Heading1, затем зарегистрируйте FontResolver для Core-сборки.
  2. Добавьте Section, задайте PageSetup и основной Footer с AddPageField.
  3. Добавьте Heading1 и вводный Paragraph.
  4. Создайте Table, объявите ширины колонок, сделайте первую строку HeadingFormat и заполните строки данными приложения.
  5. Добавьте изображение через относительный путь, задав ImagePath и WorkingDirectory.
  6. До рендеринга проверьте, что все бизнес-данные рассчитаны и не зависят от самой верстки.
  7. Сначала сохраните MDDDL через DdlWriter.WriteToFile(document, filename), если нужна диагностическая сериализация модели.
  8. Создайте PdfDocumentRenderer, присвойте Document, вызовите RenderDocument и сохраните PDF.
  9. Отдельно создайте RtfDocumentRenderer и сохраните RTF, если нужна редактируемая версия.
  10. Откройте оба результата: PDF проверяйте по страницам и фиксированной разметке, RTF — по структуре и редактируемости в целевом редакторе.

Проверка. В финальном PDF должны присутствовать заголовок, все строки таблицы, повторяемая шапка на второй странице, логотип и номера страниц. RTF должен содержать те же смысловые данные, но его разбиение на страницы может отличаться. Типичная ошибка. Сохранение только одного выходного файла без контроля, что данные полностью попали в DOM. Безопасный откат. Храните исходные данные отдельно от Document и перестраивайте документ из них; MDDDL может служить дополнительным диагностическим слепком, но не заменяет исходные бизнес-данные.

Что перестанет работать первым при проблемах окружения

У MigraDoc нет обязательного удалённого аккаунта, лицензирующего сервера или облачной очереди, поэтому потеря интернета сама по себе не блокирует генерацию уже установленной библиотеки. Первые реальные зависимости находятся внутри среды выполнения приложения: шрифты, изображения, файловые пути, права записи и совместимая версия .NET.

  • Шрифты. В Core-приложении PDF-рендеринг останавливается, если требуемый шрифт не разрешается. С версии 6.2 это относится и к предопределённому error font: по умолчанию используется Courier New, но его имя можно заменить.
  • Изображения. Относительный путь ломается при смене рабочей директории, контейнера или каталога публикации. ImagePath и WorkingDirectory должны быть частью конфигурации приложения.
  • Файловая система. Save не сможет создать результат, если процесс не имеет права записи или путь неверен. Это ограничение хост-приложения, а не облачная квота MigraDoc.
  • Flavor пакета. GDI/WPF зависят от Windows. Перенос такого проекта на Linux требует Core-пакета и проверки функций, прежде всего шрифтов и изображений.
  • Совместимость версий. Код старой 1.5 или ранней 6.x может требовать адаптации к изменениям 6.2, включая font resolver и поведение PageSetup.

Интернет нужен только тогда, когда его требует ваш собственный процесс: первоначальное получение NuGet-пакетов, загрузка удалённых изображений до передачи в MigraDoc, внешняя база данных или API. Библиотека сама по себе предназначена для выполнения внутри процесса .NET-приложения и не является SaaS.

Требования, производительность и масштабирование

Для стабильной 6.2.4 Core-пакет публикует цели net8.0, net9.0, net10.0 и netstandard2.0. NuGet вычисляет совместимость и для других .NET-целей через netstandard2.0, но при проектировании лучше ориентироваться на реально включённые целевые платформы пакета и официальные рекомендации. GDI/WPF рассчитаны на Windows; у них есть Windows-цели современных .NET и .NET Framework 4.6.2.

В документации нет универсальных обещаний «N страниц в секунду» или фиксированного потребления памяти, поэтому оценивать производительность следует на собственном типовом документе. Сложность рендеринга растёт вместе с количеством элементов, строк таблиц, изображений, диаграмм и операций разметки. В 6.2.4 отдельно исправлена утечка памяти, при которой последний отрендеренный документ удерживался до следующего рендеринга; это существенная причина не опираться на замеры старых релизов при оценке текущей версии.

Для серверной генерации полезно разделять подготовку данных и построение DOM. Сначала приложение получает и валидирует данные, затем создаёт новый Document, после чего рендерер превращает его в файл. Это облегчает повторную генерацию после ошибки ресурса и не заставляет хранить состояние рендерера между независимыми заданиями. Большие изображения желательно масштабировать на уровне ресурсов осознанно: уменьшение визуального размера в документе не меняет того факта, что исходный растровый файл нужно прочитать и обработать.

Автоматизация — естественный сценарий MigraDoc, но не отдельная пакетная кнопка. Приложение само запускает генерацию в цикле, очереди, фоновой службе, веб-эндпоинте или задании CI. Библиотека предоставляет API, а контроль параллелизма, очередей, повторов и именования файлов остаётся на стороне вашей архитектуры.

Безопасность и приватность

MigraDoc выполняется локально внутри .NET-приложения и не требует передачи содержимого документа в облачный сервис empira. В библиотеке нет функции облачного хранения, совместного аккаунта или ИИ-анализа документов. Поэтому модель приватности определяется главным образом кодом хост-приложения: откуда оно получает данные, куда сохраняет PDF, какие логи ведёт и какие ресурсы загружает по сети.

MIT-лицензия позволяет изучать исходный код и встраивать библиотеку в собственные приложения при соблюдении условий лицензии. Для PDF доступно парольное шифрование через PDFsharp после рендеринга MigraDoc. Шифрование защищает сам итоговый файл, но не отменяет требований к безопасному хранению исходных данных, временных файлов и паролей. Пароль не следует записывать в исходный код или журналы приложения.

Отдельный риск — внешние ресурсы. Если приложение получает изображения из недоверенного источника, оно должно самостоятельно ограничивать размеры, проверять тип и обрабатывать ошибки до передачи файла в документ. MigraDoc не является антивирусом и не заменяет валидацию пользовательского ввода. То же относится к ссылкам: библиотека способна создавать веб- и файловые гиперссылки, поэтому адреса из внешних данных нужно проверять на уровне бизнес-логики.

Цена, лицензирование и ограничения бесплатного использования

MigraDoc и PDFsharp распространяются под лицензией MIT. У библиотеки нет платной редакции, которая разблокирует дополнительные возможности рендеринга, нет пробного периода, водяного знака или лимита на количество документов. Основные NuGet-пакеты доступны бесплатно. Отдельно empira предлагает профессиональную помощь и коммерческие услуги поддержки, но покупка поддержки не является условием использования библиотеки.

Модель стоимости поэтому отличается от SaaS и коммерческих SDK. Прямой лицензионный платёж за сам MigraDoc отсутствует, но остаются инженерные расходы: реализация шаблонов на C#, поддержка FontResolver для кроссплатформенного окружения, регрессионные тесты PDF, подготовка ресурсов и обновление кода при переходе между крупными версиями. Для команды, которая хочет визуально собирать шаблоны без программирования, именно стоимость разработки может оказаться важнее нулевой цены лицензии.

Плюсы и минусы MigraDoc

Плюсы

  • MIT-лицензия без платы за количество разработчиков, серверов или сгенерированных документов.
  • Высокоуровневая объектная модель с автоматическим переносом текста и созданием страниц для PDF.
  • Стили и наследование позволяют централизовать оформление большого семейства документов.
  • Поддерживаются таблицы, изображения, диаграммы, поля, закладки, ссылки, колонтитулы и текстовые фреймы.
  • Core-сборка работает без Windows-зависимостей на совместимых .NET-платформах; отдельные GDI/WPF-сборки сохраняют Windows-специфичные возможности.
  • PDF-результат можно дополнительно обрабатывать через PDFsharp, включая шифрование и низкоуровневую графику.
  • RTF даёт отдельный редактируемый результат, когда фиксированный PDF недостаточен.
  • Проект активно поддерживается, а стабильная 6.2.4 и будущая 7.0 Preview разделены по статусу.

Минусы

  • Нет визуального дизайнера документов как обязательной части продукта; шаблоны создаются кодом.
  • Нет штатного импорта DOCX, HTML или существующего PDF в объектную модель MigraDoc.
  • Core требует внимательной настройки шрифтов; приложение должно гарантировать доступность всех используемых faces.
  • Поддержка растровых форматов в Core уже, чем в Windows-сборках: базовый набор — JPEG, PNG и BMP.
  • RTF не сохраняет фиксированную пагинацию PDF, поскольку страницы рассчитывает приложение просмотра.
  • Сложные уникальные элементы с точными координатами иногда требуют перехода к более низкоуровневому PDFsharp.
  • Переход со старой версии 1.5 и ранних 6.x требует проверки flavor-пакета, font resolver и изменений PageSetup.

Кому подойдёт

  • .NET-разработчикам, которые формируют счета, отчёты, акты, ведомости и печатные формы из структурированных данных.
  • Сервисам, где документ должен строиться автоматически на сервере без ручного участия оператора.
  • Проектам, которым нужен PDF с автоматической версткой и возможность после рендера применить функции PDFsharp.
  • Кроссплатформенным .NET-приложениям, если команда готова явно поставлять и разрешать шрифты для Core.
  • Windows-приложениям, которым полезны GDI/WPF-сборки и встроенный preview-контрол в интерфейсе собственного приложения.
  • Проектам с требованием открытой MIT-лицензии и доступом к исходному коду.

Кому не подойдёт

  • Пользователям без навыков программирования, которым нужен готовый визуальный редактор шаблонов.
  • Проектам, где основной вход — сложный HTML/CSS и требуется точный браузерный рендеринг в PDF.
  • Системам, которые должны открывать и редактировать существующие DOCX как документную модель без отдельного преобразования.
  • Задачам, где нужен исключительно низкоуровневый контроль над каждой PDF-командой; там прямой PDFsharp может быть проще.
  • Командам, которым нужна готовая коммерческая SLA-поддержка как часть самой лицензии SDK без отдельного договора.

Сравнение с другими аналогами

Решение Основная задача Платформа Порог освоения Форматы Автоматизация Модель оплаты Ограничение Подходящий сценарий
MigraDoc 6.2.4 Документы из объектной модели с автоматической пагинацией .NET; Core кроссплатформенный, GDI/WPF для Windows Средний: требуется C#/.NET и понимание DOM PDF, RTF; MDDDL как сериализация Через код приложения MIT, бесплатно Нет штатного DOCX/HTML-импорта и визуального дизайнера Отчёты, счета, акты и формы из данных .NET
QuestPDF Генерация PDF через Fluent C# API .NET, локальное выполнение Средний: декларативный Fluent API PDF как основной результат Через код приложения Community бесплатно для подходящих пользователей; Professional и Enterprise — платные бессрочные лицензии с обновлениями/поддержкой Community имеет критерии допустимости; продукт source-available, а не MIT Современные PDF-макеты, когда нужен Fluent API и PDF является единственным главным выходом
iText Core 9 Создание и программная обработка PDF Java и .NET Выше среднего: большой PDF-ориентированный API PDF и специализированные PDF-функции Через код приложения AGPL либо коммерческая лицензия Закрытый proprietary-проект обычно требует коммерческой лицензии; часть расширений коммерческая Сложные PDF-сценарии, формы, подписи, PDF/A и другие функции экосистемы iText
Open XML SDK 3.5.1 Создание и изменение Office Open XML .NET Высокий: API близок к структуре OOXML и стандарту DOCX, XLSX, PPTX и связанные Open XML-пакеты Через код приложения MIT, бесплатно Не является PDF-рендерером и не даёт высокоуровневую верстку уровня MigraDoc Когда главным редактируемым результатом должен быть DOCX/Excel/PowerPoint, а не PDF

MigraDoc и QuestPDF находятся ближе всего по сценарию «C#-код формирует документ», но делают разные акценты. MigraDoc использует документную объектную модель, стили и RTF как второй выходной формат; QuestPDF строит PDF через Fluent API и в 2026 году использует source-available коммерческую модель с бесплатной Community-лицензией для определённых категорий. Для небольшого проекта критерий выбора обычно сводится не к цене функции рендеринга, а к тому, какой API проще поддерживать в конкретной команде и нужен ли RTF.

iText Core уместнее, когда задача выходит за генерацию печатного отчёта и требует богатого набора PDF-ориентированных операций. Его лицензирование принципиально отличается: открытая ветка распространяется по AGPL, а для многих proprietary-сценариев нужна коммерческая лицензия. MigraDoc проще юридически для закрытого приложения благодаря MIT, но не пытается покрыть всю PDF-экосистему iText.

Open XML SDK решает другой класс задач: он работает с форматами Microsoft Office Open XML и не предназначен для прямого высокоуровневого PDF-рендеринга. Если пользователь должен открыть результат в Word и продолжать полноценно редактировать DOCX, Open XML SDK логичнее, чем попытка заставить MigraDoc экспортировать формат, которого у него нет. Если же исходный документ создаётся в Google Docs и нужен простой PDF без программной генерации, можно использовать обычный экспорт; у GeekHow есть отдельное руководство по преобразованию Google Docs в PDF.

Типичные проблемы и диагностика

PDF-рендеринг завершается ошибкой о неразрешённом шрифте

Симптом: генерация останавливается с сообщением, что запрошенный font family не удалось разрешить. Возможная причина: Core-сборка не получает нужный файл шрифта через FontResolver, особенно на Linux или macOS. Диагностика: сопоставьте имена Font.Name в стилях и локальном форматировании с наборами, которые возвращает ваш IFontResolver; отдельно проверьте regular, bold и italic faces. Исправление: поставляйте нужные font files вместе с приложением и зарегистрируйте собственный resolver до первого использования PDFsharp/MigraDoc. Проверка результата: минимальный документ с каждым используемым начертанием должен рендериться без замены шрифта и исключений.

Ошибка связана с Courier New, хотя документ этот шрифт не использует

Симптом: рендерер требует Courier New при обработке MigraDoc. Возможная причина: с 6.2 предопределённый error font также должен быть разрешим; по умолчанию это Courier New. Диагностика: проверьте PredefinedFontsAndChars.ErrorFontName и способность FontResolver вернуть выбранный face. Исправление: либо добавьте Courier New в resolver, либо замените ErrorFontName на шрифт, который гарантированно поставляется приложением. Проверка результата: отрендерите документ в среде, где системного Courier New нет; генерация не должна падать из-за error font.

В PDF вместо изображения появляется ошибка или картинка не находится

Симптом: ожидаемый логотип или иллюстрация отсутствуют. Возможная причина: относительный путь вычисляется из другого рабочего каталога, чем предполагал разработчик. Диагностика: сравните фактический WorkingDirectory рендерера, Document.ImagePath и имя, переданное в AddImage; затем проверьте наличие файла в рассчитанном месте. Исправление: задайте стабильный WorkingDirectory и ImagePath в конфигурации публикации либо передавайте нормализованный абсолютный путь из доверенного каталога. Проверка результата: запустите тот же build из production-каталога или контейнера и убедитесь, что ресурс появляется без локальных IDE-путей.

Core-сборка не принимает изображение, которое работает в Windows GDI/WPF

Симптом: один и тот же файл отображается в Windows flavor, но не обрабатывается Core. Возможная причина: у Core базовый поддерживаемый набор изображений ограничен JPEG, PNG и BMP, тогда как GDI/WPF используют дополнительные возможности Windows. Диагностика: определите реальный формат файла, а не только расширение. Исправление: предварительно преобразуйте ресурс в JPEG/PNG/BMP либо выберите Windows flavor, если вся система сознательно Windows-only и это оправдано архитектурой. Проверка результата: используйте небольшой образец того же формата в минимальном Core-документе.

Landscape остаётся Portrait после клонирования PageSetup

Симптом: после изменения Orientation или PageFormat итоговая страница имеет неожиданные размеры. Возможная причина: в 6.2 изменено поведение размеров страницы; при работе с Clone ранее заданные Width/Height могут конфликтовать с новым форматом. Диагностика: проверьте, клонировался ли DefaultPageSetup и задавались ли перед Orientation свойства Width/Height. Исправление: вызовите ResetPageSize перед установкой PageFormat и Orientation, как требует обновлённая модель 6.2. Проверка результата: проверьте фактическую ширину/высоту страницы в полученном PDF и повторите тест для всех форматов, используемых приложением.

RTF и PDF имеют разное число страниц

Симптом: одинаковый Document даёт различную пагинацию в PDF и RTF. Возможная причина: это различие архитектуры, а не обязательно дефект: PDF пагинируется MigraDoc, а RTF остаётся динамическим и рассчитывается Word или другим редактором. Диагностика: сравнивайте содержимое, структуру и стили, а не только номера страниц. Исправление: используйте PDF как каноническую печатную форму, если важна точная разбивка; RTF оставляйте как редактируемый вариант. Проверка результата: все логические элементы должны присутствовать в обоих форматах, даже если границы страниц различаются.

Изменение стиля после подготовки рендера не влияет на результат

Симптом: код меняет стиль, но уже подготовленный документ сохраняет прежние значения. Возможная причина: PrepareRenderPages или RenderDocument запускает flattening и присваивает конкретным объектам итоговые значения наследуемого форматирования. Диагностика: определите, происходит ли изменение DOM до или после flattening. Исправление: завершайте настройку стилей до подготовки страниц; при необходимости создайте новый Document или рендерер и повторите построение из исходных данных. Проверка результата: изменение тестового стиля до RenderDocument должно отражаться в новом PDF.

Текст выходит за нижнюю границу строки таблицы

Симптом: содержимое ячейки пересекает границу или выглядит обрезанным. Возможная причина: строка имеет HeightRule.Exactly и высоту меньше фактического текста. Документация прямо предупреждает, что в таком режиме текст может превысить нижнюю границу. Диагностика: найдите строки с фиксированной высотой и подставьте самое длинное реальное значение. Исправление: снимите жёсткое правило там, где высота должна расти, либо увеличьте её с запасом только для действительно фиксированных макетов. Проверка результата: тестовый набор с многострочным текстом должен помещаться без пересечения границ.

Шапка таблицы не повторяется на следующей странице

Симптом: длинная таблица продолжается без заголовков колонок. Возможная причина: верхняя строка не имеет HeadingFormat = true или заголовок состоит из нескольких строк, но флаг установлен только не на всех верхних строках. Диагностика: проверьте первые Rows таблицы и их HeadingFormat. Исправление: отметьте все последовательные строки шапки в начале таблицы. Проверка результата: сформируйте достаточно данных для перехода на вторую страницу и убедитесь, что шапка появляется сверху продолжения.

Заголовок остаётся последней строкой страницы

Симптом: Heading располагается внизу страницы, а связанный текст начинается на следующей. Возможная причина: в стиле заголовка отключён KeepWithNext или заголовок оформлен как обычный Paragraph с ручным шрифтом. Диагностика: проверьте Style и ParagraphFormat.KeepWithNext. Исправление: используйте Heading1–Heading9 либо собственный стиль с KeepWithNext. Проверка результата: создайте документ, где заголовок попадает близко к границе страницы; он должен перейти вместе со следующим абзацем.

Новая секция неожиданно сохраняет старый колонтитул

Симптом: раздел должен начинаться без старого Footer/Header, но продолжает его показывать. Возможная причина: MigraDoc наследует копию колонтитула предыдущей секции, если новый HeaderFooter не назначен. Диагностика: проверьте Headers/Footers Primary, FirstPage и EvenPage новой секции. Исправление: явно замените нужные варианты пустыми HeaderFooter либо задайте новый содержательный колонтитул. Проверка результата: первая страница новой секции и её чётные/нечётные страницы должны показывать только ожидаемый набор элементов.

FAQ

Поддерживает ли MigraDoc настоящие сноски в PDF?

В объектной модели есть класс Footnote, но актуальная документация прямо указывает, что его PDF-рендеринг пока не поддерживается. В примерах сноски имитируются обычными абзацами, форматированным текстом, закладками и ссылками. Поэтому Footnote нельзя считать готовой функцией PDF-вывода в стабильной 6.2.4.

Как устроены маркированные и нумерованные списки?

Отдельного «контейнера списка» в модели нет: список представляет собой последовательность Paragraph, у которых ParagraphFormat.ListInfo задаёт тип и параметры списка. Документация описывает маркированные, нумерованные и смешанные списки; для маркеров предусмотрены три уровня BulletList.

Можно ли передать изображение из памяти без временного файла?

Да. Хотя AddImage принимает строковую ссылку, MigraDoc поддерживает псевдопротокол base64:, в котором байты изображения кодируются в строку и передаются вместо имени файла. Это относится к данным внутри приложения и не имеет отношения к вставке Base64-картинок в HTML страницы.

Увеличивается ли TextFrame автоматически, если текста стало больше?

Нет. TextFrame имеет собственный размер и не растёт вместе с содержимым. Если рамка слишком мала, разработчик должен заранее изменить её размеры или переработать компоновку. Это особенно важно для шаблонов, где объём текста приходит из внешних данных.

Можно ли один и тот же Paragraph вставить в две секции?

Один объект DOM может иметь только одного родителя и не прикрепляется повторно в другое место. Для повторного использования документация предусматривает Clone: копия объекта со всеми дочерними элементами может быть добавлена к другому родителю.

Может ли веб-ссылка из PDF принудительно открываться в новой вкладке браузера?

Для URI-ссылок PDF-спецификация не даёт MigraDoc способа заставить браузерный PDF-плагин открыть адрес именно в новой вкладке. Управление NewWindow документировано для переходов к PDF-файлам и связанным действиям, но не для обычной веб-URI. Поведение веб-ссылки в итоге зависит от просмотрщика.

Подходит ли MDDDL как современный универсальный обменный формат?

Нет. MDDDL — внутренне ориентированное текстовое представление объектной модели MigraDoc, исторически связанное с Grammar by Example. Документация отдельно отмечает, что MDDDL всё ещё использует ANSI-кодировку. Для обмена с офисными редакторами лучше выбирать их собственные форматы, а MDDDL использовать как сериализацию и диагностическое представление MigraDoc.

Можно ли удержать небольшую таблицу целиком на одной странице?

Для этого предназначено свойство Row.KeepWith, которое объединяет текущую строку с указанным количеством следующих строк в неразрываемую группу. Оно подходит для короткой таблицы или логически связанных строк, но слишком большую группу нельзя физически уместить на одной странице, поэтому правило требует контроля реального объёма.

Итог

MigraDoc имеет наиболее ясный смысл в .NET-системе, где документ является результатом бизнес-данных, а не объектом ручной верстки. Для счетов, актов и отчётов его сильная сторона — сочетание структурной модели, стилей и автоматической пагинации, а MIT-лицензия снимает лицензионный барьер при серверном и коммерческом использовании. Критическим условием для кроссплатформенного Core остаётся управляемая поставка шрифтов и ресурсов.

Если нужен исключительно PDF и команде ближе Fluent-разметка, стоит сопоставить MigraDoc с QuestPDF. Если задача требует глубокой обработки существующих PDF, сложных стандартов и функций большой PDF-экосистемы, iText Core может оказаться ближе по инструментарию, но его AGPL/коммерческая модель требует отдельной юридической оценки. Если главным результатом должен быть DOCX, MigraDoc не стоит растягивать на несвойственный ему формат — Open XML SDK решает эту задачу непосредственно.

Для стабильного production-кода на дату обзора базовой версией остаётся 6.2.4. Ветка 7.0.0 Preview 1 полезна как направление развития, но не меняет главный выбор: MigraDoc нужен разработчику, который готов описывать документ кодом и хочет получить локальный, воспроизводимый PDF/RTF-конвейер без SaaS, регистрации и платного runtime.