赞
踩
Apache PDFBox 是一个用于处理 PDF 文档的 Java 库。它提供了许多功能和方法来读取、创建、操作和提取 PDF 文档的内容。
- <!-- https://mvnrepository.com/artifact/org.apache.pdfbox/pdfbox -->
- <dependency>
- <groupId>org.apache.pdfbox</groupId>
- <artifactId>pdfbox</artifactId>
- <version>2.0.24</version>
- </dependency>
- try {
- // 创建一个空白的PDF文档
- PDDocument document = new PDDocument();
- // 创建一个页面
- PDPage page = new PDPage(PDRectangle.A4);
- document.addPage(page);
- // 创建一个内容流
- PDPageContentStream contentStream = new PDPageContentStream(document, page);
- // 设置字体和字号
- contentStream.setFont(PDType1Font.HELVETICA_BOLD, 12);
- // 在页面上绘制文本
- contentStream.beginText();
- contentStream.newLineAtOffset(100, 700);
- contentStream.showText("Hello, World!");
- contentStream.endText();
- // 关闭内容流
- contentStream.close();
- // 保存PDF文档
- document.save("output.pdf");
- // 关闭PDF文档
- document.close();
- System.out.println("PDF生成成功!");
- } catch (IOException e) {
- e.printStackTrace();
- }
引用源码中对PDDocument 类的描述
This is the in-memory representation of the PDF document
这是PDF文档的内存表示,在 java 程序中,你可以简单理解为他就是 pdf 文档,后续对他的一系列操作就是对 pdf 文档的一系列操作。
创建全新的 pdf 文档:文档中无任何页面
PDDocument document=new PDDocument();
如果你想对原有的 pdf 模板进行动态数据的填充,可以使用PDDocument.load()方法来加载已经制作好的 pdf 模板,
PDDocument document = PDDocument.load(new ClassPathResource("/static/reportTemplate.pdf").getInputStream());
你也可以用文件形式来加载 pdf 模板,不过更推荐文件流的形式
PDDocument document = PDDocument.load(new ClassPathResource("/static/reportTemplate.pdf").getFile());
如果你想对你生成的 pdf 进行加密操作,你可以使用PDDocument load(InputStream input, String password)方法,如下设置了解密的密码为 123456.
PDDocument document = PDDocument.load(new ClassPathResource("/static/reportTemplate.pdf").getInputStream(),"123456");
PDDocument.load()中有好多重载的方法,这里就不一一列出。感兴趣的可以查看 pdfbox 的源码,
- ByteArrayOutputStream baos = new ByteArrayOutputStream();;
- document.save(baos); //保存文件到文件流
-
- document.save("output.pdf"); //保存文件到文件
保存成文件流之后,有时候我们需要将文件传输到前端进行下载,
- // 将PDF文件转换为字节数组
- byte[] pdfBytes = baos.toByteArray();
-
- // 创建InputStreamResource对象
- ByteArrayInputStream bis = new ByteArrayInputStream(pdfBytes);
- InputStreamResource resource = new InputStreamResource(bis);
-
- // 设置HTTP响应头信息
- HttpHeaders headers = new HttpHeaders();
- headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=output.pdf");
- headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_PDF_VALUE);
- // 返回带有PDF内容的响应实体
- return ResponseEntity.ok()
- .headers(headers)
- .body(resource);
在对document 操作完成之后,一定要执行document.close()方法关闭 pdf 文档。
document.close();
PDPage 属于 pdf 文档中的的页面,
int pageNumber=document.getNumberOfPages();
获取指定页面,
PDPage page = document.getPage(0);
如果你是对 pdf 模板进行操作,你可以通过document.getPage(index)方法来获取 pdf 文档的指定页面,并对其进行操作(index 从 0 开始)。你也可以通过new PDPage();创建一个全新的 page,
PDPage newPage = new PDPage(PDRectangle.A4);
如果我们是通过 new PDPage()的方式生成 page 页面时,我们需要将 page 页面添加到 pdf 文档中去(document),
document.addPage(newPage);
不过这种方式会将 page 添加到 pdf 文档的末尾,我们有时候需要将 page 添加到指定的位置,可以使用以下方法。
- PDPage page=document.getPage(1); //获取第2页
- PDPage newPage = new PDPage(PDRectangle.A4);
- PDPageTree pages = document.getPages();
- pages.insertAfter(newPage,page); //插入到第2页后面
- pages.insertBefore(newPage,page); //插入到第2页前面
获取 page 页面总高度和总宽度,这个在后续的文字坐标定位中很有用,在 page 中原点坐标位于左下角,如果你想你的元素左边距为 10,上边距为 10,那么你的坐标将是(10,pageHeight-10)
float pageWidth = page.getMediaBox().getWidth();
float pageHeight = page.getMediaBox().getHeight();
PDPageContentStream 类提供写入页面内容流的功能,它需要绑定 pdf 文档和指定的 page 页面,这样相当于创建了 page 当前页面的内容流。
PDPageContentStream contentStream = new PDPageContentStream(document, page);
如果不指定PDPageContentStream.AppendMode,默认会以重写模式执行,后续对 page 页面添加元素会覆盖现有页面内容流。
PDPageContentStream contentStream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, true);
模式代码 | 模式 | 注释 |
PDPageContentStream.AppendMode.OVERWRITE | 重写模式 | 覆盖现有页面内容流 |
PDPageContentStream.AppendMode.APPEND | 追加模式 | 将内容流附加到所有现有页面内容流之后 |
PREPENDPDPageContentStream.AppendMode. | 准备模式 | 在所有其他页面内容流之前插入 |
对contentStream 操作完成之后,需要关闭内容流。
contentStream.close();
在 Apache PDFBox 中,字体相关的类主要位于 org.apache.pdfbox.pdmodel.font 包下。下面是一些常用的字体类:
PDType1Font:这个类表示 Type 1 字体,它是一种基于轮廓的字体格式。Type 1 字体常用于 PDF 文档中,如 Helvetica、Times Roman 和 Courier 等。
示例:
PDType1Font font = PDType1Font.HELVETICA_BOLD;
- public static final PDType1Font TIMES_ROMAN = new PDType1Font("Times-Roman");
- public static final PDType1Font TIMES_BOLD = new PDType1Font("Times-Bold");
- public static final PDType1Font TIMES_ITALIC = new PDType1Font("Times-Italic");
- public static final PDType1Font TIMES_BOLD_ITALIC = new PDType1Font("Times-BoldItalic");
- public static final PDType1Font HELVETICA = new PDType1Font("Helvetica");
- public static final PDType1Font HELVETICA_BOLD = new PDType1Font("Helvetica-Bold");
- public static final PDType1Font HELVETICA_OBLIQUE = new PDType1Font("Helvetica-Oblique");
- public static final PDType1Font HELVETICA_BOLD_OBLIQUE = new PDType1Font("Helvetica-BoldOblique");
- public static final PDType1Font COURIER = new PDType1Font("Courier");
- public static final PDType1Font COURIER_BOLD = new PDType1Font("Courier-Bold");
- public static final PDType1Font COURIER_BOLD_OBLIQUE = new PDType1Font("Courier-BoldOblique");
- public static final PDType1Font SYMBOL = new PDType1Font("Symbol");
- public static final PDType1Font ZAPF_DINGBATS = new PDType1Font("ZapfDingbats");
PDTrueTypeFont:这个类表示 TrueType 字体,也是一种基于轮廓的字体格式。TrueType 字体在 PDF 中也很常见。
PDTrueTypeFont font = PDType1Font.TIMES_ROMAN;
PDType0Font:这个类表示 Type 0 字体,它是一种复合字体格式,可以包含多个子字体。Type 0 字体通常用于支持多语言和复杂字形需求,你可以使用它来加载自己自定义的字体文件。
PDType0Font font = PDType0Font.load(document, new ClassPathResource("/static/wryhRegular.ttf").getInputStream());
- contentStream.setFont(PDType1Font.COURIER_BOLD_OBLIQUE, 16);
- contentStream.beginText();
- contentStream.newLineAtOffset(50, pageHeight-50);
- contentStream.showText("测试文本");
- contentStream.endText();
在写入文本之前需要通过contentStream.setFont(PDFont font, float fontSize) 方法设置字体和字号,并通过beginText()方法开始一个新的文本段落,通过newLineAtOffset(x, y);方法设置文本的坐标位置,这里设置(50, pageHeight-50)表示文本位置位于左上角,离上面和左边 50 个单位。然后通过showText(String text)显示你需要展示的文本,最后用endText()方法结束文本段落。
- contentStream.setFont(PDType1Font.HELVETICA_BOLD, 12);
-
- // 设置文本起始坐标
- float startX = 50;
- float startY = page.getMediaBox().getHeight() - 50;
-
- // 设置行间距
- float leading = 15;
-
- // 写入多行文本
- String[] lines = {
- "第一行文本",
- "第二行文本",
- "第三行文本"
- };
-
- contentStream.beginText();
- contentStream.newLineAtOffset(startX, startY);
-
- for (String line : lines) {
- contentStream.showText(line);
- contentStream.newLineAtOffset(0, -leading);
- }
-
- contentStream.endText();
写入多行文本和单行文本流程差不多,都需要先设置字体和字号,确定写入文字的坐标,不同的是,我们在 beginText()方法和endText()方法之间,多次执行了showText()和newLineAtOffset(),newLineAtOffset(0, -leading)方法代表着在上一行的位置基础上,X 轴不变,Y 轴向下移动leading 个单位。多次循环之后将多行文本添加到 pdf 文档中。
- PDImageXObject image = PDImageXObject.createFromFileByExtension(new File("path/to/image.jpg"), document);
- float imageWidth = image.getWidth();
- float imageHeight = image.getHeight();
-
- PDPageContentStream contentStream = new PDPageContentStream(document, page);
- contentStream.drawImage(image, x, y, imageWidth, imageHeight);
这里我们使用PDImageXObject.createFromFileByExtension()方法加载图片文件,创建一个PDImageXObject对象。确保将"path/to/image.jpg"替换为实际图片文件的路径,这里我将图片的宽度和高度设置为真实图片的宽高,在实际情况中你也可以自定义宽高,最后通过drawImage(image, x, y, imageWidth, imageHeight)方法将图片写入到 pdf 文档中,x,y 代表其 xy 坐标,后面的imageWidth, imageHeight 分别代表图片的宽度和高度。
- //设置边框颜色
- contentStream.setStrokingColor(new Color(213, 213, 213));
- //设置边框宽度为1
- contentStream.setLineWidth(1);
- // 添加矩形框到页面内容流
- contentStream.addRect(50, pageHeight-50, 100, 100);
- // 绘制矩形框的边框
- contentStream.stroke();
- //恢复原来的颜色,否则会影响文字颜色
- contentStream.setStrokingColor(Color.BLACK);
- /**
- * 获取字体高度
- * */
- float getFontHeight(PDType0Font customFont,float fontSize){
- return customFont.getFontDescriptor().getFontBoundingBox().getHeight() / 1000 * fontSize;
- }
- /**
- * 计算文本宽度
- * */
- float getTextWidth(String text,float fontSize){
- return fontSize * text.length();
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。