首页 > 代码库 > iText生成PDF的关键源码分析

iText生成PDF的关键源码分析

对于iText的学习,基本上都是来源于官网上的例子。这和我学习easyUI、jQuery的途径都是一致的。

这也再次证明了,想用好一个软件,官方提供的例子和文档都是最佳的学习资料。

因为对方是最了解这款软件的人,设计出来的demo当然是最有应用价值的~

这里吐槽一下,iText的demo真难找,官网上反反复复找了好多次才找到,不知道大家是否和我一样,在这里给大家一个捷径。

下面就拿官网的例子来讲一讲,首先如何生成PDF?

    /**
     * 这也就是所有demo中最核心的代码
     * Creates a PDF document.
     * @param filename the path to the new PDF document
     * @throws DocumentException 
     * @throws IOException 
     * @throws    DocumentException 
     * @throws    IOException
     */
    public void createPdf(String filename) throws IOException, DocumentException {
        // step 1	创建一个文档对象
        Document document = new Document();
        // step 2	将文档和一个硬盘文件关联,也就是要输出到文件系统了
        PdfWriter.getInstance(document, new FileOutputStream(filename));
        // step 3	打开文档,只有打开后才能添加内容
        document.open();
        // step 4	添加内容
        BaseFont bf;
        Font font;
 
        for (int i = 0; i < 3; i++) {
            bf = BaseFont.createFont(MOVIES[i][0], MOVIES[i][1], BaseFont.NOT_EMBEDDED);
            font = new Font(bf, 12);
            document.add(new Paragraph(bf.getPostscriptFontName(), font));
            for (int j = 2; j < 5; j++)
                document.add(new Paragraph(MOVIES[i][j], font));
            document.add(Chunk.NEWLINE);
        }
 
 
        // step 5	关闭文档
        document.close();
    }

其中,Document并不和生成的PDF文档对应,我们看看PdfWriter.getInstance(..)的源码:

    public static PdfWriter getInstance(final Document document, final OutputStream os)
    throws DocumentException {
        PdfDocument pdf = new PdfDocument();
        document.addDocListener(pdf);
        PdfWriter writer = new PdfWriter(pdf, os);
        pdf.addWriter(writer);
        return writer;
    }

这里又创建了一个PdfDocument,并将它添加到document的DocListener中,很明显,这里是一个观察者模型的应用。

接下来,对Document对象的所有操作都会被DocListener接收到,并做出相应的动作,比如,我们看看下面document.open()这个方法是如何实现的:

    public void open() {
	if (!close) {
            open = true;
        }
	for (DocListener listener : listeners) {
            listener.setPageSize(pageSize);
	    listener.setMargins(marginLeft, marginRight, marginTop,
            <span style="white-space:pre">	</span>marginBottom);
            listener.open();
        }
    }

看到了吗?里面也调用了所有listener的open方法。add和close方法也都是类似。

所以Document对象在这里担当了被监听的对象,实际上的操作都被应用到了观察者的身上,而观察者继承了Document,并增加了Writer用于输出文件。

当PdfWriter被添加到一个指定的PdfDocument上时,那么对Document的任何添加操作都会被写到关联的OutputStream中。

根据上面说的,其实我们可以对一个document添加多个,比如:

// creation of the document with a certain size and certain margins
 Document document = new Document(PageSize.A4, 50, 50, 50, 50);
  try {
   // creation of the different writers
   HtmlWriter.getInstance(document , System.out);
   PdfWriter.getInstance(document , new FileOutputStream("text.pdf"));
   // we add some meta information to the document
   document.addAuthor("Bruno Lowagie"); 
   document.addSubject("This is the result of a Test."); 
   // we open the document for writing
   document.open(); 
   document.add(new Paragraph("Hello world"));
  } catch(DocumentException de) {
   System.err.println(de.getMessage());
  }
  document.close();

这样的话对document添加的信息,就既能出现在控制台,又能出现在text.pdf中了


iText生成PDF的关键源码分析