+2

Đọc và Ghi File PDF trong Java

PDF (Portable Document Format) là một định dạng tập tin văn bản khá phổ biển của hãng Adobe Systems. Tương tự như định dạng Word (.doc), PDF hỗ trợ văn bản thô (text) cùng với phông chữ, hình ảnh đồ họa, âm thanh và nhiều hiệu ứng khác. Tuy nhiên, việc hiển thị văn bản PDF không phụ thuộc vào môi trường làm việc của người sử dụng (cấu hình máy, phần mềm và hệ điều hành). Không như văn bản Word, một văn bản PDF, trong hầu hết các trường hợp, sẽ được hiển thị giống nhau trên những môi trường làm việc khác nhau. Chính vì ưu điểm này, định dạng PDF đã trở nên phổ biển cho việc phát hành sách, báo hay các tài liệu khác qua mạng Internet.

Có nhiều lựa chọn để tạo file .pdf trong Java: 1. Từ data object chuyển đổi thành XML (sủ dụng JAXB, XStream...), sau đó chuyển đổi thành XSL-FO (XSL Formatting Objects) và từ đó render ra file PDF bằng cách sử dụng Formatting Objects Processor (thường là Apache™ FOP). 2. Ngoài ra bạn của thể lựa chọn sử dụng library để thực hiện việc này. Một số library phổ biến: - iText - Apache PDFBox - BFO

Trong khuôn khổ blog này tôi xin giới thiệu với các bạn cách đọc và ghi file .pdf sử dụng iText. Itext là một thư viện cho phép bạn đọc, tạo và chỉnh sửa file pdf trên nhiều ngôn ngữ như Java, .Net, Android...

Để sử dụng itext trước tiên bạn cần download itext http://sourceforge.net/projects/itext/ và include itext vào chương trình của bạn.

I. Tạo file PDF đơn giản với Itext.

Chúng ta cùng tìm hiểu qua một chút về cấu trúc cơ bản của 1 file pdf. Mọi file pdf đều gồm các thành phần sau: 110612_1237_PDFFileForm2.png 1. Header là dòng đầu tiên của file .pdf xác định version kĩ thuật được sử dụng trong file pdf. 2. Body được sử dụng để giữ toàn bộ dữ liệu được hiển thi cho người dùng bao gồm : text stream, image, các thành phần multimedia... 3.'xref' Table là bảng tham khảo chéo, trong đó có chứa các tài liệu tham khảo cho tất cả các đối tượng trong tài liệu. 4. Trailer quy định cách đọc các 'xref' Table và các đối tượng đặc biệt khác.

Bây giờ chúng ta sẽ thực hiện tạo một file .pdf đơn giản.

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfWriter;

import java.io.FileOutputStream;
import java.io.FileNotFoundException;

public class HelloWorldExample {

    public static void main(String[] args) {
		// tạo một document
        Document document = new Document();

        try {
        	// khởi tạo một PdfWriter truyền vào document và FileOutputStream
            PdfWriter.getInstance(document, new FileOutputStream("HelloWorld.pdf"));

            // mở file để thực hiện viết
            document.open();
            // thêm nội dung sử dụng add function
            document.add(new Paragraph("A Hello World PDF document."));
            // đóng file
            document.close();

        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}

Và đây là kết quả mà ta nhận được. Capture.PNG

Bây giờ chúng ta sẽ tìm hiểu một số Element đơn giản trong iText:

Chunk : dùng để thêm một đoạn nhỏ của văn bản

    import com.itextpdf.text.Chunk;

    ...

    	for(int i = 0; i < 10; i++) {
        	Chunk chunk = new Chunk("Hello World!!");
        	document.add(chunk);
        }
    ...
kết quả nhận được sẽ là:

Capture.PNG

Chunk chỉ thực hiện việc viết từ trái sang phải và không biết khi nào cần phải xuống dòng, để làm điều này chúng ta cần bọc nó trong 1 Phrase.

Phrase:

    import com.itextpdf.text.Phrase;

    ...

    	Phrase phrase = new Phrase();
    	for(int i = 0; i < 10; i++) {
        	Chunk chunk = new Chunk("Hello World!!");
        	phrase.add(chunk);
        }
        document.add(phrase);
    ...

Capture.PNG Phrase giúp bạn thêm được dấu xuống dòng nhưng nếu bạn muốn căn chỉnh vị trí, thụt đầu dòng thì nó lại không thực hiện được. Để giải quyết vấn đề này ta sử dụng Paragraph.

Paragraph:

	import com.itextpdf.text.Element;

    ...
	//Khai báo 2 paragraph
    Paragraph paragraph1 = new Paragraph("This is Paragraph 1");
    Paragraph paragraph2 = new Paragraph("This is Paragraph 2");
    //Định dạng đoạn văn bản thứ nhất
    paragraph1.setIndentationLeft(80);
    paragraph1.setIndentationRight(80);
    paragraph1.setAlignment(Element.ALIGN_CENTER);
    paragraph1.setSpacingAfter(15);
    //Đinh dạng đoạn văn bản thứ 2
    paragraph2.setSpacingBefore(15);
    paragraph2.setAlignment(Element.ALIGN_LEFT);
    //Thêm nội dung cho cả 2 đoạn văn bản trên
    Phrase phrase = new Phrase("This is a large sentence.");
    for(int i = 0; i < 10; i++)
    {
        paragraph1.add(phrase);
        paragraph2.add(phrase);
    }
    //Thêm 2 đoạn văn bản vào document
    document.add(paragraph1);
    document.add(paragraph2);
    ...

Và đây là kết quả thu được: Capture.PNG Bạn có thể thực hiện hầu hết các format văn bản khi sử dụng Paragraph

II. Anchor (link), Image, List, Table trong iText

  1. Anchor (link)

    Để tạo link với iText ta sử dụng class Anchor. Link được tạo ra tương tự như trong Html.

        import com.itextpdf.text.Anchor;

        ...

        //Tạo 1 đoạn văn bản
        Paragraph paragraph = new Paragraph();
        paragraph.add(new Phrase("You can download the IText at "));
        //Tạo 1 link
        Anchor anchor = new Anchor("Download");
        anchor.setReference("http://sourceforge.net/projects/itext/");
        //Thêm link vào đoạn văn bản
        paragraph.add(anchor);
        //Thêm đoạn văn bản vào document
        document.add(paragraph);

        ...
Kết quả:
![Untitled.png](https://images.viblo.asia/0aafc5df-204e-4c19-a117-16d81e7fc0d8.png)
Ngoài ra bạn có thể tạo internal links trong document của bạn tương tự như internal links trong HTML.
  1. Image

    Bạn có thể làm rất nhiểu thứ với Image khi sử dụng itext như là zoom, xoay, tạo border...

    import com.itextpdf.text.Image;

    ...

    //Thêm 1 ảnh
    Image image1 = Image.getInstance("framgia.png");
    document.add(new Paragraph("Image 1"));
    document.add(image1);

	//Thêm 1 ảnh được zoom 300%
    Image image2 = Image.getInstance("framgia.png");
    document.add(new Paragraph("Image 2"));
    image2.scalePercent(300f);
    document.add(image2);

	//Thêm 1 ảnh xoay 45 độ

    Image image3 = Image.getInstance("framgia.png");
    document.add(new Paragraph("Image 3"));
    image3.setRotationDegrees(45f);
    document.add(image3);

    ...
Kết quả:

Capture.PNG

  1. List

    Bạn có thể thêm ordered list hoặc unordered list vào document của bạn khi sử dụng class List của iText.

    import com.itextpdf.text.List;

    ...

    //Tạo một ordered list
    List orderedList = new List(List.ORDERED);
    orderedList.add(new ListItem("Item 1"));
    orderedList.add(new ListItem("Item 2"));
    orderedList.add(new ListItem("Item 3"));

    document.add(orderedList);

    //Tạo một unordered list
    List unorderedList = new List(List.UNORDERED);
    unorderedList.add(new ListItem("Item 1"));
    unorderedList.add(new ListItem("Item 2"));
    unorderedList.add(new ListItem("Item 3"));

    document.add(unorderedList);

    ...
Kết quả
![Capture.PNG](https://images.viblo.asia/81905a1f-b4e1-4595-9098-8949b511af92.png)
  1. Table

    Khi bạn muốn tạo 1 table trong document thì PdfPTable là class mà bạn cần dùng đến

    import com.itextpdf.text.pdf.PdfPCell;
	import com.itextpdf.text.pdf.PdfPTable;

    ...
    //Khởi tạo một table có 3 cột
    PdfPTable table = new PdfPTable(3);
	//Khởi tạo 3 ô header
    PdfPCell header1 = new PdfPCell(new Paragraph("Header 1"));
    PdfPCell header2 = new PdfPCell(new Paragraph("Header 2"));
    PdfPCell header3 = new PdfPCell(new Paragraph("Header 3"));
	//Thêm 3 ô header vào table
    table.addCell(header1);
    table.addCell(header2);
    table.addCell(header3);

	//Khởi tạo 3 ô data: ô số 1 là string, ô số 2 là ảnh, ô số 3 là table
    PdfPCell data1 = new PdfPCell(new Paragraph("Data String"));
    PdfPCell data2 = new PdfPCell(Image.getInstance("framgia.png"), false);

    PdfPTable nestedTable = new PdfPTable(2);
    nestedTable.addCell(new Paragraph("Nested Cell 1"));
    nestedTable.addCell(new Paragraph("Nested Cell 2"));
    PdfPCell data3 = new PdfPCell(nestedTable);
	//Thêm data vào bảng.
    table.addCell(data1);
    table.addCell(data2);
    table.addCell(data3);

    document.add(table);

    ...
Với đoạn code trên thì đây là kết quả ta thu được.
![Capture.PNG](https://images.viblo.asia/e2eef3df-7368-41c5-945a-8aa0ecf405a4.png)
Nếu sử dụng PdfTable thì bạn chỉ có lựa chọn là thêm từng ô dữ liệu.

III. Đọc file PDF với iText

Bây giờ ta sẽ tiến hành đọc file .pdf có sẵn.

import java.io.IOException;

import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.parser.PdfTextExtractor;

public class Progam {
    public static void main(String[] args) {
    	 try {
             //Khai báo PdfReader với giá trị truyền vào là path của file cần đọc
             PdfReader reader = new PdfReader("Java How to Program, 9th edition.pdf");
             //In ra số lượng page của file đã đọc
             System.out.println("This PDF has "+reader.getNumberOfPages()+" pages.");
             //Sử dụng PdfTextExtractor để đọc toàn bộ text ở trang 100
             String page = PdfTextExtractor.getTextFromPage(reader, 100);
             System.out.println("Page 100 Content:\n\n"+page+"\n\n");

         } catch (IOException e) {
             e.printStackTrace();
         }
    }
}

Và đây là kết quả thu được:

Capture.PNG

IV. Lời kết

iText là 1 library rất tiện ích khi làm việc với file PDF trong java. Trong khuôn khổ blog này mình chỉ giới thiệu được những tính năng cơ bản nhất của iText. Hẹn gặp lại các bạn ở blog sau.

Tài liệu tham khảo: - Itext documents: http://itextpdf.com/apis - Ebook : iText in Action, Second Edition

Link Git sản phẩm: Đang cập nhật


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí