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 }