Перейти к основному содержимому

Создание PDF-файлов в Java

· 7 мин. чтения

1. Введение

В этом кратком руководстве мы сосредоточимся на создании PDF-документов с нуля на основе библиотек iText и PdfBox.

2. Зависимости Maven

Во-первых, нам нужно включить в наш проект следующие зависимости Maven:

<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.10</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.4</version>
</dependency>

Последние версии библиотек можно найти здесь: iText и PdfBox .

Важно знать, что iText доступен по лицензии AGPL с открытым исходным кодом, а также по коммерческой лицензии. Если мы приобретем коммерческую лицензию, мы можем оставить исходный код себе, что позволит нам сохранить нашу интеллектуальную собственность. Если мы будем использовать версию AGPL, нам потребуется бесплатно выпустить наш исходный код. Мы можем перейти по этой ссылке , чтобы определить, как убедиться, что наше программное обеспечение соответствует AGPL.

Нам также нужно добавить одну дополнительную зависимость на случай, если нам понадобится зашифровать наш файл. Пакет Bouncy Castle Provider содержит реализации криптографических алгоритмов и требуется для обеих библиотек:

<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.56</version>
</dependency>

Последнюю версию библиотеки можно найти здесь: The Bouncy Castle Provider .

3. Обзор

iText и PdfBox — это библиотеки Java, которые мы используем для создания файлов PDF и управления ими. Хотя конечный результат библиотек одинаков, они работают по-разному. Давайте подробнее рассмотрим каждый из них.

4. Создайте PDF в IText

4.1. Вставить текст в PDF

Давайте посмотрим, как мы вставляем новый файл с текстом «Hello World» в pdf-файл:

Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream("iTextHelloWorld.pdf"));

document.open();
Font font = FontFactory.getFont(FontFactory.COURIER, 16, BaseColor.BLACK);
Chunk chunk = new Chunk("Hello World", font);

document.add(chunk);
document.close();

Создание pdf с использованием библиотеки iText основано на манипулировании объектами, реализующими интерфейс Elements в Document (в версии 5.5.10 таких реализаций 45).

Наименьший элемент, который мы можем добавить в документ и использовать, — это Chunk , который в основном представляет собой строку с примененным шрифтом.

Кроме того, мы можем комбинировать Chunk с другими элементами, такими как Paragraphs , Section и т. д., в результате чего документы будут выглядеть красиво.

4.2. Вставка изображения

Библиотека iText предоставляет простой способ добавления изображения в документ. Нам просто нужно создать экземпляр изображения и добавить его в документ:

Path path = Paths.get(ClassLoader.getSystemResource("Java_logo.png").toURI());

Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream("iTextImageExample.pdf"));
document.open();
Image img = Image.getInstance(path.toAbsolutePath().toString());
document.add(img);

document.close();

4.3. Вставка таблицы

Мы можем столкнуться с проблемой, если захотим добавить таблицу в наш PDF-файл. К счастью, iText предоставляет эту функциональность «из коробки».

Во-первых, нам нужно создать объект PdfTable и указать количество столбцов для нашей таблицы в конструкторе.

Затем мы можем просто добавить новые ячейки, вызвав метод addCell для только что созданного объекта таблицы. iText будет создавать строки таблицы, пока определены все необходимые ячейки. Это означает, что как только мы создадим таблицу с тремя столбцами и добавим в нее восемь ячеек, будут отображаться только две строки с тремя ячейками в каждой.

Давайте посмотрим на пример:

Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream("iTextTable.pdf"));

document.open();

PdfPTable table = new PdfPTable(3);
addTableHeader(table);
addRows(table);
addCustomRows(table);

document.add(table);
document.close();

Теперь мы создадим новую таблицу с тремя столбцами и тремя строками. Мы будем рассматривать первую строку как заголовок таблицы с измененным цветом фона и шириной границы:

private void addTableHeader(PdfPTable table) {
Stream.of("column header 1", "column header 2", "column header 3")
.forEach(columnTitle -> {
PdfPCell header = new PdfPCell();
header.setBackgroundColor(BaseColor.LIGHT_GRAY);
header.setBorderWidth(2);
header.setPhrase(new Phrase(columnTitle));
table.addCell(header);
});
}

Вторая строка будет состоять из трех ячеек только с текстом и без дополнительного форматирования:

private void addRows(PdfPTable table) {
table.addCell("row 1, col 1");
table.addCell("row 1, col 2");
table.addCell("row 1, col 3");
}

Мы также можем включать изображения в ячейки. Кроме того, мы можем отформатировать каждую ячейку отдельно.

В этом примере мы применяем выравнивание по горизонтали и вертикали:

private void addCustomRows(PdfPTable table) 
throws URISyntaxException, BadElementException, IOException {
Path path = Paths.get(ClassLoader.getSystemResource("Java_logo.png").toURI());
Image img = Image.getInstance(path.toAbsolutePath().toString());
img.scalePercent(10);

PdfPCell imageCell = new PdfPCell(img);
table.addCell(imageCell);

PdfPCell horizontalAlignCell = new PdfPCell(new Phrase("row 2, col 2"));
horizontalAlignCell.setHorizontalAlignment(Element.ALIGN_CENTER);
table.addCell(horizontalAlignCell);

PdfPCell verticalAlignCell = new PdfPCell(new Phrase("row 2, col 3"));
verticalAlignCell.setVerticalAlignment(Element.ALIGN_BOTTOM);
table.addCell(verticalAlignCell);
}

4.4. Шифрование файлов

Чтобы применить разрешения с помощью библиотеки iText, нам нужно уже создать документ в формате pdf. В нашем примере мы будем использовать ранее сгенерированный файл iTextHelloWorld.pdf .

Как только мы загрузим файл с помощью PdfReader , нам нужно создать PdfStamper, который мы будем использовать для применения к файлу дополнительного содержимого, такого как метаданные, шифрование и т. д.:

PdfReader pdfReader = new PdfReader("HelloWorld.pdf");
PdfStamper pdfStamper
= new PdfStamper(pdfReader, new FileOutputStream("encryptedPdf.pdf"));

pdfStamper.setEncryption(
"userpass".getBytes(),
".getBytes(),
0,
PdfWriter.ENCRYPTION_AES_256
);

pdfStamper.close();

В нашем примере мы зашифровали файл двумя паролями: паролем пользователя («userpass»), где пользователь имеет права только на чтение без возможности его распечатать, и паролем владельца («ownerpass»), который используется как мастер-ключ, чтобы дать человеку полный доступ к pdf.

Если мы хотим разрешить пользователю распечатать pdf, то вместо 0 (третий параметр setEncryption ) мы можем передать:

PdfWriter.ALLOW_PRINTING

Конечно, мы также можем смешивать разные разрешения, например:

PdfWriter.ALLOW_PRINTING | PdfWriter.ALLOW_COPY

Имейте в виду, что при использовании iText для установки прав доступа мы также создаем временный PDF-файл, который следует удалить. Если мы не удалим его, он может стать полностью доступным для всех.

5. Создайте PDF в PdfBox

5.1. Вставить текст в PDF

В отличие от iText , библиотека PdfBox предоставляет API, основанный на манипулировании потоком. Нет таких классов, как Chunk / Paragraph и т. д. Класс PDDocument представляет собой представление Pdf в памяти, где пользователь записывает данные, манипулируя классом PDPageContentStream .

Давайте посмотрим на пример кода:

PDDocument document = new PDDocument();
PDPage page = new PDPage();
document.addPage(page);

PDPageContentStream contentStream = new PDPageContentStream(document, page);

contentStream.setFont(PDType1Font.COURIER, 12);
contentStream.beginText();
contentStream.showText("Hello World");
contentStream.endText();
contentStream.close();

document.save("pdfBoxHelloWorld.pdf");
document.close();

5.2. Вставка изображения

Вставка изображений также проста.

Нам нужно загрузить файл и создать PDImageXObject , впоследствии отрисовав его на документе (необходимо указать точные координаты x, y):

PDDocument document = new PDDocument();
PDPage page = new PDPage();
document.addPage(page);

Path path = Paths.get(ClassLoader.getSystemResource("Java_logo.png").toURI());
PDPageContentStream contentStream = new PDPageContentStream(document, page);
PDImageXObject image
= PDImageXObject.createFromFile(path.toAbsolutePath().toString(), document);
contentStream.drawImage(image, 0, 0);
contentStream.close();

document.save("pdfBoxImage.pdf");
document.close();

5.3. Вставка таблицы

К сожалению, PdfBox не предоставляет готовых методов, позволяющих нам создавать таблицы. Что мы можем сделать в этой ситуации, так это нарисовать его вручную, буквально рисуя каждую линию, пока наш рисунок не станет напоминать желаемую таблицу.

5.4. Шифрование файлов

Библиотека PdfBox предоставляет возможность шифрования и настройки прав доступа к файлам для пользователя. По сравнению с iText нам не нужно использовать уже существующий файл, так как мы просто используем PDDocument . Разрешения файла Pdf обрабатываются классом AccessPermission , где мы можем указать, сможет ли пользователь изменять, извлекать содержимое или печатать файл.

Затем мы создаем объект StandardProtectionPolicy , который добавляет к документу защиту на основе пароля. Мы можем указать два типа паролей. Пароль пользователя позволяет пользователю открыть файл с примененными правами доступа, а пароль владельца не имеет ограничений для файла:

PDDocument document = new PDDocument();
PDPage page = new PDPage();
document.addPage(page);

AccessPermission accessPermission = new AccessPermission();
accessPermission.setCanPrint(false);
accessPermission.setCanModify(false);

StandardProtectionPolicy standardProtectionPolicy
= new StandardProtectionPolicy("ownerpass", "userpass", accessPermission);
document.protect(standardProtectionPolicy);
document.save("pdfBoxEncryption.pdf");
document.close();

Наш пример демонстрирует, что если пользователь предоставляет пароль пользователя, файл нельзя изменить или распечатать.

6. Выводы

В этой статье мы узнали, как создать файл PDF в двух популярных библиотеках Java.

Полные примеры из этой статьи можно найти в проекте на основе Maven на GitHub .