PDF PrinterJob get Job status

2.4k views Asked by At

I have an issue to print a PDF using java. I know that Java doesn't support print PDF natively cause java doesn't have a PDF renderer. So to solve this problem I'm using a PDFRenderer library and here is an example for printing with it:

 File f = new File("myfile.pdf");
 FileInputStream fis = new FileInputStream(f);
 FileChannel fc = fis.getChannel();
 ByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0,
 fc.size());
 PDFFile pdfFile = new PDFFile(bb); 
 PDFPrintPage pages = new PDFPrintPage(pdfFile);
 PrinterJob pjob = PrinterJob.getPrinterJob();
 PageFormat pf = PrinterJob.getPrinterJob().defaultPage();
 pjob.setJobName(f.getName());
 pjob.setPrintService(mPrintService);
 Book book = new Book();
 book.append(pages, pf, pdfFile.getNumPages());
 pjob.setPageable(book);
 pjob.print();

It works fine, but I need some way to get status of my printer job. I need to know when my printer job was finished that I can start another. Java API has a good solution with DocPrintJob and PrintJobListener but I need to use PrinterJob for my PDF printing. So how I can listen the job status from my PrinterJob like it does in DocPrintJob?

2

There are 2 answers

2
Shankar On BEST ANSWER
javafx.print
Enum PrinterJob.JobStatus

java.lang.Object
java.lang.Enum<PrinterJob.JobStatus>
javafx.print.PrinterJob.JobStatus


public static PrinterJob.JobStatus[] values()
Returns an array containing the constants of this enum type, in the order they are declared. This method may be used to iterate over the constants as follows:
for (PrinterJob.JobStatus c : PrinterJob.JobStatus.values())
    System.out.println(c);
0
Michael Sims On

For anyone dealing with this problem here in 2020, I found a pretty slick way of printing PDF files while being able to monitor the print job, without using JavaFX - as people don't seem to be too hip on using JavaFX for printing PDF files, and I'm not to keen on object node printing, as it is really diffiult to get the print out to look like a normal document in my opinion ... JavaFX seems to like the idea of - basically - screen shotting a portion of your form, then rendering that snap shot as a graphic, then you have to scale it for the printer and it just ends up looking kinda weird ... whereas taking something like nicely formatted HTML, and printing it through a PDF library is really clean, and really fast. So here is what I found:

First, I used this library, which is free, to render my HTML String into a PDF file. Here is the Maven source for the library:

<dependency>
    <groupId>org.icepdf.os</groupId>
    <artifactId>icepdf-core</artifactId>
    <version>6.2.2</version>
</dependency>

And here is my code for rendering the PDF:

        String docPath = "/Users/michael/Documents/JavaFile.pdf";
        String html = "<html>Any HTML Code you want, including embedded CSS for a really clean look</html>
        OutputStream outputStream = new FileOutputStream(docPath);
        ITextRenderer renderer = new ITextRenderer();
        renderer.setDocumentFromString(html);
        renderer.layout();
        renderer.createPDF(outputStream);
        outputStream.close();

And here is my class for printing the PDF ... its a little lengthy, but VERY simple, and it uses native Java API which is nice (i'm using 1.8):

import javafx.application.Platform;
import javafx.scene.control.Label;
import java.io.*;
import javax.print.*;
import javax.print.event.PrintJobAdapter;
import javax.print.event.PrintJobEvent;

public class PrintHandler {

    private void delay(int msec) {
        try {
            Thread.sleep(msec);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public PrintHandler (FileInputStream fis, Label statusLabel) {
        this.statusLabel = statusLabel;
        this.fis = fis;
    }
    private FileInputStream fis;
    private Label statusLabel;
    private String state;

    public void startPrintJob () {
        try {
            Platform.runLater(()->statusLabel.setText("PRINTING"));
            delay(5000);
            InputStream is = new BufferedInputStream(this.fis);
            DocFlavor flavor = DocFlavor.INPUT_STREAM.PDF;
            PrintService service = PrintServiceLookup.lookupDefaultPrintService();
            DocPrintJob printJob = service.createPrintJob();
            JobMonitor monitor = new JobMonitor();
            printJob.addPrintJobListener(monitor);
            Doc doc = new SimpleDoc(is, flavor, null);
            printJob.print(doc, null);
            monitor.waitForJobCompletion();
            is.close();
        } catch (PrintException | IOException e) {
            e.printStackTrace();
        }
    }

    private class JobMonitor extends PrintJobAdapter {
        private boolean notify = false;
        final int DATA_TRANSFERRED      = 10;
        final int JOB_COMPLETE          = 11;
        final int JOB_FAILED            = 12;
        final int JOB_CANCELED          = 13;
        final int JOB_NO_MORE_EVENTS    = 14;
        final int JOB_NEEDS_ATTENTION   = 15;

        private int status;
        @Override
        public void printDataTransferCompleted(PrintJobEvent pje) {
            status = DATA_TRANSFERRED;
            markAction();
        }
        @Override
        public void printJobCompleted(PrintJobEvent pje) {
            status = JOB_COMPLETE;
            markAction();
        }
        @Override
        public void printJobFailed(PrintJobEvent pje) {
            status = JOB_FAILED;
            markAction();
        }
        @Override
        public void printJobCanceled(PrintJobEvent pje) {
            status = JOB_CANCELED;
            markAction();
        }
        @Override
        public void printJobNoMoreEvents(PrintJobEvent pje) {
            status = JOB_NO_MORE_EVENTS;
            markAction();
        }
        @Override
        public void printJobRequiresAttention(PrintJobEvent pje) {
            status = JOB_NEEDS_ATTENTION;
            markAction();
        }
        private void markAction() {
            synchronized (JobMonitor.this) {
                notify = true;
                JobMonitor.this.notify();
            }
        }
        public synchronized void waitForJobCompletion() {
            Runnable runner = ()->{
                boolean keepRunning = true;
                while (keepRunning) {
                    try {
                        while (!notify) {
                            wait();
                        }
                        switch(this.status){
                            case DATA_TRANSFERRED:
                                state = "DATA_TRANSFERRED";
                                break;
                            case JOB_COMPLETE:
                                state = "JOB_FINISHED";
                                keepRunning = false;
                                break;
                            case JOB_FAILED:
                                state = "JOB_FAILED";
                                keepRunning = false;
                                break;
                            case JOB_CANCELED:
                                state = "JOB_CANCELED";
                                keepRunning = false;
                                break;
                            case JOB_NO_MORE_EVENTS:
                                state = "JOB_COMPLETE";
                                keepRunning = false;
                                break;
                            case JOB_NEEDS_ATTENTION:
                                state = "JOB_NEEDS_ATTENTION";
                                break;

                        }
                        Platform.runLater(()->statusLabel.setText(state));
                        delay(5000);
                        notify = false;
                    }
                    catch (InterruptedException e) {}
                }
                delay(5000);
                Platform.runLater(()->statusLabel.setText(""));
            };
            Thread monitor = new Thread(runner);
            monitor.start();
        }
    }
}

And here is how I invoke the class to print and monitor the job:

FileInputStream fis = new FileInputStream(docPath);
Label jobStatus = new Label(); //Already in my AnchorPane but included here for clarity
new PrintHandler(fis,jobStatus).startPrintJob();