zoukankan      html  css  js  c++  java
  • 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 }
    View Code
  • 相关阅读:
    ReactiveCocoa入门教程——第一部分
    How Do I Declare A Block in Objective-C?
    Xcode 6制作动态及静态Framework
    用CocoaPods做iOS程序的依赖管理
    oracle误删除数据恢复
    搭建第一个web项目:quartz+spring实现定时任务
    通过jsoup对网页进行数据抓取。
    使用httpClient模拟登陆开心网过程中登陆成功但是跳转不成功
    service
    搭建第一个web项目:实现用户的增删改查(四)
  • 原文地址:https://www.cnblogs.com/xdecode/p/8000828.html
Copyright © 2011-2022 走看看