PDF PrinterJob получить статус работы
У меня есть проблема для печати PDF с использованием Java. Я знаю, что Java не поддерживает печать PDF изначально, потому что у Java нет PDF рендера. Поэтому, чтобы решить эту проблему, я использую библиотеку PDFRenderer, и вот пример для печати с ней:
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();
Это работает нормально, но мне нужен какой-то способ получить статус моей работы с принтером. Мне нужно знать, когда работа моего принтера была закончена, чтобы я мог начать другую. Java API имеет хорошее решение с DocPrintJob и PrintJobListener, но мне нужно использовать PrinterJob для моей печати PDF. Итак, как я могу прослушивать статус задания из моего PrinterJob, как это происходит в DocPrintJob?
1 ответ
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);
Для тех, кто сталкивается с этой проблемой здесь, в 2020 году, я нашел довольно удобный способ печати файлов PDF, при этом имея возможность контролировать задание печати без использования JavaFX - поскольку люди, похоже, не слишком модно используют JavaFX для печати файлов PDF., и я не в восторге от печати узла объекта, так как, на мой взгляд, очень сложно заставить распечатку выглядеть как обычный документ... JavaFX, похоже, нравится идея - в основном - снимка экрана части ваша форма, затем визуализируйте этот снимок как графику, затем вам нужно масштабировать его для принтера, и он просто выглядит странно... тогда как взять что-то вроде красиво отформатированного HTML и распечатать его через библиотеку PDF действительно чисто, и очень быстро. Итак, вот что я нашел:
Во-первых, я использовал эту бесплатную библиотеку для преобразования моей строки HTML в файл PDF. Вот исходный код библиотеки Maven:
<dependency>
<groupId>org.icepdf.os</groupId>
<artifactId>icepdf-core</artifactId>
<version>6.2.2</version>
</dependency>
А вот мой код для рендеринга 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();
И вот мой класс для печати PDF ... он немного длинный, но ОЧЕНЬ простой, и он использует собственный Java API, который хорош (я использую 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();
}
}
}
А вот как я вызываю класс для печати и отслеживания задания:
FileInputStream fis = new FileInputStream(docPath);
Label jobStatus = new Label(); //Already in my AnchorPane but included here for clarity
new PrintHandler(fis,jobStatus).startPrintJob();