Tạo tệp PDF trong Java

1. Giới thiệu

Trong bài viết nhanh này, chúng tôi sẽ tập trung vào việc tạo tài liệu PDF từ đầu dựa trên thư viện iText và PdfBox phổ biến.

2. Sự phụ thuộc của Maven

Chúng ta hãy xem xét các phụ thuộc Maven, cần được đưa vào dự án của chúng tôi:

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

Bạn có thể tìm thấy phiên bản mới nhất của các thư viện tại đây: iText và PdfBox.

Cần thêm một phần phụ thuộc bổ sung, trong trường hợp tệp của chúng tôi cần được mã hóa. Gói Bounty Castle Provider chứa các triển khai các thuật toán mật mã và được yêu cầu bởi cả hai thư viện:

 org.bouncycastle bcprov-jdk15on 1.56  

Bạn có thể tìm thấy phiên bản mới nhất của thư viện tại đây: Nhà cung cấp Lâu đài Tiền thưởng.

3. Tổng quan

Cả hai, iText và PdfBox đều là thư viện java được sử dụng để tạo / thao tác các tệp pdf. Mặc dù đầu ra cuối cùng của các thư viện là giống nhau, nhưng chúng hoạt động theo cách khác nhau một chút. Chúng ta hãy nhìn vào chúng.

4. Tạo Pdf trong IText

4.1. Chèn văn bản trong Pdf

Hãy cùng xem, cách một tệp mới có văn bản “Hello World” được chèn vào tệp 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();

Tạo pdf bằng cách sử dụng thư viện iText dựa trên việc thao tác các đối tượng thực hiện giao diện Elements trong Document (trong phiên bản 5.5.10 có 45 trong số các cách triển khai đó).

Phần tử nhỏ nhất có thể được thêm vào tài liệu và được sử dụng được gọi là Chunk , về cơ bản là một chuỗi có phông chữ được áp dụng.

Ngoài ra, Chunk có thể được kết hợp với các phần tử khác như Đoạn văn , Phần , v.v. để tạo ra các tài liệu đẹp mắt.

4.2. Chèn hình ảnh

Thư viện iText cung cấp một cách dễ dàng để thêm hình ảnh vào tài liệu. Chúng ta chỉ cần tạo một cá thể Hình ảnh và thêm nó vào Tài liệu .

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. Chèn bảng

Chúng tôi có thể gặp sự cố khi muốn thêm bảng vào pdf của mình. May mắn thay, iText cung cấp các chức năng như vậy.

Đầu tiên những gì chúng ta cần làm là tạo một đối tượng PdfTable và trong hàm tạo cung cấp một số cột cho bảng của chúng ta. Bây giờ chúng ta có thể chỉ cần thêm ô mới bằng cách gọi

Bây giờ chúng ta có thể chỉ cần thêm ô mới bằng cách gọi phương thức addCell trên đối tượng bảng mới được tạo. iText sẽ tạo các hàng trong bảng miễn là tất cả các ô cần thiết được xác định, điều đó có nghĩa là khi bạn tạo bảng có 3 cột và thêm 8 ô vào đó, chỉ 2 hàng với 3 ô trong mỗi ô sẽ được hiển thị.

Hãy xem ví dụ:

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

Chúng tôi tạo một bảng mới với 3 cột và 3 hàng. Hàng đầu tiên chúng tôi sẽ coi là tiêu đề bảng với màu nền và chiều rộng đường viền đã thay đổi:

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

Hàng thứ hai sẽ bao gồm ba ô chỉ với văn bản, không có định dạng bổ sung.

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

Chúng tôi không chỉ có thể bao gồm văn bản trong ô mà còn bao gồm cả hình ảnh. Ngoài ra, mỗi ô có thể được định dạng riêng lẻ, trong ví dụ được trình bày bên dưới, chúng tôi áp dụng các điều chỉnh căn chỉnh theo chiều ngang và chiều dọc:

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. Mã hóa tệp

Để áp dụng quyền sử dụng thư viện iText, chúng ta cần phải tạo tài liệu pdf. Trong ví dụ của chúng tôi, chúng tôi sẽ sử dụng tệp iTextHelloWorld.pdf đã tạo trước đó.

Khi chúng tôi tải tệp bằng PdfReader , chúng tôi cần tạo PdfStamper được sử dụng để áp dụng nội dung bổ sung vào tệp như siêu dữ liệu, mã hóa, v.v.:

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

Trong ví dụ của chúng tôi, chúng tôi đã mã hóa tệp bằng hai mật khẩu. Mật khẩu người dùng (“userpass”) trong đó người dùng chỉ có quyền chỉ đọc không có khả năng in ra và mật khẩu của chủ sở hữu (“ownerpass”) được sử dụng làm khóa chính cho phép một người có toàn quyền truy cập vào pdf.

Nếu chúng ta muốn cho phép người dùng in pdf, thay vì 0 (tham số thứ ba của setEncryption ), chúng ta có thể chuyển:

PdfWriter.ALLOW_PRINTING

Tất nhiên, chúng tôi có thể kết hợp các quyền khác nhau như:

PdfWriter.ALLOW_PRINTING | PdfWriter.ALLOW_COPY

Hãy nhớ rằng việc sử dụng iText để đặt quyền truy cập, chúng tôi cũng đang tạo một bản pdf tạm thời sẽ bị xóa và nếu không, mọi người hoàn toàn có thể truy cập được.

5. Tạo Pdf trong PdfBox

5.1. Chèn văn bản trong Pdf

Trái ngược với iText , thư viện PdfBox cung cấp API dựa trên thao tác luồng. Không có các lớp như Chunk / Paragraph, v.v. Lớp PDDocument là một biểu diễn Pdf trong bộ nhớ nơi người dùng ghi dữ liệu bằng cách thao tác với lớp PDPageContentStream .

Hãy xem ví dụ mã:

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. Chèn hình ảnh

Chèn hình ảnh là đơn giản.

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

Ví dụ của chúng tôi đưa ra một tình huống mà nếu người dùng cung cấp mật khẩu người dùng, thì tệp không thể được sửa đổi và in.

6. Kết luận

Trong hướng dẫn này, chúng tôi đã thảo luận về các cách tạo tệp pdf trong hai thư viện Java phổ biến.

Có thể tìm thấy đầy đủ các ví dụ trong dự án dựa trên Maven trên GitHub.