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

1. Въведение

В тази бърза статия ще се съсредоточим върху създаването на PDF документ от нулата въз основа на популярната библиотека iText и PdfBox.

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

Нека да разгледаме зависимостите на Maven, които трябва да бъдат включени в нашия проект:

 com.itextpdf itextpdf 5.5.10   org.apache.pdfbox pdfbox 2.0.4 

Най-новата версия на библиотеките можете да намерите тук: iText и PdfBox.

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

 org.bouncycastle bcprov-jdk15on 1.56  

Най-новата версия на библиотеката може да бъде намерена тук: The Bounty 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 , който всъщност е низ с приложен шрифт.

Освен това парчетата могат да се комбинират с други елементи като абзаци , раздели и др. , Което води до приятно изглеждащи документи.

4.2. Вмъкване на изображение

Библиотеката iText предоставя лесен начин за добавяне на изображение към документа. Просто трябва да създадем екземпляр на Image и да го добавим към документа .

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 ще създаде редове на таблица, докато са дефинирани всички необходими клетки, което означава, че след като създадете таблица с 3 колони и добавите 8 клетки към нея, ще бъдат показани само 2 реда с по 3 клетки във всяка.

Нека да разгледаме примера:

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();

Създаваме нова таблица с 3 колони и 3 реда. Първият ред ще третираме като заглавка на таблица с променен цвят на фона и ширина на границата:

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. Вмъкване на изображение

Поставянето на изображения е лесно.

First we need to load a file and create a PDImageXObject, subsequently draw it on the document (need to provide exact x,y coordinates).

That's all:

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. Inserting a Table

Unfortunately, PdfBox does not provide any out-of-box methods allowing creating tables. What we can do in such situation is to draw it manually – literally, draw each line until our drawing resembles our dreamed table.

5.4. File Encryption

PdfBox library provides a possibility to encrypt, and adjust file permission for the user. Comparing to iText, it does not require to use an already existing file, as we simply use PDDocument. Pdf file permissions are handled by AccessPermission class, where we can set if a user will be able to modify, extract content or print a file.

Subsequently, we create a StandardProtectionPolicy object which adds password-based protection to the document. We can specify two types of password. The user password, after which person will be able to open a file with applied access permissions and owner password (no limitations to the file):

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.