PDFBox 打印带背景的文件速度慢
时间:2022-04-24
本文章向大家介绍PDFBox 打印带背景的文件速度慢,主要内容包括打印慢的原因、慢在哪、怎么解决、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。
打印慢的原因
java的RasterPrinterJob会执行很多次printPage方法
他应该是按块填充的, 如果页面元素非常复杂, 那么printPage方法可能会执行十几次.
而如果你用了如下代码中流式打印的方式, 每页pdf单独实现Printable接口, 重写print方法.
1 private static class FinePrintableDemo implements Printable {
2
3 public FinePrintableDemo(PDDocument document, int index) {
4 this.index = index;
5 this.printable = new PDFPrintable(document);
6 }
7
8 private int index;
9 private PDFPrintable printable;
10
11 @Override
12 public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
13 long start1 = System.currentTimeMillis();
14 int res = printable.print(graphics, pageFormat, index);
15 long end1 = System.currentTimeMillis();
16 System.out.println("打印第 " + (index + 1) + "页 耗时 : " + (end1 - start1) +" 毫秒 ");
17
18 return res;
19 }
20 }
会发现print方法同样被执行了十几次, 造成一个带背景的pdf打印耗时十几秒.
慢在哪
慢在每次都重复解析同一页pdf内容. 打了断点后会发现每页都在PDFStreamEngine.processStream
1 public void renderPageToGraphics(int pageIndex, Graphics2D graphics, float scale) throws IOException {
2 PDPage page = this.document.getPage(pageIndex);
3 this.transform(graphics, page, scale);
4 PDRectangle cropBox = page.getCropBox();
5 graphics.clearRect(0, 0, (int)cropBox.getWidth(), (int)cropBox.getHeight());
6 PageDrawerParameters parameters = new PageDrawerParameters(this, page);
7 PageDrawer drawer = this.createPageDrawer(parameters);
8 drawer.drawPage(graphics, cropBox);
9 }
这个方法每次都会消耗1s左右.
怎么解决
最好的方式自然是改pdfbox源码, 不用每次都重新生成解析pdf文件. 不过那样稍微有点麻烦.
还有个更简单的方式, 既然pdf会被反复解析, 那么我们在print之前把pdf转成图片, 然后直接打印图片即可.
即使RasterPrinterJob.printPage执行十几次, 也不过在绘制Image, 时间会非常短.
因此我们将代码稍微改造下, 在printable.print方法中直接打印图片.
1 private static class FinePrintableDemo implements Printable {
2
3 private BufferedImage image;
4
5 public FinePrintableDemo(PDDocument document, int index) {
6 // 获取pdf文件, 将其中指定的页面转成图片.
7 PDFRenderer renderer = new PDFRenderer(document);
8 try {
9 this.image = renderer.renderImage(index, 1, ImageType.RGB);
10 } catch (IOException e) {
11 e.printStackTrace();
12 }
13
14 }
15
16 @Override
17 public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
18 long start1 = System.currentTimeMillis();
19 Graphics2D g2d = (Graphics2D) graphics.create();
20 Paint paint = g2d.getPaint();
21
22 int width = this.image.getWidth();
23 int height = this.image.getHeight();
24
25 Shape shape = new Rectangle2D.Double(0, 0, width, height);
26 g2d.setPaint(createPaint(shape, StableUtils.isNotSupportARGB(g2d), image, width, height));
27 g2d.fill(shape);
28 g2d.setPaint(paint);
29 g2d.dispose();
30 long end1 = System.currentTimeMillis();
31 System.out.println("打印第 " + (pageIndex + 1) + "页 耗时 : " + (end1 - start1) +" 毫秒 ");
32 return Printable.PAGE_EXISTS;
33 }
34
35 private Paint createPaint(Shape shape, boolean isNotSupportARGB, BufferedImage image, int width, int height) {
36 Rectangle2D rec2D = shape.getBounds2D();
37 if ((int) rec2D.getWidth() <= 0) {
38 rec2D.setRect(rec2D.getX(), rec2D.getY(), rec2D.getWidth() + 40, rec2D.getHeight());
39 }
40 if ((int) rec2D.getHeight() <= 0) {
41 rec2D.setRect(rec2D.getX(), rec2D.getY(), rec2D.getWidth(), rec2D.getHeight() + 40);
42 }
43 BufferedImage buffered = new BufferedImage((int) rec2D.getWidth(), (int) rec2D.getHeight(), isNotSupportARGB ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB);
44 Graphics2D g2 = buffered.createGraphics();
45 GraphHelper.paintImage(g2, (int) rec2D.getWidth(), (int) rec2D.getHeight(), image,
46 Constants.IMAGE_CENTER , Constants.LEFT, Constants.TOP, width, height, isNotSupportARGB);
47
48 g2.dispose();
49
50 return new TexturePaint(buffered, rec2D);
51 }
52 }
这一次print方法同样被执行了十几次, 但是每次也就十几毫秒, 文件很快就被打印出来了.
完整代码如下
1 package com.fr.base;
2
3 import com.fr.stable.Constants;
4 import com.fr.stable.StableUtils;
5 import org.apache.pdfbox.pdmodel.PDDocument;
6 import org.apache.pdfbox.rendering.ImageType;
7 import org.apache.pdfbox.rendering.PDFRenderer;
8
9 import java.awt.Graphics;
10 import java.awt.Graphics2D;
11 import java.awt.Paint;
12 import java.awt.Shape;
13 import java.awt.TexturePaint;
14 import java.awt.geom.Rectangle2D;
15 import java.awt.image.BufferedImage;
16 import java.awt.print.Book;
17 import java.awt.print.PageFormat;
18 import java.awt.print.Paper;
19 import java.awt.print.Printable;
20 import java.awt.print.PrinterException;
21 import java.awt.print.PrinterJob;
22 import java.io.FileInputStream;
23 import java.io.IOException;
24 import java.io.InputStream;
25
26 public class doStreamImagePrint {
27
28 public static void main(String[] args) throws IOException, PrinterException {
29 PrinterJob job = PrinterJob.getPrinterJob();
30
31 int width = 595;
32 int height = 842;
33 int marginLeft = 0;
34 int marginRight = 0;
35 int marginTop = 0;
36 int marginBottom = 0;
37
38 Paper paper = new Paper();
39 paper.setSize(width, height);
40 // 设置边距
41 paper.setImageableArea(marginLeft, marginRight, width - (marginLeft + marginRight), height - (marginTop + marginBottom));
42 // 自定义页面设置
43 PageFormat pageFormat = new PageFormat();
44 // 设置页面横纵向
45 pageFormat.setOrientation(PageFormat.PORTRAIT);
46 pageFormat.setPaper(paper);
47
48 // 构建一个有size的空book, book里都是引用. 实际打印哪一页就从远程获取哪一页
49 Book printBook = new Book();
50 // 真正打印的时候, 每页的printable都new pdfprintable.print();
51 printBook.append(convertPDFToPrint("D:\bg.pdf", 0), pageFormat);
52 printBook.append(convertPDFToPrint("D:\bg.pdf", 0), pageFormat);
53
54
55 job.setPageable(printBook);
56 job.print();
57 }
58
59 private static FinePrintableDemo convertPDFToPrint(String path, int index) throws IOException {
60 InputStream in = new FileInputStream(path);
61 PDDocument document = PDDocument.load(in);
62 return new FinePrintableDemo(document, index);
63 }
64
65 private static class FinePrintableDemo implements Printable {
66
67 private BufferedImage image;
68
69 public FinePrintableDemo(PDDocument document, int index) {
70 // 获取pdf文件, 将其中指定的页面转成图片.
71 PDFRenderer renderer = new PDFRenderer(document);
72 try {
73 this.image = renderer.renderImage(index, 1, ImageType.RGB);
74 } catch (IOException e) {
75 e.printStackTrace();
76 }
77
78 }
79
80 @Override
81 public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
82 long start1 = System.currentTimeMillis();
83 Graphics2D g2d = (Graphics2D) graphics.create();
84 Paint paint = g2d.getPaint();
85
86 int width = this.image.getWidth();
87 int height = this.image.getHeight();
88
89 Shape shape = new Rectangle2D.Double(0, 0, width, height);
90 g2d.setPaint(createPaint(shape, StableUtils.isNotSupportARGB(g2d), image, width, height));
91 g2d.fill(shape);
92 g2d.setPaint(paint);
93 g2d.dispose();
94 long end1 = System.currentTimeMillis();
95 System.out.println("打印第 " + (pageIndex + 1) + "页 耗时 : " + (end1 - start1) +" 毫秒 ");
96 return Printable.PAGE_EXISTS;
97 }
98
99 private Paint createPaint(Shape shape, boolean isNotSupportARGB, BufferedImage image, int width, int height) {
100 Rectangle2D rec2D = shape.getBounds2D();
101 if ((int) rec2D.getWidth() <= 0) {
102 rec2D.setRect(rec2D.getX(), rec2D.getY(), rec2D.getWidth() + 40, rec2D.getHeight());
103 }
104 if ((int) rec2D.getHeight() <= 0) {
105 rec2D.setRect(rec2D.getX(), rec2D.getY(), rec2D.getWidth(), rec2D.getHeight() + 40);
106 }
107 BufferedImage buffered = new BufferedImage((int) rec2D.getWidth(), (int) rec2D.getHeight(), isNotSupportARGB ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB);
108 Graphics2D g2 = buffered.createGraphics();
109 GraphHelper.paintImage(g2, (int) rec2D.getWidth(), (int) rec2D.getHeight(), image,
110 Constants.IMAGE_CENTER , Constants.LEFT, Constants.TOP, width, height, isNotSupportARGB);
111
112 g2.dispose();
113
114 return new TexturePaint(buffered, rec2D);
115 }
116 }
117
118 }
- C#中Dispose和Close的区别!
- C#调用SQL中的存储过程中有output参数,存储过程执行过程中返回信息
- 你真的会玩SQL吗?查询指定节点及其所有父节点的方法
- ASP.Net MVC框架配置与分析
- MVC利用MvcHtmlString在后台生成HTML
- ExtJs学习笔记(7)_获取GridPanel选中行的详细信息
- ExtJs学习笔记(5)_Ajax示例
- shell脚本之特殊符号总结性梳理
- Centos6.X 下安装并使用VNC的操作记录
- Linux系统是否被植入木马的排查流程梳理
- 添加php的memcached扩展模块
- Android TextView中显示图片
- Nginx配置中的log_format用法梳理(设置详细的日志格式)
- 分享一个刷网页PV的python小脚本
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法