We are using PDFPageable to send PDF files to a Java print job.  We are not
in control of the PDF files themselves.  Here is the document:
https://drive.google.com/file/d/1iTKQ-xluJFXm5Qg4DJt2svQ64vi93a1U/view?usp=sharing

We are seeing some content that is failing to print (page 4), but with
very, very strange behavior.  The content that fails to print is complex
(graphs, lots of fonts).

- If the problem page is Page 4 of the document, then the print job prints
Page 1-3 and only some of the content for Page 4 (page 4 is quite complex,
and all that prints is the page footer content).

- If the problem page is Page 1 of the document (i.e. we move pages
around), then it prints fine.

- The specific content of the problem page that actually prints depends on
how many/which pages are printed before it.

- The problem page prints fine on some printers but not others (I have it
failing on a small laser printer, and two customers have it failing on
large MFP devices).

- If I print to the MS PDF Print driver, the problem pages are in the
output.

- If I print using a regular PDF viewer (Acrobat, Foxit), it prints fine.

So the only way I can demonstrate the failure is to actually print to
physical paper (you can imagine that this is driving us crazy).  I am
including code to actually run the print jobs at the bottom of this email.


Diagnostic Attempts
-----------------------

The problem page renders in the PDFDebugger without issues.

I have added diagnostics to PageDrawer, and can confirm that the same
rendering operations execute regardless of whether the page prints to paper
or not.

If I force rasterizing during printing (be specifying a dpi in the
PDFPageable constructor), then the content prints fine (assuming the JVM
has enough heap).

I have tested with Java 11 and Java 23, with the same results.


I'm not sure what to conclude at this point - maybe this is a rare JRE bug
of some sort that is triggered by specific Graphics2D draw operations?

I would love to hear what anything thinks might be going on.

Next Steps
---------------

At this point, unless someone can explain why we are observing this print
behavior, it seems like my best bet is to switch to rasterizing.

Assuming that I am going to need to switch to rasterizing, I would like to
discuss an improvement to PDFPrintable so it doesn't require an explicit
dpi to be provided.  Printer DPI information is not readily available from
PrinterJob, which makes it almost impossible to set this in a reliable way.

Based on my research, I found that the affine transform of the graphics2d
passed to PDFPrintable has the necessary scaling information to determine
the dpi for the printer.

So the idea would be to have a boolean autoRasterize setting, instead of an
explicit dpi setting, then compute dpi from the affine transform like this:

dpi = graphics2D.getTransform().getScaleX() * 72.0

(assuming that X and Y scaling are the same, of course).

Would this be a reasonable enhancement?  I'm happy to code it if you will
accept a patch.


A few final comments
----------------------------

A) Looking at the current PDFPrintable.print() method, I wonder if things
wouldn't be simpler to create a raster at the top of the print() method?

B)  While unrelated to my current situation, I also note that there is an
opportunity to improve printing performance quite a bit by:
1.  In PDFPageable, cache the last PDFPrintable and page number.  If the
page is the same as previous, re-use the cached PDFPrintable instead of
creating a new one.
2.  then, in PDFPrintable, cach the raster BufferedImage and send it
straight to the printer instead of re-rendering

My debugging shows that the above caching changes would double the printing
speed if rasterizing is enabled.  My debugging also shows that rasterizing
improves printing performance by a factor of 10.

Thanks in advance,

- K

Code for running the print job
------------

public class Main {

private static PrintService getPrintService(String name){
        PrintService[] services =
PrintServiceLookup.lookupPrintServices(null, null);
       for (PrintService service : services) {
           if (service.getName().equalsIgnoreCase(name)){
               return service;
           }
       }
       return null;
}

public static void main(String[] args) throws Exception {
File pdf = new File("path to.pdf");

       PrintService printService = getPrintService("printer name");
       //PrintService printService = getPrintService("Microsoft Print to
PDF");

PrinterJob job = PrinterJob.getPrinterJob();
job.setPrintService(printService);

try(PDDocument doc = Loader.loadPDF(pdf)){
final PDFPageable pageable = new PDFPageable(doc, Orientation.AUTO, false,
0, true); // change 0 to 300 or 600 to rasterize

job.setPageable(pageable);
job.setJobName(pdf.getName());

job.print();

}
}
}

Reply via email to