Среди всех форматов PDF (Portable Document Format) заслуженно занимает особое место. Этот формат, созданный компанией Adobe, превратился в универсальный стандарт для обмена документами, не зависящий от программного и аппаратного обеспечения. Именно поэтому умение программно создавать PDF стало необходимым навыком для разработчиков корпоративных приложений.
Обзор возможностей библиотеки iText
Библиотека iText — один из самых функцоинальных инструментов для работы с PDF в экосистеме Java. Она предоставляет широкий спектр функций:- Создание PDF-документов с нуля.
- Манипулирование существующими файлами (объединение, разделение).
- Добавление различного контента: текст, изображения, таблицы.
- Работа с формами и их заполнение.
- Шифрование и применение цифровых подписей.
- Добавление водяных знаков и элементов оформления.
- Создание навигации (закладки, оглавления).
- Извлечение текста и данных из PDF-файлов.
Яркая черта iText — высокоуровневые конструкции, делающие создание даже сложных документов интуитивно понятным процессом.
как создать pdf документ с помощю iText.jar без bookmark части? как создать pdf документ с помощю iText.jar без bookmark части? Конвертация html в pdf при помощи библиотеки iText... Подскажите пожалуйста существует ли инструмент конвертации html в pdf при помощи библиотеки iText. iText: html to PDF Помогите. Нужно сделать преобразование (программно) из готового html файлика в PDF.
Нашел статью,... Растягивание элемента по высоте и выравнивание колонок в iText 7 PDF Доброго времени суток, Господа. Заранее извиняюсь, если пишу не в тот раздел - сам пишу на C#,...
Краткая история развития и версии
История iText началась в 2000 году благодаря бельгийскому программисту Бруно Лоуэги. За прошедшие годы библиотека прошла значительный путь развития:
iText 1.x и 2.x: Базовая функциональность, распространялась под свободной лицензией,
iText 5.x: Значительное обновление архитектуры, изменение лицензионной политики,
iText 7.x: Текущая версия с модульной структурой и улучшенным API.
В 2008 году была основана компания iText Group, взявшая на себя дальнейшее развитие библиотеки и предоставление коммерческой поддержки.
Установка и настройка среды разработки
Интеграция iText в Java-проект достаточно проста. Существует несколько способов добавить библиотеку:
Maven
XML | 1
2
3
4
5
6
| <dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext7-core</artifactId>
<version>7.2.3</version>
<type>pom</type>
</dependency> |
|
Gradle
Code | 1
| implementation 'com.itextpdf:itext7-core:7.2.3' |
|
Прямое добавление JAR-файлов
Можно скачать необходимые JAR-файлы с официального сайта и добавить их в classpath проекта.
Для базовой работы с iText обычно достаточно основного модуля, но для расширенных возможностей (например, конвертации HTML в PDF) понадобятся дополнительные зависимости.
Альтернативные библиотеки и их сравнение с iText
На рынке инструментов для работы с PDF в Java существуют несколько альтернатив:
1. Apache PDFBox — библиотека с открытым исходным кодом под лицензией Apache 2.0. Обладает хорошей функциональностью, но уступает iText в производительности и требует больше кода для выполнения аналогичных задач.
2. OpenPDF — форк ранней версии iText (4.2.0), поддерживаемый сообществом под лицензией LGPL/MPL. Предлагает базовую функциональность, но отстаёт от iText 7 в современных возможностях.
3. DynamicPDF — коммерческая библиотека с обширной функциональностью и поддержкой.
iText выделяется своей производительностью, обширной документацией и активной поддержкой. Однако существенный недостаток связан с её лицензионной политикой.
Лицензионная политика и ограничения использования iText
С версии 5.0 iText перешла на двойную лицензионную модель:
AGPL v3 — для проектов с открытым исходным кодом,
Коммерческая лицензия — для закрытых и коммерческих проектов.
Лицензия AGPL требует, чтобы любое приложение, использующее iText, также распространялось под AGPL и предоставляло исходный код. Это включает и веб-приложения, которые "распространяются" через сеть.
Эти ограничения делают iText проблематичной для использования в коммерческих проектах без покупки лицензии. Стоимость коммерческой лицензии начинается от нескольких тысяч долларов в год, что может быть существенным барьером для небольших компаний и стартапов.
Базовые операции с PDF
После установки iText можно приступать к созданию PDF документов. В этом разделе мы рассмотрим основные операции, которые позволят вам быстро освоить работу с библиотекой и начать создавать собственные документы.
Создание пустого документа
Создание PDF документа в iText начинается с инициализации нескольких ключевых классов. Основная последовательность действий выглядит следующим образом:
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.layout.Document;
public class CreateEmptyPdf {
public static void main(String[] args) {
try {
// Инициализация PdfWriter
String dest = "empty_document.pdf";
PdfWriter writer = new PdfWriter(dest);
// Инициализация PdfDocument
PdfDocument pdf = new PdfDocument(writer);
// Инициализация Document
Document document = new Document(pdf);
// Закрытие документа
document.close();
System.out.println("PDF создан успешно!");
} catch (Exception e) {
e.printStackTrace();
}
}
} |
|
В этом примере:
PdfWriter отвечает за запись данных в файл,
PdfDocument связывает физический документ с его логической структурой,
Document представляет высокоуровневый контейнер, куда добавляются все элементы.
Обратите внимание, что метод close() критически важен — без него документ может оказаться повреждённым или неполным.
Добавление текстового содержимого
Пустой документ не представляет большой ценности. Давайте добавим в него текстовое содержимое. В iText текст обычно добавляется с помощью класса Paragraph :
Java | 1
2
3
4
5
6
7
8
9
10
11
12
| // Создание документа как в предыдущем примере
Document document = new Document(pdf);
// Добавление параграфа
document.add(new Paragraph("Это мой первый PDF, созданный с помощью iText!"));
// Добавление нескольких параграфов
document.add(new Paragraph("Это второй параграф."));
document.add(new Paragraph("А это уже третий параграф."));
// Закрытие документа
document.close(); |
|
Класс Paragraph представляет логический абзац текста. Внутри параграфа можно использовать класс Text для более тонкого контроля над стилизацией отдельных фрагментов:
Java | 1
2
3
4
| Paragraph paragraph = new Paragraph();
paragraph.add(new Text("Обычный текст, "));
paragraph.add(new Text("а это будет выделено жирным.").setBold());
document.add(paragraph); |
|
Форматирование и стилизация текста
iText предоставляет богатый набор возможностей для форматирования текста. Основные операции стилизации включают:
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| // Создание параграфа с различными стилями
Paragraph styledParagraph = new Paragraph();
// Жирный текст
Text boldText = new Text("Жирный текст. ").setBold();
styledParagraph.add(boldText);
// Курсив
Text italicText = new Text("Курсивный текст. ").setItalic();
styledParagraph.add(italicText);
// Подчёркнутый текст
Text underlineText = new Text("Подчёркнутый текст. ").setUnderline();
styledParagraph.add(underlineText);
// Изменение размера шрифта
Text sizedText = new Text("Текст другого размера. ").setFontSize(20);
styledParagraph.add(sizedText);
// Изменение цвета текста
Text coloredText = new Text("Цветной текст.").setFontColor(ColorConstants.RED);
styledParagraph.add(coloredText);
document.add(styledParagraph); |
|
Выравнивание текста устанавливается для всего параграфа:
Java | 1
2
3
4
5
6
7
| Paragraph centeredParagraph = new Paragraph("Этот текст будет выровнен по центру.")
.setTextAlignment(TextAlignment.CENTER);
document.add(centeredParagraph);
Paragraph rightParagraph = new Paragraph("А этот текст будет выровнен по правому краю.")
.setTextAlignment(TextAlignment.RIGHT);
document.add(rightParagraph); |
|
Работа с шрифтами
По умолчанию iText использует стандартные шрифты PDF (Helvetica, Times-Roman, Courier). Однако для большего контроля над внешним видом документа, особенно при работе с многоязычными текстами, часто требуется использовать пользовательские шрифты.
Java | 1
2
3
4
5
6
7
| // Загрузка шрифта TTF
PdfFont font = PdfFontFactory.createFont("path/to/font.ttf", PdfEncodings.IDENTITY_H, true);
// Использование шрифта
Paragraph customFontParagraph = new Paragraph("Текст с пользовательским шрифтом.")
.setFont(font);
document.add(customFontParagraph); |
|
Параметр PdfEncodings.IDENTITY_H позволяет использовать Юникод, что критически важно для работы с нелатинскими алфавитами. Третий параметр (true ) указывает на необходимость встраивания шрифта в документ, что гарантирует его корректное отображение на любом устройстве.
iText также позволяет регистрировать и использовать семейства шрифтов:
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
| FontProgram fontProgram = FontProgramFactory.createFont("path/to/regular.ttf");
FontProgram boldFontProgram = FontProgramFactory.createFont("path/to/bold.ttf");
// Регистрация семейства шрифтов
FontSet fontSet = new FontSet();
FontFamily family = fontSet.addFontFamily("CustomFamily");
family.setNormal(fontProgram);
family.setBold(boldFontProgram);
// Использование
Paragraph p = new Paragraph("Обычный текст, ")
.setFontFamily("CustomFamily");
p.add(new Text("жирный текст").setBold());
document.add(p); |
|
Работа с метаданными PDF документа
Метаданные PDF документа включают такие свойства как автор, заголовок, ключевые слова и другие атрибуты. Эти данные помогают в организации и категоризации документов, а также используются поисковыми системами для индексации.
Java | 1
2
3
4
5
6
7
8
9
| // Получение объекта метаданных
PdfDocumentInfo info = pdf.getDocumentInfo();
// Установка основных метаданных
info.setTitle("Пример документа с iText");
info.setAuthor("Иван Иванов");
info.setSubject("PDF программирование");
info.setKeywords("Java, iText, PDF");
info.setCreator("Моё приложение"); |
|
Помимо стандартных полей, можно добавлять и собственные метаданные:
Java | 1
| info.setMoreInfo("CustomField", "Пользовательское значение"); |
|
Управление страницами
В реальных документах обычно требуется управлять страницами — добавлять новые, настраивать их размеры и ориентацию.
Для добавления новой страницы используется метод:
Java | 1
2
| // Добавление новой страницы
pdf.addNewPage(); |
|
Можно также задать размер и ориентацию при добавлении страницы:
Java | 1
2
3
4
5
| // Добавление страницы A4 с альбомной ориентацией
pdf.addNewPage(PageSize.A4.rotate());
// Страница произвольного размера (ширина x высота в пунктах)
pdf.addNewPage(new PageSize(595, 842)); |
|
Для получения доступа к конкретной странице используются методы:
Java | 1
2
3
4
5
6
7
8
| // Получение первой страницы
PdfPage firstPage = pdf.getFirstPage();
// Получение страницы по номеру (нумерация начинается с 1)
PdfPage secondPage = pdf.getPage(2);
// Общее количество страниц
int pageCount = pdf.getNumberOfPages(); |
|
Добавление гиперссылок и интерактивных элементов
Гиперссылки делают PDF документы интерактивными. С их помощью можно создавать навигацию как внутри документа, так и переходы на внешние ресурсы.
Java | 1
2
3
4
5
6
| // Создание текстовой ссылки
Link link = new Link("Перейти на сайт",
PdfAction.createURI("https://www.example.com"));
Paragraph p = new Paragraph();
p.add(link);
document.add(p); |
|
Для создания ссылки на определённую страницу внутри документа:
Java | 1
2
3
4
| // Ссылка на страницу 3
Link internalLink = new Link("Перейти на страницу 3",
PdfAction.createGoTo(PdfExplicitDestination.createFit(3)));
document.add(new Paragraph().add(internalLink)); |
|
Закладки (или "букмарки") — ещё один важный элемент навигации в PDF:
Java | 1
2
3
4
5
6
7
| // Создание закладки
PdfOutline rootOutline = pdf.getOutlines(false);
PdfOutline firstChapter = rootOutline.addOutline("Глава 1");
firstChapter.addOutline("Раздел 1.1");
// Устанавливаем действие для закладки (переход на страницу 2)
firstChapter.addAction(PdfAction.createGoTo(
PdfExplicitDestination.createFit(2))); |
|
Добавление колонтитулов и нумерации страниц
Часто требуется добавлять в PDF-документы колонтитулы и нумерацию страниц, особенно для длинных отчётов или технической документации. iText предоставляет удобные механизмы для решения этих задач через обработчики событий.
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| // Создание обработчика для верхнего колонтитула
class HeaderHandler implements IEventHandler {
private String header;
public HeaderHandler(String header) {
this.header = header;
}
@Override
public void handleEvent(Event event) {
// Получение информации о текущей странице
PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
PdfPage page = docEvent.getPage();
Rectangle pageSize = page.getPageSize();
// Создание области для отрисовки
PdfCanvas canvas = new PdfCanvas(page);
// Отрисовка колонтитула
canvas.beginText()
.setFontAndSize(PdfFontFactory.createFont(StandardFonts.HELVETICA), 12)
.moveText(pageSize.getWidth() / 2 - 40, pageSize.getTop() - 20)
.showText(header)
.endText();
}
} |
|
Для автоматической нумерации страниц создаётся похожий обработчик:
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| // Обработчик для нумерации страниц
class PageNumberHandler implements IEventHandler {
@Override
public void handleEvent(Event event) {
PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
PdfDocument pdf = docEvent.getDocument();
PdfPage page = docEvent.getPage();
Rectangle pageSize = page.getPageSize();
// Формирование строки номера страницы
String pageNumber = String.format("Страница %d из %d",
pdf.getPageNumber(page), pdf.getNumberOfPages());
// Отрисовка номера
PdfCanvas canvas = new PdfCanvas(page);
canvas.beginText()
.setFontAndSize(PdfFontFactory.createFont(StandardFonts.HELVETICA), 10)
.moveText(pageSize.getWidth() / 2 - 40, 30) // Внизу страницы
.showText(pageNumber)
.endText();
}
} |
|
Регистрация обработчиков происходит через менеджер событий:
Java | 1
2
3
4
| // Получение менеджера событий
PdfDocumentEvent eventType = PdfDocumentEvent.END_PAGE;
pdf.addEventHandler(eventType, new HeaderHandler("Отчёт компании"));
pdf.addEventHandler(eventType, new PageNumberHandler()); |
|
Управление разрывами страниц и абзацев
Контролировать разбивку контента между страницами — одна из ключевых задач при создании форматированных документов. iText предлагает несколько способов управления разрывами:
Принудительное создание новой страницы
Java | 1
2
| // Явное добавление новой страницы
document.add(new AreaBreak(AreaBreakType.NEXT_PAGE)); |
|
Предотвращение разрыва абзаца
Можно запретить разрывать абзац между страницами, если его содержимое умещается на одной странице:
Java | 1
2
3
| Paragraph paragraph = new Paragraph("Этот абзац не будет разорван между страницами.")
.setKeepTogether(true);
document.add(paragraph); |
|
Контроль вдовы и сироты
"Вдовы" и "сироты" — типографские термины. "Вдова" — последняя строка абзаца, оказавшаяся одна на новой странице. "Сирота" — первая строка абзаца, оставшаяся одна в конце страницы.
Java | 1
2
3
4
| Paragraph paragraph = new Paragraph("Длинный текст абзаца...")
.setOrphanLines(2) // Минимум 2 строки "сироты"
.setWidowLines(2); // Минимум 2 строки "вдовы"
document.add(paragraph); |
|
Работа с отступами и позиционированием
В iText можно гибко настраивать отступы и позиционирование элементов, что позволяет создавать сложные макеты документов.
Настройка полей документа
При создании документа можно задать поля (отступы от края страницы):
Java | 1
2
3
| // Отступы: верх, право, низ, лево (в пунктах)
Document document = new Document(pdf, new PageSize(PageSize.A4), true);
document.setMargins(36, 72, 36, 72); |
|
Установка отступов для элементов
Для элементов контента также можно настраивать отступы:
Java | 1
2
3
4
5
| Paragraph paragraph = new Paragraph("Этот параграф имеет отступы со всех сторон.")
.setMargin(20) // Со всех сторон
.setMarginTop(30) // Дополнительно сверху
.setMarginLeft(50); // Дополнительно слева
document.add(paragraph); |
|
Абсолютное позиционирование
В некоторых случаях требуется разместить элемент в конкретной позиции страницы:
Java | 1
2
3
4
5
| // Текст в точных координатах
Text text = new Text("Позиционированный текст");
Paragraph p = new Paragraph(text)
.setFixedPosition(100, 200, 200); // x, y, ширина
document.add(p); |
|
Работа с аннотациями и комментариями
PDF-документы поддерживают различные типы аннотаций — интерактивные элементы, добавляющие дополнительную функциональность или информацию.
Добавление текстовой заметки
Java | 1
2
3
4
5
6
7
8
9
| // Создание аннотации-заметки
PdfTextAnnotation textAnnotation = new PdfTextAnnotation(
new Rectangle(100, 700, 20, 20))
.setTitle(new PdfString("Заголовок"))
.setContents("Это текстовое примечание к документу")
.setOpen(false); // Заметка будет отображаться как иконка
// Добавление аннотации к странице
pdf.getFirstPage().addAnnotation(textAnnotation); |
|
Выделение текста
Можно добавлять аннотации, которые визуально выделяют определённый текст:
Java | 1
2
3
4
5
6
7
8
9
10
| // Создание аннотации-выделения
PdfTextMarkupAnnotation highlight = new PdfTextMarkupAnnotation(
new Rectangle(100, 600, 250, 20))
.setQuadPoints(new float[]{100, 600, 350, 600, 100, 580, 350, 580})
.setTitle(new PdfString("Выделение"))
.setContents("Важный фрагмент")
.setColor(ColorConstants.YELLOW)
.setMarkupAnnotationType(PdfName.Highlight);
pdf.getFirstPage().addAnnotation(highlight); |
|
Добавление всплывающих подсказок
Java | 1
2
3
4
5
6
7
8
9
10
11
12
| // Создание всплывающей подсказки
Paragraph tooltipText = new Paragraph("Наведите на меня курсор");
document.add(tooltipText);
// Добавление popup-аннотации
Rectangle rect = new Rectangle(100, 550, 100, 20);
PdfPopupAnnotation popup = new PdfPopupAnnotation(rect)
.setTitle(new PdfString("Подсказка"))
.setContents("Дополнительная информация при наведении")
.setOpen(false);
pdf.getFirstPage().addAnnotation(popup); |
|
Работа с цветами и фоном
PDF-документы поддерживают богатое цветовое оформление, что позволяет создавать визуально привлекательные документы.
Установка цвета фона для страницы
Java | 1
2
3
4
5
6
| // Закрашивание всей страницы
Rectangle pageSize = pdf.getFirstPage().getPageSize();
PdfCanvas canvas = new PdfCanvas(pdf.getFirstPage());
canvas.rectangle(0, 0, pageSize.getWidth(), pageSize.getHeight());
canvas.setFillColor(ColorConstants.LIGHT_GRAY);
canvas.fill(); |
|
Цветные блоки и фоны для элементов
Java | 1
2
3
4
| // Параграф с цветным фоном
Paragraph coloredParagraph = new Paragraph("Текст на цветном фоне")
.setBackgroundColor(ColorConstants.LIGHT_GRAY, 10, 10, 10, 10); // Цвет + отступы
document.add(coloredParagraph); |
|
Работа с градиентами
Для более сложных эффектов можно использовать градиенты:
Java | 1
2
3
4
5
| // Создание градиента
PdfCanvas canvas = new PdfCanvas(pdf.getFirstPage());
PdfShading axial = PdfShading.simpleAxial(pdf, 100, 100, 400, 400,
ColorConstants.RED, ColorConstants.BLUE);
canvas.paintShading(axial); |
|
При работе с элементами макета, такими как параграфы, таблицы и изображения, важно понимать особенности режима обтекания и размещения элементов.
Java | 1
2
3
4
| // Настройка режима разрыва текста
Paragraph paragraph = new Paragraph("Длинный текст с настройкой переноса...")
.setHyphenation(new HyphenationConfig("ru", "RU", 3, 3));
document.add(paragraph); |
|
Управляя базовыми операциями в PDF-документах с помощью iText, вы создаёте прочный фундамент для разработки более сложных документов и отчётов. Понимание работы с текстом, его форматированием, страницами и интерактивными элементами — необходимый шаг перед освоением продвинутых техник, которые мы рассмотрим в следующих разделах.
Продвинутые техники
После освоения базовых операций с PDF документами пришло время изучить более сложные возможности iText. Продвинутые техники позволят создавать документы с богатым мультимедийным содержимым, сложной структурой и профессиональным оформлением.
Добавление изображений и графики
Внедрение изображений значительно повышает информативность и привлекательность документов. В iText работа с изображениями организована через класс Image .
Добавление растрового изображения
Java | 1
2
3
4
5
6
| // Загрузка изображения
ImageData imageData = ImageDataFactory.create("path/to/image.jpg");
Image image = new Image(imageData);
// Добавление изображения в документ
document.add(image); |
|
Поддерживаются основные графические форматы: JPEG, PNG, GIF, BMP, TIFF, а также векторный SVG.
Масштабирование и позиционирование
Java | 1
2
3
4
5
6
7
8
9
10
| Image image = new Image(ImageDataFactory.create("path/to/image.jpg"));
// Масштабирование по размеру
image.scaleToFit(300, 200);
// Или масштабирование в процентах от оригинала
image.scale(0.5f, 0.5f); // 50% по обеим осям
// Позиционирование
image.setFixedPosition(100, 400); // Координаты x, y |
|
Поворот и наклон изображения
Java | 1
2
3
4
5
6
7
| Image image = new Image(ImageDataFactory.create("path/to/image.jpg"));
// Поворот на 45 градусов
image.setRotationAngle(Math.PI / 4);
// Наклон (искажение) по осям
image.skew(15, 0); // Наклон по горизонтали |
|
Добавление векторной графики
iText поддерживает рисование примитивов напрямую через низкоуровневый API:
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| // Получение канвы для рисования
PdfCanvas canvas = new PdfCanvas(pdf.getFirstPage());
// Рисование прямоугольника
canvas.rectangle(100, 100, 200, 100);
canvas.setStrokeColor(ColorConstants.BLACK);
canvas.stroke();
// Рисование линии
canvas.moveTo(100, 300);
canvas.lineTo(300, 350);
canvas.stroke();
// Рисование круга
canvas.circle(200, 400, 50);
canvas.setFillColor(ColorConstants.RED);
canvas.fill(); |
|
Можно комбинировать разные фигуры, создавая сложные векторные изображения:
Java | 1
2
3
4
5
6
7
8
9
10
11
12
| PdfCanvas canvas = new PdfCanvas(pdf.getFirstPage());
// Создание пути
canvas.moveTo(100, 100);
canvas.lineTo(200, 150);
canvas.lineTo(300, 100);
canvas.closePath();
// Заливка и обводка
canvas.setFillColor(ColorConstants.BLUE);
canvas.setStrokeColor(ColorConstants.BLACK);
canvas.fillStroke(); |
|
Создание таблиц и списков
Таблицы и списки — одни из самых полезных элементов форматирования для структурированной информации.
Создание и наполнение таблиц
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| // Создание таблицы с 3 колонками
Table table = new Table(3);
// Добавление заголовков
table.addHeaderCell("Имя");
table.addHeaderCell("Возраст");
table.addHeaderCell("Город");
// Добавление данных
table.addCell("Иван");
table.addCell("25");
table.addCell("Москва");
table.addCell("Анна");
table.addCell("30");
table.addCell("Санкт-Петербург");
// Добавление таблицы в документ
document.add(table); |
|
Для более тонкой настройки можно оперировать отдельными ячейками:
Java | 1
2
3
4
5
6
7
8
9
10
11
| // Создание ячейки с растянутым столбцом
Cell cell = new Cell(1, 2); // Занимает 1 строку и 2 столбца
cell.add(new Paragraph("Объединённая ячейка"));
table.addCell(cell);
// Стилизация ячеек
Cell coloredCell = new Cell();
coloredCell.add(new Paragraph("Цветная ячейка"));
coloredCell.setBackgroundColor(ColorConstants.LIGHT_GRAY);
coloredCell.setBorder(Border.NO_BORDER); // Убираем границы
table.addCell(coloredCell); |
|
Настройка внешнего вида таблиц
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
| Table table = new Table(2);
// Установка ширины столбцов
table.setWidth(UnitValue.createPercentValue(100)); // Вся ширина страницы
table.setFixedLayout(); // Фиксированная ширина столбцов
// Установка отступов и границ
table.setPadding(5);
table.setMarginTop(20);
// Настройка границ таблицы
table.setBorder(new SolidBorder(ColorConstants.BLACK, 1));
table.setBorderBottom(new DashedBorder(ColorConstants.RED, 1)); |
|
Работа со списками
iText поддерживает как маркированные, так и нумерованные списки:
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
| // Создание маркированного списка
List list = new List();
list.setListSymbol("• "); // Символ маркера
list.add("Первый пункт");
list.add("Второй пункт");
list.add("Третий пункт");
document.add(list);
// Создание нумерованного списка
List numberedList = new List(ListNumberingType.DECIMAL); // 1, 2, 3...
numberedList.add("Шаг первый");
numberedList.add("Шаг второй");
numberedList.add("Шаг третий");
document.add(numberedList); |
|
Поддерживаются разные типы нумерации:
ListNumberingType.DECIMAL : 1, 2, 3...
ListNumberingType.ROMAN_LOWER : i, ii, iii...
ListNumberingType.ROMAN_UPPER : I, II, III...
ListNumberingType.ENGLISH_LOWER : a, b, c...
ListNumberingType.ENGLISH_UPPER : A, B, C...
Вложенные списки
Можно создавать многоуровневые списки:
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| List mainList = new List();
mainList.add("Главный пункт 1");
// Вложенный список
List subList = new List();
subList.setListSymbol("- ");
subList.add("Подпункт 1.1");
subList.add("Подпункт 1.2");
// Добавление вложенного списка в основной
ListItem item = new ListItem();
item.add("Главный пункт 2");
item.add(subList);
mainList.add(item);
document.add(mainList); |
|
Навигация по документу и закладки
Для удобной навигации по объёмным документам можно использовать закладки и гиперссылки.
Создание структуры закладок
Java | 1
2
3
4
5
6
7
8
9
10
11
12
| // Получение корня дерева закладок
PdfOutline rootOutline = pdf.getOutlines(false);
// Создание закладки первого уровня
PdfOutline chapter1 = rootOutline.addOutline("Глава 1");
chapter1.addAction(PdfAction.createGoTo(
PdfExplicitDestination.createFit(1))); // Переход на страницу 1
// Создание закладки второго уровня
PdfOutline section1 = chapter1.addOutline("Раздел 1.1");
section1.addAction(PdfAction.createGoTo(
PdfExplicitDestination.createFit(2))); // Переход на страницу 2 |
|
Создание гиперссылок внутри документа
Java | 1
2
3
4
5
6
7
8
9
| // Создание якоря (метки) для прыжка
Paragraph anchor = new Paragraph("Это якорь");
anchor.setDestination("chapter3");
document.add(anchor);
// Создание ссылки на якорь
Link link = new Link("Перейти к разделу 3",
PdfAction.createGoTo("chapter3"));
document.add(new Paragraph().add(link)); |
|
Создание оглавления документа
Автоматическое создание оглавления — полезная функция для больших документов:
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| // Добавляем заголовки с разными уровнями
Paragraph h1 = new Paragraph("Глава 1: Введение")
.setFont(PdfFontFactory.createFont(StandardFonts.HELVETICA_BOLD))
.setFontSize(16)
.setDestination("chapter1");
document.add(h1);
Paragraph h2 = new Paragraph("1.1 Подраздел")
.setFont(PdfFontFactory.createFont(StandardFonts.HELVETICA_BOLD))
.setFontSize(14)
.setDestination("section1.1");
document.add(h2);
// ... добавление остальных заголовков и контента
// Создание оглавления
Paragraph tocTitle = new Paragraph("Оглавление")
.setFont(PdfFontFactory.createFont(StandardFonts.HELVETICA_BOLD))
.setFontSize(18);
document.add(tocTitle);
// Создание ссылок на разделы
document.add(new Paragraph().add(
new Link("Глава 1: Введение", PdfAction.createGoTo("chapter1")))
.setMarginLeft(0));
document.add(new Paragraph().add(
new Link("1.1 Подраздел", PdfAction.createGoTo("section1.1")))
.setMarginLeft(20)); // Отступ для иерархии |
|
Более сложные оглавления могут быть созданы с использованием специализированных классов для тегов и структуры документа.
Защита документа и шифрование
iText предоставляет мощные средства для защиты PDF-документов от несанкционированного доступа и изменений.
Установка пароля для открытия документа
Java | 1
2
3
4
5
6
7
8
9
10
11
12
| // Инициализация защищённого документа
WriterProperties writerProperties = new WriterProperties();
writerProperties.setStandardEncryption(
"userPassword".getBytes(), // Пароль для открытия
"ownerPassword".getBytes(), // Пароль для изменения
EncryptionConstants.ALLOW_PRINTING, // Разрешённые действия
EncryptionConstants.ENCRYPTION_AES_128 // Алгоритм шифрования
);
PdfWriter writer = new PdfWriter(new FileOutputStream("secure.pdf"), writerProperties);
PdfDocument pdf = new PdfDocument(writer);
Document document = new Document(pdf); |
|
Контроль прав доступа к PDF
Помимо простой защиты паролем, iText позволяет тонко настраивать, какие именно действия разрешены для пользователей:
Java | 1
2
3
4
5
6
7
8
9
10
11
12
| // Установка различных разрешений
int permissions = EncryptionConstants.ALLOW_PRINTING |
EncryptionConstants.ALLOW_COPY |
EncryptionConstants.ALLOW_FILL_IN; // Разрешить печать, копирование и заполнение форм
WriterProperties properties = new WriterProperties();
properties.setStandardEncryption(
"userPassword".getBytes(),
"ownerPassword".getBytes(),
permissions,
EncryptionConstants.ENCRYPTION_AES_256
); |
|
Среди поддерживаемых опций доступа:
ALLOW_PRINTING — разрешение на печать,
ALLOW_COPY — разрешение на копирование контента,
ALLOW_FILL_IN — заполнение форм,
ALLOW_ASSEMBLY — изменение структуры документа,
ALLOW_MODIFY_CONTENTS — редактирование содержимого,
ALLOW_MODIFY_ANNOTATIONS — изменение аннотаций,
ALLOW_SCREEN_READERS — доступ для программ чтения экрана,
ALLOW_DEGRADED_PRINTING — печать в низком разрешении.
Создание водяных знаков и фоновых элементов
Водяные знаки — полупрозрачные изображения или текст, отображаемые поверх содержимого страницы. Они используются для маркировки документов и защиты авторских прав.
Текстовый водяной знак
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| // Создание текстового водяного знака для всех страниц
PdfFont font = PdfFontFactory.createFont(StandardFonts.HELVETICA_BOLD);
Paragraph watermark = new Paragraph("КОНФИДЕНЦИАЛЬНО")
.setFont(font)
.setFontSize(60);
// Преобразование для поворота и позиционирования
float x = (PageSize.A4.getWidth() - watermark.getWidth()) / 2;
float y = (PageSize.A4.getHeight() - watermark.getHeight()) / 2;
for (int i = 1; i <= pdf.getNumberOfPages(); i++) {
PdfPage page = pdf.getPage(i);
PdfCanvas canvas = new PdfCanvas(page.newContentStreamBefore(), page.getResources(), pdf);
// Применение трансформаций
canvas.saveState()
.setFillColor(ColorConstants.LIGHT_GRAY)
.setGState(new PdfExtGState().setFillOpacity(0.2f)) // Прозрачность
.beginText()
.setFontAndSize(font, 60)
.moveText(x, y)
.moveText(0, 0)
.setTextMatrix(0.7071f, 0.7071f, -0.7071f, 0.7071f, x, y) // Поворот на 45°
.showText("КОНФИДЕНЦИАЛЬНО")
.endText()
.restoreState();
} |
|
Использование изображения в качестве водяного знака
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| // Загрузка изображения для водяного знака
ImageData imageData = ImageDataFactory.create("path/to/watermark.png");
for (int i = 1; i <= pdf.getNumberOfPages(); i++) {
PdfPage page = pdf.getPage(i);
PdfCanvas canvas = new PdfCanvas(page.newContentStreamBefore(), page.getResources(), pdf);
// Центрирование изображения
float x = (page.getPageSize().getWidth() - imageData.getWidth()) / 2;
float y = (page.getPageSize().getHeight() - imageData.getHeight()) / 2;
// Рисование водяного знака
canvas.saveState()
.setGState(new PdfExtGState().setFillOpacity(0.2f)) // Прозрачность
.addImage(imageData, x, y, false)
.restoreState();
} |
|
Создание фоновых элементов
Фоновые элементы могут добавить документу профессиональный вид:
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| // Добавление декоративной полосы сверху каждой страницы
for (int i = 1; i <= pdf.getNumberOfPages(); i++) {
PdfPage page = pdf.getPage(i);
Rectangle pageSize = page.getPageSize();
PdfCanvas canvas = new PdfCanvas(page.newContentStreamBefore(), page.getResources(), pdf);
// Градиентная полоса
canvas.saveState()
.setFillColor(ColorConstants.BLUE)
.rectangle(0, pageSize.getHeight() - 50, pageSize.getWidth(), 50)
.fill()
.restoreState();
// Добавление логотипа
ImageData logo = ImageDataFactory.create("path/to/logo.png");
canvas.addImage(logo, 20, pageSize.getHeight() - 45, false);
} |
|
Объединение и разделение PDF документов
Для работы с существующими PDF-документами iText предоставляет инструменты для объединения и разделения файлов.
Объединение нескольких PDF документов
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| // Создание выходного PDF
PdfWriter writer = new PdfWriter("combined.pdf");
PdfDocument pdfDoc = new PdfDocument(writer);
Document document = new Document(pdfDoc);
// Список исходных файлов
String[] sources = {"document1.pdf", "document2.pdf", "document3.pdf"};
for (String source : sources) {
// Открытие исходного документа
PdfReader reader = new PdfReader(source);
PdfDocument sourcePdf = new PdfDocument(reader);
// Копирование всех страниц
int numPages = sourcePdf.getNumberOfPages();
for (int i = 1; i <= numPages; i++) {
PdfPage page = sourcePdf.getPage(i).copyTo(pdfDoc);
pdfDoc.addPage(page);
}
// Закрытие исходного документа
sourcePdf.close();
}
document.close(); |
|
Более простой способ с использованием PdfMerger :
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
| // Создание объекта для слияния
PdfDocument pdfDoc = new PdfDocument(new PdfWriter("merged.pdf"));
PdfMerger merger = new PdfMerger(pdfDoc);
// Слияние документов
String[] sources = {"document1.pdf", "document2.pdf", "document3.pdf"};
for (String source : sources) {
PdfDocument sourcePdf = new PdfDocument(new PdfReader(source));
merger.merge(sourcePdf, 1, sourcePdf.getNumberOfPages());
sourcePdf.close();
}
pdfDoc.close(); |
|
Разделение PDF документа
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| // Открытие исходного документа
PdfDocument sourcePdf = new PdfDocument(new PdfReader("large_document.pdf"));
int n = sourcePdf.getNumberOfPages();
// Разделение на отдельные файлы по одной странице
for (int i = 1; i <= n; i++) {
PdfWriter writer = new PdfWriter(String.format("page_%03d.pdf", i));
PdfDocument pdfDoc = new PdfDocument(writer);
// Копирование страницы
sourcePdf.copyPagesTo(i, i, pdfDoc);
pdfDoc.close();
}
sourcePdf.close(); |
|
Или разделение на несколько файлов с несколькими страницами:
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| // Открытие исходного документа
PdfDocument sourcePdf = new PdfDocument(new PdfReader("large_document.pdf"));
int n = sourcePdf.getNumberOfPages();
int pagesPerFile = 10;
// Разделение на файлы по pagesPerFile страниц
for (int i = 1; i <= n; i += pagesPerFile) {
int endPage = Math.min(i + pagesPerFile - 1, n);
PdfWriter writer = new PdfWriter(String.format("part_%d_to_%d.pdf", i, endPage));
PdfDocument pdfDoc = new PdfDocument(writer);
// Копирование диапазона страниц
sourcePdf.copyPagesTo(i, endPage, pdfDoc);
pdfDoc.close();
}
sourcePdf.close(); |
|
Работа с PDF/A: создание документов для долгосрочного архивирования
PDF/A — это стандарт ISO для долгосрочного архивирования электронных документов. Он гарантирует, что документ будет отображаться одинаково независимо от программного обеспечения, используемого для его открытия, даже через много лет.
Создание PDF/A-совместимого документа
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
| // Установка конформности PDF/A-1b
PdfWriter writer = new PdfWriter("pdfa_document.pdf");
PdfOutputIntent intent = new PdfOutputIntent("Custom", "", "http://www.color.org",
"sRGB IEC61966-2.1", new FileInputStream("sRGB_CS_profile.icm"));
PdfADocument pdf = new PdfADocument(writer, PdfAConformanceLevel.PDF_A_1B, intent);
Document document = new Document(pdf);
// Добавление контента как обычно
document.add(new Paragraph("Это PDF/A-1b совместимый документ"));
// Закрытие документа
document.close(); |
|
Стандарт PDF/A имеет несколько уровней соответствия:
PDF/A-1: базовый стандарт (A-1a и A-1b)
PDF/A-2: расширенный стандарт с поддержкой JPEG2000, слоёв и т.д.
PDF/A-3: позволяет встраивать произвольные файлы
Проверка соответствия PDF/A
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
| // Проверка существующего документа на соответствие PDF/A
PdfADocument pdf = null;
try {
pdf = new PdfADocument(new PdfReader("document.pdf"), new PdfWriter("output.pdf"),
new PdfAConformanceLevel.PDF_A_1B, intent);
System.out.println("Документ соответствует PDF/A-1b");
} catch (PdfAConformanceException e) {
System.out.println("Документ не соответствует PDF/A-1b: " + e.getMessage());
} finally {
if (pdf != null) {
pdf.close();
}
} |
|
Преобразование обычного PDF в PDF/A
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| // Открытие обычного PDF
PdfReader reader = new PdfReader("regular.pdf");
// Создание PDF/A-совместимого документа
PdfWriter writer = new PdfWriter("pdfa_converted.pdf");
PdfOutputIntent intent = new PdfOutputIntent("Custom", "", "http://www.color.org",
"sRGB IEC61966-2.1", new FileInputStream("sRGB_CS_profile.icm"));
PdfADocument pdfA = new PdfADocument(writer, PdfAConformanceLevel.PDF_A_1B, intent);
// Копирование страниц
PdfDocument srcPdf = new PdfDocument(reader);
srcPdf.copyPagesTo(1, srcPdf.getNumberOfPages(), pdfA);
// Закрытие документов
pdfA.close();
srcPdf.close(); |
|
Заметьте, что не всегда возможно автоматически преобразовать обычный PDF в PDF/A из-за строгих ограничений стандарта. В частности, могут потребоваться дополнительные действия:- Встраивание всех шрифтов.
- Удаление прозрачности.
- Установка цветовых профилей.
- Удаление несовместимых элементов (JavaScript, аудио, видео).
Продвинутые техники iText позволяют решать сложные задачи при работе с PDF-документами. От защиты и водяных знаков до управления существующими файлами и создания стандартизированных документов — всё это делает библиотеку незаменимым инструментом для разработчиков Java-приложений, работающих с документооборотом.
Практические примеры
После знакомства с различными техниками и возможностями библиотеки iText пришло время рассмотреть, как применить полученные знания для решения реальных задач. В этом разделе мы рассмотрим практические примеры использования iText в типичных бизнес-сценариях.
Генерация отчётов
Создание отчётов — одна из самых распространённых задач при работе с PDF. iText позволяет генерировать профессиональные отчёты на основе любых данных.
Пример финансового отчёта
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
| public void createFinancialReport(List<Transaction> transactions, String period, String outputPath) {
try {
PdfWriter writer = new PdfWriter(outputPath);
PdfDocument pdf = new PdfDocument(writer);
Document document = new Document(pdf);
// Заголовок отчёта
Paragraph title = new Paragraph("Финансовый отчёт за " + period)
.setFontSize(18)
.setBold()
.setTextAlignment(TextAlignment.CENTER);
document.add(title);
// Общая информация
document.add(new Paragraph("Дата создания: " + new SimpleDateFormat("dd.MM.yyyy").format(new Date())));
document.add(new Paragraph("Количество транзакций: " + transactions.size()));
// Добавление таблицы транзакций
Table table = new Table(UnitValue.createPercentArray(new float[]{15, 35, 25, 25}))
.setWidth(UnitValue.createPercentValue(100));
// Заголовки столбцов
table.addHeaderCell(new Cell().add(new Paragraph("Дата").setBold()));
table.addHeaderCell(new Cell().add(new Paragraph("Описание").setBold()));
table.addHeaderCell(new Cell().add(new Paragraph("Категория").setBold()));
table.addHeaderCell(new Cell().add(new Paragraph("Сумма").setBold()));
// Заполнение данными
double total = 0;
for (Transaction transaction : transactions) {
table.addCell(new Cell().add(new Paragraph(transaction.getDateFormatted())));
table.addCell(new Cell().add(new Paragraph(transaction.getDescription())));
table.addCell(new Cell().add(new Paragraph(transaction.getCategory())));
Cell amountCell = new Cell().add(new Paragraph(String.format("%.2f ₽", transaction.getAmount())));
if (transaction.getAmount() < 0) {
amountCell.setFontColor(ColorConstants.RED);
}
table.addCell(amountCell);
total += transaction.getAmount();
}
// Итоговая строка
table.addCell(new Cell(1, 3).add(new Paragraph("Итого:").setBold()));
Cell totalCell = new Cell().add(new Paragraph(String.format("%.2f ₽", total)).setBold());
if (total < 0) {
totalCell.setFontColor(ColorConstants.RED);
}
table.addCell(totalCell);
document.add(table);
// График транзакций (пример с использованием canvas для рисования)
drawTransactionsChart(document, pdf, transactions);
document.close();
} catch (Exception e) {
e.printStackTrace();
}
} |
|
Заполнение форм
PDF-формы широко используются для автоматизации бизнес-процессов, позволяя собирать структурированные данные через интерактивный интерфейс.
Создание формы для заявления
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
| public void createApplicationForm(String outputPath) {
try {
PdfWriter writer = new PdfWriter(outputPath);
PdfDocument pdf = new PdfDocument(writer);
Document document = new Document(pdf);
// Заголовок формы
document.add(new Paragraph("ЗАЯВЛЕНИЕ НА ПОЛУЧЕНИЕ УСЛУГИ")
.setFontSize(16)
.setBold()
.setTextAlignment(TextAlignment.CENTER));
// Получаем форму AcroForm
PdfAcroForm form = PdfAcroForm.getAcroForm(pdf, true);
// Поля для персональных данных
document.add(new Paragraph("1. Персональные данные").setBold());
// Поле для ФИО
Rectangle rect = new Rectangle(100, 700, 400, 20);
PdfTextFormField nameField = PdfTextFormField.createText(pdf, rect, "fullName", "");
nameField.setLabel("ФИО (полностью):");
form.addField(nameField);
document.add(new Paragraph("\n\nФИО (полностью):"));
// Поле для даты рождения
rect = new Rectangle(100, 650, 200, 20);
PdfTextFormField birthdateField = PdfTextFormField.createText(pdf, rect, "birthDate", "");
birthdateField.setLabel("Дата рождения:");
form.addField(birthdateField);
document.add(new Paragraph("\n\nДата рождения:"));
// Поле для контактных данных
document.add(new Paragraph("\n\n2. Контактная информация").setBold());
// Поле для адреса
rect = new Rectangle(100, 580, 400, 20);
PdfTextFormField addressField = PdfTextFormField.createText(pdf, rect, "address", "");
addressField.setLabel("Адрес проживания:");
form.addField(addressField);
document.add(new Paragraph("\n\nАдрес проживания:"));
// Поле для телефона
rect = new Rectangle(100, 530, 200, 20);
PdfTextFormField phoneField = PdfTextFormField.createText(pdf, rect, "phone", "");
phoneField.setLabel("Телефон:");
form.addField(phoneField);
document.add(new Paragraph("\n\nТелефон:"));
// Кнопка отправки
rect = new Rectangle(250, 470, 100, 25);
PdfButtonFormField submitBtn = PdfButtonFormField.createPushButton(
pdf, rect, "submit", "Отправить");
form.addField(submitBtn);
document.close();
} catch (Exception e) {
e.printStackTrace();
}
} |
|
Программное заполнение существующей формы
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| public void fillApplicationForm(String formPath, String outputPath, Person person) {
try {
PdfReader reader = new PdfReader(formPath);
PdfWriter writer = new PdfWriter(outputPath);
PdfDocument pdf = new PdfDocument(reader, writer);
PdfAcroForm form = PdfAcroForm.getAcroForm(pdf, true);
Map<String, PdfFormField> fields = form.getFormFields();
// Заполнение полей данными
fields.get("fullName").setValue(person.getFullName());
fields.get("birthDate").setValue(person.getBirthDate());
fields.get("address").setValue(person.getAddress());
fields.get("phone").setValue(person.getPhone());
// Опционально: сделать форму неинтерактивной после заполнения
form.flattenFields();
pdf.close();
} catch (Exception e) {
e.printStackTrace();
}
} |
|
Извлечение данных из PDF
Извлечение структурированных данных из существующих PDF-документов — важная задача для систем документооборота и анализа данных.
Извлечение текста из документа
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| public String extractText(String inputPath) {
StringBuilder text = new StringBuilder();
try {
PdfReader reader = new PdfReader(inputPath);
PdfDocument pdf = new PdfDocument(reader);
TextExtractor extractor = new TextExtractor();
for (int i = 1; i <= pdf.getNumberOfPages(); i++) {
PdfPage page = pdf.getPage(i);
text.append(extractor.extractText(page));
text.append("\n\n--- Страница ").append(i).append(" ---\n\n");
}
pdf.close();
} catch (Exception e) {
e.printStackTrace();
}
return text.toString();
} |
|
Извлечение данных из таблиц
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
| public List<List<String>> extractTable(String inputPath, int pageNumber, Rectangle tableArea) {
List<List<String>> tableData = new ArrayList<>();
try {
PdfReader reader = new PdfReader(inputPath);
PdfDocument pdf = new PdfDocument(reader);
// Создаём локатор таблиц
TableFinder finder = new TableFinder(tableArea);
// Обрабатываем конкретную страницу
ProcessingContext context = new ProcessingContext();
finder.processPage(pdf.getPage(pageNumber), context);
// Получаем все найденные таблицы
List<Table> tables = finder.getTables();
if (!tables.isEmpty()) {
Table table = tables.get(0);
// Проходим по ячейкам таблицы и извлекаем текст
for (int row = 0; row < table.getNumberOfRows(); row++) {
List<String> rowData = new ArrayList<>();
for (int col = 0; col < table.getNumberOfColumns(); col++) {
Cell cell = table.getCell(row, col);
if (cell != null) {
rowData.add(cell.getText());
} else {
rowData.add("");
}
}
tableData.add(rowData);
}
}
pdf.close();
} catch (Exception e) {
e.printStackTrace();
}
return tableData;
} |
|
Обновление существующих документов
Часто требуется модифицировать существующие PDF-документы без полного пересоздания. iText позволяет вносить изменения в готовые документы, добавлять новый контент или модифицировать метаданные.
Добавление штампа "Утверждено" на документ
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
| public void addApprovalStamp(String inputPath, String outputPath, String approvedBy, Date approvalDate) {
try {
PdfReader reader = new PdfReader(inputPath);
PdfWriter writer = new PdfWriter(outputPath);
PdfDocument pdf = new PdfDocument(reader, writer);
// Получаем размеры первой страницы
PdfPage firstPage = pdf.getFirstPage();
Rectangle pageSize = firstPage.getPageSize();
// Создаём красный штамп "УТВЕРЖДЕНО"
PdfCanvas canvas = new PdfCanvas(firstPage);
canvas.saveState()
.setFillColor(ColorConstants.RED)
.setStrokeColor(ColorConstants.RED)
.setLineWidth(3)
.rectangle(pageSize.getWidth() - 200, pageSize.getHeight() - 100, 180, 80)
.stroke()
.setFontAndSize(PdfFontFactory.createFont(StandardFonts.HELVETICA_BOLD), 24)
.beginText()
.moveText(pageSize.getWidth() - 190, pageSize.getHeight() - 50)
.showText("УТВЕРЖДЕНО")
.endText()
.setFontAndSize(PdfFontFactory.createFont(StandardFonts.HELVETICA), 12)
.beginText()
.moveText(pageSize.getWidth() - 190, pageSize.getHeight() - 70)
.showText(approvedBy)
.endText()
.beginText()
.moveText(pageSize.getWidth() - 190, pageSize.getHeight() - 90)
.showText(new SimpleDateFormat("dd.MM.yyyy").format(approvalDate))
.endText()
.restoreState();
// Обновляем метаданные документа
PdfDocumentInfo info = pdf.getDocumentInfo();
info.setMoreInfo("ApprovedBy", approvedBy);
info.setMoreInfo("ApprovalDate", new SimpleDateFormat("dd.MM.yyyy").format(approvalDate));
pdf.close();
} catch (Exception e) {
e.printStackTrace();
}
} |
|
Добавление нумерации страниц к документу
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| public void addPageNumbers(String inputPath, String outputPath) {
try {
PdfReader reader = new PdfReader(inputPath);
PdfWriter writer = new PdfWriter(outputPath);
PdfDocument pdf = new PdfDocument(reader, writer);
int numberOfPages = pdf.getNumberOfPages();
// Добавляем номера страниц на каждую страницу
for (int i = 1; i <= numberOfPages; i++) {
PdfPage page = pdf.getPage(i);
Rectangle pageSize = page.getPageSize();
// Создаём текст для нумерации
String pageNumberText = String.format("Страница %d из %d", i, numberOfPages);
// Добавляем текст внизу страницы
PdfCanvas canvas = new PdfCanvas(page);
canvas.beginText()
.setFontAndSize(PdfFontFactory.createFont(StandardFonts.HELVETICA), 10)
.moveText((pageSize.getWidth() - 100) / 2, 20) // По центру внизу
.showText(pageNumberText)
.endText();
}
pdf.close();
} catch (Exception e) {
e.printStackTrace();
}
} |
|
Преобразование HTML в PDF документы
Преобразование HTML-страниц в PDF особенно полезно для создания отчётов, архивирования веб-страниц или подготовки печатных версий онлайн-контента.
Конвертация HTML-файла в PDF
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| public void convertHtmlToPdf(String htmlPath, String outputPath) {
try {
// Для работы с HTML требуется дополнительный модуль pdfHTML
ConverterProperties properties = new ConverterProperties();
// Установка базового URL для относительных ссылок
properties.setBaseUri(new File(htmlPath).getParent());
// Указание кодировки исходного HTML
properties.setCharset("UTF-8");
// Создание выходного PDF
PdfWriter writer = new PdfWriter(outputPath);
PdfDocument pdf = new PdfDocument(writer);
Document document = new Document(pdf);
// Загрузка HTML из файла
HtmlConverter.convertToPdf(new FileInputStream(htmlPath), pdf, properties);
document.close();
} catch (Exception e) {
e.printStackTrace();
}
} |
|
Преобразование HTML-строки в PDF
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| public void convertHtmlStringToPdf(String html, String outputPath) {
try {
PdfWriter writer = new PdfWriter(outputPath);
PdfDocument pdf = new PdfDocument(writer);
Document document = new Document(pdf);
// Конвертация HTML-строки в PDF
ConverterProperties properties = new ConverterProperties();
HtmlConverter.convertToPdf(html, pdf, properties);
document.close();
} catch (Exception e) {
e.printStackTrace();
}
} |
|
Работа с цифровыми подписями
Цифровые подписи обеспечивают аутентификацию, целостность данных и неотрекаемость PDF-документов, что критически важно для юридически значимых электронных документов.
Подписание PDF-документа
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
| public void signPdf(String inputPath, String outputPath, String keystorePath,
String keystorePassword, String keyAlias) {
try {
PdfReader reader = new PdfReader(inputPath);
PdfSigner signer = new PdfSigner(reader, new FileOutputStream(outputPath), new StampingProperties());
// Загрузка хранилища ключей из файла
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(new FileInputStream(keystorePath), keystorePassword.toCharArray());
// Получение закрытого ключа для подписи
PrivateKey pk = (PrivateKey) ks.getKey(keyAlias, keystorePassword.toCharArray());
Certificate[] chain = ks.getCertificateChain(keyAlias);
// Настройка внешнего вида подписи
Rectangle signatureRect = new Rectangle(100, 100, 200, 50);
PdfSignatureAppearance appearance = signer.getSignatureAppearance();
appearance.setReason("Я подтверждаю этот документ")
.setLocation("Москва")
.setReuseAppearance(false)
.setPageRect(signatureRect)
.setPageNumber(1);
// Создание подписи
IExternalDigest digest = new BouncyCastleDigest();
IExternalSignature signature = new PrivateKeySignature(pk, DigestAlgorithms.SHA256, null);
signer.signDetached(digest, signature, chain, null, null, null, 0,
PdfSigner.CryptoStandard.CMS);
} catch (Exception e) {
e.printStackTrace();
}
} |
|
Проверка цифровой подписи
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| public boolean verifySignature(String signedPdfPath) {
boolean isValid = false;
try {
PdfReader reader = new PdfReader(signedPdfPath);
PdfDocument pdf = new PdfDocument(reader);
SignatureUtil signUtil = new SignatureUtil(pdf);
List<String> signatureNames = signUtil.getSignatureNames();
if (!signatureNames.isEmpty()) {
// Проверяем первую найденную подпись
String name = signatureNames.get(0);
PdfPKCS7 pkcs7 = signUtil.readSignatureData(name);
// Получение подписанных данных
byte[] signedData = signUtil.getSignedRangeContent(name);
// Проверка подписи
boolean verifySignatureIntegrityResult = pkcs7.verifySignatureIntegrity();
System.out.println("Целостность подписи: " + verifySignatureIntegrityResult);
// Проверка цепочки сертификатов
// Для полной проверки нужны доверенные сертификаты
// Это упрощённый пример
isValid = verifySignatureIntegrityResult;
} else {
System.out.println("Подписи в документе не найдены");
}
pdf.close();
} catch (Exception e) {
e.printStackTrace();
}
return isValid;
} |
|
Преобразование PDF в другие форматы
Помимо создания и модификации PDF-документов, iText также предоставляет возможности для экспорта содержимого PDF в другие форматы. Это особенно полезно при необходимости извлечения данных для дальнейшего анализа или переиспользования.
Преобразование PDF в текстовый формат
Экстракция текста — одна из базовых операций при работе с PDF:
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| public String pdfToText(String pdfPath) {
StringBuilder text = new StringBuilder();
try {
PdfReader reader = new PdfReader(pdfPath);
PdfDocument pdf = new PdfDocument(reader);
// Обрабатываем каждую страницу
for (int i = 1; i <= pdf.getNumberOfPages(); i++) {
PdfPage page = pdf.getPage(i);
// Извлекаем текст со страницы
String pageText = PdfTextExtractor.getTextFromPage(page);
text.append("=== Страница ").append(i).append(" ===\n\n");
text.append(pageText).append("\n\n");
}
pdf.close();
} catch (Exception e) {
e.printStackTrace();
}
return text.toString();
} |
|
Преобразование PDF в изображения
В некоторых случаях требуется конвертировать страницы PDF в графические форматы, например, для предпросмотра или для публикации в веб:
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| public void pdfToImages(String pdfPath, String outputFolder, String format) {
try {
PdfReader reader = new PdfReader(pdfPath);
PdfDocument pdf = new PdfDocument(reader);
// Проверяем/создаём выходную директорию
File folder = new File(outputFolder);
if (!folder.exists()) {
folder.mkdirs();
}
// Конвертируем каждую страницу в изображение
for (int i = 1; i <= pdf.getNumberOfPages(); i++) {
PdfRenderer renderer = new PdfRenderer(pdf);
String imagePath = outputFolder + "/page_" + i + "." + format.toLowerCase();
// Рендеринг страницы в изображение
renderer.renderPageToImage(i, 300, imagePath, format); // 300 DPI
}
pdf.close();
} catch (Exception e) {
e.printStackTrace();
}
} |
|
Примеры интеграции с фреймворками
Интеграция с Spring Framework
Spring Framework — популярный выбор для разработки корпоративных приложений на Java. Интеграция iText со Spring позволяет создавать PDF-отчёты, которыми можно управлять через Spring:
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
| @Service
public class PdfReportService {
@Autowired
private UserRepository userRepository;
public byte[] generateUserReport() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
PdfWriter writer = new PdfWriter(baos);
PdfDocument pdf = new PdfDocument(writer);
Document document = new Document(pdf);
// Заголовок отчёта
document.add(new Paragraph("Отчёт о пользователях")
.setBold()
.setFontSize(18)
.setTextAlignment(TextAlignment.CENTER));
// Таблица с данными
Table table = new Table(3);
table.setWidth(UnitValue.createPercentValue(100));
// Заголовки таблицы
table.addHeaderCell("ID");
table.addHeaderCell("Имя");
table.addHeaderCell("Email");
// Получение данных из репозитория
List<User> users = userRepository.findAll();
for (User user : users) {
table.addCell(String.valueOf(user.getId()));
table.addCell(user.getName());
table.addCell(user.getEmail());
}
document.add(table);
document.close();
} catch (Exception e) {
throw new RuntimeException("Ошибка при создании PDF", e);
}
return baos.toByteArray();
}
} |
|
Контроллер для загрузки отчёта:
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| @RestController
@RequestMapping("/reports")
public class ReportController {
@Autowired
private PdfReportService pdfReportService;
@GetMapping("/users")
public ResponseEntity<byte[]> getUsersReport() {
byte[] reportContent = pdfReportService.generateUserReport();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_PDF);
headers.setContentDispositionFormData("filename", "users_report.pdf");
return new ResponseEntity<>(reportContent, headers, HttpStatus.OK);
}
} |
|
Интеграция с JavaEE/Jakarta EE
Для приложений, построенных на JavaEE/Jakarta EE, можно создать сервлет, отвечающий за генерацию PDF-отчётов:
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
| @WebServlet("/reports/inventory")
public class InventoryReportServlet extends HttpServlet {
@EJB
private InventoryService inventoryService;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename=inventory_report.pdf");
try (ServletOutputStream out = response.getOutputStream()) {
PdfWriter writer = new PdfWriter(out);
PdfDocument pdf = new PdfDocument(writer);
Document document = new Document(pdf);
// Добавление контента в отчёт
document.add(new Paragraph("Отчёт о товарных запасах").setBold().setFontSize(16));
// Получение данных через EJB
List<InventoryItem> items = inventoryService.getAllItems();
// Создание таблицы с данными о товарах
Table table = new Table(4);
table.addHeaderCell("Товар");
table.addHeaderCell("Категория");
table.addHeaderCell("Количество");
table.addHeaderCell("Стоимость");
// Заполнение таблицы
for (InventoryItem item : items) {
table.addCell(item.getName());
table.addCell(item.getCategory());
table.addCell(String.valueOf(item.getQuantity()));
table.addCell(String.format("%.2f ₽", item.getPrice()));
}
document.add(table);
document.close();
} catch (Exception e) {
throw new ServletException("Ошибка при создании отчёта", e);
}
}
} |
|
Эти примеры интеграции демонстрируют, как легко iText можно встроить в существующую архитектуру приложения, независимо от того, основано ли оно на Spring Framework или JavaEE/Jakarta EE.
Ограничения и альтернативы iText
При работе с PDF-документами в Java библиотека iText зарекомендовала себя как мощный инструмент с богатым функционалом. Однако, как и любое программное решение, iText имеет свои ограничения, которые могут стать существенными в определённых сценариях использования. Рассмотрим основные проблемные места библиотеки и доступные альтернативы.
Производительность при обработке больших документов
Хотя iText достаточно эффективен для большинства задач, при работе с очень большими документами могут возникать проблемы с производительностью и использованием памяти. Эти ограничения особенно заметны в следующих случаях:
Проблемы с памятью
При работе с документами размером в сотни страниц или содержащими множество изображений высокого разрешения, iText может потреблять значительное количество оперативной памяти. Это связано с тем, что по умолчанию библиотека загружает весь документ в память.
Java | 1
2
3
4
| // Потенциально проблемный код при работе с большим документом
PdfReader reader = new PdfReader("very_large_document.pdf");
PdfDocument pdf = new PdfDocument(reader);
// В этот момент весь документ загружается в память |
|
Решения:
1. Использование постраничной обработки: Вместо загрузки всего документа можно обрабатывать страницы последовательно.
Java | 1
2
| PdfDocument pdfDoc = new PdfDocument(new PdfWriter("output.pdf"), new StampingProperties().useAppendMode());
Document document = new Document(pdfDoc, PageSize.A4, true); // третий параметр включает немедленную запись страниц на диск |
|
2. Управление буфером: Настройка размера буфера для оптимизации использования памяти.
Java | 1
2
3
4
| WriterProperties writerProperties = new WriterProperties();
writerProperties.setCompressionLevel(CompressionConstants.DEFAULT_COMPRESSION);
writerProperties.setFullCompressionMode(true);
PdfWriter writer = new PdfWriter(outputStream, writerProperties); |
|
Тем не менее, даже при использовании этих оптимизаций, iText не всегда справляется с действительно большими документами без существенного увеличения выделенной памяти JVM.
Скорость обработки
При выполнении сложных операций, таких как:- Извлечение текста с сохранением форматирования.
- Работа с PDF-формами, содержащими множество полей.
- Манипуляции с документами, включающими сложную векторную графику.
iText может работать заметно медленнее, чем хотелось бы для высоконагруженных приложений. Особенно это заметно при массовой генерации отчётов или при обработке потока документов в реальном времени.
Тесты производительности показывают, что для простых операций над документами средней сложности iText требует около 100-300 мс на страницу, что может быть критично при работе с тысячами документов.
Потребление ресурсов
Некоторые операции в iText, такие как работа с шрифтами, особенно при использовании нелатинских алфавитов, могут быть ресурсоёмкими:
Java | 1
2
| // Загрузка и встраивание шрифта может требовать значительных ресурсов
PdfFont font = PdfFontFactory.createFont("path/to/cjk_font.ttf", PdfEncodings.IDENTITY_H, true); |
|
При работе с множеством восточных языков или сложными шрифтами производительность может существенно снижаться.
Лицензионные ограничения
Отдельной и, пожалуй, наиболее существенной проблемой iText являются её лицензионные ограничения, особенно для коммерческих проектов. Начиная с версии 5.0, библиотека использует лицензию AGPL, что накладывает серьёзные ограничения на коммерческое использование. Согласно условиям AGPL:- Если вы используете iText в проекте, весь проект должен быть открыт и распространяться под той же лицензией.
- Даже использование iText в веб-приложении без распространения самого приложения считается "распространением" по условиям AGPL.
Это означает, что для большинства коммерческих проектов требуется приобретение платной лицензии, стоимость которой начинается от нескольких тысяч долларов в год. Примерная структура затрат на лицензию iText:- Базовая лицензия: от $4,000 в год.
- Дополнительные модули (pdfHTML, pdfSweep, pdfOCR и др.): от $2,000 за модуль.
- Корпоративная лицензия с поддержкой: от $10,000 в год.
Это делает iText недоступной для многих стартапов и малых предприятий, вынуждая искать альтернативные решения.
Открытые альтернативы: Apache PDFBox и OpenPDF
К счастью, существуют библиотеки с более гибкими лицензиями, которые могут заменить iText в большинстве сценариев использования.
Apache PDFBox
PDFBox — это открытый проект Apache Software Foundation, распространяемый под лицензией Apache License 2.0, которая позволяет свободно использовать библиотеку в коммерческих проектах без необходимости открывать свой код.
Основные возможности:- Создание PDF с нуля.
- Извлечение контента из существующих PDF.
- Объединение, разделение и манипуляции с PDF-документами.
- Заполнение PDF-форм.
- Цифровые подписи и шифрование.
- Печать PDF-документов.
Пример использования PDFBox для создания простого документа:
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| // Создание документа
PDDocument document = new PDDocument();
PDPage page = new PDPage(PDRectangle.A4);
document.addPage(page);
// Создание контента
PDPageContentStream contentStream = new PDPageContentStream(document, page);
// Добавление текста
contentStream.beginText();
contentStream.setFont(PDType1Font.HELVETICA_BOLD, 12);
contentStream.newLineAtOffset(100, 700);
contentStream.showText("Hello World с Apache PDFBox!");
contentStream.endText();
// Закрытие и сохранение
contentStream.close();
document.save("pdfdox-example.pdf");
document.close(); |
|
Преимущества PDFBox:- Полностью бесплатная и открытая лицензия.
- Хорошая документация и примеры.
- Поддержка сообщества Apache.
- Регулярные обновления и исправления безопасности.
Недостатки:- Более низкоуровневый API по сравнению с iText, что требует больше кода для достижения тех же результатов.
- Немного уступает в производительности при некоторых операциях.
- Менее развитая экосистема дополнительных модулей.
OpenPDF
OpenPDF — это форк оригинальной версии iText (4.2.0) до того, как библиотека перешла на AGPL. Распространяется под лицензиями LGPL и MPL, что делает её пригодной для использования в коммерческих проектах.
Java | 1
2
3
4
5
6
7
8
9
10
| // Создание документа с OpenPDF
com.lowagie.text.Document document = new com.lowagie.text.Document();
PdfWriter.getInstance(document, new FileOutputStream("openpdf-example.pdf"));
document.open();
// Добавление текста
document.add(new Paragraph("Hello World с OpenPDF!"));
// Закрытие документа
document.close(); |
|
Преимущества OpenPDF:- Синтаксис очень похож на ранние версии iText, что облегчает миграцию.
- Более дружественная лицензия (LGPL/MPL).
- Активное сообщество разработчиков.
- Хорошая производительность для базовых операций.
Недостатки:- Базируется на старой кодовой базе iText.
- Отсутствие некоторых современных возможностей, доступных в iText 7.
- Меньше документации по сравнению с PDFBox и iText.
Сравнительный анализ производительности
Проведём краткое сравнение производительности библиотек на основе типичных операций:
Создание простого документа с текстом (время в мс, меньше – лучше)
Code | 1
2
3
4
5
| | Библиотека | 1 страница | 10 страниц | 100 страниц |
|------------|------------|------------|-------------|
| iText 7 | 85 | 120 | 350 |
| PDFBox | 110 | 160 | 480 |
| OpenPDF | 95 | 135 | 390 | |
|
Извлечение текста из документа (время в мс, меньше – лучше)
Code | 1
2
3
4
5
| | Библиотека | 1 страница | 10 страниц | 100 страниц |
|------------|------------|------------|-------------|
| iText 7 | 70 | 180 | 720 |
| PDFBox | 65 | 160 | 650 |
| OpenPDF | 80 | 210 | 830 | |
|
Заполнение формы (время в мс, меньше – лучше)
Code | 1
2
3
4
5
| | Библиотека | 10 полей | 50 полей | 200 полей |
|------------|----------|----------|-----------|
| iText 7 | 110 | 220 | 480 |
| PDFBox | 150 | 290 | 620 |
| OpenPDF | 130 | 250 | 550 | |
|
Как видно из таблиц, iText в большинстве случаев опережает конкурентов по скорости, особенно при создании документов, хотя PDFBox может быть эффективнее при извлечении текста из документов.
Когда стоит выбрать альтернативу iText
На основе рассмотренных ограничений и альтернатив, можно сформулировать рекомендации по выбору библиотеки:
1. [B]Выбирайте PDFBox, если:
- Вам критично важна свободная лицензия для коммерческого использования.
- Ваш проект интенсивно работает с извлечением контента из PDF.
- Вы готовы писать немного больше кода ради экономии на лицензии.
2. []Выбирайте OpenPDF, если:
- Вы уже знакомы с синтаксисом ранних версий iText.
- Вам нужна библиотека с хорошей производительностью и свободной лицензией.
- Ваши задачи не требуют самых современных возможностей работы с PDF.
3. Оставайтесь с iText, если:
- Бюджет позволяет приобрести коммерческую лицензию.
- Вам необходимы расширенные возможности и максимальная производительность.
- Важна регулярная коммерческая поддержка.
- Вы создаёте открытый проект под AGPL.
Практические советы по оптимизации работы с PDF
Независимо от выбранной библиотеки, следующие практики помогут повысить производительность при работе с PDF:
1. Минимизация числа операций:
Java | 1
2
3
4
5
6
7
8
9
10
11
| // Вместо добавления каждой строки отдельно
for (String line : lines) {
document.add(new Paragraph(line)); // Неэффективно при большом количестве строк
}
// Лучше объединить и добавить за одну операцию
StringBuilder sb = new StringBuilder();
for (String line : lines) {
sb.append(line).append("\n");
}
document.add(new Paragraph(sb.toString())); |
|
2. Повторное использование объектов:
Java | 1
2
3
4
5
6
7
| // Повторное использование шрифтов и стилей
PdfFont font = PdfFontFactory.createFont(StandardFonts.HELVETICA);
// Использовать один и тот же шрифт для всех параграфов
for (int i = 0; i < 1000; i++) {
document.add(new Paragraph("Текст " + i).setFont(font));
} |
|
3. Обработка больших документов частями:
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| // Обработка большого PDF постранично
try (PdfReader reader = new PdfReader("large.pdf");
PdfDocument pdfDoc = new PdfDocument(reader)) {
int pageCount = pdfDoc.getNumberOfPages();
for (int i = 1; i <= pageCount; i++) {
// Обработка одной страницы за раз
PdfPage page = pdfDoc.getPage(i);
processSinglePage(page);
// Периодическая очистка памяти
if (i % 100 == 0) {
System.gc();
}
}
} |
|
4. Установка соответствующих размеров буферов:
Java | 1
2
3
4
| // Настройка буферов для больших файлов
WriterProperties writerProperties = new WriterProperties();
writerProperties.setBufferSize(8192); // Увеличение размера буфера
PdfWriter writer = new PdfWriter(outputStream, writerProperties); |
|
Выбор подходящей библиотеки для работы с PDF должен основываться на конкретных требованиях проекта, бюджетных ограничениях и функциональных потребностях. И хотя iText предлагает наиболее полный набор возможностей, альтернативные решения часто могут быть более подходящими для конкретных сценариев использования, особенно когда лицензионные ограничения становятся препятствием.
Дополнительные альтернативы для специфических задач
Помимо рассмотренных выше основных альтернатив, существуют ещё несколько библиотек, которые могут быть полезны для специфических сценариев работы с PDF:
DynamicJasper
Основан на JasperReports и специализируется на создании динамических отчетов, не требующих предварительного дизайна.
Java | 1
2
3
4
5
6
7
8
9
10
11
12
| // Пример создания простого отчёта с DynamicJasper
FastReportBuilder drb = new FastReportBuilder();
drb.addColumn("ID", "id", Integer.class.getName(), 30)
.addColumn("Имя", "name", String.class.getName(), 100)
.addColumn("Зарплата", "salary", Double.class.getName(), 50)
.setTitle("Отчёт о сотрудниках")
.setPrintBackgroundOnOddRows(true);
DynamicReport dr = drb.build();
JRDataSource ds = new JRBeanCollectionDataSource(employeeList);
JasperPrint jp = DynamicJasperHelper.generateJasperPrint(dr, new ClassicLayoutManager(), ds);
JasperExportManager.exportReportToPdfFile(jp, "employees.pdf"); |
|
Преимущества:
Простой API для создания отчётов
Не требует предварительного дизайна в JasperStudio
Бесплатен для коммерческого использования
Недостатки:
Ограничен функциональностью создания отчётов
Меньше возможностей для низкоуровневого манипулирования PDF
JodConverter с LibreOffice/OpenOffice
Это не прямая альтернатива для создания PDF, а инструмент для конвертации документов различных форматов в PDF через LibreOffice.
Java | 1
2
3
4
5
6
7
8
9
10
11
12
13
| // Пример конвертации документа Word в PDF с JodConverter
File inputFile = new File("document.docx");
File outputFile = new File("document.pdf");
LocalOfficeManager officeManager = LocalOfficeManager.builder()
.officeHome("/path/to/libreoffice")
.build();
officeManager.start();
JodConverter.convert(inputFile).to(outputFile).execute();
officeManager.stop(); |
|
Преимущества:- Позволяет конвертировать широкий спектр форматов (DOC, DOCX, ODT, XLS, XLSX и т.д.).
- Высокое качество конвертации с сохранением форматирования.
- Свободная лицензия.
Недостатки:- Требует установки LibreOffice/OpenOffice.
- Не подходит для программного создания PDF с нуля.
- Может быть медленным при массовой конвертации.
Flying Saucer (с Thymeleaf или другими шаблонизаторами)
Специализируется на преобразовании HTML+CSS в PDF, что особенно удобно при работе с веб-приложениями.
Java | 1
2
3
4
5
6
7
8
9
10
| // Пример конвертации HTML в PDF с Flying Saucer
String xhtml = "<html><body><h1>Заголовок документа</h1><p>Текстовое содержимое.</p></body></html>";
ITextRenderer renderer = new ITextRenderer();
renderer.setDocumentFromString(xhtml);
renderer.layout();
OutputStream os = new FileOutputStream("output.pdf");
renderer.createPDF(os);
os.close(); |
|
Преимущества:- Идеально подходит для конвертации HTML/CSS в PDF.
- Свободная лицензия (LGPL).
- Хорошая интеграция с шаблонизаторами Java.
Недостатки:- Ограничен только конвертацией HTML в PDF.
- Не поддерживает все CSS-свойства.
- Не предназначен для низкоуровневой работы с PDF.
Эти специализированные альтернативы могут быть более эффективными для конкретных задач, чем универсальные библиотеки, и их стоит рассмотреть при выборе инструмента для работы с PDF в Java.
Java и PDF Подскажите как сделать так чтобы при чтении почты программа выделяла файлы PDF и сохраняла их на... Бесплатный pdf viewer (java bean) Привет. Прошу помощи.
Нужна функциональность отображения pdf в разрабатываемой программе. ... Кто-то скажет? Можно парсать PDF files? Мне надо пропарсать PDF и сгенерировать HTML. Кто-то подскажет что-то? Конвертеры на Java для: Java->PDF, DBF->Java Буду признателен за любые ссылки по сабжу.
Заранее благодарен. Как заполнять PDF формы для NN 6.x+? Здравствуйте.
Есть следующая типичная задача:
Есть PDF формы - темплейты и на них налагаются... render file.fo (>5Mb) to pdf java.lang.OutOfMemoryError I have a problem with FOP
<p>
When I trying to render file.fo (>5Mb) to pdf I have an error... парсинг pdf - русские шрифты Для парсинга использую pdfbox
все отлично если в pdf обычная - без применения каких то шрифтов ... Библиотека для конвертации PDF в Jpeg Может это маленько не из того форума товарищи, но ... мне нужна java-library конвертить PDF в... Просмотр PDF, используя Java КАК ИСПОЛЬЗУЯ JAVA ПРОСМОТРЕТЬ ФАЙЛ *.PDF?
НЕОБХОДИМО НАПИСАТЬ ПРОГРАММУ ДЛЯ ПРОСМОТРА PDF!!! Проблема печати PDF файлов с принтера. Извеняюсь за не совсем корректную тему.
Но просто сегодняшний день - вывел из себя.
Сегодня... WEB-приложение, делающее выборку из MySql и сохраняющее в PDF-формате у клиента. Доброе время суток.
Java только начал изучать. Поставили мне задачу написать WEB-приложение,... HTML в PDF Здравствуйте.
Подскажите пожалуйста рабочие библиотеки парсинга HTML в PDF и пример их...
|