前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java(iText)工具包生成PDF

java(iText)工具包生成PDF

作者头像
王念博客
发布2019-07-25 18:15:59
9.5K1
发布2019-07-25 18:15:59
举报
文章被收录于专栏:王念博客王念博客

PDF操作类库 iText

iText是一个非常著名的能够快速产生PDF文件的Java类库。支持文本,表格,图形的操作,可以方便的跟 Servlet 进行结合

iText的更新变化很大,早期版本在PDF样式上可能会有瑕疵,所有我使用的最新的5.5.6包

1.添加Maven依赖

itext核心包 和xmlworder字体包

代码语言:javascript
复制
<dependency>  
    <groupId>com.itextpdf</groupId> 
    <artifactId>itextpdf</artifactId> 
    <version>5.5.6</version>
</dependency>
<dependency>
   <groupId>com.itextpdf.tool</groupId>
   <artifactId>xmlworker</artifactId>
   <version>5.5.6</version>
</dependency>

2.直接生成pdf

非常简单,用文字创建段落等即可,设置好字体、间距、对齐方式等等即可,弄个Hello World 的例子。

代码语言:javascript
复制
package iText;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfPHeaderCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import org.junit.Test;
import java.io.FileOutputStream;
/**
 * author wangnian
 * date 2016/4/1
 */
public class PdfDemo_1 {

    private static void create() throws Exception {

        // 创建一个文档(默认大小A4,边距36, 36, 36, 36)
        Document document = new Document();  
        // 设置文档大小  
        document.setPageSize(PageSize.A4);  
        // 设置边距,单位都是像素,换算大约1厘米=28.33像素  
        document.setMargins(50, 50, 50, 50);
        // 设置pdf生成的路径
        FileOutputStream fileOutputStream= new FileOutputStream("D:/demo.pdf");
        // 创建writer,通过writer将文档写入磁盘
        PdfWriter writer = PdfWriter.getInstance(document,fileOutputStream);
        // demo
        String title = "打油诗";
        String content = "大学校园真开放,宿舍竟能打麻将。东南西北皆可碰,哪管父母心血浓。";
    
        // 定义字体  
        FontFactoryImp ffi = new FontFactoryImp();  
        // 注册全部默认字体目录,windows会自动找fonts文件夹的,返回值为注册到了多少字体  
        ffi.registerDirectories();  
        // 获取字体,其实不用这么麻烦,后面有简单方法  
        Font font = ffi.getFont("宋体",BaseFont.IDENTITY_H,BaseFont.EMBEDDED, 12, Font.UNDEFINED, null);  
    
        // 打开文档,只有打开后才能往里面加东西  
        document.open();  
    
        // 设置作者  
        document.addAuthor("校园作者");
        // 设置创建者  
        document.addCreator("wangnian");
        // 设置主题  
        document.addSubject("测试");
        // 设置标题  
        document.addTitle("打油诗");
    
        // 增加一个段落  
        document.add(new Paragraph(title, font));  
        document.add(new Paragraph(content, font));  
        document.add(new Paragraph("\n\r", font));  
    
        // 创建表格,5列的表格  
        PdfPTable table = new PdfPTable(4);  
        table.setTotalWidth(PageSize.A4.getWidth()- 100);  
        table.setLockedWidth(true);  
        // 创建头  
        PdfPHeaderCell header = new PdfPHeaderCell();  
        header.addElement(new Paragraph(title, font));  
        header.setColspan(4);  
        table.addCell(header);  
        // 添加内容  
        table.addCell(new Paragraph("大学校园真开放",font));
        table.addCell(new Paragraph("宿舍竟能打麻将",font));
        table.addCell(new Paragraph("东南西北皆可碰",font));
        table.addCell(new Paragraph("哪管父母心血浓",font));
    
        document.add(table);  
        // 关闭文档,才能输出  
        document.close();  
        writer.close();  
   }  
    @Test
   public  void test()  {
       try {
           create();
           System.out.println("生成成功");
       }catch (Exception ex){
           System.out.println("文件路径错误或者权限不够");
       }

   }
}

3.字体

我们项目文书字体比较特殊,比如用到了宋体(99%都这个吧)、华文仿宋(安装office后自带)、仿宋_GB2312等,于是就研究了一下pdf字体,网上有很多方法使用中文字体,其实5.0版以后的iText加入字体还是很方便的。

代码语言:javascript
复制
package iText;
import java.io.FileOutputStream;
import com.itextpdf.text.Document;  
import com.itextpdf.text.Font;  
import com.itextpdf.text.FontFactoryImp;  
import com.itextpdf.text.Paragraph;  
import com.itextpdf.text.pdf.PdfWriter;  
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
import org.junit.Test;

/** 
 * 字体 
 * 
 * author wangnian
 * date 2016/4/1
 * 
 */  
public class PdfDemo_2 {  
    
    public static void create() throws Exception {  
        Document document = new Document();  
        PdfWriter writer = PdfWriter.getInstance(document,new FileOutputStream("D:/demo2.pdf"));
        String title = "凉州词";  
        String content = "黄河远上白云间,一片孤城万仞山。羌笛何须怨杨柳,春风不度玉门关。";  
        document.open();  
        document.add(new Paragraph(title, getFont("方正兰亭黑简体")));
        document.add(new Paragraph(content, getFont("迷你简娃娃篆")));
        document.close();  
        writer.close();  
    }  
    
    private static Font getFont(String fontName) {  
        // xmlworker主要功能是html转pdf用的,非常好用,也是itext官方的  
    
        // 这个是xmlworker提供的获取字体方法,很方便,对中文支持很好  
        FontFactoryImp fp = new XMLWorkerFontProvider();
        // 注册指定的字体目录,默认构造方法中会注册全部目录,我这里注册了src/font目录  
        fp.registerDirectory(PdfDemo_2.class.getClassLoader().getResource("weiruanyahei").getFile(), true);
    
        // 最好的地方是直接支持获取中文的名字  
        return fp.getFont(fontName);  
    
        // 当然,最好的方法是自己继承XMLWorkerFontProvider,提供一些常用字体,简单方便  
    }  

    @Test
    public void test() throws Exception {
        create();
        System.out.println("生成成功");
    }  
}

xmlworker的XMLWorkerFontProvider提供了很方便的获取字体方法:

1.注册一个文件夹,里面有哪些字体都可以,比如我demo中的字体

2.使用getFont(字体名)即可获得,不过字体名从哪来的呢

4.页眉页脚

iText5中并没有之前版本HeaderFooter对象设置页眉和页脚,可以利用PdfPageEvent来完成页眉页脚的设置工作。

PdfPageEvent提供了几个pdf在创建时的事件,页眉页脚就是在每页加载完写入的。

每一页加个页码还是很简单的,但是总页码就麻烦了,iText是流模式的写入内容,只有写到最后,才能知道有多少页,那么显示总页数就麻烦了,不过麻烦不代表不可能。

其实iText仅在调用释放模板方法后才将PdfTemplate写入到OutputStream中,否则对象将一直保存在内存中,直到关闭文档。

所以我们可以在最后关闭文档前,使用PdfTemplate写入总页码。可以理解成先写个占位符,然后统一替换。

还是HelloWorld例子:

代码语言:javascript
复制
package iText;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
/**
 * iText5中并没有之前版本HeaderFooter对象设置页眉和页脚<br> 
 * 不过,可以利用PdfPageEventHelper来完成页眉页脚的设置工作。<br> 
 * 就是在页面完成但写入内容之前触发事件,插入页眉、页脚、水印等。<br> 
 * 
 * author wangnian
 * date 2016/4/1
 * 
 */  
   public class MyHeaderFooter extends PdfPageEventHelper {
    Font font = new XMLWorkerFontProvider().getFont("宋体", 12, BaseColor.RED);
    // 总页数  
    PdfTemplate totalPage;
    // 打开文档时,创建一个总页数的模版  
    public void onOpenDocument(PdfWriter writer, Document document) {
        PdfContentByte cb =writer.getDirectContent();
        totalPage = cb.createTemplate(30, 16);  
    }  
    // 一页加载完成触发,写入页眉和页脚  
    public void onEndPage(PdfWriter writer, Document document) {
        PdfPTable table = new PdfPTable(3);
        try {  
            table.setTotalWidth(PageSize.A4.getWidth() - 100);
            table.setWidths(new int[] { 24, 24, 3});  
            table.setLockedWidth(true);  
           table.getDefaultCell().setFixedHeight(-10);  
           table.getDefaultCell().setBorder(Rectangle.BOTTOM);
   
            table.addCell(new Paragraph("我是文字", font));// 可以直接使用addCell(str),不过不能指定字体,中文无法显示
           table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_RIGHT);  
            table.addCell(new Paragraph("第" + writer.getPageNumber() + "页/", font));  
            // 总页数  
            PdfPCell cell = new PdfPCell(Image.getInstance(totalPage));  
            cell.setBorder(Rectangle.BOTTOM);  
            table.addCell(cell);  
            // 将页眉写到document中,位置可以指定,指定到下面就是页脚  
            table.writeSelectedRows(0, -1, 50,PageSize.A4.getHeight() - 20, writer.getDirectContent());  
        } catch (Exception de) {  
            throw new ExceptionConverter(de);  
        }  
    }  
   
    // 全部完成后,将总页数的pdf模版写到指定位置  
    public void onCloseDocument(PdfWriter writer,Document document) {  
        String text = "总" + (writer.getPageNumber() - 1) + "页";  
        ColumnText.showTextAligned(totalPage, Element.ALIGN_LEFT, new Paragraph(text,font), 2, 2, 0);  
    }  
}
代码语言:javascript
复制
package iText;
import java.io.FileOutputStream;
import com.itextpdf.text.BaseColor;  
import com.itextpdf.text.Document;  
import com.itextpdf.text.Element;  
import com.itextpdf.text.ExceptionConverter;  
import com.itextpdf.text.Font;  
import com.itextpdf.text.Image;  
import com.itextpdf.text.PageSize;  
import com.itextpdf.text.Paragraph;  
import com.itextpdf.text.Rectangle;  
import com.itextpdf.text.pdf.ColumnText;  
import com.itextpdf.text.pdf.PdfContentByte;  
import com.itextpdf.text.pdf.PdfPCell;  
import com.itextpdf.text.pdf.PdfPTable;  
import com.itextpdf.text.pdf.PdfPageEventHelper;  
import com.itextpdf.text.pdf.PdfTemplate;  
import com.itextpdf.text.pdf.PdfWriter;  
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
import org.junit.Test;

/** 
 * 页眉、页脚 
 * author wangnian
 * date 2016/4/1
 */
public class PdfDemo_3 {  
   
    public static void create() throws Exception {  
        Document document = new Document(PageSize.A4, 50, 50, 50, 50);
        PdfWriter writer = PdfWriter.getInstance(document,new FileOutputStream("d:/demo3.pdf"));
   
        // 增加页眉页脚  
        writer.setPageEvent(new MyHeaderFooter());
   
        String title = "凉州词";  
        String content = "黄河远上白云间,一片孤城万仞山。羌笛何须怨杨柳,春风不度玉门关。";  
        document.open();  
   
        Font font = new XMLWorkerFontProvider().getFont("宋体");
        for (int i = 0; i <100; i++) {  
            document.add(new Paragraph(title, font));
            document.add(new Paragraph(content,font));  
            document.add(new Paragraph("\n"));  
        }  
        document.close();  
        writer.close();  
    }  

    @Test
    public  void test() throws Exception {
        create();
        System.out.println("生成成功");
    }  
}

5.html转pdf

结果还不错,虽然可以满足我们的要求,但是比较复杂,动态创建一个个的表格和内容过于繁琐,方法太粗暴了,用户 的文档内容或格式变化,就要修改程序了。

先创建html,然后转换成pdf,demo如下:

代码语言:javascript
复制
package iText;

import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;  
import java.io.InputStream;  
import java.io.OutputStream;  
import com.itextpdf.text.Document;  
import com.itextpdf.text.pdf.PdfWriter;  
import com.itextpdf.tool.xml.XMLWorkerHelper;
import org.junit.Test;

/** 
 * html转pdf
 * author wangnian
 * date 2016/4/1
 * 
 */  
public class PdfDemo_4 {  
    
    public static void create() throws Exception {  
    
        // html中字体非常郁闷  
        // 1. html中不指定字体,则默认使用英文字体,中文会不显示。  
        // 2. html中指定的字体必须是英文名称,如宋体:font-family:SimSun;  
        // 3. html中不能指定自定义字体,必须指定itext支持的字体,还好itext支持字体比较多,常见操作系统带的都支持  
        // 4. 暂没有找到如何html中支持自定义字体方法,网上都是修改源码实现默认字体中文,也很重要  
    
        StringBuilder html = new StringBuilder();
        html.append("<html>");  
        html.append("<body style='font-size:20px;font-family:SimSun;'>");
        html.append("<table width='19cm'border='1' cellpadding='0' cellspacing='0'>");  
        html.append("<tr>");  
        html.append("<td colspan='2'>凉州词</td>");  
        html.append("</tr>");  
        html.append("<tr>");  
        html.append("<td>黄河远上白云间,一片孤城万仞山。</td>");  
        html.append("<td>羌笛何须怨杨柳,春风不度玉门关。</td>");  
        html.append("</tr>");  
        html.append("</table>");  
        html.append("</body>");  
        html.append("</html>");  
    
        InputStream is = new ByteArrayInputStream(html.toString().getBytes());
    
        OutputStream os = new FileOutputStream("D:/demo4.pdf");
        Document document = new Document();  
    
        PdfWriter writer = PdfWriter.getInstance(document,os);  
    
        document.open();  
    
        // 将html转pdf  
        XMLWorkerHelper.getInstance().parseXHtml(writer,document, is);  
    
        document.close();  
    }  

    @Test
    public  void test() throws Exception {
        create();
        System.out.println("生成成功");
    }  
}

此处使用了XmlWorker,XmlWorker也是iText官方的,目前和iText版本一起更新,可以讲XHTML转换成pdf,支持大部分样式和标签,是大部分哦,不是全部。

目前我们就用的这个方式,写好html文档,使用时动态替换html中的标记位,然后生成pdf。

使用XHTML转pdf要注意的地方:

1. html中不指定字体,则默认使用英文字体,中文会不显示;

2. html中指定的字体必须是英文名称;如宋体:font-family:SimSun;正确 font-family:宋体;则错误,竟然unicode也不行。

3. html中不能指定自定义字体(比如上文中的方正兰亭黑),但是itext一般操作系统的字体都支持,如果ubuntu上没有微软雅 黑,可以从windows下拷贝雅黑字体Yahei.ttf 放进来ubuntu上/usr/share/fonts/路径。

4. pdf中添加图片也非常简单,例如:<img src='d:/1.jpg'/>,就可以了。

5. XHTML不是HTML,所以任何标签都要完整结束,比如<br>错误,必须<br/>才行。

写一个html模版很简单,需要对html和css熟练,调生成的样式部分比较麻烦(比如文字多了会切掉,不切会影响整体样式,表格线有粗有细,xmlworker不支持全部css等),一般A4纸都是厘米单位的,html中最好也使用厘米,处理简单点。

本文地址(防爬虫不标注来源):http://my.oschina.net/wangnian/blog/661389

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • PDF操作类库 iText
    • 1.添加Maven依赖
      • 2.直接生成pdf
        • 3.字体
          • 4.页眉页脚
            • 5.html转pdf
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档