Blog Post

Printing a PDF with Java

Illustration: 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!

Related Products
Share Post
Free 60-Day Trial Try PSPDFKit in your app today.
Free Trial

Related Articles

Explore more
RELEASES  |  Android • Development • Products

PSPDFKit 8 for Android Adds Electronic Signatures and Jetpack Compose

BLOG  |  Android • Development • Jetpack Compose • UI

Introducing Jetpack Compose Support

DEVELOPMENT  |  Web • Development • JavaScript

Practical Uses of Object URLs