• Springboot集成ItextPdf


    目录

    一、概述

    二、Itext API

    1.PDF文档生成

    3.常用对象

    一、文档对象

    二、操作对象 

    三、内容对象

    四、表格对象

    四、常用案例

    一、水印

    三、页眉页脚

    四、合并多个PDF

    五、表单PDF

    六、模板PDF

    一、html模板

     二、使用工具构建PDF模板

     7、HTML转PDF

    8、删除页码

    九、读取PDF内容

    十、删除pdf内容

     十一、一张A4打印多个面单


    一、概述

            因公司前段时间需要自定义面单,在原有的pdf上追加内容和编辑内容,水印,页码等需求,当时采用了itext5实现,因而最近闲下来总结一下。

            Apache iText 是一个开源 Java 库,支持 PDF 文档的开发和转换。其目前遵从AGPL开源协议,AGPL 可以说是最严格的 GPL 了,并且Itext有很多product开始收费,但所需的功能基本上开源的API都能满足。

    当前使用版本:5.5.11

    二、Itext API

    1.PDF文档生成

    构建步骤:

            创建文档对象、初始化PdfWriter、打开文档、填充内容、关闭文档。

    1. /**
    2. * 创建pdf
    3. */
    4. public static void createPdf() throws Exception{
    5. // 1-创建文本对象 Document
    6. Document document = new Document(PageSize.A4, 500, 150, 50, 50);
    7. FileOutputStream out=new FileOutputStream("./doc/1.pdf");
    8. // 2-初始化 pdf输出对象 PdfWriter
    9. PdfWriter.getInstance(document, out);
    10. // 3-打开 Document
    11. document.open();
    12. // 4-往 Document 添加内容
    13. document.add(new Paragraph("test! PDF!!!"));
    14. // 5-关闭 Document
    15. document.close();
    16. }

     2.PDF内部结构

    分为四层,第一层和第四层由低级操作来进行操作,第二层、第三层由高级对象操作

    层对象: PdfContentByte:包含用户定位的文本和页面的图形内容的对象。

    第一层操作只能使用PdfWriter.DirectContent操作,第四层使用DirectContentUnder操作。

    第二层和第三层的PdfContentByte是由IText内部操作,没有提供api接口。

    4、 操作:

     ⑴ PdfWriter 对象:写入PDF文档

    第 1 层操作:PdfWriter. getDirectContent(),

    第 2 层操作:getDirectContentUnder()。

    ⑵ PdfStamper 对象:将额外内容应用于PDF文档的页面。

    第 1 层操作: PdfStamper. getUnderContent(1),-可以加页数

    第 2 层操作: PdfStamper .getOverContent(1)。

    5、作用:添加水印、背景、添加内容到绝对位置、合并PDF

    3.常用对象

    一、文档对象

    Document、Rectangle、PageSize

    1、 Document — 文档对象

    构造方法: 有参构造、无参构造

    无参构造:

            Document() :默认是A4大小,做左右上下外边距分别是36.

    有参构造:

             Document(Rectangle pageSize, float marginLeft, float marginRight, float marginTop,

      float marginBottom)

    marginLeft:左外边距  marginRight:右外边距
    marginTop:上外边距  marginBottom:下外边距 

    PDF文档对象跟html页面相似。

    属性

    Document document =new Document(); // 默认页面大小是A4
    Document document =new Document(PageSize.A4); // 指定页面大小为A4
    Document document =new Document(PageSize.A4,50,50,30,20); // 指定页面大小为A4,且自定义页边距(marginLeft、marginRight、marginTop、marginBottom)
    其中页面大小PageSize也可自定义大小,例:new Document(new Rectangle(400, 500));

    // 作者
    document.addAuthor("作者");
    // 创建日期
    document.addCreationDate();
    // 创建关键字
    document.addKeywords("测试");
    // 创建生产商,自动使用iText
    document.addProducer();
    // 创建程序
    document.addCreator("创建人");
    // 标题
    document.addTitle("标题");
    // 主题
    document.addSubject("主题");

    //页边空白
    document.setMargins(10, 20, 30, 40);

    方法

    //PDF添加内容
    document.add(new Paragraph("PDF添加内容"));
    //添加Page
    document.newPage();
    //控制是否显示空白页
    writer.setPageEmpty(true);
    //监听器
    document.addDocListener();
    //添加js脚本
    document.setJavaScript_onLoad(); 

    //横向打印

    document = new Document(PageSize.A4.rotate());

    document = new Document(tRectangle.rotate());

    2、PdfWriter-文档解析器

    PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("./doc/11.pdf"));
    //面框大小。允许的名称有:“crop”、“trim”、“art”和“bleach”。
    writer.setBoxSize("crop",PageSize.A6);
    writer.setPageEmpty(true);
    //设置裁剪框大小
    writer.setCropBoxSize(PageSize.A8);
    // 设置密码为:"123" 需要根绝itext版本添加加密算法依赖:http://mvnrepository.com/artifact/com.itextpdf/itextpdf/
    writer.setEncryption("密码".getBytes(), "123".getBytes(),PdfWriter.ALLOW_SCREENREADERS,PdfWriter.STANDARD_ENCRYPTION_128);
    //PDF版本
    writer.setPdfVersion(PdfWriter.PDF_VERSION_1_2); 

     2、 Rectangle— 页面对象

    构造方法:

    Rectangle(final float llx, final float lly, final float urx, final float ury)
    Rectangle(PageSize.A4)
    Rectangle(float urx, float ury)
    //rotation旋转比例
    Rectangle(float urx, float ury, int rotation)
    Rectangle(Rectangle rect) 

    四个参数:

            前面两个参数代表第一个点的 xy 坐标,后面两个参数代表第二个点的 xy 坐标值,Itext 将以这两个点作为对角点来创建一个矩形。

    方法:

     //旋转比例
    tRectangle.setRotation();
    //背景
    tRectangle.setBackgroundColor();
    //边框
    tRectangle.setBorder();
    //边框背景
    tRectangle.setBorderColor();
    //边框宽度
    tRectangle.setBorderWidth();
    tRectangle.setTop();
    tRectangle.setLeft();
    tRectangle.setRight();
    tRectangle.setBottom();

    1. public static void getRectangle() throws Exception {
    2. // 1-创建一个pdf文档,document
    3. Document document = new Document();// 默认PageSize.A4, 36, 36, 36, 36
    4. // 2-Rectangle(pdf页面)创建Document
    5. // 一般是四个参数表示:左下角的坐标和右上角的坐标
    6. Rectangle tRectangle = PageSize.A4;// PageSize封装了大量常用的Rectangle数据
    7. tRectangle = new Rectangle(800, 600);// 长宽
    8. tRectangle = new Rectangle(0, 0, 800, 600);// 等于上面
    9. //其他页面属性:不能和PageSize封装的静态一起使用
    10. tRectangle.setBackgroundColor(BaseColor.BLACK);// 背景色
    11. tRectangle.setBorder(1220);// 边框
    12. tRectangle.setBorderColor(BaseColor.BLUE);
    13. tRectangle.setBorderWidth(244.2f);
    14. document = new Document(tRectangle);
    15. // 解析器
    16. PdfWriter.getInstance(document, new FileOutputStream("./doc/3.pdf"));
    17. document.open();
    18. document.newPage();
    19. document.add(new Paragraph("New page"));
    20. document.close();
    21. }

    二、操作对象 

    PdfWriter、PdfStamper、PdfReader、PdfCopy

    三、内容对象

    1.字体对象

    1)BaseFont-确认支持中文

    1. com.itextpdf
    2. itext-asian
    3. 5.2.0

    2)Font-字体的设置,如颜色,字体,大小等

    方式一:使用Windows系统字体(TrueType)
            BaseFont baseFont = BaseFont.createFont("C:/Windows/Fonts/SIMYOU.TTF", BaseFont.IDENTITY_H,
                    BaseFont.NOT_EMBEDDED);
    方式二:使用资源字体(ClassPath)
           BaseFont baseFont = BaseFont.createFont("/SIMYOU.TTF", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
    方式三:使用iTextAsian.jar中的字体
            BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);

    Font font = new Font(baseFont);
    // 设置字体大小
    font.setSize(13);
    // 设置字体颜色
    font.setColor(new BaseColor(255, 0, 0));
    // 设置类型,为正常
    font.setStyle(Font.NORMAL);
    // 设置类型,加粗
    font.setStyle(Font.BOLD);
    // 设置类型,倾斜
    font.setStyle(Font.ITALIC);
    // 设置类型,下划线
    font.setStyle(Font.UNDERLINE);
    // 设置类型,可组合,倾斜+删除线
    font.setStyle(Font.ITALIC | Font.STRIKETHRU);

    1. public static Font getChineseFont() {
    2. BaseFont bfChinese;
    3. Font fontChinese = null;
    4. try {
    5. //支持中文
    6. bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
    7. fontChinese = new Font(bfChinese, 12, Font.NORMAL, BaseColor.BLUE);
    8. } catch (DocumentException e) {
    9. e.printStackTrace();
    10. } catch (IOException e) {
    11. e.printStackTrace();
    12. }
    13. return fontChinese;
    14. }

    2.Element - 元素

            内容对象基本都实现这个接口。如Chunk、 Phrase、 Paragraph

            一般用于内容居中定位。

    ALIGN_LEFT, ALIGN_CENTER、 ALIGN_RIGHT, ALIGN_JUSTIFIED 。

    如设置居中对齐:setAlignment(Element.ALIGN_CENTER)

    3.Chunk - 块对象

         能被添加到文档的文本的最小单位,块可以用于构建其他基础元素如短句、段落、锚点等,块是一个有确定字体的字符串,要添加块到文档中时,其他所有布局变量均要被定义。它有字体、大小、颜色、粗体,背景色、下划线,删除线等属性。

    Chunk.NEWLINE-换行,
    setUnderline(0.2f, -2f)- 下划线
    setTextRise(6)-上浮

    1. public static void testChunk() throws Exception {
    2. // 1-创建一个pdf文档,document
    3. Document document = new Document();// 默认PageSize.A4, 36, 36, 36, 36
    4. // 解析器
    5. PdfWriter.getInstance(document, new FileOutputStream("./doc/4.pdf"));
    6. document.open();
    7. document.newPage();
    8. String[] contries = new String[] {"美国", "英甲", "中国", "朝鲜", "日本"};
    9. for (int index = 1; index <= contries.length; index++) {
    10. String contry = contries[index - 1];
    11. Chunk chunk = new Chunk(contry, getChineseFont());
    12. //字间隔
    13. // chunk.setWordSpacing(10f);
    14. //行间距
    15. // chunk.setLineHeight(20f);
    16. document.add(chunk);
    17. //块之间设置间隔
    18. document.add(new Chunk(" "));
    19. Font font = FontFactory.getFont("STSong-Light", "UniGB-UCS2-H", 6, Font.BOLD, BaseColor.WHITE);
    20. Chunk id = new Chunk(index + "", font);
    21. // 设置块的背景色
    22. id.setBackground(BaseColor.BLACK, 1f, 0.5f, 1f, 1.5f);
    23. // 设置上标,其中参数表示,离开基线的距离,如果设置负数就表示设置下标
    24. id.setTextRise(6);
    25. document.add(id);
    26. //块之间设置间隔
    27. document.add(new Chunk(" "));
    28. // 换行 需要设置行间距 不然上移 覆盖
    29. // document.add(Chunk.NEWLINE);
    30. }
    31. document.close();
    32. }

    3.Phrase - 短语对象

            短句(Phrase)是一系列以特定间距(两行之间的距离)作为参数的块,一个短句有一个主字体,但短句中的一些块具有不同于主字体的字体,你有更多的选择去创建短句。简单来说,就是由多个同一行间距块组成。

    默认情况下,行间距是1.5倍字体大小,可以不用设置行间距,就比较好的显示文档。

     add(Element)-添加方法
    add(Chunk.NEWLINE)-内部换行
    setLeading(14f)-行间距

    1. public static void testPhrase() throws Exception {
    2. // 1-创建一个pdf文档,document
    3. Document document = new Document();// 默认PageSize.A4, 36, 36, 36, 36
    4. // 解析器
    5. PdfWriter.getInstance(document, new FileOutputStream("./doc/5.pdf"));
    6. document.open();
    7. document.newPage();
    8. String[] contries = new String[] {"美国", "英甲", "中国", "朝鲜", "日本"};
    9. Font BOLD_UNDERLINED = FontFactory.getFont("STSong-Light", "UniGB-UCS2-H", 12, Font.BOLD | Font.UNDERLINE);
    10. Font NORMAL = FontFactory.getFont("STSong-Light", "UniGB-UCS2-H", 12);
    11. for (int index = 1; index <= contries.length; index++) {
    12. String contry = contries[index - 1];
    13. Phrase director = new Phrase();
    14. director.add(new Chunk(contry, BOLD_UNDERLINED));
    15. director.add(new Chunk(",", BOLD_UNDERLINED));
    16. director.add(new Chunk(" ", NORMAL));
    17. director.add(new Chunk(contry, NORMAL));
    18. //设置行间距
    19. director.setLeading(66f);
    20. document.add(director);
    21. //内部换行
    22. document.add(Chunk.NEWLINE);
    23. }
    24. document.close();
    25. }

    4.Paragraph

            段落是一系列块和(或)短句。同短句一样,段落有确定的间距。用户还可以指定缩排;在边和(或)右边保留一定空白,段落可以左对齐、右对齐和居中对齐。添加到文档中的每一个段落将自动另起一行。

            说明:一个段落有一个且仅有一个间距,如果你添加了一个不同字体的短句或块,原来的间距仍然有效,你可以通过setLeading来改变间距,但是段落中所有内容将使用新的中的间距。

    add(Element)-添加;

    setLeading(20f)-行间距,一个Paragraph只有一个行间距;
    setIndentationLeft()-左缩进,

    setIndentationRight-右缩进,

    setFirstLineIndent-首行缩进;
    setSpacingBefore-设置上空白,

    setSpacingAfter(10f)-设置段落下空;
    setAlignment(Element.ALIGN_CENTER)-居中对齐;

    //直线
    Paragraph p1 =new Paragraph();
    p1.add(new Chunk(new LineSeparator()));
    doc.add(p1);

    //点线
    Paragraph p2 =new Paragraph();
    p2.add(new Chunk(new DottedLineSeparator()));

    //下滑线
    LineSeparator UNDERLINE = new LineSeparator(1, 100, null, Element.ALIGN_CENTER, -2);
    Paragraph p3 = new Paragraph("NNNNNNNNNNN");
    p3.add(UNDERLINE);
    document.add(p3);

    1. public static void testParagraph() throws Exception {
    2. // 1-创建一个pdf文档,document
    3. Document document = new Document();// 默认PageSize.A4, 36, 36, 36, 36
    4. // 解析器
    5. PdfWriter.getInstance(document, new FileOutputStream("./doc/6.pdf"));
    6. document.open();
    7. document.newPage();
    8. String[] contries = new String[] {"美国", "英甲", "中国", "朝鲜", "日本"};
    9. Font BOLD_UNDERLINED = FontFactory.getFont("STSong-Light", "UniGB-UCS2-H", 12, Font.BOLD | Font.UNDERLINE);
    10. Font NORMAL = FontFactory.getFont("STSong-Light", "UniGB-UCS2-H", 12);
    11. for (int index = 1; index <= contries.length; index++) {
    12. String contry = contries[index - 1];
    13. Paragraph p = new Paragraph();
    14. p.add(new Chunk("年代: ", BOLD_UNDERLINED));
    15. p.add(new Phrase("标题: ", NORMAL));
    16. p.add(new Phrase(contry, NORMAL));
    17. // 设置行间距
    18. p.setLeading(20f);
    19. document.add(p);
    20. // 内部换行
    21. document.add(Chunk.NEWLINE);
    22. }
    23. Paragraph paragraph = new Paragraph("这是一个缩进演示:段落是一系列块和(或)短句。同短句一样,段落有确定的间距。用户还可以指定缩排;"
    24. + "在边和(或)右边保留一定空白,段落可以左对齐、右对齐和居中对齐。添加到文档中的每一个段落将自动另起一行。说明:一个段落有一个且仅有一个间距,"
    25. + "如果你添加了一个不同字体的短句或块,原来的间距仍然有效,你可以通过SetLeading来改变间距,但是段落中所有内容将使用新的中的间距。更改分割符 通常," +
    26. "当文本不能放在一行时,文本将被分割成不同的部分,iText首先会查找分割符,如果没有找到,文本将在行尾被截断。有一些预定的分割符如“ ”空格和“-”连字符," +
    27. "但是你可以使用setSplitCharacter方法来覆盖这些默认值。",
    28. NORMAL);
    29. // 默认情况下,文本的对齐方式为左对齐
    30. // paragraph.setAlignment(Element.ALIGN_JUSTIFIED);
    31. // 首行缩进(FirstLineIndent),左边缩进(indentationLeft),右边缩进(IndentationRight)
    32. paragraph.setFirstLineIndent(10f);
    33. paragraph.setIndentationLeft(10f);
    34. paragraph.setIndentationLeft(12f);
    35. document.add(paragraph);
    36. document.close();
    37. }

    5、列表(List)

            列表就是一个有顺序的段落对象集合。

    1. public static void testList() throws Exception {
    2. // 1-创建一个pdf文档,document
    3. Document document = new Document();// 默认PageSize.A4, 36, 36, 36, 36
    4. // 解析器
    5. PdfWriter.getInstance(document, new FileOutputStream("./doc/7.pdf"));
    6. document.open();
    7. document.newPage();
    8. String[] contries = new String[] {"美国", "英甲", "中国", "朝鲜", "日本"};
    9. Font NORMAL = FontFactory.getFont("STSong-Light", "UniGB-UCS2-H", 12);
    10. document.add(new Chunk("默认列表演示1:", NORMAL));
    11. document.add(Chunk.NEWLINE);
    12. List list = new com.itextpdf.text.List();
    13. for (int index = 1; index <= contries.length; index++) {
    14. String contry = contries[index - 1];
    15. list.add(new ListItem(contry, NORMAL));
    16. }
    17. document.add(list);
    18. document.add(Chunk.NEWLINE);
    19. document.add(new Chunk("不显示数字演示2:", NORMAL));
    20. document.add(Chunk.NEWLINE);
    21. // 编号
    22. list = new List(false);
    23. for (int index = 1; index <= contries.length; index++) {
    24. String contry = contries[index - 1];
    25. list.add(new ListItem(contry, NORMAL));
    26. }
    27. document.add(list);
    28. document.add(Chunk.NEWLINE);
    29. document.add(new Chunk("使用#作为列表符号3:", NORMAL));
    30. document.add(Chunk.NEWLINE);
    31. list = new List();
    32. // 设置编号
    33. list.setListSymbol("#");
    34. for (int index = 1; index <= contries.length; index++) {
    35. String contry = contries[index - 1];
    36. list.add(new ListItem(contry, NORMAL));
    37. }
    38. document.add(list);
    39. // 换行
    40. document.add(Chunk.NEWLINE);
    41. document.add(new Chunk("显示数字演示4:", NORMAL));
    42. document.add(Chunk.NEWLINE);
    43. list = new List(true);
    44. for (int index = 1; index <= contries.length; index++) {
    45. String contry = contries[index - 1];
    46. list.add(new ListItem(contry, NORMAL));
    47. }
    48. document.add(list);
    49. document.add(Chunk.NEWLINE);
    50. document.add(new Chunk("罗马数字列表演示5:", NORMAL));
    51. document.add(Chunk.NEWLINE);
    52. List list1 = new RomanList();
    53. for (int index = 1; index <= contries.length; index++) {
    54. String contry = contries[index - 1];
    55. list1.add(new ListItem(contry, NORMAL));
    56. }
    57. document.add(list1);
    58. document.add(Chunk.NEWLINE);
    59. document.add(new Chunk("希腊字母列表演示6:", NORMAL));
    60. document.add(Chunk.NEWLINE);
    61. List list2 = new GreekList();
    62. for (int index = 1; index <= contries.length; index++) {
    63. String contry = contries[index - 1];
    64. list2.add(new ListItem(contry, NORMAL));
    65. }
    66. document.add(list2);
    67. document.add(Chunk.NEWLINE);
    68. document.add(new Chunk("ZapfDingbatsNumberList演示7:", NORMAL));
    69. document.add(Chunk.NEWLINE);
    70. List list3 = new ZapfDingbatsNumberList(10);
    71. for (int index = 1; index <= contries.length; index++) {
    72. String contry = contries[index - 1];
    73. list3.add(new ListItem(contry, NORMAL));
    74. }
    75. document.add(list3);
    76. document.add(Chunk.NEWLINE);
    77. document.add(new Chunk("ZapfDingbatsList演示8:", NORMAL));
    78. document.add(Chunk.NEWLINE);
    79. List list4 = new ZapfDingbatsList(43, 30);
    80. for (int index = 1; index <= contries.length; index++) {
    81. String contry = contries[index - 1];
    82. list4.add(new ListItem(contry, NORMAL));
    83. }
    84. document.add(list4);
    85. document.add(Chunk.NEWLINE);
    86. document.add(new Chunk("列表嵌套演示9:", NORMAL));
    87. document.add(Chunk.NEWLINE);
    88. List rootList = new List(List.UNORDERED);
    89. rootList.add(new ListItem("Item 1"));
    90. // 子列表
    91. List sublist = new List(true, false, 30);
    92. sublist.setListSymbol(new Chunk("", FontFactory.getFont(FontFactory.HELVETICA, 6)));
    93. sublist.add("A");
    94. sublist.add("B");
    95. rootList.add(sublist);
    96. rootList.add(new ListItem("Item 2"));
    97. // 子列表
    98. sublist = new List(true, false, 30);
    99. sublist.setListSymbol(new Chunk("", FontFactory.getFont(FontFactory.HELVETICA, 6)));
    100. sublist.add("C");
    101. sublist.add("D");
    102. rootList.add(sublist);
    103. document.add(rootList);
    104. document.close();
    105. }

    参考来源:
    一步一步 IText.Sharp Chunk Phrase Paragraph List使用 - cdboy - 博客园上面两篇介绍了PDF文档的创建和中文支持设置方法,下面对文档经常使用的对象时行介绍:块(Chunk)、短句(Phrase)、段落(Paragraph)、列表(List)文档中的对象UML图,如下:一、icon-default.png?t=N7T8https://www.cnblogs.com/LifelongLearning/archive/2011/03/30/2000072.html

    6.Image - 图像,抽象类 继承了Rectangle。 

    Image img = Image.getInstance("./doc/a.png");

    setAlignment(Image.LEFT)-对齐方式
    setBorder(Image.BOX)-边框
    setBorderWidth(10)-边框宽度
    setBorderColor(BaseColor.WHITE)-边框颜色,  
    scaleToFit(1000, 72)-大小
    setRotation(-20);//旋转 弧度
    setRotationDegrees(-30);// 旋转 角度
    scalePercent(50);//依照比例缩放
    setAbsolutePosition()-绝对位置

    1. public static void testImage() throws Exception {
    2. // 1-创建一个pdf文档,document
    3. Document document = new Document();// 默认PageSize.A4, 36, 36, 36, 36
    4. // 解析器
    5. PdfWriter.getInstance(document, new FileOutputStream("./doc/9.pdf"));
    6. document.open();
    7. document.newPage();
    8. // 图片Image对象
    9. Image img = Image.getInstance("./doc/a.jpeg");
    10. img.setAlignment(Image.LEFT);
    11. img.setBorder(Image.BOX);
    12. img.setBorderWidth(10);
    13. img.setBorderColor(BaseColor.WHITE);
    14. img.scaleToFit(800, 72);// 大小
    15. img.setRotation(-20);//旋转 弧度
    16. img.setRotationDegrees(-30);// 旋转 角度
    17. img.scalePercent(30);//依照比例缩放
    18. document.add(img);
    19. document.close();
    20. }

    7、Anchor(锚点、超链接)

    //超链接
    Anchor anchor =new Anchor("this is anchor");

    //定位 点击后,跳到topline的位置
    Anchor gotop =new Anchor("go top");
    gotop.setReference("#us");

    1. public static void testAnchor() throws Exception {
    2. // 1-创建一个pdf文档,document
    3. Document document = new Document();// 默认PageSize.A4, 36, 36, 36, 36
    4. // 解析器
    5. PdfWriter.getInstance(document, new FileOutputStream("./doc/10.pdf"));
    6. document.open();
    7. document.newPage();
    8. // Anchor超链接和锚点对象: internal and external links
    9. Paragraph country = new Paragraph();
    10. Anchor dest = new Anchor("我是锚点,也是超链接", getChineseFont());
    11. dest.setName("CN"); // 设置锚点的名字
    12. dest.setReference("http://www.baidu.com");// 连接
    13. country.add(dest);
    14. country.add(String.format(": %d sites", 10000));
    15. document.add(country);
    16. document.close();
    17. }

    8、 Chapter、Section(大纲)

    1. public static void testChapterAndSection() throws Exception {
    2. // 1-创建一个pdf文档,document
    3. Document document = new Document();// 默认PageSize.A4, 36, 36, 36, 36
    4. // 解析器
    5. PdfWriter.getInstance(document, new FileOutputStream("./doc/11.pdf"));
    6. document.open();
    7. Paragraph title = new Paragraph("一级标题", getChineseFont());
    8. Chapter chapter = new Chapter(title, 1);
    9. Paragraph title2 = new Paragraph("二级标题-1", getChineseFont());
    10. Section section = chapter.addSection(title2);
    11. section.setBookmarkTitle("sectionName");// 左边目录显示的名字,不写就默认名
    12. section.setIndentation(30);
    13. section.setIndentationLeft(5);
    14. section.setBookmarkOpen(false);
    15. section.setNumberStyle(Section.NUMBERSTYLE_DOTTED_WITHOUT_FINAL_DOT);
    16. Section section2 = chapter.addSection(new Paragraph("二级标题-2", getChineseFont()));
    17. section2.setIndentation(30);
    18. section2.setIndentationLeft(5);
    19. section2.setBookmarkOpen(false);
    20. section2.setNumberStyle(Section.NUMBERSTYLE_DOTTED_WITHOUT_FINAL_DOT);
    21. Section subsection = section.addSection(new Paragraph("三级标题-1", getChineseFont()));
    22. subsection.setIndentationLeft(10);
    23. // subsection.setNumberDepth(1);
    24. subsection.setNumberStyle(Section.NUMBERSTYLE_DOTTED);
    25. Section subsection2 = section2.addSection(new Paragraph("三级标题-2", getChineseFont()));
    26. subsection2.setIndentationLeft(10);
    27. subsection2.setNumberStyle(Section.NUMBERSTYLE_DOTTED);
    28. document.add(chapter);
    29. document.close();
    30. }

    9、PdfOutline - 目录 / 书签 更每一页相关

    PdfOutline(PdfOutline parent, PdfAction action, String title, boolean open)

    parent:根目录

    PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("./doc/11.pdf"));
    PdfContentByte cb = writer.getDirectContent();

    //获取外部根目录
    PdfOutline root = cb.getRootOutline();

    PdfAction:pdf点击事件,title:标题,open:是否打开

    1. public static void testPdfOutline() throws Exception {
    2. // 1-创建一个pdf文档,document
    3. Document document = new Document();// 默认PageSize.A4, 36, 36, 36, 36
    4. // 解析器
    5. PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("./doc/11.pdf"));
    6. document.open();
    7. document.add(new Chunk("Chapter 1").setLocalDestination("1"));
    8. document.newPage();
    9. document.add(new Chunk("Chapter 2").setLocalDestination("2"));
    10. document.add(new Paragraph(new Chunk("Sub 2.1").setLocalDestination("2.1")));
    11. document.add(new Paragraph(new Chunk("Sub 2.2").setLocalDestination("2.2")));
    12. document.newPage();
    13. document.add(new Chunk("Chapter 3").setLocalDestination("3"));
    14. //内容对象
    15. PdfContentByte cb = writer.getDirectContent();
    16. //获取外部根目录
    17. PdfOutline root = cb.getRootOutline();
    18. //一级目录
    19. new PdfOutline(root, PdfAction.gotoLocalPage("1", false), "Chapter 1");
    20. //一级目录
    21. PdfOutline oline2 = new PdfOutline(root, PdfAction.gotoLocalPage("2", false), "Chapter 2");
    22. //是否打开
    23. oline2.setOpen(false);
    24. //添加二级子目录
    25. new PdfOutline(oline2, PdfAction.gotoLocalPage("2.1", false), "Sub 2.1");
    26. new PdfOutline(oline2, PdfAction.gotoLocalPage("2.2", false), "Sub 2.2");
    27. //添加三级目录
    28. new PdfOutline(root, PdfAction.gotoLocalPage("3", false), "Chapter 3");
    29. document.close();
    30. }

    10、Header, Footer

    1. public static void testHeadFooter() throws Exception{
    2. Document doc = new Document();
    3. PdfWriter writer = PdfWriter.getInstance(doc, new FileOutputStream("./doc/12.pdf"));
    4. writer.setPageEvent(new PdfPageEventHelper() {
    5. public void onEndPage(PdfWriter writer, Document document) {
    6. PdfContentByte cb = writer.getDirectContent();
    7. cb.saveState();
    8. cb.beginText();
    9. BaseFont bf = null;
    10. try {
    11. bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
    12. } catch (Exception e) {
    13. e.printStackTrace();
    14. }
    15. cb.setFontAndSize(bf, 10);
    16. float x = document.top(-20);
    17. //左
    18. cb.showTextAligned(PdfContentByte.ALIGN_LEFT,"顶部-左",document.left(), x, 0);
    19. //中
    20. cb.showTextAligned(PdfContentByte.ALIGN_CENTER,writer.getPageNumber()+ " page",(document.right() + document.left())/2,x, 0);
    21. //右
    22. cb.showTextAligned(PdfContentByte.ALIGN_RIGHT,"顶部-右",document.right(), x, 0);
    23. //Footer
    24. float y = document.bottom(-20);
    25. //左
    26. cb.showTextAligned(PdfContentByte.ALIGN_LEFT,"底部-左",document.left(), y, 0);
    27. //中
    28. cb.showTextAligned(PdfContentByte.ALIGN_CENTER,writer.getPageNumber()+" page",(document.right() + document.left())/2, y, 0);
    29. //右
    30. cb.showTextAligned(PdfContentByte.ALIGN_RIGHT,"底部-右",document.right(), y, 0);
    31. cb.endText();
    32. cb.restoreState();
    33. }
    34. });
    35. doc.open();
    36. doc.add(new Paragraph("1 page"));
    37. doc.close();
    38. }

    四、表格对象

    PdfPTable、PdfPCell

    1、构造方法:

    //列数
    PdfPTable datatable = new PdfPTable(6);
    //每个单元格宽度
    PdfPTable datatable = new PdfPTable(new float[]{1,2,3})
    //表格嵌套
    PdfPTable rootTable=new PdfPTable(new PdfPTable(6));

    PdfPCell cell= new PdfPCell(new Paragraph(“表格”, 中文支持)
    //默认单元格
    PdfPCell cell1=new PdfPCell();
    //单元格放入table
    PdfPCell cell2=new PdfPCell(table,new PdfPCell())
    //单元格放入图片
    PdfPCell cell3=new PdfPCell(Image image);

    2、结构:

    PdfPTable[PdfPTable[PdfPCell[Paragraph]]]
    PdfPTable[PdfPTable[PdfPCell[PdfPTable,PdfPCell]]]

    3、方法:

    PdfPTable:

     //设置表格上面空白行
    setSpacingBefore(15f);
    //设置表格下面空白行
    setSpacingAfter(40f);
    //第一行作为标题. 定义为标题的行应该保留在新页面上.
    setHeaderRows(1);
    // 设置列的宽度 百分比
    setWidths(cellsWidth);
    //表格的总宽度
    setTotalWidth(300f);
    // 表格的宽度百分比
    setWidthPercentage(100);
    //得到默认单元格
    getDefaultCell()
    添加单元格
    addCell()

    //写入绝对位置
    pdfPTable.writeSelectedRows(0,-1, 0, -1, 100, 200, tContent);

    PdfPCell:
    //背景色
    setBackgroundColor(BaseColor.CYAN)
    //最小高度
    2)setMinimumHeight(30f)
    //固定高度。表格的高度通过单元格高度完成
    setFixedHeight(40f)
    //无边框
    setBorder(Rectangle.NO_BORDER)
    //无边框。不设,默认是有边框的
    setBorderWidth(0)
    setBorderWidthBottom(Rectangle.NO_BORDER);
    setBorderWidthRight(Rectangle.NO_BORDER);
    setBorderWidthTop(Rectangle.NO_BORDER);
    setBorderWidthLeft(Rectangle.NO_BORDER);
    //边框颜色
    setBorderColor(new BaseColor(255, 0, 0))
    //水平居中
    setHorizontalAlignment(Element.ALIGN_CENTER)
    //垂直居中。设置单元格内容的显示
    setVerticalAlignment(Element.ALIGN_MIDDLE)
    //跨2行
    setRowspan(2)
    //跨2列
    setColspan(2)

    1. public static void insertTableAndPdfPCell() throws Exception {
    2. Document document = new Document(PageSize.A4, 50, 50, 50, 50);
    3. // 使用PDFWriter进行写文件操作
    4. PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("./doc/13.pdf"));
    5. document.open();
    6. // 中文字体
    7. Font fontChinese = getChineseFont();
    8. Paragraph titlle=new Paragraph("测试表格",fontChinese);
    9. //中间
    10. titlle.setAlignment(Element.ALIGN_CENTER);
    11. document.add(titlle);
    12. PdfPTable pTable=new PdfPTable(2);
    13. PdfPCell pdfPCell=new PdfPCell(new Paragraph("编号:"+"111111111",fontChinese));
    14. pdfPCell.setBorder(Rectangle.NO_BORDER);
    15. pTable.addCell(pdfPCell);
    16. pdfPCell=new PdfPCell(new Paragraph("名称"+"aaaa",fontChinese));
    17. pdfPCell.setBorder(Rectangle.NO_BORDER);
    18. pTable.addCell(pdfPCell);
    19. float[] widths={1f,1f}; //设置列的宽度 百分比
    20. pTable.setWidths(widths);
    21. pTable.setSpacingBefore(15f);
    22. document.add(pTable);
    23. //设置表头
    24. String[] tableHeader=new String[6];
    25. String[] tableCont=new String[6];
    26. int colNumber = 6;
    27. for (int i = 0; i < 6; i++) {
    28. tableHeader[i]="表头"+(i+1);
    29. tableCont[i]="内容"+(i+1);
    30. }
    31. // 创建有6列的表格 可以设置重复表头
    32. PdfPTable datatable = new PdfPTable(colNumber);
    33. //设置表格上面空白行
    34. datatable.setSpacingBefore(15f);
    35. //每个单元格宽度
    36. // PdfPTable datatable = new PdfPTable(new float[]{1, 1, 1, 1, 1, 1})
    37. //第一行作为标题. 定义为标题的行应该保留在新页面上.
    38. datatable.setHeaderRows(1);
    39. // 定义表格的宽度
    40. int[] cellsWidth = {1, 1, 1, 1, 1, 1};
    41. // 设置列的宽度 百分比
    42. datatable.setWidths(cellsWidth);
    43. //表格的总宽度
    44. // datatable.setTotalWidth(300f);
    45. // 表格的宽度百分比
    46. datatable.setWidthPercentage(100);
    47. // 单元格的间隔
    48. datatable.getDefaultCell().setPadding(2);
    49. // 边框宽度
    50. datatable.getDefaultCell().setBorderWidth(2);
    51. // 设置表格的底色
    52. datatable.getDefaultCell().setBackgroundColor(BaseColor.GREEN);
    53. datatable.getDefaultCell().setHorizontalAlignment(Element.ALIGN_CENTER);
    54. // 添加表头元素
    55. for (int i = 0; i < colNumber; i++) {
    56. datatable.addCell(new Paragraph(tableHeader[i], fontChinese));
    57. }
    58. // 添加表格的内容
    59. for (int i = 0; i < colNumber; i++) {
    60. datatable.addCell(new Paragraph(tableCont[i], fontChinese));
    61. }
    62. // 空白表格
    63. for (int i = 0; i < colNumber; i++) {
    64. PdfPCell cell = new PdfPCell(new Paragraph(""));
    65. // 单元格高度
    66. cell.setFixedHeight(20);
    67. datatable.addCell(cell);
    68. }
    69. // 设置表格下面空白行
    70. datatable.setSpacingAfter(40f);
    71. // 把表格加入文档
    72. document.add(datatable);
    73. // 跨行跨列表格
    74. PdfPTable table = new PdfPTable(3);
    75. // 3列表格
    76. PdfPCell cell; // 单元格
    77. cell = new PdfPCell(new Phrase("跨三列", getChineseFont()));
    78. // 跨3列
    79. cell.setColspan(3);
    80. table.addCell(cell);
    81. cell = new PdfPCell(new Phrase("跨二行", getChineseFont()));
    82. // 跨2行
    83. cell.setRowspan(2);
    84. table.addCell(cell);
    85. table.addCell(new PdfPCell(new Phrase("第一行,第一列", getChineseFont())));
    86. table.addCell(new PdfPCell(new Phrase("第一行,第二列", getChineseFont())));
    87. table.addCell(new PdfPCell(new Phrase("第二行,第一列", getChineseFont())));
    88. table.addCell(new PdfPCell(new Phrase("第二行,第二列", getChineseFont())));
    89. document.add(table);
    90. // 表格的嵌套 4列
    91. PdfPTable tableFather = new PdfPTable(4);
    92. //设置表格上面空白行
    93. tableFather.setSpacingBefore(20f);
    94. // 1行2列
    95. PdfPTable nested1 = new PdfPTable(2);
    96. //设置无边框
    97. nested1.getDefaultCell().setBorderWidthBottom(Rectangle.NO_BORDER);
    98. nested1.getDefaultCell().setBorderWidthRight(Rectangle.NO_BORDER);
    99. nested1.getDefaultCell().setBorderWidthTop(Rectangle.NO_BORDER);
    100. nested1.getDefaultCell().setBorderWidthLeft(Rectangle.NO_BORDER);
    101. nested1.addCell("1.1");
    102. nested1.getDefaultCell().setBorderWidthLeft(1);
    103. nested1.addCell("1.2");
    104. // 2行1列
    105. PdfPTable nested2 = new PdfPTable(1);
    106. nested2.getDefaultCell().setBorderWidthBottom(Rectangle.NO_BORDER);
    107. nested2.getDefaultCell().setBorderWidthRight(Rectangle.NO_BORDER);
    108. nested2.getDefaultCell().setBorderWidthTop(Rectangle.NO_BORDER);
    109. nested2.getDefaultCell().setBorderWidthLeft(Rectangle.NO_BORDER);
    110. nested2.addCell("2.1");
    111. nested2.getDefaultCell().setBorderWidthTop(1);
    112. nested2.addCell("2.2");
    113. // 将表格插入到指定位置
    114. for (int i = 0; i < 12; i++) {
    115. switch (i){
    116. case 1:
    117. tableFather.addCell(nested1);
    118. break;
    119. case 6:
    120. tableFather.addCell(nested2);
    121. break;
    122. default:
    123. tableFather.addCell("cell " + i);
    124. break;
    125. }
    126. }
    127. // 设置表格下面空白行
    128. tableFather.setSpacingAfter(40f);
    129. // 把表格加入文档
    130. document.add(tableFather);
    131. //表格嵌套
    132. PdfPTable rootTable=new PdfPTable(tableFather);
    133. document.add(rootTable);
    134. PdfPTable pdfPTable=new PdfPTable(1);
    135. pdfPTable.setTotalWidth(300f);
    136. //得到层
    137. PdfContentByte tContent = writer.getDirectContent();
    138. PdfPCell pdfPCell1=new PdfPCell(new Paragraph("编号:"+"fsddd",fontChinese));
    139. pdfPTable.addCell(pdfPCell1);
    140. //写入绝对位置
    141. pdfPTable.writeSelectedRows(0,-1, 0, -1, 100, 200, tContent);
    142. pTable.setSpacingBefore(15f);
    143. document.add(pdfPTable);
    144. document.close();
    145. }

    四、常用案例

            PDF分为四层,第一层和第四层由低级操作来进行操作,第二层、第三层由高级对象操作(从下往上) 

    操作对象:PdfWriter、PdfStamper

    PdfWriter writer = PdfWriter.getInstance(document, out);
    //在内容下方
    PdfContentByte under = writer.getDirectContentUnder();
    //在内容上方
    under = writer.getDirectContent();

    PdfStamper stamp = new PdfStamper(reader, out);
    //在内容下方添加
    PdfContentByte under = stamp.getUnderContent(1);// 拿到层,页数
    //在内容上方添加
    PdfContentByte over = stamp.getOverContent(1);// 拿到层

    一、水印

    1.PdfWriter

    1. public static void testShuiyin() throws Exception {
    2. FileOutputStream out = new FileOutputStream("./doc/13.pdf");
    3. Document document = new Document(PageSize.A4);
    4. PdfWriter writer = PdfWriter.getInstance(document, out);
    5. JLabel label = new JLabel();
    6. int textH = 0;
    7. int textW = 0;
    8. int interval = -5;
    9. String waterMarkName="测试水印"; //需要添加的水印文字
    10. label.setText(waterMarkName);
    11. FontMetrics metrics = label.getFontMetrics(label.getFont());
    12. textH = metrics.getHeight(); //字符串的高, 只和字体有关
    13. textW = metrics.stringWidth(label.getText()); //字符串的宽
    14. float opacity=0.1f;//水印字体透明度
    15. int fontsize=12; //水印字体大小
    16. int angle=30; //水印倾斜角度(0-360)
    17. int heightRatio=2; //数值越大每页竖向水印越少
    18. int widthRatio=2; //数值越大每页横向水印越少
    19. // 设置水印透明度
    20. PdfGState gs = new PdfGState();
    21. //这里是透明度设置
    22. gs.setFillOpacity(opacity);
    23. //这里是条纹不透明度
    24. gs.setStrokeOpacity(0.1f);
    25. document.open();
    26. // 在内容下方
    27. PdfContentByte under = writer.getDirectContentUnder();
    28. // 在内容上方
    29. // under = writer.getDirectContent();
    30. under.beginText();
    31. under.setGState(gs);
    32. BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);
    33. under.setFontAndSize(bf, fontsize);
    34. Rectangle rectangle = document.getPageSize();
    35. // under.setTextMatrix(30, 30);
    36. // 水印文字成45度角倾斜
    37. for (int height = interval + textH; height < rectangle.getHeight()*2; height = height + textH * heightRatio) {
    38. for (int width = interval + textW; width < rectangle.getWidth()*1.5 + textW; width = width + textW * widthRatio) {
    39. // rotation:倾斜角度
    40. under.showTextAligned(Element.ALIGN_LEFT, waterMarkName, width - textW, height - textH, angle);
    41. }
    42. }
    43. under.endText();
    44. document.add(new Paragraph("测试",getChineseFont()));
    45. document.close();
    46. }

     2.PdfStamper

    1. public static void testShuiyin1() throws Exception {
    2. FileOutputStream out = new FileOutputStream("./doc/14.pdf");
    3. // 读取器
    4. PdfReader reader = new PdfReader("./doc/12.pdf");
    5. // 解析器与输出
    6. PdfStamper stamp = new PdfStamper(reader, out);
    7. // 图片水印
    8. Image img = Image.getInstance("./doc/aaa.jpg");
    9. img.setAbsolutePosition(100, 100);// 位置
    10. // 在内容下方添加
    11. PdfContentByte under = stamp.getOverContent(1);// 拿到层,页数
    12. under.addImage(img);
    13. // 文字水印
    14. // 在内容上方添加
    15. PdfContentByte over = stamp.getOverContent(1);// 拿到层
    16. over.beginText();
    17. BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
    18. over.setFontAndSize(bf, 18);
    19. over.setTextMatrix(30, 30);
    20. over.showTextAligned(Element.ALIGN_LEFT, "文字水印", 230, 430, 45);
    21. over.endText();
    22. // 背景图
    23. Image img2 = Image.getInstance("./doc/a.jpeg");
    24. //水印与背景的区别:背景只需要把绝对置为从 文档左下角开始。即设置setAbsolutePosition(0, 0)
    25. img2.setAbsolutePosition(0, 0);
    26. PdfContentByte under2 = stamp.getUnderContent(1);
    27. under2.addImage(img2);
    28. // 关闭
    29. stamp.close();
    30. reader.close();
    31. }

     3.监听器

    1. /**
    2. * 添加水印
    3. * @author ShaoMin
    4. * @throws IOException
    5. *
    6. */
    7. public static void testShuiyin2() throws Exception {
    8. FileOutputStream out = new FileOutputStream("./doc/15.pdf");
    9. Document doc = new Document();
    10. PdfWriter writer = PdfWriter.getInstance(doc, out);
    11. doc.open();
    12. writer.setPageEvent(new PdfPageHelper());
    13. doc.newPage();
    14. doc.add(new Chunk("aaa"));
    15. doc.close();
    16. }
    17. class PdfPageHelper extends PdfPageEventHelper {
    18. @Override
    19. public void onOpenDocument(PdfWriter writer, Document document) {
    20. super.onOpenDocument(writer, document);
    21. writer.getDirectContent().createTemplate(30, 16);
    22. }
    23. @Override
    24. public void onStartPage(PdfWriter writer, Document document) {
    25. // 获取当前页码,以便我们可以自定义每个页面的标题。
    26. super.onStartPage(writer, document);
    27. }
    28. @Override
    29. public void onEndPage(PdfWriter writer, Document document) {
    30. BaseFont bf = null;
    31. try {
    32. bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
    33. } catch (Exception e) {
    34. e.printStackTrace();
    35. }
    36. extracted(writer, document, bf);
    37. addWaterMark(writer, bf);
    38. }
    39. private void extracted(PdfWriter writer, Document document, BaseFont bf) {
    40. PdfContentByte cb = writer.getDirectContent();
    41. cb.saveState();
    42. cb.beginText();
    43. cb.setFontAndSize(bf, 10);
    44. float x = document.top(-20);
    45. // 左
    46. cb.showTextAligned(PdfContentByte.ALIGN_LEFT, "顶部-左", document.left(), x, 0);
    47. // 中
    48. cb.showTextAligned(PdfContentByte.ALIGN_CENTER, writer.getPageNumber() + " page", (document.right() + document.left()) / 2, x, 0);
    49. // 右
    50. cb.showTextAligned(PdfContentByte.ALIGN_RIGHT, "顶部-右", document.right(), x, 0);
    51. // Footer
    52. float y = document.bottom(-20);
    53. // 左
    54. cb.showTextAligned(PdfContentByte.ALIGN_LEFT, "底部-左", document.left(), y, 0);
    55. // 中
    56. cb.showTextAligned(PdfContentByte.ALIGN_CENTER, writer.getPageNumber() + " page", (document.right() + document.left()) / 2, y, 0);
    57. // 右
    58. cb.showTextAligned(PdfContentByte.ALIGN_RIGHT, "底部-右", document.right(), y, 0);
    59. cb.endText();
    60. cb.restoreState();
    61. }
    62. /**
    63. * 添加水印
    64. * @param writer
    65. * @param bf
    66. */
    67. private void addWaterMark(PdfWriter writer, BaseFont bf) {
    68. for (int i = 1; i < 7; i++) {
    69. for (int j = 1; j < 10; j++) {
    70. PdfContentByte cb = writer.getDirectContent();
    71. cb.saveState();
    72. cb.beginText();
    73. cb.setColorFill(BaseColor.GRAY);
    74. PdfGState gs = new PdfGState();
    75. gs.setFillOpacity(0.1f);
    76. cb.setGState(gs);
    77. cb.setFontAndSize(bf, 12);
    78. cb.showTextAligned(Element.ALIGN_MIDDLE, "添加水印", 75 * i, 80 * j, 30);
    79. cb.endText();
    80. cb.restoreState();
    81. }
    82. }
    83. }
    84. }

    三、页眉页脚

    第一种方式:现有的PDF追加页眉页码

    1. public static void insertHeadAndFoot2() throws Exception {
    2. FileOutputStream out = new FileOutputStream("./doc/17.pdf");
    3. Document doc = new Document(PageSize.A4);
    4. ByteArrayOutputStream outputStream=new ByteArrayOutputStream();
    5. PdfWriter.getInstance(doc, outputStream);
    6. doc.open();
    7. doc.add(new Paragraph("1 page"));
    8. doc.newPage();
    9. doc.add(new Paragraph("2 page"));
    10. doc.close();
    11. BaseFont bf = null;
    12. try {
    13. bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
    14. } catch (Exception e) {
    15. e.printStackTrace();
    16. }
    17. //读取现存在的pdf文件 追加页码
    18. PdfReader reader = new PdfReader(outputStream.toByteArray());
    19. int numberOfPages = reader.getNumberOfPages();
    20. PdfStamper stamp = new PdfStamper(reader, out);
    21. for (int i = 1; i <= numberOfPages; i++) {
    22. PdfContentByte cb = stamp.getOverContent(i);// 页数
    23. cb.beginText();
    24. cb.setFontAndSize(bf, 10);
    25. cb.showTextAligned(PdfContentByte.ALIGN_CENTER, "- " + (i) + " -", (doc.right() + doc.left()) / 2, doc.bottom(-20), 0);
    26. cb.endText();
    27. }
    28. stamp.close();
    29. reader.close();
    30. }

    第二种方式:   监听器 - PdfPageEvent. 如果无法确定总页数,可以该监听器重写onEndPage方法。

    writer.setPageEvent() 方法要放在 document.open() 方法之前,这样才能确定总数

    1. public static void insertHeadAndFoot() throws Exception {
    2. FileOutputStream out = new FileOutputStream("./doc/16.pdf");
    3. Document doc = new Document();
    4. PdfWriter writer = PdfWriter.getInstance(doc, out);
    5. // 内部类,处理器
    6. writer.setPageEvent(new PdfPageEventHelper() {
    7. // 模板
    8. public PdfTemplate total;
    9. private BaseFont bf = null;
    10. private Font basefont = null;
    11. {
    12. try {
    13. bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
    14. basefont = new Font(bf, 12, Font.NORMAL);
    15. } catch (Exception e) {
    16. e.printStackTrace();
    17. }
    18. }
    19. /**
    20. * 文档打开时创建模板
    21. */
    22. public void onOpenDocument(PdfWriter writer, Document document) {
    23. total = writer.getDirectContent().createTemplate(50, 50);// 共 页 的矩形的长宽高
    24. }
    25. @Override
    26. public void onEndPage(PdfWriter writer, Document document) {
    27. PdfContentByte cb = writer.getDirectContent();
    28. // 写入页眉
    29. ColumnText.showTextAligned(cb, Element.ALIGN_LEFT, new Phrase("页眉", basefont), document.left(), document.top() + 20, 0);
    30. //写入页码
    31. int pageS = writer.getPageNumber();
    32. String foot1 = "第 " + pageS + " 页 /共";
    33. float len = bf.getWidthPoint(foot1, 12);
    34. Phrase footer = new Phrase(foot1, basefont);
    35. ColumnText.showTextAligned(cb, Element.ALIGN_CENTER, footer,(document.rightMargin() + document.right() + document.leftMargin() - document.left() - len) / 2.0F + 20F, document.bottom() - 20, 0);
    36. cb.addTemplate(total, (document.rightMargin() + document.right() + document.leftMargin() - document.left()) / 2.0F + 20F, document.bottom() - 20);
    37. }
    38. /**
    39. * 关闭文档时,替换模板,完成整个页眉页脚组件
    40. */
    41. public void onCloseDocument(PdfWriter writer, Document document) {
    42. // 关闭文档的时候,将模板替换成实际的 Y 值,至此,page x of y 制作完毕,完美兼容各种文档size。
    43. total.beginText();
    44. total.setFontAndSize(bf, 12);// 生成的模版的字体、颜色
    45. String foot2 = " " + (writer.getPageNumber()) + " 页";
    46. total.showText(foot2);// 模版显示的内容
    47. total.endText();
    48. total.closePath();
    49. }
    50. });
    51. doc.open();
    52. doc.add(new Paragraph("1 page"));
    53. doc.newPage();
    54. doc.add(new Paragraph("2 page"));
    55. doc.close();
    56. }

    四、合并多个PDF

    1、涉及的核心类:PdfReader,PdfWriter、PdfCopy(PdfWriter的子类)

    2、实现:2次循环

    1)第一层循环:PDF合并的文件个数,有几个PDF需要合并。

    2)第二层循环:一个PDF文件的页数,一个PDF有几页。将其存放在新的PDF上。

    1)使用PdfCopy

    1. public static boolean mergePdfFiles(String[] files, String newfile) {
    2. boolean retValue = false;
    3. Document document = null;
    4. try {
    5. document = new Document();
    6. PdfCopy copy = new PdfCopy(document, new FileOutputStream(newfile));
    7. document.open();
    8. for (int i = 0; i < files.length; i++) {// 几个pdf文件循环
    9. PdfReader reader = new PdfReader(files[i]);
    10. int n = reader.getNumberOfPages();
    11. for (int j = 1; j <= n; j++) {// 一个文件有多少页循环
    12. document.newPage();
    13. // 从reader读取原始pdf每一页的数据追加进新的pdf中
    14. PdfImportedPage page = copy.getImportedPage(reader, j);
    15. copy.addPage(page);
    16. }
    17. }
    18. retValue = true;
    19. } catch (Exception e) {
    20. e.printStackTrace();
    21. } finally {
    22. document.close();
    23. }
    24. return retValue;
    25. }

    2)使用PdfWriter实现PDF合并

    1. public static void mergePdf(String[] files, String savepath) throws Exception {
    2. Document document = new Document();
    3. PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(savepath));
    4. document.open();
    5. PdfContentByte cb = writer.getDirectContent();// 得到层
    6. for (int i = 0; i < files.length; i++) {
    7. PdfReader reader = new PdfReader(files[i]);
    8. int n = reader.getNumberOfPages();
    9. for (int j = 1; j <= n; j++) {
    10. document.newPage();
    11. PdfImportedPage page = writer.getImportedPage(reader, j);
    12. // 使用writer需要使用pdf的层,然后后添加
    13. // 可以 放大 缩小
    14. cb.addTemplate(page, 0, 0);
    15. // 扩大比例
    16. // cb.addTemplate(page, 0.6f, 0, 0, 0.6f, 0, page.getHeight() + 10);
    17. // cb.addTemplate(page, 1.0f, 0, 0, 1.0f, 0, page.getHeight() + 10);
    18. }
    19. }
    20. document.close();
    21. }

    五、表单PDF

    1. package com.lean.itextpdf;
    2. import java.io.FileOutputStream;
    3. import java.text.SimpleDateFormat;
    4. import java.util.Date;
    5. import com.itextpdf.text.*;
    6. import com.itextpdf.text.pdf.BaseFont;
    7. import com.itextpdf.text.pdf.PdfPCell;
    8. import com.itextpdf.text.pdf.PdfPTable;
    9. import com.itextpdf.text.pdf.PdfWriter;
    10. public class PdfExampleDemo {
    11. public static void main(String[] args) {
    12. Document document = new Document(PageSize.A4, 10, 10, 36, 36);
    13. try {
    14. PdfWriter.getInstance(document, new FileOutputStream("./doc/12.pdf"));
    15. document.open();
    16. BaseFont bfChines = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
    17. Font FontChinese = new Font(bfChines, 18, Font.BOLD);
    18. Font FontData = new Font(bfChines, 12, Font.UNDEFINED);
    19. Font FontTable = new Font(bfChines, 10, Font.NORMAL);
    20. Font FontTableHeader = new Font(bfChines, 8, Font.BOLD);
    21. Paragraph titlle = new Paragraph("项目成本单", FontChinese);
    22. titlle.setAlignment(Element.ALIGN_CENTER);
    23. document.add(titlle);
    24. PdfPTable tableHeader = new PdfPTable(2);
    25. PdfPCell cell = new PdfPCell(new Paragraph("项目编号: " + "0333333333", FontData));
    26. cell.setBorder(Rectangle.NO_BORDER);
    27. tableHeader.addCell(cell);
    28. cell = new PdfPCell(new Paragraph("项目名称: " + "xxxxx开发项目", FontData));
    29. cell.setBorder(Rectangle.NO_BORDER);
    30. tableHeader.addCell(cell);
    31. cell = new PdfPCell(new Paragraph("项目例属: " + "xxxxx", FontData));
    32. cell.setBorder(Rectangle.NO_BORDER);
    33. tableHeader.addCell(cell);
    34. cell = new PdfPCell(new Paragraph("负责人: " + "xxxxx", FontData));
    35. cell.setBorder(Rectangle.NO_BORDER);
    36. tableHeader.addCell(cell);
    37. cell = new PdfPCell(new Paragraph("时间: " + new SimpleDateFormat("yyyy-MM-dd").format(new Date()), FontData));
    38. cell.setBorder(Rectangle.NO_BORDER);
    39. // 设置表上边的距离
    40. tableHeader.setSpacingBefore(30f);
    41. tableHeader.addCell(cell);
    42. float[] widths = {0.5f, 0.5f}; // 设置列的宽度 百分比
    43. tableHeader.setWidths(widths);
    44. tableHeader.setSpacingBefore(15f);
    45. document.add(tableHeader);
    46. PdfPTable table = new PdfPTable(7);
    47. cell = new PdfPCell(new Paragraph("编号", FontTableHeader));
    48. cell.setHorizontalAlignment(Element.ALIGN_CENTER);// 剧中显示
    49. table.addCell(cell);
    50. cell = new PdfPCell(new Paragraph("名称", FontTableHeader));
    51. cell.setHorizontalAlignment(Element.ALIGN_CENTER);// 剧中显示
    52. table.addCell(cell);
    53. cell = new PdfPCell(new Paragraph("数量", FontTableHeader));
    54. cell.setHorizontalAlignment(Element.ALIGN_CENTER);// 剧中显示
    55. table.addCell(cell);
    56. cell = new PdfPCell(new Paragraph("单位", FontTableHeader));
    57. cell.setHorizontalAlignment(Element.ALIGN_CENTER);// 剧中显示
    58. table.addCell(cell);
    59. cell = new PdfPCell(new Paragraph("单价(元)", FontTableHeader));
    60. cell.setHorizontalAlignment(Element.ALIGN_CENTER);// 剧中显示
    61. table.addCell(cell);
    62. cell = new PdfPCell(new Paragraph("折扣(%)", FontTableHeader));
    63. cell.setHorizontalAlignment(Element.ALIGN_CENTER);// 剧中显示
    64. table.addCell(cell);
    65. cell = new PdfPCell(new Paragraph("公式", FontTableHeader));
    66. cell.setHorizontalAlignment(Element.ALIGN_CENTER);// 剧中显示
    67. table.addCell(cell);
    68. // 固定高度
    69. cell.setFixedHeight(20f);
    70. for (int i = 0; i < 40; i++) {
    71. cell = new PdfPCell(new Paragraph((i + 1) + "", FontTable));
    72. cell.setHorizontalAlignment(Element.ALIGN_CENTER);// 水平居中
    73. cell.setVerticalAlignment(Element.ALIGN_MIDDLE); // 垂直居中
    74. table.addCell(cell);
    75. cell = new PdfPCell(new Paragraph("JAVA", FontTable));
    76. cell.setHorizontalAlignment(Element.ALIGN_CENTER);// 水平居中
    77. cell.setVerticalAlignment(Element.ALIGN_MIDDLE); // 垂直居中
    78. table.addCell(cell);
    79. cell = new PdfPCell(new Paragraph("1", FontTable));
    80. cell.setHorizontalAlignment(Element.ALIGN_CENTER);// 水平居中
    81. cell.setVerticalAlignment(Element.ALIGN_MIDDLE); // 垂直居中
    82. table.addCell(cell);
    83. cell = new PdfPCell(new Paragraph("部", FontTable));
    84. cell.setHorizontalAlignment(Element.ALIGN_CENTER);// 水平居中
    85. cell.setVerticalAlignment(Element.ALIGN_MIDDLE); // 垂直居中
    86. table.addCell(cell);
    87. cell = new PdfPCell(new Paragraph("5000", FontTable));
    88. cell.setHorizontalAlignment(Element.ALIGN_CENTER);// 水平居中
    89. cell.setVerticalAlignment(Element.ALIGN_MIDDLE); // 垂直居中
    90. table.addCell(cell);
    91. cell = new PdfPCell(new Paragraph("80%", FontTable));
    92. cell.setHorizontalAlignment(Element.ALIGN_CENTER);// 水平居中
    93. cell.setVerticalAlignment(Element.ALIGN_MIDDLE); // 垂直居中
    94. table.addCell(cell);
    95. cell = new PdfPCell(new Paragraph("xxxx", FontTable));
    96. cell.setHorizontalAlignment(Element.ALIGN_CENTER);// 水平居中
    97. cell.setVerticalAlignment(Element.ALIGN_MIDDLE); // 垂直居中
    98. table.addCell(cell);
    99. // 每页设置表头
    100. table.setHeaderRows(1);
    101. }
    102. float[] width = {0.2f, 0.2f, 0.1f, 0.1f, 0.1f, 0.1f, 0.2f};
    103. table.setWidths(width);
    104. table.setSpacingBefore(15f);
    105. document.add(table);
    106. PdfPTable tableBottom = new PdfPTable(2);
    107. cell = new PdfPCell(new Paragraph("负责人:xxxx", FontData));
    108. cell.setBorder(Rectangle.NO_BORDER);
    109. tableBottom.addCell(cell);
    110. cell = new PdfPCell(new Paragraph("编号:xxxx", FontData));
    111. cell.setBorder(Rectangle.NO_BORDER);
    112. tableBottom.addCell(cell);
    113. cell = new PdfPCell(new Paragraph("最近修改人:xxxx", FontData));
    114. cell.setBorder(Rectangle.NO_BORDER);
    115. tableBottom.addCell(cell);
    116. cell = new PdfPCell(new Paragraph("业务归属人:xxxx", FontData));
    117. cell.setBorder(Rectangle.NO_BORDER);
    118. cell.setColspan(2);
    119. tableBottom.addCell(cell);
    120. cell = new PdfPCell(new Paragraph("备注:开发进度", FontData));
    121. cell.setBorder(Rectangle.NO_BORDER);
    122. cell.setColspan(2);
    123. tableBottom.addCell(cell);
    124. tableBottom.setSpacingBefore(15f);
    125. document.add(tableBottom);
    126. document.close();
    127. } catch (Exception e) {
    128. e.printStackTrace();
    129. }
    130. }
    131. }

    1. package com.lean.itextpdf.example;
    2. import com.itextpdf.text.*;
    3. import com.itextpdf.text.pdf.*;
    4. import lombok.Builder;
    5. import lombok.Data;
    6. import java.io.FileOutputStream;
    7. import java.io.IOException;
    8. import java.util.ArrayList;
    9. import java.util.List;
    10. public class PdfTest {
    11. public static void main(String[] args) throws Exception {
    12. Document document = new Document(PageSize.A4);
    13. PdfWriter pdfWriter = PdfWriter.getInstance(document, new FileOutputStream("./doc/test.pdf"));
    14. //
    15. pdfWriter.setPageEvent(new MyHeaderFooterPageEventHelper("左上标题", "右上标题", "左下标题", "测试水印"));
    16. document.open();
    17. document.addAuthor("作责");
    18. document.addCreationDate();
    19. document.addTitle("标题");
    20. document.addKeywords("关键字");
    21. document.addCreator("创建人");
    22. // Title
    23. document.add(createTitle("Java PDF生成"));
    24. // Chapter 1
    25. document.add(createChapter("1. 知识准备",22));
    26. document.add(createChapter("1.1 什么是TEXT",18));
    27. document.add(createParagraph(
    28. "Apache iText 是一个开源 Java 库,支持 PDF 文档的开发和转换。其目前遵从AGPL开源协议,AGPL 可以说是最严格的 GPL 了,并且Itext有很多product开始收费,但所需的功能基本上开源的API都能满足。"));
    29. document.add(createChapter("1.2 Apache iText中基础概念",18));
    30. document.add(createParagraph("基本上开源的API"));
    31. // Chapter 2
    32. document.add(createChapter("2. 实现案例",22));
    33. document.add(createChapter("2.1 用户列表示例",18));
    34. document.add(createParagraph("以导出用户列表为例"));
    35. // 表格
    36. List userList = new ArrayList<>();
    37. for (int i = 0; i < 5; i++) {
    38. userList.add(User.builder().id(Long.parseLong(i + "")).userName("姓名" + i).email("邮箱" + i).phoneNumber(123456L)
    39. .description("hello world" + i).build());
    40. }
    41. PdfPTable table = new PdfPTable(new float[] {20, 40, 50, 40, 40});
    42. table.setTotalWidth(500);
    43. table.setLockedWidth(true);
    44. table.setHorizontalAlignment(Element.ALIGN_CENTER);
    45. table.getDefaultCell().setBorder(1);
    46. for (int i = 0; i < userList.size(); i++) {
    47. table.addCell(createCell(userList.get(i).getId() + ""));
    48. table.addCell(createCell(userList.get(i).getUserName()));
    49. table.addCell(createCell(userList.get(i).getEmail()));
    50. table.addCell(createCell(userList.get(i).getPhoneNumber() + ""));
    51. table.addCell(createCell(userList.get(i).getDescription()));
    52. }
    53. document.add(table);
    54. document.add(createChapter("2.2 图片导出示例",18));
    55. document.add(createParagraph("以导出图片为例"));
    56. // 图片
    57. Image image = Image.getInstance("./doc/aaa.jpg");
    58. image.setAlignment(Element.ALIGN_CENTER);
    59. image.scalePercent(60); // 缩放
    60. document.add(image);
    61. // close
    62. document.close();
    63. }
    64. /**
    65. * 标题
    66. * @param content
    67. * @return
    68. * @throws IOException
    69. * @throws DocumentException
    70. */
    71. public static Paragraph createTitle(String content) throws IOException, DocumentException {
    72. Font font = new Font(getBaseFont(), 24, Font.BOLD);
    73. Paragraph paragraph = new Paragraph(content, font);
    74. paragraph.setAlignment(Element.ALIGN_CENTER);
    75. return paragraph;
    76. }
    77. /**
    78. * @param content
    79. * @return
    80. * @throws IOException
    81. * @throws DocumentException
    82. */
    83. public static Paragraph createChapter(String content,int fontSize) throws IOException, DocumentException {
    84. Font font = new Font(getBaseFont(), fontSize, Font.BOLD);
    85. Paragraph paragraph = new Paragraph(content, font);
    86. paragraph.setAlignment(Element.ALIGN_LEFT);
    87. return paragraph;
    88. }
    89. /**
    90. * 段落
    91. * @param content
    92. * @return
    93. * @throws IOException
    94. * @throws DocumentException
    95. */
    96. public static Paragraph createParagraph(String content) throws IOException, DocumentException {
    97. Font font = new Font(getBaseFont(), 12, Font.NORMAL);
    98. Paragraph paragraph = new Paragraph(content, font);
    99. paragraph.setAlignment(Element.ALIGN_LEFT);
    100. paragraph.setIndentationLeft(12); //设置左缩进
    101. paragraph.setIndentationRight(12); //设置右缩进
    102. paragraph.setFirstLineIndent(24); //设置首行缩进
    103. paragraph.setLeading(20f); //行间距
    104. paragraph.setSpacingBefore(5f); //设置段落上空白
    105. paragraph.setSpacingAfter(10f); //设置段落下空白
    106. return paragraph;
    107. }
    108. /**
    109. * 单元格
    110. * @param content
    111. * @return
    112. * @throws IOException
    113. * @throws DocumentException
    114. */
    115. public static PdfPCell createCell(String content) throws IOException, DocumentException {
    116. PdfPCell cell = new PdfPCell();
    117. cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
    118. cell.setHorizontalAlignment(Element.ALIGN_CENTER);
    119. Font font = new Font(getBaseFont(), 12, Font.NORMAL);
    120. cell.setPhrase(new Phrase(content, font));
    121. return cell;
    122. }
    123. /**
    124. * 字体
    125. * @return
    126. * @throws IOException
    127. * @throws DocumentException
    128. */
    129. public static BaseFont getBaseFont() throws IOException, DocumentException {
    130. return BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
    131. }
    132. }
    133. @Data
    134. @Builder
    135. class User {
    136. private Long id;
    137. private String userName;
    138. private String email;
    139. private Long phoneNumber;
    140. private String description;
    141. }
    142. class MyHeaderFooterPageEventHelper extends PdfPageEventHelper {
    143. private String headLeftTitle;
    144. private String headRightTitle;
    145. private String footerLeft;
    146. private String waterMark;
    147. // 模板
    148. public PdfTemplate total;
    149. public BaseFont bf = null;
    150. private Font basefont = null;
    151. {
    152. try {
    153. bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
    154. basefont = new Font(bf, 12, Font.NORMAL);
    155. } catch (Exception e) {
    156. e.printStackTrace();
    157. }
    158. }
    159. public MyHeaderFooterPageEventHelper(String headLeftTitle, String headRightTitle, String footerLeft, String waterMark) {
    160. this.headLeftTitle = headLeftTitle;
    161. this.headRightTitle = headRightTitle;
    162. this.footerLeft = footerLeft;
    163. this.waterMark = waterMark;
    164. }
    165. /**
    166. * 文档打开时创建模板
    167. */
    168. public void onOpenDocument(PdfWriter writer, Document document) {
    169. total = writer.getDirectContent().createTemplate(50, 50);// 共 页 的矩形的长宽高
    170. }
    171. // 一页加载完成触发,写入页眉和页脚
    172. @Override
    173. public void onEndPage(PdfWriter writer, Document document) {
    174. // page header and footer
    175. addPageHeaderAndFooter(writer, document, bf);
    176. // watermark
    177. if (waterMark != null) {
    178. addWaterMark(writer, document, bf);
    179. }
    180. }
    181. private void addPageHeaderAndFooter(PdfWriter writer, Document document, BaseFont bf) {
    182. PdfContentByte cb = writer.getDirectContent();
    183. cb.saveState();
    184. cb.beginText();
    185. cb.setColorFill(BaseColor.GRAY);
    186. cb.setFontAndSize(bf, 10);
    187. // header
    188. float x = document.top(-10);
    189. cb.showTextAligned(PdfContentByte.ALIGN_LEFT, headLeftTitle, document.left(), x, 0);
    190. cb.showTextAligned(PdfContentByte.ALIGN_RIGHT, headRightTitle, document.right(), x, 0);
    191. // footer
    192. float y = document.bottom(-10);
    193. cb.showTextAligned(PdfContentByte.ALIGN_LEFT, footerLeft, document.left(), y, 0);
    194. cb.showTextAligned(PdfContentByte.ALIGN_CENTER, String.format("- %d /", writer.getPageNumber()), (document.right() + document.left()) / 2, y, 0);
    195. cb.endText();
    196. cb.restoreState();
    197. cb.addTemplate(total, (document.rightMargin() + document.right() + document.leftMargin() - document.left()) / 2.0F + 10F, document.bottom() - 10);
    198. }
    199. private void addWaterMark(PdfWriter writer, Document document, BaseFont bf) {
    200. for (int i = 1; i < 7; i++) {
    201. for (int j = 1; j < 10; j++) {
    202. PdfContentByte cb = writer.getDirectContent();
    203. cb.saveState();
    204. cb.beginText();
    205. cb.setColorFill(BaseColor.GRAY);
    206. PdfGState gs = new PdfGState();
    207. gs.setFillOpacity(0.1f);
    208. cb.setGState(gs);
    209. cb.setFontAndSize(bf, 12);
    210. cb.showTextAligned(Element.ALIGN_MIDDLE, waterMark, 75 * i, 80 * j, 30);
    211. cb.endText();
    212. cb.restoreState();
    213. }
    214. }
    215. }
    216. // 全部完成后,将总页数的pdf模版写到指定位置
    217. @Override
    218. public void onCloseDocument(PdfWriter writer, Document document) {
    219. basefont.setColor(BaseColor.GRAY);
    220. basefont.setSize(10);
    221. Paragraph paragraph = new Paragraph((writer.getPageNumber()) + " -", basefont);
    222. ColumnText.showTextAligned(total, Element.ALIGN_LEFT, paragraph, 0, 0, 0);
    223. }
    224. }

    六、模板PDF

    一、html模板

    1. com.itextpdf.tool
    2. xmlworker
    3. 5.5.11
    4. org.freemarker
    5. freemarker
    6. 2.3.31
    7. org.xhtmlrenderer
    8. flying-saucer-pdf
    9. 9.1.6

    模板:freemarker.html

    1. "en">
    2. "UTF-8"/>
    3. Title
    4. "color pos">
    5. "color: #4787ed">你好,${name}
    6. "${imgUrl}" width="600px"/>
    7. "div-head">
    8. "font-size: 24px;">HTML模板生成PDF文件111
  • "margin-bottom: 18px">
  • "margin: 0;padding: 0;display: inherit;float: left">
  • "font-size: 15px" >级别:123456
  • "margin: 0;padding: 0;display: inherit;float: right;">
  • "font-size: 15px" >编号:123456
  • "margin-top: 12px">
  • "9">2013年度图书销售统计
    "2">图书分类 "2">一季度"2">二季度"2">三季度"2">四季度
    销售量 销售额 销售量 销售额 销售量 销售额 销售量 销售额
    小说 23521 ?599,940.00 18423 ?44,841.00 32125 ?829,870.0025100 ?586,564.00
    文艺 7643?180,423.008010?192,420.0010289?321,717.009012?266,134.00
    励志/成功 13328?428,371.0015021?592,987.0013496?471,620.0010130?386,845.00
    童书 20328?358,891.0024030?392,713.0027444?461,770.0018027?328,451.00
    小说 23521 ?599,940.00 18423 ?44,841.00 32125 ?829,870.0025100 ?586,564.00
    文艺 7643?180,423.008010?192,420.0010289?321,717.009012?266,134.00
    励志/成功 13328?428,371.0015021?592,987.0013496?471,620.0010130?386,845.00
    童书 20328?358,891.0024030?392,713.0027444?461,770.0018027?328,451.00
    小说 23521 ?599,940.00 18423 ?44,841.00 32125 ?829,870.0025100 ?586,564.00
    文艺 7643?180,423.008010?192,420.0010289?321,717.009012?266,134.00
    励志/成功 13328?428,371.0015021?592,987.0013496?471,620.0010130?386,845.00
    童书 20328?358,891.0024030?392,713.0027444?461,770.0018027?328,451.00
    小说 23521 ?599,940.00 18423 ?44,841.00 32125 ?829,870.0025100 ?586,564.00
    文艺 7643?180,423.008010?192,420.0010289?321,717.009012?266,134.00
    励志/成功 13328?428,371.0015021?592,987.0013496?471,620.0010130?386,845.00
    童书 20328?358,891.0024030?392,713.0027444?461,770.0018027?328,451.00
    小说 23521 ?599,940.00 18423 ?44,841.00 32125 ?829,870.0025100 ?586,564.00
    文艺 7643?180,423.008010?192,420.0010289?321,717.009012?266,134.00
    励志/成功 13328?428,371.0015021?592,987.0013496?471,620.0010130?386,845.00
    童书 20328?358,891.0024030?392,713.0027444?461,770.0018027?328,451.00
    小说 23521 ?599,940.00 18423 ?44,841.00 32125 ?829,870.0025100 ?586,564.00
    文艺 7643?180,423.008010?192,420.0010289?321,717.009012?266,134.00
    励志/成功 13328?428,371.0015021?592,987.0013496?471,620.0010130?386,845.00
    童书 20328?358,891.0024030?392,713.0027444?461,770.0018027?328,451.00
    1. package com.lean.itextpdf.html;
    2. import com.itextpdf.text.*;
    3. import com.itextpdf.text.pdf.*;
    4. import com.itextpdf.tool.xml.XMLWorkerFontProvider;
    5. import com.itextpdf.tool.xml.XMLWorkerHelper;
    6. import freemarker.template.Configuration;
    7. import freemarker.template.Template;
    8. import org.apache.commons.codec.binary.Base64;
    9. import sun.misc.BASE64Encoder;
    10. import java.io.*;
    11. import java.nio.charset.Charset;
    12. import java.util.HashMap;
    13. import java.util.Map;
    14. /**
    15. * html 模板 生成pdf
    16. */
    17. public class HtmlToPdfTest {
    18. /**
    19. * html渲染为pdf
    20. *
    21. * @param data 变量
    22. * @param htmlTmp 模板文件名
    23. * @param pdftemp pdf导出路径
    24. * @return
    25. */
    26. public static void freeMarkerRender(Map data, String htmlTmp, String pdftemp) throws Exception {
    27. // 获取模板,并设置编码方式
    28. Configuration freemarkerCfg = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
    29. //文件夹目录位置
    30. freemarkerCfg.setDirectoryForTemplateLoading(new File("./doc"));
    31. Template template = freemarkerCfg.getTemplate(htmlTmp,"UTF-8");
    32. StringWriter out = new StringWriter();
    33. // 合并模板跟数据
    34. template.process(data, out);
    35. // htmlData 模板字符流
    36. String htmlData = out.toString();
    37. // 设置文档格式,数字边距
    38. Document document = new Document(PageSize.A4);
    39. PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(pdftemp));
    40. // 添加页码
    41. writer.setPageEvent(new PdfReportM1HeaderFooter());
    42. // 打开文档
    43. document.open();
    44. // HTML 转成pdf
    45. XMLWorkerHelper.getInstance().parseXHtml(writer, document, new ByteArrayInputStream(htmlData.getBytes()), Charset.forName("UTF-8"),
    46. new MyFontsProvider(12));
    47. // 关闭文档
    48. document.close();
    49. }
    50. /**
    51. * @param file
    52. * @return
    53. */
    54. public static String fileToBase64Str(File file) {
    55. byte[] data = null;
    56. InputStream inputStream = null;
    57. if (file != null) {
    58. try {
    59. inputStream = new FileInputStream(file);
    60. data = new byte[inputStream.available()];
    61. inputStream.read(data);
    62. } catch (Exception e) {
    63. e.printStackTrace();
    64. } finally {
    65. try {
    66. inputStream.close();
    67. } catch (IOException e) {
    68. e.printStackTrace();
    69. }
    70. }
    71. BASE64Encoder encoder = new BASE64Encoder();
    72. return Base64.encodeBase64String(data);
    73. }
    74. return null;
    75. }
    76. public static void main(String[] args) throws Exception {
    77. Map data = new HashMap();
    78. data.put("name",123);
    79. data.put("imgUrl","https://ccdn.goodq.top/caches/4a7b7daf436f3e5cb2e29433375ccd5d/aHR0cHM6Ly81NTlhNDQ3YzczMmVlLnQ3My5xaWZlaXllLmNvbS9xZnktY29udGVudC91cGxvYWRzLzIwMTQvMDYvYjU5YzY3YmYxOTZhNDc1ODE5MWU0MmY3NjY3MGNlYmEuanBn.jpg");
    80. freeMarkerRender(data, "freemarker.html", "./doc/ad.pdf");
    81. }
    82. }
    83. class MyFontsProvider extends XMLWorkerFontProvider {
    84. private int fontSize;
    85. public MyFontsProvider() {
    86. this.fontSize = 0;
    87. }
    88. public MyFontsProvider(int fontSize) {
    89. this.fontSize = fontSize;
    90. }
    91. @Override
    92. public Font getFont(final String fontname, final String encoding, final boolean embedded, final float size, final int style, final BaseColor color) {
    93. BaseFont bf = null;
    94. try {
    95. bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
    96. } catch (DocumentException e) {
    97. e.printStackTrace();
    98. } catch (IOException e) {
    99. e.printStackTrace();
    100. }
    101. Font font = null;
    102. if (fontSize != 0) {
    103. font = new Font(bf, fontSize, style, color);
    104. } else {
    105. font = new Font(bf, size, style, color);
    106. }
    107. font.setColor(color);
    108. return font;
    109. }
    110. public int getFontSize() {
    111. return fontSize;
    112. }
    113. public void setFontSize(int fontSize) {
    114. this.fontSize = fontSize;
    115. }
    116. }
    117. class PdfReportM1HeaderFooter extends PdfPageEventHelper {
    118. /**
    119. * 页眉
    120. */
    121. public String header = "页眉";
    122. /**
    123. * 文档字体大小,页脚页眉最好和文本大小一致
    124. */
    125. public int presentFontSize = 12;
    126. // 模板
    127. public PdfTemplate total;
    128. private BaseFont bf = null;
    129. public PdfReportM1HeaderFooter() {
    130. }
    131. /**
    132. * 文档打开时创建模板
    133. */
    134. public void onOpenDocument(PdfWriter writer, Document document) {
    135. total = writer.getDirectContent().createTemplate(50, 50);// 共 页 的矩形的长宽高
    136. }
    137. /**
    138. * 关闭每页的时候,写入页眉,写入'第几页共'这几个字。
    139. *
    140. * @see com.itextpdf.text.pdf.PdfPageEventHelper#onEndPage(com.itextpdf.text.pdf.PdfWriter, com.itextpdf.text.Document)
    141. */
    142. public void onEndPage(PdfWriter writer, Document document) {
    143. Font fontDetail = null;
    144. try {
    145. bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", false);
    146. fontDetail = new Font(bf, presentFontSize, Font.NORMAL);
    147. } catch (DocumentException e) {
    148. e.printStackTrace();
    149. } catch (IOException e) {
    150. e.printStackTrace();
    151. }
    152. // 1.写入页眉
    153. ColumnText.showTextAligned(writer.getDirectContent(), Element.ALIGN_LEFT, new Phrase(header, fontDetail), document.left(), document.top() + 20, 0);
    154. // 2.写入前半部分的 第 X页/共
    155. int pageS = writer.getPageNumber();
    156. String foot1 = "第 " + pageS + " 页 /共";
    157. Phrase footer = new Phrase(foot1, fontDetail);
    158. // 3.计算前半部分的foot1的长度,后面好定位最后一部分的'Y页'这俩字的x轴坐标,字体长度也要计算进去 = len
    159. float len = bf.getWidthPoint(foot1, presentFontSize);
    160. // 4.拿到当前的PdfContentByte
    161. PdfContentByte cb = writer.getDirectContent();
    162. // 5.写入页脚
    163. ColumnText.showTextAligned(cb, Element.ALIGN_CENTER, footer,(document.rightMargin() + document.right() + document.leftMargin() - document.left() - len) / 2.0F + 20F, document.bottom() - 20, 0);
    164. cb.addTemplate(total, (document.rightMargin() + document.right() + document.leftMargin() - document.left()) / 2.0F + 20F, document.bottom() - 20);
    165. }
    166. /**
    167. * 关闭文档时,替换模板,完成整个页眉页脚组件
    168. */
    169. public void onCloseDocument(PdfWriter writer, Document document) {
    170. // 关闭文档的时候,将模板替换成实际的 Y 值,至此,page x of y 制作完毕,完美兼容各种文档size。
    171. total.beginText();
    172. total.setFontAndSize(bf, presentFontSize);// 生成的模版的字体、颜色
    173. String foot2 = " " + (writer.getPageNumber()) + " 页";
    174. total.showText(foot2);// 模版显示的内容
    175. total.endText();
    176. total.closePath();
    177. }
    178. }

     二、使用工具构建PDF模板

    工具:

    Adobe Acrobat DC 工具 - 免费

            链接: https://pan.baidu.com/s/1c7C2ZLmDXfAWWmpoPevD1w?pwd=ivn8 提取码: ivn8

    迅捷PDF编辑器 - 收费

           下载地址

    如下是迅捷PDF编辑:

    1. package com.lean.itextpdf.fremarker;
    2. import java.io.BufferedOutputStream;
    3. import java.io.ByteArrayOutputStream;
    4. import java.io.FileOutputStream;
    5. import java.io.IOException;
    6. import java.lang.reflect.Field;
    7. import java.util.*;
    8. import java.util.List;
    9. import java.util.stream.Collectors;
    10. import java.util.stream.Stream;
    11. import lombok.Data;
    12. import org.springframework.util.CollectionUtils;
    13. import com.itextpdf.text.*;
    14. import com.itextpdf.text.pdf.*;
    15. import org.springframework.util.StringUtils;
    16. /**
    17. * @ClassName: PdfUtils
    18. * @Description:
    19. * @Author: zhanghongwei
    20. * @Date: 2022/5/17 14:11
    21. */
    22. public class PdfUtils {
    23. public static void main(String[] args) {
    24. try {
    25. PdfDataModel pdfDataModel = new PdfDataModel();
    26. pdfDataModel.setText1("511300T15163");//条形码
    27. pdfDataModel.setText2("xxxxx业务员自费账户");//送检单位
    28. pdfDataModel.setText3("xxxx");//姓名
    29. pdfDataModel.setText4("男");//性别
    30. pdfDataModel.setText14("27");//年龄
    31. pdfDataModel.setText5("xxxxxxxxxxxxxxxxxxxx");//身份证号
    32. pdfDataModel.setText6("送检医师");//送检医师
    33. pdfDataModel.setText7("病 员 号");//病 员 号
    34. pdfDataModel.setText8("科 别");//科 别
    35. pdfDataModel.setText9("xxxxxxxxx");//病人电话
    36. pdfDataModel.setText10("咽拭子");//标本类型
    37. pdfDataModel.setText11("肉眼未见异常");//标本性状
    38. pdfDataModel.setText12("2022-04-27 17:35 ");//采样时间
    39. pdfDataModel.setText13("2022-04-27 17:35 ");
    40. pdfDataModel.setText15("xxx xxx Ao xxx Laboratory Results Report");//英文主题
    41. pdfDataModel.setText22("xxxxxxxxxx检验实验室检验报告单");//汉语主题
    42. pdfDataModel.setText23("此结果仅为2019-nCoV新型冠状病毒核酸定性筛查; \n" +
    43. "本检测结果所使用的检测方法为实时荧光RT-PCR技术,最低检测限: 500 拷贝/mL\n" +
    44. ",检测新型冠状病毒(2019-nCoV)的ORF1ab和编码核衣壳蛋白基因N。");//建议与解释:
    45. pdfDataModel.setText16("xxxxx");//备 注
    46. pdfDataModel.setText17("LABxxxxxxxx");//院方条形码
    47. pdfDataModel.setText18("www.xxxxx.com");//网站地址:
    48. pdfDataModel.setText19("xxxxxxxxxxxxxxxxxxxxxxxxxx");//地址:
    49. pdfDataModel.setText20("xxxxxxxxxx/xxxxxxxxx(转602)");//客服电话:
    50. pdfDataModel.setText21(" 2022-11-2301:58");//报告日期
    51. //图片
    52. PdfDataImgaModel pdfDataImgaModel = new PdfDataImgaModel();
    53. pdfDataImgaModel.setImage1("doc/1.png");//左上角图片
    54. pdfDataImgaModel.setImage2("doc/2.jpeg");//专用章图片
    55. pdfDataImgaModel.setImage3("doc/3.png");//右下角图片
    56. pdfDataImgaModel.setImage5("doc/4.png");//检验者
    57. pdfDataImgaModel.setImage6("doc/5.png");//审核者
    58. pdfDataImgaModel.setImage7("doc/6.png");//批准人
    59. pdfDataImgaModel.setImage4("doc/7.png");//条形码图片
    60. List testItemsModels = new ArrayList<>();
    61. for (int i = 0; i < 10; i++) {
    62. TestItemsModel testItemsModel = new TestItemsModel();
    63. testItemsModel.setTitle("新型冠状病毒核酸检测(10合1)(2019-nCoV)" + i);
    64. testItemsModel.setResult("阴性");
    65. testItemsModel.setTag("阴性");
    66. testItemsModel.setUnit("单位");
    67. testItemsModels.add(testItemsModel);
    68. }
    69. ByteArrayOutputStream outputStream = getPdfUrl(testItemsModels, pdfDataModel, pdfDataImgaModel);
    70. FileOutputStream fos = new FileOutputStream("./doc/re.pdf");
    71. BufferedOutputStream bos = new BufferedOutputStream(fos);
    72. bos.write(outputStream.toByteArray());
    73. } catch (Exception e) {
    74. e.printStackTrace();
    75. }
    76. }
    77. /**
    78. * 检测报告
    79. * @param testItemsModels
    80. * @param pdfDataModel
    81. * @param pdfDataImgaModel
    82. * @return
    83. */
    84. public static ByteArrayOutputStream getPdfUrl(List testItemsModels, PdfDataModel pdfDataModel, PdfDataImgaModel pdfDataImgaModel) {
    85. ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    86. try {
    87. BaseFont chinese = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
    88. ByteArrayOutputStream outputStream = generateTempPDF("./doc/pdf_template.pdf", chinese, pdfDataModel, pdfDataImgaModel);
    89. List pdfReaderList = new ArrayList<>();
    90. if (!CollectionUtils.isEmpty(testItemsModels)) {
    91. byte[] bytes = outputStream.toByteArray();
    92. List> splitList = splitList(testItemsModels, 20);
    93. for (List itemsModels : splitList) {
    94. //填充数据
    95. PdfReader pdfReader = new PdfReader(filleTestItemsData(chinese, itemsModels, bytes).toByteArray());
    96. pdfReaderList.add(pdfReader);
    97. }
    98. } else {
    99. PdfReader pdfReader = new PdfReader(outputStream.toByteArray());
    100. pdfReaderList.add(pdfReader);
    101. }
    102. mergePdfFiles(pdfReaderList, byteArrayOutputStream);
    103. } catch (Exception e) {
    104. e.printStackTrace();
    105. }
    106. return byteArrayOutputStream;
    107. }
    108. /**
    109. * 填充检测数据
    110. *
    111. * @param chinese
    112. * @param testItemsModels
    113. * @param bytes
    114. * @throws IOException
    115. * @throws DocumentException
    116. */
    117. private static ByteArrayOutputStream filleTestItemsData(BaseFont chinese, List testItemsModels, byte[] bytes) throws IOException, DocumentException {
    118. ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    119. PdfReader reader = new PdfReader(bytes);
    120. Rectangle rectangle = reader.getPageSize(1);
    121. Document doc = new Document(rectangle, 50, 50, 50, 50);
    122. PdfWriter writer = PdfWriter.getInstance(doc, byteArrayOutputStream);
    123. doc.open();
    124. doc.newPage();
    125. PdfContentByte cb = writer.getDirectContent();
    126. PdfImportedPage page = writer.getImportedPage(reader, 1);
    127. cb.addTemplate(page, 0, 0);
    128. //首页追加信息
    129. PdfContentByte directContent = writer.getDirectContent();
    130. directContent.beginText();
    131. directContent.setFontAndSize(chinese, 10);
    132. directContent.setColorFill(BaseColor.BLACK);
    133. for (int i = 1; i <= testItemsModels.size() - 1; i++) {
    134. TestItemsModel testItemsModel = testItemsModels.get(i - 1);
    135. directContent.showTextAligned(Element.ALIGN_LEFT, testItemsModel.getTitle(), 20, 630 - (i * 20), 0);
    136. directContent.showTextAligned(Element.ALIGN_LEFT, testItemsModel.getResult(), 280, 630 - (i * 20), 0);
    137. directContent.showTextAligned(Element.ALIGN_LEFT, testItemsModel.getTag(), 380, 630 - (i * 20), 0);
    138. directContent.showTextAligned(Element.ALIGN_LEFT, testItemsModel.getUnit(), 520, 630 - (i * 20), 0);
    139. }
    140. directContent.endText();
    141. doc.close();
    142. return byteArrayOutputStream;
    143. }
    144. public static ByteArrayOutputStream generateTempPDF(String fileName, BaseFont chinese, PdfDataModel pdfDataModel, PdfDataImgaModel pdfDataImgaModel) {
    145. PdfReader reader = null;
    146. PdfStamper ps = null;
    147. ByteArrayOutputStream bos = null;
    148. try {
    149. reader = new PdfReader(fileName);
    150. bos = new ByteArrayOutputStream();
    151. ps = new PdfStamper(reader, bos);
    152. //填充文字
    153. AcroFields fields = ps.getAcroFields();
    154. fillData(fields, beanToMap(pdfDataModel), chinese);//渲染
    155. //填充图片
    156. Map imageMap = beanToMap(pdfDataImgaModel);
    157. // 处理图片
    158. for (String key : imageMap.keySet()) {
    159. String value = imageMap.get(key);
    160. String imgpath = value;
    161. if (!org.springframework.util.StringUtils.isEmpty(imgpath)) {
    162. int pageNo = fields.getFieldPositions(key).get(0).page;
    163. Rectangle signRect = fields.getFieldPositions(key).get(0).position;
    164. float x = signRect.getLeft();
    165. float y = signRect.getBottom();
    166. // 根据路径读取图片
    167. Image image = Image.getInstance(imgpath);
    168. // 获取图片页面
    169. PdfContentByte under = ps.getOverContent(pageNo);
    170. // 图片大小自适应
    171. image.scaleToFit(signRect.getWidth(), signRect.getHeight());
    172. // 设置图片位置,以为我们以左下角为起始点,所以这里x、y加上偏移量,偏移量为计算的居中量
    173. image.setAbsolutePosition(x + (signRect.getWidth() - image.getScaledWidth()) / 2, y + (signRect.getHeight() - image.getScaledHeight()) / 2);
    174. // 添加图片
    175. under.addImage(image);
    176. }
    177. }
    178. //必须要调用这个,否则文档不会生成的
    179. ps.setFormFlattening(true);
    180. if (ps != null) {
    181. ps.close();
    182. }
    183. } catch (Exception e) {
    184. e.printStackTrace();
    185. } finally {
    186. try {
    187. if (bos != null) {
    188. bos.close();
    189. }
    190. if (reader != null) {
    191. reader.close();
    192. }
    193. } catch (IOException e) {
    194. e.printStackTrace();
    195. }
    196. }
    197. return bos;
    198. }
    199. /**
    200. * PDF文件合并
    201. *
    202. * @param pdfReaderList
    203. * @author
    204. */
    205. public static boolean mergePdfFiles(List pdfReaderList, ByteArrayOutputStream outputStream) {
    206. boolean retValue = false;
    207. Document document = null;
    208. try {
    209. document = new Document();
    210. PdfCopy copy = new PdfCopy(document, outputStream);
    211. document.open();
    212. for (PdfReader reader : pdfReaderList) {
    213. int n = reader.getNumberOfPages();
    214. for (int j = 1; j <= n; j++) {// 一个文件有多少页循环
    215. document.newPage();
    216. PdfImportedPage page = copy.getImportedPage(reader, j);
    217. copy.addPage(page);
    218. }
    219. }
    220. retValue = true;
    221. } catch (Exception e) {
    222. e.printStackTrace();
    223. } finally {
    224. document.close();
    225. }
    226. return retValue;
    227. }
    228. /**
    229. * 填充模板中的数据
    230. */
    231. public static void fillData(AcroFields fields, Map data, BaseFont chinese) {
    232. try {
    233. // 默认字体
    234. float fontSize = 10.0f;
    235. for (String key : data.keySet()) {
    236. String value = data.get(key);
    237. if (!StringUtils.isEmpty(value)) {
    238. // 文本框宽度
    239. Rectangle position = fields.getFieldPositions(key).get(0).position;
    240. float textBoxWidth = position.getWidth();
    241. // 文本框高度
    242. float textBoxHeight = position.getHeight();
    243. float ascent = chinese.getFontDescriptor(chinese.ASCENT, fontSize);
    244. // baseFont渲染后的文字宽度
    245. float textWidth = chinese.getWidthPoint(value, fontSize);
    246. // 文本框高度只够写一行,并且文字宽度大于文本框宽度,则缩小字体
    247. if (textBoxHeight < ascent * 1.6) {
    248. while (textWidth > textBoxWidth) {
    249. fontSize--;
    250. textWidth = chinese.getWidthPoint(value, fontSize);
    251. }
    252. }
    253. fields.setFieldProperty(key, "textsize", 10.0f, null);
    254. if (key.equalsIgnoreCase("Text15")) {
    255. fields.setFieldProperty(key, "textsize", 13.0f, null);
    256. }
    257. if(!key.equalsIgnoreCase("Text15")
    258. || !key.equalsIgnoreCase("Text22")
    259. || !key.equalsIgnoreCase("Text18")
    260. || !key.equalsIgnoreCase("Text19")
    261. || !key.equalsIgnoreCase("Text20") ){
    262. fields.setFieldProperty(key, "textfont", chinese, null);
    263. }
    264. // 为字段赋值,注意字段名称是区分大小写的
    265. fields.setField(key, value);
    266. }
    267. }
    268. } catch (Exception e) {
    269. e.printStackTrace();
    270. }
    271. }
    272. public static List> splitList(List list, int splitSize) {
    273. //判断集合是否为空
    274. if (CollectionUtils.isEmpty(list)) {
    275. return Collections.emptyList();
    276. }
    277. //计算分割后的大小
    278. int maxSize = (list.size() + splitSize - 1) / splitSize;
    279. //开始分割
    280. return Stream.iterate(0, n -> n + 1)
    281. .limit(maxSize)
    282. .parallel()
    283. .map(a -> list.parallelStream().skip(a * splitSize).limit(splitSize).collect(Collectors.toList()))
    284. .filter(b -> !b.isEmpty())
    285. .collect(Collectors.toList());
    286. }
    287. /**
    288. * 对象转Map
    289. *
    290. * @param object
    291. * @return
    292. * @throws IllegalAccessException
    293. */
    294. public static Map beanToMap(Object object) {
    295. Map map = new HashMap();
    296. try {
    297. Field[] fields = object.getClass().getDeclaredFields();
    298. for (Field field : fields) {
    299. field.setAccessible(true);
    300. map.put(field.getName(), field.get(object));
    301. }
    302. } catch (IllegalAccessException e) {
    303. e.printStackTrace();
    304. }
    305. return map;
    306. }
    307. }
    308. @Data
    309. class PdfDataImgaModel {
    310. private String Image1 = null;//左上角图片
    311. private String Image2 = null; //专用章图片
    312. private String Image3 = null; //右下角图片
    313. private String Image5 = null; //检验者
    314. private String Image6 = null; //审核者
    315. private String Image7 = null;//批准人
    316. private String Image4 = null; //条形码图片
    317. }
    318. @Data
    319. class PdfDataModel {
    320. private String Text1 = null; //条形码
    321. private String Text2 = null; //送检单位
    322. private String Text3 = null; //姓名
    323. private String Text4 = null; //性别
    324. private String Text14 = null;//年龄
    325. private String Text5 = null; //身份证号
    326. private String Text6 = null; //送检医师
    327. private String Text7 = null; //病 员 号
    328. private String Text8 = null; //科 别
    329. private String Text9 = null; //病人电话
    330. private String Text10 = null; //标本类型
    331. private String Text11 = null;//标本性状
    332. private String Text12 = null; //采样时间
    333. private String Text13 = null; //接收时间
    334. private String Text15 = null; //英文主题
    335. private String Text22 = null; //汉语主题
    336. private String Text23 = null; //建议与解释:
    337. private String Text16 = null; //备 注
    338. private String Text17 = null; //院方条形码
    339. private String Text18 = null; //网站地址:
    340. private String Text19 = null;//地址:
    341. private String Text20 = null; //客服电话
    342. private String Text21 = null; //报告日期
    343. }
    344. @Data
    345. class TestItemsModel {
    346. //检测项目
    347. private String title;
    348. //结果
    349. private String result;
    350. //提示参考范围
    351. private String tag;
    352. //单位
    353. private String unit;
    354. }

     7、HTML转PDF

    1. com.itextpdf.tool
    2. xmlworker
    3. 5.5.11
    1. /**
    2. * html 转成pdf
    3. * @param src
    4. * @param target
    5. * @throws IOException
    6. * @throws DocumentException
    7. */
    8. public static void htmlToPdf(String src, String target) throws IOException, DocumentException {
    9. Document document = new Document(PageSize.B5, 20, 20, 30, 20);
    10. PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(target));
    11. document.open();
    12. XMLWorkerHelper.getInstance().parseXHtml(writer, document, new FileInputStream(src), null, Charset.forName("UTF-8"), new XMLWorkerFontProvider() {
    13. @Override
    14. public Font getFont(final String fontname, final String encoding, final boolean embedded, final float size, final int style,
    15. final BaseColor color) {
    16. BaseFont bf = null;
    17. try {
    18. bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
    19. } catch (DocumentException e) {
    20. e.printStackTrace();
    21. } catch (IOException e) {
    22. e.printStackTrace();
    23. }
    24. Font font = new Font(bf, 6, style, color);
    25. font.setColor(color);
    26. return font;
    27. }
    28. });
    29. document.close();
    30. }

    8、删除页码

    思路:读取pdf文档,然后页码,然后输出到新的PDF

    1. public static void deletePage() throws Exception {
    2. FileOutputStream out = new FileOutputStream("./doc/a2.pdf");
    3. // 删除的方法在于读取,然后选择页数,然后在输出到另一个pdf
    4. PdfReader reader = new PdfReader("./doc/a1.pdf");// 读取pdf
    5. reader.selectPages("1,3");// 选择页数
    6. PdfStamper stamp = new PdfStamper(reader, out);// 输出
    7. stamp.close();
    8. reader.close();
    9. }

    九、读取PDF内容

    1. org.apache.pdfbox
    2. pdfbox
    3. 2.0.25
    1. /**
    2. * 读取PDF 内容
    3. * @return
    4. * @throws Exception
    5. */
    6. public static String testPdfContent() throws Exception{
    7. PDDocument document = PDDocument.load(new FileInputStream("doc/99.pdf"));
    8. document.getClass();
    9. //使用PDFTextStripper 工具
    10. PDFTextStripper tStripper = new PDFTextStripper();
    11. //设置文本排序,有规则输出
    12. tStripper.setSortByPosition(true);
    13. //获取所有文字信息
    14. String info = tStripper.getText(document);
    15. return info;
    16. }

    十、删除pdf内容

    1. public static void deletePdfContent(String srcUrl, String outputPdfFile) throws Exception {
    2. PdfReader reader = new PdfReader(srcUrl);
    3. Document doc = new Document(reader.getPageSize(1));
    4. PdfWriter writer = PdfWriter.getInstance(doc, new FileOutputStream(outputPdfFile));
    5. doc.open();
    6. doc.newPage();
    7. PdfContentByte cb = writer.getDirectContent();
    8. PdfImportedPage page = writer.getImportedPage(reader, 1);
    9. cb.addTemplate(page, 0, 0);
    10. //??底的覆盖层
    11. cb.saveState();
    12. cb.setColorFill(BaseColor.WHITE);
    13. cb.rectangle(0f, 0f, doc.getPageSize().getWidth(), doc.bottom(85));
    14. cb.fill();
    15. cb.restoreState();
    16. doc.close();
    17. }

                                      

     十一、一张A4打印多个面单

    1. public static void mergePdf(java.util.List orginPdfList, String outputPdfFile) throws Exception {
    2. Document doc = new Document(PageSize.A4);
    3. PdfWriter writer = PdfWriter.getInstance(doc, new FileOutputStream(outputPdfFile));
    4. writer.setPageEvent(new PdfPageEventHelper(){
    5. @Override
    6. public void onStartPage(PdfWriter writer, Document document) {
    7. PdfContentByte cb = writer.getDirectContent();
    8. cb.saveState();
    9. cb.beginText();
    10. BaseFont bf = null;
    11. try {
    12. bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
    13. } catch (Exception e) {
    14. e.printStackTrace();
    15. }
    16. cb.setFontAndSize(bf, 10);
    17. float y = document.bottom(-20);
    18. cb.showTextAligned(PdfContentByte.ALIGN_CENTER, "-"+writer.getPageNumber()+"-", (document.right() + document.left()) / 2, y, 0);
    19. cb.endText();
    20. cb.restoreState();
    21. }
    22. });
    23. doc.open();
    24. float height = 0f;
    25. for (int i = 0; i < orginPdfList.size(); i++) {
    26. PdfReader reader = new PdfReader(orginPdfList.get(i));
    27. PdfContentByte cb = writer.getDirectContent();
    28. PdfImportedPage page = writer.getImportedPage(reader, 1);
    29. height = page.getHeight();
    30. if (i == 0) {
    31. //设置 比例 放大或者缩小 以及防止位置
    32. cb.addTemplate(page, 0.95, 0, 0, 0.95, 0, height);
    33. }
    34. if (i == 1) {
    35. cb.addTemplate(page, 0.95, 0, 0, 0.95, 300, height);
    36. }
    37. if (i == 2) {
    38. cb.addTemplate(page, 0.95, 0, 0, 0.95, 0, height - 410);
    39. }
    40. if (i == 3) {
    41. cb.addTemplate(page, 0.95, 0, 0, 0.95, 300, height - 410);
    42. }
    43. }
    44. doc.close();
    45. }

     

    官方地址

    官方源码

    代码地址 

  • 相关阅读:
    【Java基础】深入理解反射、反射的应用(工厂模式、代理模式)
    使用Qt实现命令行解析
    安全运营中心即服务提供商评估
    这么简单,还不会使用java8 stream流的map()方法吗?
    【LeetCode】Day129-组合总和 II
    解决 for 循环中使用 var 定义函数的问题(解决循环中异步问题)
    2、RocketMQ消息的分类
    超纯水制备
    我献出这篇 go 精华总结,阁下该如何应对
    【菜鸡学艺--Vue2--002】[基础指令&[条件与循环]
  • 原文地址:https://blog.csdn.net/weixin_43549578/article/details/124093460