Printing a PDF with Java
With the popularity of digital documents on the rise, more people are being exposed to both their wonders and their challenges. However, content related to PDFs specifically is somewhat scarce and often outdated. So with that in mind, this blog post will cover a straightforward way of printing a PDF using Java and PSPDFKit Library for Java.
The Solution
You’ll be using PSPDFKit’s PdfDocument
and PdfPage
classes for opening a document and rendering each page into a BufferedImage
. These will then be used by the Java PrinterJob
class and other utilities found within the java.awt.print
package.
The following snippet demonstrates how to print a PDF. This code can then be adapted to your specific needs:
public void printDocument() { // Here you're opening the file. File file = new File("Assets/A.pdf"); PdfDocument document = PdfDocument.open(new FileDataProvider(file)); // Getting an instance of `PrinterJob` and the default `PageFormat`. PrinterJob printerJob = PrinterJob.getPrinterJob(); PageFormat pageFormat = printerJob.defaultPage(); // Removing the default margins. Paper paperFormat = pageFormat.getPaper(); paperFormat.setImageableArea(0, 0, paperFormat.getWidth(), paperFormat.getHeight()); pageFormat.setPaper(paperFormat); // A `Book` is a Java structure representing multiple printable pages. Book printableBook = new Book(); // Each page you wish to print must be added to the `Book` as a printable object. // You can specify a width and height for `renderPage()` to get your desired DPI when printing. for (int i = 0; i < document.getPageCount(); i++) { BufferedImage render = document.getPage(i).renderPage(); printableBook.append(new ExamplePrintable(render), pageFormat); } printerJob.setPageable(printableBook); // Here you can choose to display a print dialog before the actual print call. // You're using the default dialog from `PrinterJob`. if (printerJob.printDialog()) { try { printerJob.print(); } catch (PrinterException prt) { prt.printStackTrace(); } } } // This is a simple `Printable` implementation compatible with `BufferedImage`. // A `BufferedImage` is returned by the `PdfPage.renderPage()` method. private class ExamplePrintable implements Printable { private BufferedImage image; public ExamplePrintable(BufferedImage image) { this.image = image; } // This is the only method you must implement for the `Printable` interface. // You're choosing to use the newer Graphics2D class instead. public int print(Graphics graphicsOld, PageFormat pageFormat, int pageIndex) throws PrinterException { Graphics2D graphics = (Graphics2D) graphicsOld; // Here, your X and Y could be 0, but you're following what's set in `PageFormat` instead. Then you use its width and height to draw the image over the whole page. graphics.drawImage(image, (int) pageFormat.getImageableX(), (int) pageFormat.getImageableY(), (int) pageFormat.getWidth(), (int) pageFormat.getHeight(), null); return PAGE_EXISTS; } }
Now, let’s break down what’s shown above.
Java Printing
For printing in Java, you need to use PrinterJob
, together with either a Printable
or a Pageable
implementation:
public void printDocument() { PrinterJob printerJob = PrinterJob.getPrinterJob(); printerJob.setPrintable(...); }
As Printable
is an interface, you must implement it. To do so, first implement the print
method, like so:
private class ExamplePrintable implements Printable { public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) { return PAGE_EXISTS; } }
Inside it, you’ll be returning either PAGE_EXISTS
or NO_SUCH_PAGE
, depending on your document’s needs.
Next, inside the print
method, you’ll need to render whatever it is you want to print in some way:
private class ExamplePrintable implements Printable { public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) { graphics.drawImage(image, (int) pageFormat.getImageableX(), (int) pageFormat.getImageableY(), (int) pageFormat.getWidth(), (int) pageFormat.getHeight(), null); return PAGE_EXISTS; } ... }
The drawImage
method expects an Image
, which, in this case, is the PDF document. The next section will go over how you can get a page with PSPDFKit for rendering in the code above, but the general structure should be the same regardless of the document library or extraction method you choose.
Finally, you’re ready to call printerJob.print
in your original method:
public void printDocument() { PrinterJob printerJob = PrinterJob.getPrinterJob(); printerJob.setPrintable(new ExamplePrintable(image)); try { printerJob.print(); } catch (PrinterException prt) { prt.printStackTrace(); } }
This code will silently print the file as instructed by the Printable
implementation, which might not be the ideal solution if you want to notify your user that something is printing, give them the option to manually choose printers, etc.
For that, you can call in the default dialog:
if (printerJob.printDialog()) { try { printerJob.print(); } catch (PrinterException prt) { prt.printStackTrace(); } }
Note that if the printing method chosen is to save as a PDF, the printerJob.print
call will, by default, open the system’s file picker so the user can choose where to save the document, which is very handy.
PSPDFKit Library for Java
The previous section goes over printing an image, but you’ll also need to convert your PDF document into an appropriate format for the PrinterJob
to work. Here’s where PSPDFKit Library for Java can help you out!
First, you’ll need to open the document:
File file = new File("Assets/A.pdf"); PdfDocument document = PdfDocument.open(new FileDataProvider(file));
Here, you’ll use a File
, but you can check out our documentation for information on other ways you can provide your PDF to PdfDocument
.
Then, you need to get the pages you want to print through PdfDocument.getPage
. This method will give you a single PdfPage
at the chosen index, which you can then render through renderPage
:
PdfPage page = document.getPage(0);
BufferedImage image = page.renderPage();
This BufferedImage
can then be used inside your implemented Printable
from the last section, in your graphics.drawImage
call.
The default renderPage
method uses the height and width found in PdfPageInfo
. These might not be ideal, depending on your chosen paper size and resolution. As such, you can specify the desired height and width with the overload.
You can find the page size of the document through the PdfPageInfo
class. Then, depending on your desired paper size and pixels per inch, you might want to multiply that value:
PdfPageInfo pageInfo = page.getPageInfo(); Rect boundingBox = pageInfo.getBoundingBox(); int updatedWidth = (int) boundingBox.getWidth() * 10; int updatedHeight = (int) boundingBox.getHeight() * 10; BufferedImage image = page.renderPage(updatedWidth, updatedHeight);
These values will depend on both your needs and the document at hand. For example, the correct resolution for an A4 paper size at 300 PPI is 2480×3508. You can find many different tools to calculate these values online, such as this one.
Rendering Multiple Pages
For multiple pages (a whole document, for example), you’ll (basically) use the code detailed above for whichever pages you want to include. Java comes in handy here with the Book
class, which is a Pageable
that’s also accepted by PrinterJob
.
Each “page” on this Book
is a Printable
, and it can also have specific a PageFormat
. This means you have a great deal of control over how each page is presented:
PrinterJob printerJob = PrinterJob.getPrinterJob(); PageFormat pageFormat = printerJob.defaultPage(); Book printableBook = new Book(); for (int i = 0; i < document.getPageCount(); i++) { BufferedImage image = document.getPage(i).renderPage(); printableBook.append(new ExamplePrintable(image), pageFormat); } printerJob.setPageable(printableBook); try { printerJob.print(); } catch (PrinterException prt) { prt.printStackTrace(); }
Conclusion
In this blog post, we provided an overview of how you can easily integrate the robust Java printing API with PSPDFKit Library for Java. It should serve as a good example of how the Java SDK complements native Java functionality for operations involving PDFs. However, we’re always happy to help if anything remains unclear!