PdfBox使用-创建PDF

PDF(Portable Document Format的简称,意为“便携式文档格式”)

1、Java PDF开源库

名称

描述

优缺点

iText

iText是一个能够快速产生PDF文件的java类库。iText的java类对于那些要产生包含文本,表格,图形的只读文档是很有用的。它的类库尤其与java Servlet有很好的给合。使用iText与PDF能够使你正确的控制Servlet的输出。

Api使用简单,官网提供的资料很多

许可协议:APGL

简单说:就是商业用途要收费

PDF Box

PDFBox是一个Apache开源的x项目。可以操作PDF文档的Java PDF类库。它可以创建一个新PDF文档,操作现有PDF文档并提取文档中的内容。

文档少,表格不支持,api相对比较底层Apache License v2.0

免费使用,基本没有限制

FOP

FOP是由James Tauber发起的一个开源项目,原先的版本是利用xsl-fo将xml文件转换成pdf文件。但最新的版本它可以将xml文件转换成pdf,mif,pcl,txt等多种格式以及直接输出到打印机,并且支持使用SVG描述图形

本人没使用过,不很清楚

 

为什么使用Pdfbox?

1)使用没有限制

2)基本的pdf操作都满足

3)学习啊,学习啊

2、简单使用

要使用一个Java库,当然是先查看官网文档。

比较悲剧的是,pdfbox官网的资料很少,仅仅有功能特性的介绍。但是有一些使用案例:可以github上下载查看(https://github.com/apache/pdfbox)

PdfBox使用-创建PDF_第1张图片依赖Jar(有这一个就够了哈,当然你也可以按需导入你需要的,pdfbox(核心)、fontbox、pdfbox-tools、pdfbox-debugger、xmpbox、preflight)


    org.apache.pdfbox
    pdfbox-app
    2.0.18

输出一行文本(其他的基本操作可以参考: https://iowiki.com/pdfbox/pdfbox_quick_guide.html

public void createPdf() throws IOException {
    PDDocument document = new PDDocument();
    PDPage page = new PDPage(PDRectangle.A4);
    document.addPage(page);
    try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {
      contentStream.beginText();
      contentStream.newLineAtOffset(200, 700);
      contentStream.setFont(PDType1Font.TIMES_ROMAN, 12.5f);
      contentStream.showText("Hello PdfBox");
      contentStream.endText();
    }
    document.save("target/pdfboxtest.pdf");
    document.close();
}

 

3、坐标系

介绍

平面直接坐标系,其中横轴为X轴,纵轴为Y轴。简称直角坐标系。分为第一象限,第二象限,第三象限,第四象限。从右上角开始数起,逆时针方向算起。

PdfBox使用-创建PDF_第2张图片

x的正方向是水平相右,y的正方向是垂直相上(没有旋转的页面)

PdfBox的坐标系统,也就是你能看到的部分在【第一象限】视图,x值从左到右增加,y从下到上增加。

因此,如果您使用new PDPage()或new PDPage(PDPage.PAGE_SIZE_*)创建页面,则坐标系的原点将从页面的左下角开始。

坐标:旋转、原点移动

http://www.voidcn.com/article/p-pfgyxuyl-btn.html

4、文本测量

PDRectangle mediaBox = page.getMediaBox();
PDRectangle cropBox = page.getCropBox();
System.out.println("页面的高度:" + mediaBox.getHeight());
System.out.println("页面的宽度:" + mediaBox.getWidth());
//字体的高度
float fontCapHeight = font.getFontDescriptor().getCapHeight() / 1000f * fontSize;
//文字的宽度
float textWidth = font.getStringWidth(text);

5、画表格

PDDocument document = new PDDocument();
PDPage page = new PDPage(PDRectangle.A4);
document.addPage(page);
try (PDPageContentStream contentStream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, true, true)) {
  float x = 30f;
  float y = page.getMediaBox().getUpperRightY() - 30f;
  //3行4列的表格
  int rows = 3;
  int cols = 4;
  //行高
  float rowHeight = 15.0f;
  float colWidth = 40.0f;
  contentStream.saveGraphicsState();
  //线条颜色
  contentStream.setStrokingColor(Color.RED);
  //线条宽度
  contentStream.setLineWidth(1.0f);
  //drawTable
  for (int row = 0; row <= rows; row++) {
    float xStart = x;
    float yStart = y - row * rowHeight;
    float xEnd = xStart + cols * colWidth;
    float yEnd = yStart;
    contentStream.moveTo(xStart, yStart);
    contentStream.lineTo(xEnd, yEnd);
  }
  for (int col = 0; col <= cols; col++) {
    float xStart = x + col * colWidth;
    float yStart = y;
    float xEnd = xStart;
    float yEnd = yStart - rows * rowHeight;
    contentStream.moveTo(xStart, yStart);
    contentStream.lineTo(xEnd, yEnd);
  }
  contentStream.stroke();
  contentStream.restoreGraphicsState();
}
document.save("target/pdfboxtest.pdf");
document.close();

6、easytable

github: https://github.com/vandeseer/easytable

//引入easytable Jar

   com.github.vandeseer
   easytable
   0.6.0

//3行4列的表格
PDDocument document = new PDDocument();
PDPage page = new PDPage(PDRectangle.A4);
document.addPage(page);
try (PDPageContentStream contentStream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, true, true)) {
  PDFont font = PDType1Font.TIMES_ROMAN;
  float fontSize = 12.5f;
  Settings settings = Settings.builder()
    .font(font)
    .fontSize((int) fontSize)
    .horizontalAlignment(HorizontalAlignment.CENTER)
    .verticalAlignment(VerticalAlignment.MIDDLE)
    .backgroundColor(Color.WHITE)
    .wordBreak(true)
    .build();
  // Build the table
  //3行4列的表格
  int rows = 3;
  int cols = 4;
  float colWidth = 40.0f;
  Table.TableBuilder tableBuilder = Table.builder().borderColor(Color.RED).wordBreak(true);
  for (int col = 0; col < cols; col++) {
    tableBuilder.addColumnOfWidth(colWidth);
  }
  for (int row = 0; row < rows; row++) {
    Row.RowBuilder rowBuilder = Row.builder().wordBreak(true);
    for (int col = 0; col < cols; col++) {
      String colData = "text:" + col;
      rowBuilder.add(TextCell.builder().settings(settings).text(colData).borderWidth(0.5f).build());
    }
    tableBuilder.addRow(rowBuilder.build());
  }

  Table myTable = tableBuilder.build();
  float tableHeight = myTable.getHeight();
  System.out.println("表格高度:" + tableHeight);
  // Set up the drawer
  float x = 30f;
  float y = page.getMediaBox().getUpperRightY() - 30f;
  TableDrawer tableDrawer = TableDrawer.builder()
    .contentStream(contentStream)
    .startX(x)
    .startY(y)
    .table(myTable)
    .build();
  // And go for it!
  tableDrawer.draw();
  contentStream.restoreGraphicsState();
}
document.save("target/pdfboxtest.pdf");
document.close();

7、字体支持

字体下载网站: http://font.chinaz.com/

思源字体:思源黑体是Adobe与Google宣布推出的一款开源字体,https://www.google.com/get/noto/help/cjk/

NotoSansCJKtc字体:Google 开发的思源黑体,noto是谷歌取的名字,sans思源,cjk表示中文、日文、韩文,tc是中文繁体

PdfBox加载字体

  • SDK自带
PDType1Font.TIMES_ROMAN
  • 加载ttf字体
PDDocument document = new PDDocument();
InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(fontPath);
//第一种
PDFont font = PDType0Font.load(document, inputStream)
//第二种
TrueTypeFont ttfFont = new TTFParser().parse(inputStream);
PDFont font = PDType0Font.load(document, ttfFont, true)
  • 加载otf字体
PDDocument document = new PDDocument();
InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(fontPath);
//只能这样加载
OpenTypeFont otfFont = new OTFParser(false, true).parse(inputStream);
PDFont font = PDType0Font.load(this.getDocument(), otfFont, false)

 

8、同时多种字体适应的解决方案

https://www.ojit.com/article/1798712

eg. 你好,Hello PdfBox,クーポン券手数料合計

        PDDocument document = new PDDocument();
        PDPage page = new PDPage(PDRectangle.A4);
        document.addPage(page);
        List fontList = new ArrayList<>();
        fontList.add(PDType1Font.TIMES_ROMAN);
        try (InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("fonts/NotoSansCJKtc-Regular.ttf")) {
            fontList.add(PDType0Font.load(document, inputStream));
        }
        String text = "你好,Hello PdfBox,クーポン券手数料合計";
        try (PDPageContentStream contentStream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, true, true)) {
            int len = text.length();
            contentStream.beginText();
            contentStream.newLineAtOffset(200f, 200f);
            for (int i = 0; i < len; i++) {
                String s = String.valueOf(text.charAt(i));
                System.out.println(s);
                PDFont useFont = null;
                for (PDFont font : fontList) {
                    try {
                        font.encode(s);
                        useFont = font;
                    } catch (Exception e) {
                        //ignore
                        continue;
                    }
                }
                contentStream.setFont(useFont, 12f);
                contentStream.showText(s);
            }
            contentStream.endText();
        }
        document.save("target/pdfboxtest.pdf");
        document.close();

9、参考资料

  • https://zhuanlan.zhihu.com/p/53421567

  • https://my.oschina.net/u/1240964/blog/671178

10、使用案例

  • https://github.com/mkl-public/testarea-pdfbox2

  • https://github.com/apache/pdfbox/blob/trunk/examples/src/main/java/org/apache/pdfbox/examples/util/PrintTextLocations.java

  • https://github.com/mkl-public/testarea-pdfbox2/blob/master/src/test/java/mkl/testarea/pdfbox2/content/AddTextWithDynamicFonts.java

  • https://zhuanlan.zhihu.com/p/53421567

  • https://github.com/dongdongdeng/iPDFBox

  • 添加水印

  • public static void printWatermark(PDPage page, PDPageContentStream cs, List fontList, String text) {
            try {
                PDFont useFont = null;
                for (PDFont font : fontList) {
                    try {
                        font.encode(text);
                        useFont = font;
                        break;
                    } catch (Exception e) {
                        continue;
                    }
                }
                if (useFont == null) {
                    logger.error("没有可以使用发字体");
                    useFont = PDType1Font.TIMES_ROMAN;
                    text = "Invalid Invalid Invalid";
                }
                PDRectangle mediaBox = page.getMediaBox();
                float fontSize = 30.0f;
                PDExtendedGraphicsState r0 = new PDExtendedGraphicsState();
                // 透明度
                r0.setNonStrokingAlphaConstant(0.1f);
                r0.setAlphaSourceFlag(true);
                cs.saveGraphicsState();
                cs.setGraphicsStateParameters(r0);
                cs.setNonStrokingColor(Color.RED);
                float startPoint = -100f;
                float step = 250f;
                for (float i = startPoint; i < mediaBox.getWidth(); i += step) {
                    for (float j = startPoint; j < mediaBox.getHeight(); j += step) {
                        cs.beginText();
                        cs.setFont(useFont, fontSize);
                        // 获取旋转实例
                        cs.setTextMatrix(Matrix.getRotateInstance(Math.toRadians(30f), i, j));
                        cs.showText(text);
                        cs.endText();
                    }
                }
                cs.restoreGraphicsState();
            } catch (Exception e) {
                logger.error("添加水印异常", e);
            }
        }

     

你可能感兴趣的:(java)