В iText 7 можно программно создавать PDF с абзацами, таблицами, изображениями и закладками, изменять готовые документы, заполнять формы, ставить цифровые подписи, настраивать шифрование и выпускать файлы PDF/A или PDF/UA. Основной рабочий процесс строится вокруг PdfReader, PdfWriter и PdfDocument, а высокоуровневый Document раскладывает текст и таблицы по страницам; для точного рисования используется Canvas и низкоуровневые операции содержимого. Ниже показано, как подключить модули, выбрать уровень API, управлять шрифтами и страницами, автоматизировать типовые операции и разбирать ошибки, которые возникают при сборке, обработке чужих PDF и проверке соответствия стандартам.
Работа обычно начинается с выбора одного из двух уровней. Layout API удобен для отчётов, счетов, договоров и каталогов: разработчик добавляет Paragraph, Table, Image, List и AreaBreak, а движок сам вычисляет переносы и создаёт новые страницы. Kernel API нужен, когда важно обращаться к объектам PDF, копировать страницы между документами, менять словари, управлять потоками содержимого, аннотациями, шифрованием и метаданными. Оба уровня можно сочетать в одном процессе, но смешивать их следует осознанно: прямое рисование не участвует в автоматической верстке, а уже сброшенный на диск элемент нельзя безусловно вернуть в компоновщик.
У iText 7 нет визуальной панели с кнопками для ручного правления страницы: операции описываются на Java или C#, запускаются из приложения, теста, командной утилиты либо серверного задания, а результат проверяется в обычном PDF-просмотрщике и валидаторах. Такой подход даёт воспроизводимость и позволяет обработать тысячи файлов по одинаковым правилам, однако требует понимать жизненный цикл PdfDocument, координаты PDF, встраивание шрифтов и лицензионные условия. Практическая ценность библиотеки особенно заметна там, где документ собирается из данных, должен строго соответствовать шаблону или проходит через подпись, архивирование и автоматическую проверку.
Скачать iText 7
- Редактирование PDF
- Русский интерфейс
- Просто новичкам
- Нет графического окна
- Нужен код на Java или C#
- AGPL требует открытый код
Подключение модулей и минимальная структура проекта
В Java компоненты подключают через Maven или Gradle, а в C# — через NuGet. Для базового сценария требуются модули ядра и компоновки; агрегирующий пакет подтягивает согласованный набор зависимостей. Важно не собирать приложение из случайной смеси номеров модулей: несовпадение kernel, layout, io, forms и sign приводит к ошибкам связывания, отсутствующим методам или поведению, которое трудно воспроизвести. Версии следует фиксировать в файле сборки, а обновление проводить единым изменением с повторным запуском тестов на собственном наборе PDF.
При первом запуске полезно создать отдельный каталог для результата и писать во временный файл, который переименовывается только после успешного закрытия PdfDocument. Это защищает рабочий документ от частично сформированного файла при исключении. В веб-приложении тот же принцип реализуют через поток памяти или временное хранилище: ответ клиенту отправляют после закрытия документа, потому что именно Close завершает таблицу перекрёстных ссылок, записывает трейлер и освобождает связанные ресурсы.
try (PdfWriter writer = new PdfWriter(target);
PdfDocument pdf = new PdfDocument(writer);
Document document = new Document(pdf)) {
document.add(new Paragraph("Документ сформирован"));
}
Конструкция с автоматическим закрытием особенно полезна в Java, где try-with-resources гарантирует вызов Close даже при ошибке. В C# применяют using. Не следует отдельно закрывать PdfWriter раньше PdfDocument или продолжать добавление элементов после закрытия Document. Если результат пуст, имеет нулевой размер или открывается с сообщением о повреждении, первой проверкой должны быть порядок закрытия объектов, наличие необработанного исключения и фактическая запись потока на диск.

Как связаны PdfWriter, PdfReader, PdfDocument и Document
PdfWriter отвечает за вывод новых PDF-объектов, PdfReader читает структуру существующего файла, а PdfDocument объединяет эти роли в единую модель документа. Для создания файла достаточно writer, для анализа без изменения — reader, для модификации — reader и writer одновременно. Document располагается уровнем выше: он получает PdfDocument и предоставляет блочную модель верстки. Ошибка в выборе конструктора часто объясняет неожиданное поведение: документ, открытый только с PdfReader, нельзя сохранить изменённым, а новый PdfDocument без reader не содержит страниц исходного файла.
При редактировании нельзя назначать один и тот же путь входу и выходу. Writer начинает создавать новый файл и может обнулить исходник раньше, чем Reader прочитает его объекты. Безопасная схема использует отдельный путь, затем выполняет атомарную замену. Для последовательного добавления подписи, аннотации или метаданных применяют append mode, когда новое изменение записывается как дополнительная ревизия. Он необходим для сохранения криптографической целостности ранее подписанных диапазонов, но не превращает любое изменение в допустимое: права подписи и политика сертификации по-прежнему ограничивают действия.
Document задаёт поля страницы, семейство шрифта по умолчанию и область, в которой работает компоновщик. Если после создания Document рисовать через PdfCanvas, нужно решить, должен ли рисунок находиться под уже созданным содержимым или поверх него. Новый поток содержимого перед существующими потоками используется для фона, после них — для штампа. Порядок операций заметен при прозрачности, наложении изображений и работе с формами.
Уровни API: когда выбирать Layout, Canvas или объекты ядра
Layout API подходит, когда содержание можно представить как последовательность элементов. Paragraph переносит строки и учитывает отступы; Table распределяет ширину колонок и переносит строки на следующую страницу; Div группирует блоки; List формирует маркированные и нумерованные пункты; Image участвует в потоке или позиционируется фиксированно. Разработчик задаёт свойства, а движок создаёт рендереры и рассчитывает области размещения. Это экономит код, но требует учитывать, что итоговые координаты становятся известны только во время layout.
Canvas применяется для добавления элементов в заданный прямоугольник на конкретной странице. Он использует те же высокоуровневые объекты, но не управляет всем документом. Такой режим удобен для колонтитулов, штампов, боковых меток, подписных блоков и заполнения заранее предусмотренных областей шаблона. Если прямоугольник слишком мал, часть содержимого может не поместиться; результат раскладки следует проверять, а не считать успешным только потому, что исключение не возникло.
PdfCanvas — низкоуровневый инструмент операторов PDF: перемещение точки, линии и кривые, матрицы преобразования, цвета, состояния графики, текстовые операторы и XObject. Он даёт точность, но не переносит слова и не создаёт семантическую структуру автоматически. После SaveState должен следовать RestoreState, иначе преобразование, прозрачность или цвет могут повлиять на последующие объекты. Для доступного PDF прямого рисования недостаточно: структуру тегов и альтернативные описания приходится задавать отдельно.
- Layout — для документов, где текст и таблицы должны автоматически перетекать между страницами.
- Canvas — для содержимого внутри известной области существующей или новой страницы.
- PdfCanvas — для точной графики, операторов содержимого и управления порядком наложения.
- Объекты kernel — для страниц, словарей, ресурсов, аннотаций, вложений и служебной структуры PDF.
Создание страниц, выбор формата и управление полями
Формат первой страницы можно передать при создании Document либо назначить через PdfDocument. Часто используются A4 и Letter, но PageSize допускает произвольный прямоугольник в пунктах PDF, где 72 пункта соответствуют одному дюйму. Размер страницы и поля — разные сущности: MediaBox описывает физическую область, CropBox — видимую область в просмотрщике, а поля Document ограничивают размещение элементов компоновщика, не меняя коробки страницы.
Для смешанного документа размер следующей страницы задают перед AreaBreak или создают страницу вручную. Это позволяет разместить широкую таблицу на альбомном листе, а последующий текст вернуть на портретный. Поворот страницы через rotation меняет интерпретацию просмотра, но не обязательно перестраивает существующие координаты содержимого. При добавлении штампа на повёрнутую страницу нужно учитывать флаг ignore page rotation или самостоятельно преобразовать систему координат; иначе надпись окажется повернутой либо смещённой.
Поля можно менять между разделами, но уже размещённые элементы не пересчитываются задним числом. Если нужен титульный лист без верхнего колонтитула, проще обработать номер страницы в событии, чем менять глобальные поля после каждого добавления. Для печати следует оставлять безопасную область у краёв и помнить о вылетах: iText записывает точные координаты, но физический принтер может не печатать до границы листа.
Координаты PDF и точное позиционирование
Начало координат PDF обычно находится в левом нижнем углу страницы, ось X направлена вправо, ось Y — вверх. Это отличается от многих экранных систем, где Y растёт вниз. FixedPosition у элемента Layout принимает номер страницы и координаты прямоугольника, а абсолютное рисование PdfCanvas использует текущую матрицу преобразования. При импорте координат из браузерной формы или изображения высоту страницы приходится учитывать явно: экранное значение Y преобразуют относительно верхней границы.
Точная позиция текста зависит не только от точки начала. Шрифт имеет базовую линию, восходящие и нисходящие элементы, поэтому визуальный верх строки не совпадает с заданной координатой. Для выравнивания подписи внутри поля лучше использовать Canvas с ограничивающим прямоугольником и TextAlignment, чем подбирать магическое смещение. Аналогично центрирование изображения выполняют по его масштабированным размерам, а не по исходным пикселям.
Преобразования следует локализовать через SaveState и RestoreState. После поворота на угол вокруг центра матрица влияет на все последующие операции до восстановления состояния. Если графика внезапно исчезает, стоит проверить, не переместила ли матрица объект за CropBox, не установлен ли нулевой масштаб и не оставлен ли активным путь отсечения. Эти ошибки редко видны в отладчике, поэтому полезно временно рисовать рамку целевой области.
Текст, кириллица и встраивание шрифтов
Надёжный вывод русского текста начинается с явного выбора файла шрифта, содержащего нужные глифы. Стандартные четырнадцать шрифтов PDF не дают универсальной поддержки кириллицы, а системное имя может разрешаться по-разному на сервере и рабочем компьютере. PdfFontFactory создаёт PdfFont из TTF или OTF; кодировка Identity-H позволяет обращаться к Unicode-глифам, а режим встраивания сохраняет внешний вид документа на другом устройстве.
Если в строке появляются квадраты, вопросительные знаки или пропуски, нужно разделить три причины. Первая — в шрифте нет глифа. Вторая — выбрана кодировка, которая не представляет символ. Третья — приложение передало уже испорченную строку после неверного чтения файла или базы данных. iText не может восстановить символы, потерянные до вызова Add. Проверять следует конкретные кодовые точки и фактический файл шрифта, а не только его отображаемое имя.
Один PdfFont можно повторно использовать в пределах документа, чтобы не создавать дубликаты ресурсов. Для набора языков применяют FontProvider и список семейств: движок подбирает шрифт для фрагмента, которого нет в основном семействе. Для арабского, деванагари и других сложных письменностей одного наличия глифов недостаточно, поскольку требуются формирование и позиционирование знаков; соответствующая типографическая обработка относится к отдельному компоненту. В простом документе кириллица и латиница обычно обслуживаются одним качественным Unicode-шрифтом.
В PDF/A шрифты должны быть встроены, поэтому невстраиваемый файл или неверный режим вызовет исключение соответствия. Лицензия самого шрифта также важна: техническая возможность включить данные в PDF не означает разрешения на распространение. Для производственного шаблона разумно хранить утверждённые шрифты вместе с приложением, проверять контрольные суммы и не зависеть от набора, установленного в операционной системе.
Абзацы, переносы, интервалы и выравнивание
Paragraph состоит из текстовых фрагментов и других inline-элементов, которым можно назначать разные шрифты, размеры, цвета и действия. Margin управляет внешним расстоянием между блоками, Padding — внутренним отступом, Leading — высотой строк. Когда в документе появляются неожиданные пустоты, нужно посмотреть одновременно верхний и нижний margin соседних элементов, фиксированную высоту и параметры keep together; причина редко находится в одном свойстве.
Выравнивание по ширине увеличивает межсловные интервалы, поэтому короткая последняя строка и узкая колонка могут выглядеть неестественно. Переносы слов подключаются через конфигурацию переносов для языка; без словаря длинное слово способно выйти за границу или создать большие пробелы. Для артикулов, адресов и кодов, которые нельзя разрывать, используют неразрывные пробелы или отдельный Text с запретом переноса, но массовое применение такого приёма ухудшает компоновку.
Свойства KeepTogether и KeepWithNext помогают удерживать подпись рядом с таблицей или заголовок с первым абзацем. Они не отменяют геометрию: блок, который физически выше доступной страницы, всё равно придётся разделить или уменьшить. Бесконечные предупреждения о невозможности разместить элемент часто вызваны фиксированной высотой, большим padding либо вложенной таблицей, которую запретили переносить. Диагностику удобно начинать с временного удаления ограничений.
Таблицы: ширина колонок, повтор заголовка и перенос строк
Table принимает число колонок или массив ширин. Процентная ширина удобна для адаптации к полям страницы, а фиксированные значения — для бланков, где координаты строго заданы. Автоматический алгоритм учитывает содержимое и min/max width, поэтому длинная непрерывная строка может расширить колонку сильнее ожиданий. Для предсказуемого отчёта задают явные пропорции, разрешают перенос текста и отдельно тестируют самые длинные значения из данных.
Заголовочные ячейки добавляют через AddHeaderCell, после чего они повторяются на следующих страницах. Подвал таблицы можно повторять аналогично. Объединение строк и колонок работает через rowspan и colspan, но сложная сетка повышает риск, что крупная ячейка не поместится в остаток страницы. В таком случае компоновщик переносит строку целиком или делит содержимое согласно возможностям рендерера. Визуальные разрывы проверяют на реальных объёмах, а не на двух демонстрационных строках.
Для очень большой таблицы применяют режим large table и периодически освобождают уже записанные части, чтобы не держать все рендереры в памяти. После Complete добавление строк запрещено. Такой режим требует заранее определить ширину и хуже подходит для алгоритма, которому нужно видеть весь набор данных. Если таблица формируется из запроса, строки следует читать потоково, но транзакцию и соединение закрывать только после завершения записи PDF.
Границы и фон задаются на уровне Table, Cell или отдельных сторон. При наложении соседних границ итоговая толщина может восприниматься как двойная, поэтому для строгой сетки стоит выбрать единый способ: рисовать все стороны ячейки одинаково либо оставить внешнюю рамку таблице, а ячейкам — только внутренние линии. Вертикальное выравнивание текста не исправляет слишком маленькую фиксированную высоту; если глифы обрезаются, нужно убрать ограничение или увеличить строку.

Изображения, масштабирование и повторное использование ресурсов
ImageDataFactory читает распространённые растровые форматы и создаёт данные изображения, которые затем помещаются в Image. Размер в пикселях сам по себе не определяет физический размер на странице: при ScaleToFit изображение вписывается в заданный прямоугольник, при SetWidth и SetHeight может измениться соотношение сторон, а AutoScale подбирает масштаб относительно доступной области. Для фотографии с высоким разрешением важно не только уменьшить отображение, но и оценить вес исходных данных, иначе небольшой рисунок сохранит мегабайты.
JPEG обычно включается без повторного кодирования, тогда как PNG с прозрачностью преобразуется в подходящие PDF-потоки и маску. TIFF и специализированные факсимильные данные могут содержать несколько страниц или особенности декодирования. Перед массовой обработкой полезно нормализовать изображения, ограничить размеры и отклонять повреждённые файлы. Входные данные от пользователя нельзя считать безопасными: слишком большой растр способен исчерпать память ещё до добавления на страницу.
Один и тот же XObject можно размещать многократно без копирования пикселей. Это существенно для логотипа в колонтитуле на сотнях страниц. Если каждый раз заново создавать ImageData из массива байтов, структура документа может раздуться; лучше создать ресурс один раз и повторно использовать его в пределах PdfDocument. При копировании страниц между документами iText переносит необходимые ресурсы, но интеллектуальное объединение одинаковых объектов зависит от режима writer и фактического равенства данных.
SVG обрабатывается как векторная графика, что сохраняет чёткость при масштабировании. Поддержка CSS и SVG-элементов не равна возможностям браузера: скрипты, внешние ресурсы, сложные фильтры или нестандартные шрифты могут потребовать упрощения. Для критичного изображения следует сравнить результат в нескольких просмотрщиках и при печати. Если часть SVG исчезла, сначала изолируют минимальный фрагмент и проверяют его атрибуты размеров, viewBox и ссылки на внешние файлы.
Колонтитулы, номера страниц и события
Повторяющиеся элементы удобно добавлять обработчиком событий страницы. Он получает PdfDocumentEvent и конкретную PdfPage, после чего может открыть Canvas в пределах полей, вывести номер, название раздела, логотип или линию. Обработчик регистрируют до создания страниц, иначе уже сформированные листы останутся без колонтитула. Титульный лист исключают по номеру или признаку в пользовательском состоянии обработчика.
Текст вида Страница X из Y требует знать общее число страниц. Во время первого прохода Y ещё неизвестно, поэтому используют заполнитель Form XObject: в колонтитуле выводится X и прямоугольник для Y, а после завершения основного содержания в заполнитель рисуют итоговое число. Альтернатива — второй проход по готовому PDF, но он увеличивает ввод-вывод и требует аккуратности при наличии подписей.
Колонтитул не должен пересекаться с основной областью. Layout не резервирует место под произвольное событие, поэтому верхнее и нижнее поля задают с учётом высоты повторяющегося блока. Если заголовок переменной длины, лучше ограничить его одной строкой, уменьшать шрифт по правилам или использовать фиксированную область с контролем переполнения, а не надеяться на автоматический перенос поверх текста документа.
Водяные знаки, фон и порядок потоков содержимого
Водяной знак можно создать как текст, изображение или прозрачный Form XObject. Для фона новый поток содержимого вставляют перед существующими потоками страницы; для штампа поверх текста — после них. Прозрачность задаётся через ExtGState, а состояние графики ограничивается SaveState и RestoreState. Если прозрачность применена без восстановления, бледным станет и последующее содержимое.
Диагональная надпись рассчитывается относительно центра CropBox с матрицей поворота. На страницах разного размера нельзя использовать одни и те же абсолютные координаты. Форм XObject удобен тем, что сложный знак рисуется один раз и размещается на каждой странице как ресурс. Это сокращает размер и делает поведение единообразным, но не защищает знак от удаления: PDF остаётся структурированным документом, а не растровой печатью.
Для пометки конфиденциальности не следует подменять водяным знаком реальное ограничение доступа. Текст Конфиденциально виден пользователю, но не шифрует файл и не запрещает извлечение данных. Если документ содержит защищённые сведения, дополнительно применяют шифрование, контроль выдачи и, при необходимости, цифровую подпись. Права PDF-просмотрщика сами по себе также не являются абсолютной защитой от копирования.
Изменение существующего PDF без разрушения структуры
При открытии PdfDocument с reader и writer iText создаёт новый результат, используя объекты исходного файла. Можно добавить страницы, изменить rotation, удалить листы, обновить словари, поставить аннотацию или дорисовать содержимое. Однако PDF не хранит страницу как набор абзацев, доступных обычному текстовому редактору. Видимые символы могут быть разбиты на отдельные операции и расположены координатами, поэтому замена слова в произвольном документе не равна замене строки в DOCX.
Для безопасной модификации сначала определяют, какая задача действительно нужна. Добавление штампа выполняется новым потоком содержимого. Скрытие области требует настоящего удаления данных или редактирования с очисткой, а не белого прямоугольника поверх. Перестановка страниц осуществляется копированием либо перемещением объектов страниц. Извлечение текста использует парсер, но сохранение исходной верстки после изменения длины текста обычно требует собственного алгоритма.
Чужой PDF может содержать повреждённую xref-таблицу, нестандартные ресурсы, объектные потоки, вложенные формы, слои и подписи. Если Reader сообщает о восстановлении структуры, результат следует особенно тщательно проверить. Автоматическое исправление позволяет открыть многие файлы, но не гарантирует, что исходный смысл восстановлен полностью. В критичном процессе исходник сохраняют, протоколируют предупреждения и отправляют подозрительные документы на отдельную проверку.
Объединение, разделение и копирование страниц
PdfMerger объединяет страницы нескольких документов в один PdfDocument и переносит связанные ресурсы. Диапазоны можно задавать явно, что удобно для сборки пакета из титульного листа, приложений и выбранных страниц. Исходные PdfDocument открывают по очереди и закрывают после копирования, чтобы не держать десятки файлов и потоков одновременно. Writer результата закрывают последним.
При слиянии возникают вопросы не только о страницах. Одинаковые имена полей формы могут начать ссылаться на общие значения, закладки требуют объединения, именованные назначения — устранения конфликтов, а вложения и метаданные не всегда должны переноситься автоматически. Если задача предполагает сохранение интерактивности, тест должен включать формы, ссылки, оглавление и подписи. Простая визуальная проверка страниц не обнаружит потерянное действие.
Разделение выполняют копированием диапазонов в отдельные PdfDocument. Имя файла нельзя строить напрямую из текста документа без очистки запрещённых символов и защиты от обхода каталогов. Для больших заданий лучше формировать каждый результат независимо и закрывать его сразу. Если требуется один архив, PDF сначала успешно завершают, а уже затем добавляют в ZIP; запись незакрытого PdfDocument в архив приводит к неполному файлу.
Smart mode у writer может повторно использовать одинаковые ресурсы и уменьшить результат при слиянии, но требует дополнительной памяти для сравнения объектов. На наборе с уникальными сканами экономии почти не будет. Решение принимают по измерениям: фиксируют размер, время и максимальную память на типичном пакете, а не включают режим по названию.
Закладки, назначения, ссылки и метки страниц
Закладка в панели просмотра связана с outline и назначением. Для устойчивой навигации создают явное назначение на страницу и координату, затем добавляют его к пункту outline или ссылке. Номер страницы менее надёжен при последующей вставке листов, чем назначение, которое переносится вместе с логикой документа. Иерархию оглавления строят по структуре разделов, а не по визуальному размеру шрифта.
Ссылка может вести на внутреннее назначение, внешнюю веб-страницу, файл или действие. В корпоративных документах внешние действия нередко запрещены политикой безопасности, поэтому их следует добавлять только из доверенных данных. Прямоугольник аннотации должен совпадать с видимой подписью; невидимая область поверх другого текста создаёт неудобство и может восприниматься как подмена интерфейса.
Метки страниц позволяют показывать в панели не только абсолютные числа, но и римские номера, префиксы приложений или нумерацию, начинающуюся заново. Это не меняет физический индекс страницы: обращение к GetPage(1) по-прежнему означает первый лист. При автоматической обработке нужно различать индекс, печатный номер в колонтитуле и отображаемую page label.


Аннотации, вложения и дополнительные действия
Аннотации представляют комментарии, ссылки, выделения, штампы, всплывающие заметки и другие интерактивные объекты. Они находятся над содержимым страницы и имеют собственный прямоугольник, внешний вид и флаги. Если appearance stream не сформирован, разные просмотрщики могут отрисовать аннотацию по-разному либо не показать её при печати. Для предсказуемого результата внешний вид создают явно и проверяют в нескольких программах.
Файловое вложение можно связать с документом целиком или с конкретной аннотацией. В PDF/A-3 вложения допустимы при соблюдении правил и указании отношения связанного файла, например исходных данных счёта. Простое добавление произвольного файла не делает документ соответствующим стандарту. Необходимо задать MIME-тип, имя, описание, Associated Files и метаданные, а затем пройти профильную проверку.
JavaScript и автоматические действия поддерживаются форматом PDF, но часто блокируются политиками безопасности и вызывают подозрение у защитных средств. Для обязательной бизнес-логики нельзя рассчитывать на выполнение скрипта в просмотрщике. Расчёты лучше выполнять до формирования документа, а интерактивный скрипт оставлять необязательным удобством.

AcroForm: создание, заполнение и flatten
AcroForm хранит интерактивные поля отдельно от визуального содержимого страниц. Через PdfAcroForm получают существующую форму, ищут поле по полному имени, назначают значение и при необходимости обновляют appearance. Тип поля важен: текстовое поле принимает строку, checkbox — одно из экспортных значений, radio group выбирает вариант, combo box ограничивает или разрешает произвольный ввод. Перед заполнением нужно посмотреть реальные имена и допустимые состояния, а не ориентироваться только на подписи рядом с полем.
Одинаковые полные имена означают одно логическое поле с несколькими виджетами. Изменение значения обновит все связанные представления. Если при объединении форм одинаковые имена не должны быть связаны, их переименовывают до слияния. Иерархические имена с точками требуют учитывать родительские поля; наивное добавление нового поля с конфликтующим именем способно нарушить дерево формы.
Flatten переносит внешний вид поля в обычное содержимое и удаляет интерактивность. Операцию выполняют только после проверки, что appearance соответствует значению; иначе в результате останется пустая рамка. После flatten вернуть редактируемое поле без шаблона нельзя. Для юридически значимого процесса сохраняют исходную форму, заполненный интерактивный вариант и окончательный плоский документ как разные артефакты.
XFA-формы устроены иначе и не сводятся к обычному AcroForm. Динамическая XFA может зависеть от специализированного просмотрщика, а базовые методы полей не обеспечивают полноценного преобразования. Для задач с XFA используют профильный компонент и заранее проверяют конкретные шаблоны. Если поле видно в Acrobat, но отсутствует в GetFormFields, это один из признаков, что документ использует XFA или нестандартную структуру.
Извлечение текста и анализ расположения
PdfTextExtractor получает текст страницы через стратегию извлечения. Простая стратегия следует порядку операторов, а location-aware вариант пытается восстановить строки по координатам. Ни один алгоритм не видит исходные абзацы: PDF хранит команды рисования, поэтому колонки, таблицы и отдельные символы могут возвращаться в неожиданном порядке. Результат надо оценивать на документах целевого типа и дополнять правилами по координатам.
Собственный IEventListener получает события текста и графики, включая матрицу, baseline, шрифт и bounding box. Это позволяет выделить слова в прямоугольнике, найти реквизит справа от подписи или построить карту строки. Координаты следует нормализовать с учётом rotation и преобразований. Сравнение только по точному равенству чисел ненадёжно из-за дробных значений; используют допуск и пересечение областей.
Скан без текстового слоя возвращает пустой или почти пустой результат, потому что ядро не распознаёт изображение как слова. Сначала требуется OCR, после которого можно искать и индексировать добавленный текстовый слой. Даже в OCR-документе символы могут содержать ошибки и не совпадать с видимым изображением. Для финансовых или юридических данных распознанное значение подтверждают отдельной проверкой.
Извлечение не следует использовать как доказательство отсутствия скрытых данных. Текст может находиться за пределами CropBox, под белой заливкой, в форме XObject, аннотации, вложении или метаданных. Настоящее удаление конфиденциальной информации требует редактирования, которое очищает соответствующие объекты, и последующего поиска остаточных данных.
Шифрование, пароли и разрешения
WriterProperties задаёт стандартное шифрование, пользовательский пароль, пароль владельца и флаги разрешений. Пользовательский пароль требуется для открытия, пароль владельца управляет изменением ограничений. Пустой пользовательский пароль создаёт документ, который открывается без запроса, но всё ещё может иметь ограничения; это часто путают с отсутствием шифрования. Алгоритм выбирают с учётом совместимости просмотрщиков и политики организации.
Разрешения на печать, копирование и изменение соблюдаются программой просмотра, но не являются криптографической гарантией против владельца данных. Они полезны как политика использования, а не как защита от целенаправленного извлечения. Пароль нельзя хранить в исходном коде или журнале. Его получают из защищённого хранилища, передают как массив байтов и по возможности очищают после использования.
При открытии зашифрованного файла ReaderProperties получает пароль. Сообщение bad password может означать неверную кодировку исходной строки, перепутанный owner/user password или повреждение файла. Для пакетного процесса не стоит повторять пароли бесконечно: число попыток ограничивают, а ошибку отделяют от общего сбоя чтения. Снятие защиты допустимо только при наличии прав и корректного пароля владельца.
Цифровые подписи и сохранение ревизий
Цифровая подпись связывает хэш определённого диапазона байтов с сертификатом подписанта. PdfSigner подготавливает поле, резервирует место, вычисляет digest и встраивает контейнер подписи. Закрывать или изменять документ обычным writer после подписания нельзя: любое переписывание байтов делает проверку недействительной. Несколько подписей добавляют последовательно в append mode, сохраняя предыдущие ревизии.
Закрытый ключ может находиться в файле PKCS#12, аппаратном токене, HSM или удалённом сервисе. iText не требует, чтобы ключ покидал защищённое устройство: процесс можно разделить на подготовку данных, внешнее подписание хэша и внедрение контейнера. При удалённой схеме важно зарезервировать достаточный размер Contents; слишком маленький резерв приводит к ошибке после получения подписи, а чрезмерный лишь немного увеличивает файл.
Видимый штамп подписи — только оформление. Криптографическая подпись может быть невидимой, а картинка без поля подписи не имеет проверяемой силы. Для видимого поля задают страницу, прямоугольник, текст, изображение и режим отрисовки, но окончательное доверие определяется цепочкой сертификатов, временем, отзывом и политикой валидатора.
Долговременная проверка требует встроить данные OCSP или CRL и временную метку в соответствии с выбранным профилем. Наличие сертификата в подписи не гарантирует LTV. После добавления DSS или document timestamp документ снова записывается дополнительной ревизией. Проверку проводят не только сразу после создания, но и на копии, полученной через реальный канал доставки.
Если валидатор сообщает, что документ изменён после подписи, нужно посмотреть список ревизий и тип изменений. Добавление разрешённой второй подписи отличается от переписывания исходного содержимого. Сертифицирующая подпись может разрешать заполнение форм или аннотации, но запрещать другие операции. Библиотека технически способна записать изменение, однако политика подписи определяет, будет ли оно считаться допустимым.
Зависимости криптографии и типовые конфликты Bouncy Castle
Операции подписи и часть алгоритмов шифрования используют криптографический адаптер. В Java необходимо подключить согласованные пакеты Bouncy Castle, а не одновременно несколько несовместимых вариантов. Ошибки NoClassDefFoundError, NoSuchMethodError или сообщение о невозможности выбрать factory часто возникают из-за старой транзитивной зависимости, оставшейся в classpath. Дерево зависимостей нужно вывести средствами Maven или Gradle и устранить дубликаты.
В C# криптографические пакеты также должны соответствовать набору iText. Простое копирование DLL из другого приложения создаёт труднообъяснимые конфликты. Надёжнее получать зависимости менеджером пакетов и фиксировать lock-файл. При публикации single-file или trimming следует проверить, что необходимые типы не удалены оптимизатором и доступны в целевой среде.
FIPS-режим требует отдельной совместимой конфигурации и не включается заменой одного имени алгоритма. Провайдер, версия, политика JVM или .NET и источник ключа должны образовывать проверенную цепочку. Если организация требует сертифицированный модуль, тестовая подпись стандартным провайдером не подтверждает соответствие производственной среды.
PDF/A: архивный профиль, цвет и метаданные
PDF/A накладывает ограничения, обеспечивающие воспроизводимость документа без внешних зависимостей. При создании PdfADocument выбирают часть и уровень соответствия, передают профиль вывода ICC и встраивают необходимые шрифты. Обычный PDF нельзя сделать архивным простым присвоением метаданных: запрещённые действия, невстроенные ресурсы, прозрачность в старых профилях и несоответствующие цветовые пространства должны быть устранены.
PDF/A-1, PDF/A-2, PDF/A-3 и их уровни решают разные задачи. PDF/A-3 допускает вложения произвольного типа, что используют для электронных счетов с машинно-читаемыми данными. PDF/A-1 имеет более строгие ограничения, связанные с более ранней моделью PDF. Выбирать профиль следует по требованиям получателя, а не по принципу самый новый всегда лучше: ведомственная система может принимать только конкретный уровень.
Исключение conformance появляется в момент добавления объекта или закрытия документа. Его нельзя глушить и считать файл корректным. Сообщение обычно указывает на шрифт, цвет, действие или словарь. Исправление заключается в замене ресурса либо изменении способа формирования. После успешного закрытия документ всё равно проверяют независимым валидатором, потому что бизнес-процесс может требовать дополнительные правила сверх базового стандарта.
XMP-метаданные содержат идентификаторы профиля, название, автора и пользовательские схемы. Значения должны согласовываться с Info dictionary и фактическим содержимым. Для вложения указывают имя, описание, MIME-тип и отношение AFRelationship. Неполные метаданные могут не мешать открытию, но привести к отказу архивной системы.

PDF/UA и доступная структура документа
PDF/UA требует логической структуры, по которой экранный диктор понимает порядок чтения, роли заголовков, списков, таблиц и изображений. Включение tagged PDF создаёт основу, но не гарантирует доступность. Элементам назначают корректные роли, изображениям — альтернативный текст, декоративные объекты помечают как артефакты, а язык документа задают явно. В таблице нужно различать заголовочные и обычные ячейки.
Порядок тегов должен соответствовать смыслу, а не только визуальному расположению. Абсолютно позиционированный боковой блок способен попасть в дерево раньше основного текста. Проверять следует одновременно панель тегов, порядок чтения и работу экранного диктора. Автоматический валидатор обнаруживает формальные нарушения, но не оценивает качество альтернативного описания или понятность ссылок.
Прямое рисование PdfCanvas не получает семантику автоматически. Перед операциями содержимого открывают marked content с подходящей ролью либо объявляют объект артефактом, если он декоративен. Непомеченная линия может быть допустима как артефакт, а текстовый штамп без тега нарушит порядок чтения. Поэтому документ, где много низкоуровневого рисования, требует отдельного плана тегирования.
Доступный документ не должен зависеть только от цвета. Ошибка в форме обозначается текстом, ссылка имеет осмысленную подпись, а контраст проверяется отдельно. iText записывает структуру и оформление, но выбор понятных формулировок остаётся задачей приложения. Тестирование на одном валидаторе не заменяет пользовательскую проверку.

Штрихкоды, QR-коды и машинно-читаемые элементы
Модуль barcodes создаёт одномерные и двумерные коды, включая QR. Объект штрихкода формирует Form XObject, который затем добавляют как Image или рисуют на PdfCanvas. Векторное представление остаётся чётким при печати и обычно предпочтительнее заранее созданной картинки. Размер модуля, тихая зона и контраст определяют считываемость.
Данные перед кодированием валидируют по правилам конкретного стандарта. Контрольная сумма может рассчитываться библиотекой, но бизнес-формат номера, допустимые символы и длина остаются ответственностью приложения. Для QR следует выбрать уровень коррекции ошибок с учётом плотности и возможного повреждения. Слишком большой объём в маленьком прямоугольнике создаёт мелкие модули, которые не считываются после печати.
Код проверяют физическим сканером на реальном принтере и носителе, а не только камерой с экрана. Масштабирование PDF-просмотрщиком, растрирование драйвером и низкое качество бумаги влияют на результат. Подпись под штрихкодом выводят отдельно, чтобы человек мог проверить значение; она не должна расходиться с закодированными данными.
Преобразование HTML и CSS через pdfHTML
Преобразование HTML относится к отдельному компоненту pdfHTML, который использует iText Core для создания PDF. ConverterProperties задаёт base URI, поставщика шрифтов, обработчики тегов и ресурсов. Base URI критичен для относительных путей CSS, изображений и шрифтов: если он не указан или указывает не туда, текст появится, а оформление и картинки пропадут без ожидаемого результата.
HTML для браузера и HTML для печатного документа имеют разные ограничения. Скрипты не выполняются, интерактивная модель браузера отсутствует, а часть CSS поддерживается иначе. Надёжнее использовать контролируемый шаблон, встроенные стили и фиксированный набор компонентов, чем принимать произвольную страницу из интернета. Перед обновлением зависимостей набор эталонных шаблонов сравнивают визуально.
Метод ConvertToPdf сразу записывает документ, а ConvertToElements возвращает элементы, которые можно встроить в существующий Layout-процесс. Второй вариант удобен для общего колонтитула и объединения HTML-фрагмента с таблицами, созданными API. Однако преобразованные элементы могут иметь собственные margin и width, поэтому после вставки проверяют фактическую область и каскад стилей.
Шрифты веб-страницы не появляются в PDF автоматически только потому, что имя указано в CSS. FontProvider должен знать файл и правила сопоставления. Относительная ссылка на @font-face также зависит от base URI и доступа к ресурсу. В закрытом серверном процессе лучше заранее загрузить утверждённые шрифты и запретить непредсказуемые сетевые запросы.



Производительность и расход памяти
Производительность определяется не только числом страниц. Сканированные изображения нагружают память и ввод-вывод, сложные шрифты требуют обработки глифов, огромные таблицы создают много рендереров, а слияние ресурсов может потребовать сравнения объектов. Измерять следует на документах, похожих на производственные, с прогревом JVM или .NET и отдельной фиксацией времени чтения, компоновки, закрытия и записи.
Не нужно читать весь входной файл в byte[] без необходимости. PdfReader умеет работать с потоком или random access, а результат можно направлять в файловый поток. Поток памяти оправдан для небольшого ответа, но десятки одновременных документов умножают расход. В сервере устанавливают лимиты размера, числа страниц, разрешения изображений и времени обработки.
Immediate flush уменьшает количество объектов Layout в памяти, но ограничивает возможность вернуться к уже записанному элементу. Сложные функции, которым нужен итоговый номер страницы или перерасчёт, решают через события, заполнители либо второй проход. Нельзя включать сброс механически, если алгоритм позднее меняет рендереры.
Full compression и smart mode влияют на структуру и размер, но не всегда ускоряют процесс. Сжатие требует процессорного времени, а интеллектуальное повторное использование — памяти. Для архива из одинаковых шаблонов выигрыш может быть заметным, для уникальных сканов — минимальным. Параметры writer выбирают после сравнения и сохраняют в конфигурации, чтобы результат не менялся случайно между узлами.
Один PdfDocument не рассчитан на одновременную запись из нескольких потоков. Параллелизм организуют на уровне независимых документов, каждому заданию выделяют собственные reader, writer, шрифты и состояние обработчиков. Общий кэш неизменяемых байтов шрифта возможен, но объекты, привязанные к конкретному PdfDocument, нельзя переносить между потоками без проверки.
Надёжная обработка недоверенных PDF
PDF — сложный контейнер с потоками, ссылками, фильтрами, вложениями и действиями. Файл от внешнего пользователя обрабатывают как недоверенный: ограничивают размер, число объектов, глубину вложенности и время, запускают в изолированном процессе и обновляют библиотеку при исправлениях безопасности. Расширение .pdf не подтверждает формат; сначала проверяют сигнатуру и успешное открытие Reader.
Шифрованный документ, повреждённая xref-таблица или поток с огромным коэффициентом распаковки может создать отказ в обслуживании. Пакетный сервис должен уметь отменять задание и удалять временные файлы. Ошибка одного входа не должна оставлять общий writer открытым или блокировать очередь. Журнал фиксирует идентификатор задания, класс исключения и этап, но не записывает пароли и содержимое конфиденциального документа.
Внешние ссылки, вложения и JavaScript при переносе страниц могут остаться активными. Если задача состоит в безопасной публикации, необходима отдельная политика очистки: удалить ненужные действия, вложения, аннотации, метаданные и невидимые слои, затем проверить результат. Простое открытие и повторное сохранение не является санитизацией.
Лицензирование AGPL и коммерческое применение
Открытая поставка iText 7 распространяется по AGPL. Для приложения, которое взаимодействует с пользователями по сети или распространяется как часть продукта, эта лицензия может требовать предоставить соответствующий исходный код всего производного решения на условиях AGPL. Закрытая внутренняя сборка не следует автоматически считать исключением: архитектуру, способ предоставления сервиса и модификации нужно оценивать вместе с ответственным за лицензии.
Коммерческая лицензия снимает обязанность раскрывать закрытый код в пределах договорных условий и может включать поддержку. Решение принимают до внедрения, а не после выпуска продукта. В репозитории сохраняют сведения о выбранной модели, перечень пакетов и текст лицензии; в CI проверяют, что не подтянута несовместимая зависимость или компонент, на который договор не распространяется.
AGPL не запрещает коммерческое использование и не делает библиотеку бесплатной от любых обязательств. Она задаёт условия предоставления исходного кода. С другой стороны, покупка лицензии не заменяет соблюдение правил шрифтов, сертификатов, данных и сторонних библиотек. Юридическое решение должно опираться на конкретный способ распространения, а техническая команда обязана дать точную карту зависимостей.
Диагностика сборки и запуска
Класс или метод не найден
NoClassDefFoundError обычно означает, что модуль отсутствует во время запуска, хотя был доступен компилятору. Проверяют scope зависимости, содержимое итогового JAR, контейнер приложения и дерево транзитивных пакетов. NoSuchMethodError чаще указывает на несовпадение версий: код скомпилирован против одного API, а загрузчик выбрал другую DLL или JAR. Очистка каталога сборки без выравнивания зависимостей лишь временно скрывает причину.
Предупреждение системы журналирования
Сообщение об отсутствии реализации SLF4J не обязательно мешает созданию PDF, но лишает диагностических записей. В приложение добавляют один подходящий binding и не смешивают несколько провайдеров. В библиотечном модуле не следует жёстко навязывать реализацию журналирования конечному приложению. Для C# аналогично настраивают провайдер Microsoft.Extensions.Logging на уровне хоста.
Файл создан, но не открывается
Сначала проверяют, закрыты ли Document и PdfDocument, завершён ли поток и не записан ли рядом текстовый ответ или JSON. Затем смотрят первые байты, размер и конец файла. Если PDF передавался по HTTP, ошибка может находиться в заголовках или преждевременном завершении ответа. Локально сформированный эталон помогает отделить код создания от транспортного слоя.
Разные результаты на двух компьютерах
Наиболее частые причины — разные шрифты, локаль, часовой пояс, плавающие версии зависимостей и порядок данных без сортировки. Для воспроизводимости шрифты включают в поставку, даты форматируют с явной зоной, числа — с нужной культурой, а запрос задаёт стабильный порядок. Сравнивать бинарные PDF побайтно не всегда правильно из-за идентификаторов и дат; лучше проверять извлечённые данные и визуальный эталон.
Ошибки верстки и способы их локализовать
Если элемент исчез, сначала определяют, был ли он добавлен в нужный Document и на нужную страницу. Затем временно включают рамку, фон и фиксированный контрастный цвет. Для absolute/fixed position проверяют координаты и CropBox; для поточной верстки — доступную область, margin, width, keep together и overflow. Такой пошаговый метод быстрее случайного изменения размера шрифта.
Бесконечное предупреждение о невозможности разместить элемент возникает, когда рендерер возвращает остаток, который не помещается даже на пустой странице. Причиной бывают фиксированная высота меньше содержимого, слишком большие поля, таблица с неделимой строкой или пользовательский renderer с неверным LayoutResult. Нужно получить минимальный пример и удалить ограничения по одному.
Обрезанный текст внутри ячейки часто связан с SetHeight вместо SetMinHeight или с собственным leading. Если требуется минимальная строка, задают min-height и разрешают рост. Если высота обязана быть фиксированной, приложение должно заранее уменьшать или сокращать значение по правилам, а не ожидать, что движок поместит любое содержание.
Неправильный порядок слоёв диагностируют просмотром content streams и временной прозрачностью. Белая подложка, добавленная поверх исходного текста, скрывает его; водяной знак, добавленный перед непрозрачным фоном страницы, не виден. Выбор потока до или после существующего содержимого должен быть частью явного алгоритма.
Проверка результата и автоматические тесты
Тест PDF должен проверять смысл, структуру и внешний вид на разных уровнях. На уровне данных извлекают текст, число страниц, размеры, поля формы, метаданные и наличие подписи. На уровне структуры проверяют теги, закладки, вложения и соответствие профилю. На визуальном уровне страницы растрируют в стабильной среде и сравнивают с эталоном с допуском, чтобы заметить сдвиг, исчезновение глифа или изменение таблицы.
Бинарное равенство полезно только для строго детерминированного процесса. Даты создания, document ID, порядок косвенных объектов и контейнер подписи делают файлы различными при одинаковом виде. Лучше установить набор инвариантов: текст содержит обязательные реквизиты, страница имеет нужный размер, поле заполнено, валидатор не выдаёт ошибок, а визуальная разница ниже порога.
Эталонные файлы должны включать крайние случаи: пустое значение, очень длинное имя, кириллицу, символы вне основного шрифта, таблицу на несколько страниц, повёрнутый лист, зашифрованный вход, форму с повторяющимися именами и повреждённый документ. Тест только на Hello World подтверждает подключение пакета, но не качество рабочего процесса.
После изменения зависимости тесты запускают в той же версии JVM или .NET, что используется в эксплуатации. Отдельно проверяют лицензионную конфигурацию и криптографический провайдер. Для подписи полезен локальный тестовый центр сертификации, чтобы не зависеть от внешнего сервиса и не использовать производственный ключ.
Практический сценарий: отчёт из базы данных
Отчёт строят как конвейер. Сначала приложение получает и валидирует данные, затем создаёт PdfDocument и Document с утверждёнными шрифтами и полями. Заголовок и параметры отчёта добавляются абзацами, основная выборка — large table с повторяющейся шапкой, итоговые значения — отдельным блоком, а обработчик событий выводит номер страницы и идентификатор отчёта.
- Зафиксировать порядок строк запроса, формат дат и чисел, чтобы повторный запуск давал одинаковое содержание.
- Загрузить шрифты до начала добавления элементов и проверить наличие глифов для всех языков.
- Определить ширины колонок на худших значениях, а не на среднем примере.
- Записывать результат во временный путь и публиковать только после успешного Close.
- Проверить число страниц, контрольную сумму и обязательные реквизиты перед выдачей файла.
Если отчёт должен подписываться, подпись выполняют после полного формирования и проверки. Если нужен PDF/A, PdfADocument создают с самого начала, потому что исправлять несоответствия постфактум сложнее. Для доступности таблица получает заголовочные роли, а диаграммы — альтернативные описания. Эти требования лучше включить в шаблон, чем добавлять в конце проекта.
Практический сценарий: пакетное заполнение форм
Для каждого получателя открывают чистую копию шаблона, получают PdfAcroForm и сопоставляют данные с полными именами полей. Перед записью проверяют обязательность, длину и допустимые варианты. Значения устанавливают до flatten, затем обновляют appearance и создают отдельный окончательный файл. Один PdfDocument нельзя повторно использовать для разных получателей, иначе данные и ресурсы смешаются.
Поля с одинаковым именем ожидаемо синхронизируются. Checkbox требует экспортное значение, которое может называться не Yes; его получают из структуры поля. Для многострочного текста у поля должен быть соответствующий флаг и достаточный прямоугольник. Автоматическое уменьшение шрифта удобно, но слишком длинный текст станет нечитаемым, поэтому бизнес-ограничение длины всё равно необходимо.
После flatten приложение повторно открывает файл и проверяет, что интерактивных полей не осталось, а извлечённый текст содержит критические значения. Если документ затем подписывается, любые исправления требуют нового формирования и новой подписи. Нельзя дорисовывать пропущенное значение поверх уже подписанного файла обычным writer.
Практический сценарий: объединение досье
Досье часто собирается из титульного листа, анкеты, сканов и приложений. До слияния каждый вход классифицируют: размер страницы, rotation, наличие формы, подписи, шифрования, вложений и закладок. Файлы с паролем обрабатывают отдельно, повреждённые не включают молча. Для каждого раздела создают пункт outline и внутреннее назначение на первую страницу.
Разные размеры страниц можно сохранить, если получатель умеет с ними работать, либо нормализовать размещением страницы как Form XObject на новом стандартном листе. Второй подход меняет интерактивность и может превратить аннотации в проблему, поэтому решение принимают до реализации. Простое изменение MediaBox не масштабирует существующее содержимое.
После объединения проверяют последовательность, видимость штампов, рабочие ссылки и отсутствие конфликтов полей. Если исходные подписи должны сохранять проверяемость, копирование страниц в новый документ обычно не сохраняет подпись всего исходного файла как подпись нового контейнера; исходник разумнее прикрепить как вложение или хранить отдельно. Юридическая модель должна быть определена заранее.
Практический сценарий: штамп на входящих документах
Штамп с датой, номером и ответственным добавляют в новый поток после существующего содержимого. Область выбирают по CropBox и rotation, а текст размещают Canvas внутри фиксированного прямоугольника. Перед записью приложение может проверить пересечение с известной зоной, но в произвольном PDF гарантировать свободное место без анализа содержимого нельзя.
Чтобы знак не закрывал текст, используют полупрозрачную рамку, небольшое поле у края или отдельную новую страницу. Белый непрозрачный фон допустим только при осознанном перекрытии. Если штамп должен быть частью юридической подписи, изображение и текст включают в appearance подписи до криптографической операции, а не дорисовывают после неё.
Пакетный процесс сохраняет исходник, выход и журнал. При ошибке формируется отдельный статус, а не нулевой PDF. Контрольная сумма связывает запись журнала с конкретным файлом. Личные данные в тексте штампа не должны попадать в технические логи.
Что относится к ядру, а что требует дополнительных компонентов
Ядро закрывает создание и изменение PDF, Layout, страницы, формы AcroForm, подписи, шифрование, PDF/A, базовое тегирование, штрихкоды и SVG. Преобразование HTML/CSS выполняет pdfHTML. OCR для сканов, гарантированное удаление конфиденциальных областей, сложная типографика отдельных письменностей, оптимизация, рендеринг PDF в изображения и работа с XFA относятся к специализированным компонентам.
Это разделение важно при проектировании зависимостей и лицензий. Наличие класса в примере из документации не означает, что он входит в базовый пакет. Перед реализацией проверяют namespace или package, артефакт менеджера зависимостей и условия использования. В противном случае прототип работает у разработчика с полным набором, а чистая сборка падает из-за отсутствующего модуля.
Интеграцию дополнительного компонента тестируют отдельно от ядра. Например, при HTML-конвертации эталонный набор должен охватывать CSS и ресурсы; при OCR — языки и качество сканов; при редактировании конфиденциальных данных — поиск остаточного текста и объектов. Универсальный тест PDF открылся недостаточен.
Сравнение iText 7 с аналогами
Выбор инструмента зависит от того, требуется ли ручное редактирование, генерация отчётов, глубокое изменение структуры, извлечение текста или соблюдение специальных PDF-стандартов. Ниже сопоставлены решения, которые пересекаются по задачам, но используют разные модели работы.
| Программа | Лучше подходит для | Главное ограничение |
|---|---|---|
| iText 7 | Программных PDF-процессов, форм, подписей, PDF/A и точного управления объектами | Требует кода и соблюдения AGPL либо коммерческой лицензии |
| PDF Commander | Ручного изменения текста, страниц, изображений и подписей пользователем | Не предназначен как серверный SDK для массовой автоматизации |
| Apache PDFBox | Открытой обработки и извлечения PDF в Java | Верстка сложных документов требует больше низкоуровневого кода |
| PDFsharp и MigraDoc | Отчётов и PDF-графики в проектах .NET | Узкая привязка к .NET и меньше профильных средств сложных стандартов |
| QuestPDF | Декларативной генерации отчётов на C# | Ориентирован прежде всего на создание, а не глубокую правку произвольного PDF |
| Aspose.PDF | Широкого коммерческого API и конвертации в Java или .NET | Для результата без оценочных ограничений нужна платная лицензия |
PDF Commander разумнее выбрать, когда документ нужно открыть и исправить вручную без написания приложения. QuestPDF удобен для нового отчёта с выразительной C#-разметкой, PDFsharp с MigraDoc — для традиционного .NET-сценария, а PDFBox — для Java-проекта, где приоритетом является открытая лицензия Apache и допускается более низкоуровневая работа. iText 7 предпочтителен, когда один процесс объединяет генерацию, разбор, формы, подпись, архивный профиль и точную работу со структурой. Aspose.PDF рассматривают, если нужен широкий коммерческий набор конвертаций и устраивает его модель лицензирования.
Как выбрать архитектуру проекта с iText 7
Не следует распределять вызовы PDF API по контроллерам и бизнес-классам. Лучше выделить слой формирования документа с понятными входными моделями: данные отчёта, настройки языка, профиль соответствия, параметры защиты и назначение результата. Этот слой не должен сам получать данные из базы или отправлять HTTP-ответ; тогда его можно тестировать на фиксированном наборе моделей.
Шаблон документа оформляют как набор компонентов: заголовок, карточка реквизитов, таблица, подпись, колонтитул. Каждый компонент получает стили и возвращает Layout-элемент либо рисует в явно переданную область. Шрифты, цвета и размеры хранятся в теме, а не дублируются числами. Такой подход снижает расхождения и упрощает смену фирменного оформления.
Низкоуровневые операции отделяют от компоновки. Класс для слияния страниц не должен знать о стилях абзаца, а модуль подписи — о запросе базы данных. Обработка исключений переводит технические ошибки в стабильные статусы: неверный пароль, повреждённый PDF, нехватка глифа, нарушение PDF/A, отказ ключевого хранилища. Пользователь не должен получать полный stack trace, но журнал сохраняет его с идентификатором задания.
Конфигурация включает фиксированные версии пакетов, допустимые размеры входов, каталог шрифтов, временный каталог, тайм-ауты, режим writer и лицензионные параметры. Секреты и пароли размещают в защищённом хранилище. На старте сервис может выполнить самопроверку: сформировать маленький PDF, загрузить шрифт и проверить доступность криптографического провайдера.
Контрольный список перед вводом процесса в эксплуатацию
- Все модули iText имеют согласованные версии, а дерево зависимостей не содержит старых дубликатов.
- Шрифты поставляются вместе с приложением, поддерживают нужные символы и разрешены для встраивания.
- Вход и выход никогда не используют один путь; временные файлы удаляются при сбое.
- PdfDocument закрывается во всех ветвях, а выдача файла начинается только после успешного завершения.
- Большие изображения, страницы и таблицы ограничены; память и время измерены на худшем наборе.
- PDF/A и PDF/UA проверяются независимыми валидаторами, а не только отсутствием исключения.
- Подпись выполняется последней допустимой операцией, последующие изменения идут в append mode.
- Пароли и ключи не хранятся в коде и не попадают в журнал.
- Лицензионная модель документирована для конкретной архитектуры распространения или сетевого доступа.
- Автотесты проверяют текст, структуру, формы, подписи и визуальный результат на крайних данных.
После выполнения этих пунктов iText 7 становится не набором разрозненных вызовов, а управляемым конвейером документов. Его сильная сторона — точное программное управление PDF и возможность повторить операцию на любом объёме данных. Надёжность достигается не количеством методов, а дисциплиной: явным выбором уровня API, стабильными ресурсами, корректным закрытием, независимой валидацией и тестами на реальных входах.
Итоговый рабочий подход
Для нового документа начинайте с Layout API и переходите к PdfCanvas только там, где действительно нужны фиксированные координаты. Для существующего PDF сначала определите, требуется ли дорисовка, работа с объектами, извлечение текста или полная переверстка; эти задачи используют разные алгоритмы. Шрифты и кодировки проверяйте до массового запуска, таблицы испытывайте на самых длинных данных, а страницы с rotation включайте в тестовый набор.
Формы заполняйте по полным именам и допустимым состояниям, flatten выполняйте после проверки appearance. Архивный профиль задавайте при создании PdfADocument, доступность проектируйте через теги и альтернативные описания, а подпись добавляйте после окончания всех разрешённых изменений. HTML-конвертацию рассматривайте как отдельный контролируемый этап с base URI, собственными шрифтами и набором поддерживаемых шаблонов.
При сбое сначала локализуйте уровень: зависимость, чтение входа, компоновка, запись, закрытие, транспорт или проверка. Минимальный воспроизводимый документ и явный журнал этапов почти всегда полезнее попытки исправить всё одним параметром. С таким процессом iText 7 позволяет выпускать предсказуемые PDF, которые сохраняют заданную структуру, проходят автоматические проверки и корректно обрабатываются дальше в документообороте.