Site iconJava PDF Blog

Avoid transparency when printing in Java

Java has a print mechanism called Java Print Services. In most cases this works brilliantly, but beware the use of transparency in anything you print! This article explains why this is and how you can tell if you have this issue.

Java Print Services allows you to add print capabilities to any Swing component (something it would be really nice to see in JavaFx if it wants to replace Swing). You just add a method like this to your Swing component

/**
* Implements the standard Java printing functionality.
*
* @param graphics the context into which the page is drawn
* @param pageFormat the size and orientation of the page being drawn
* @param page the zero based index of the page to be drawn
* @return int Printable.PAGE_EXISTS or Printable.NO_SUCH_PAGE
* @throws PrinterException
*/
public int print(Graphics graphics, PageFormat pageFormat, int page) throws PrinterException {

System.out.println(graphics);

System.out.println(“clip=” + graphics.getClipBounds());

//draw your component as you would in the paint() method – you can generally use the same code with the Graphics2D object

}

Like paint() it takes a Graphics2D object which we can draw on, providing a high level of abstraction and simplicity.

Let us run this on a 2 page test document containing some images as and see what we get.

sun.print.PeekGraphics[]
clip=java.awt.Rectangle[x=0,y=0,width=612,height=792]
sun.print.PSPathGraphics[]
clip=java.awt.Rectangle[x=0,y=0,width=612,height=792]
sun.print.PeekGraphics[]
clip=java.awt.Rectangle[x=0,y=0,width=612,height=792]
sun.print.PSPathGraphics[]
clip=java.awt.Rectangle[x=0,y=0,width=612,height=792]
All done

Java makes a dummy call to the print method to see what is there (PeekGraphics) and then makes ONE call to render the page onto the Graphics2D for the printer. So with 2 pages we have 4 calls in total.

Now I am going to make ONE change and see what happens with the same file….

sun.print.PeekGraphics[]
clip=java.awt.Rectangle[x=0,y=0,width=612,height=792]
sun.print.PeekGraphics[]
clip=java.awt.Rectangle[x=0,y=0,width=612,height=792]
sun.print.ProxyGraphics2D[]
clip=java.awt.Rectangle[x=415,y=25,width=31,height=20]
sun.print.ProxyGraphics2D[]
clip=java.awt.Rectangle[x=500,y=25,width=71,height=19]

and so on for a long time!

So what did we change? In both cases, we used the same document. In the first case, we converted the images to BuffferedImage of time BINARY or GRAY while in the second, the BufferedImage ARGB. As soon as we have the possibility of any transparency on the page, Java Printing goes a bit mad and draws the page as a huge number of tiny blocks rather than in a single go. And performance drops off dramatically! Unfortunately, you often need transparency to display a PDF file correctly. So the trick is to try to minimise its usage.

So if you find you have performance issues in your print code, add in some debug code to your print() method and see if it is the dreaded transparency issue. Do you have any tips for print performance in Java?