iText 直接打印

iText direct Printing

我正在使用 iText 生成 pdf 并将其写入文件系统,如下所示:

private void createPDF() throws Exception{
    com.itextpdf.text.Document doc = new com.itextpdf.text.Document();
    PdfWriter docWriter = null;
    path = "C:\PATH\TO\Desktop\EXAMPLE_FOLDER\" + pdfFilename;
    docWriter = PdfWriter.getInstance(doc, new FileOutputStream(path));
    doc.addTitle("Invoice");
    doc.setPageSize(PageSize.A4);
    doc.open();
    PdfContentByte cb = docWriter.getDirectContent();
    fillPDFDetails(cb);
    if (doc != null) {
        doc.close();
    }
    if (docWriter != null) {
        docWriter.close();
    }
}

但是,我想将 pdf 发送到打印机并打印 pdf 文件,而不是将其写入文件系统。我怎样才能做到这一点?

这个问题有理论和实践的答案。

让我们从理论上的答案开始。有一个名为 PrintStream 的 Java class 允许您将 OutputStream 发送到打印机:

Printstream extends FilterOutputStream extends OutputStream

A PrintStream adds functionality to another output stream, namely the ability to print representations of various data values conveniently. Two other features are provided as well. Unlike other output streams, a PrintStream never throws an IOException; instead, exceptional situations merely set an internal flag that can be tested via the checkError method. Optionally, a PrintStream can be created so as to flush automatically; this means that the flush method is automatically invoked after a byte array is written, one of the println methods is invoked, or a newline character or byte ('\n') is written.

所以,假设您想在内存中创建一个 PDF 并将其写入打印机,您可以这样做:

ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(baos);
Document document = new Document();
PdfWriter.getInstance(document, ps);
document.open();
// add content
document.close();

由于 PrintStream 扩展了 OutputStream 并且 PdfWriter 接受任何类型的 OutputStream,您正在将 PDF 字节写入打印机,如果您想要 PDF 字节, 你可以做 baos.toByteArray().

但是,上面的代码片段将 PDF 字节发送到打印机。很可能您的打印机不理解 PDF,只是打印出如下内容:

PDF-1.4
%âãÏÓ
2 0 obj
<</Length 64/Filter/FlateDecode>>stream
*binary stuff*
endstream
endobj
4 0 obj
<</Parent 3 0 R/Contents 2 0 R/Type/Page/Resources<</Font<</F1 1 0 R>>>>
/MediaBox[0 0 595 842]>>
endobj
1 0 obj
<</BaseFont/Helvetica/Type/Font/Encoding/WinAnsiEncoding/Subtype/Type1>>
endobj
3 0 obj
<</Type/Pages/Count 1/Kids[4 0 R]>>
endobj
5 0 obj
<</Type/Catalog/Pages 3 0 R>>
endobj
6 0 obj
<</Producer(iText® 5.4.2 ©2000-2012 1T3XT BVBA \(AGPL-version\))
/ModDate(D:20130502165150+02'00')/CreationDate(D:20130502165150+02'00')>>
endobj
xref
0 7
0000000000 65535 f 
0000000302 00000 n 
0000000015 00000 n 
0000000390 00000 n 
0000000145 00000 n 
0000000441 00000 n 
0000000486 00000 n 
trailer
<</Root 5 0 R/ID [<91bee3a87061eb2834fb6a3258bf817e><91bee3a87061eb2834fb6a3258bf817e>]
/Info 6 0 R/Size 7>>
%iText-5.4.2
startxref
639
%%EOF

更新:

在评论中,添加了以下link:https://blog.idrsolutions.com/2010/01/printing-pdf-files-from-java/

这实际上是打印文件的更好方法:

FileInputStream fis = new FileInputStream(“C:/mypdf.pdf”);
Doc pdfDoc = new SimpleDoc(fis, null, null);
DocPrintJob printJob = printService.createPrintJob();
printJob.print(pdfDoc, new HashPrintRequestAttributeSet());
fis.close();

如果您不想使用 FileInputStream,您始终可以将 PDF 创建为 ByteArrayOutputStream,然后使用生成的 byte[] 创建 ByteArrayInputStream .

这就是实际答案:在内存中创建 PDF 并不难。这样做是这样的:

ByteArrayOutputStream baos = new ByteArrayOutputStream();
Document document = new Document();
PdfWriter.getInstance(document, baos);
document.open();
// add content
document.close();
byte[] pdf = baos.toByteArray();

问题是:你打算用 pdf 做什么?

要么您的打印机理解这些字节(有些打印机接受 PDF 语法),要么您必须找到将 PDF 转换为打印机理解的格式的软件。通常,人们使用 PDF 渲染软件(例如 Adob​​e Reader)来打印文档。其中许多查看器(Adobe Reader 是其中之一)要求文件作为文件存在:Adobe Reader 不接受字节数组。

这解释了为什么实际答案不如理论答案那么简单:在实践中,您的问题远非微不足道:它取决于打印机(它接受哪些格式)和 PDF 查看器(您应该需要一个)。

试试这个:

filename = "aaaaaaa.pdf";
java.io.File fileout =  new File(filename);
com.lowagie.tools.Executable.printDocumentSilent(fileout));
 fileout.delete();  // if you don't want to keep it.    

使用 APACHE PDFBox (1.x): https://pdfbox.apache.org

完整代码:https://github.com/marcolopes/dma/blob/master/org.dma.java/src/org/dma/java/awt/PrinterHandler.java

import java.awt.print.PrinterAbortException;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.File;
import java.io.IOException;

import javax.print.PrintException;
import javax.print.PrintService;

import org.apache.pdfbox.pdmodel.PDDocument;

public class PrinterHandler {

    public static PrintService lookupPrintService(String printerName) {
        for(PrintService ps: PrinterJob.lookupPrintServices()) {
            if (ps.getName().indexOf(printerName)>=0) return ps;
        }return null;
    }

    private final PrintService service;

    private final String printerName;

    public PrinterHandler(String printerName) {
        this.printerName=printerName;
        this.service=lookupPrintService(printerName);
    }


    public void checkPrinter() throws PrinterException {
        if (service==null) throw new PrinterException("Invalid printer "+printerName);
    }


    public PrinterJob createPrinterJob() throws PrinterException {

        checkPrinter();

        PrinterJob job=PrinterJob.getPrinterJob();
        job.setPrintService(service);
        return job;

    }


    /** Prints a PDF using apache pdfbox */
    public void printPdf(File file) throws PrinterException, PrintException {

        PrinterJob job=createPrinterJob();

        if (file!=null) try{

            job.setJobName(file.getName());

            PDDocument doc=PDDocument.load(file);

            try{doc.silentPrint(job);
            }catch(PrinterAbortException e){
                 //avoid abort exception
            }catch(PrinterException e){
                throw new PrinterException("Error while printing");
            }finally{
                doc.close();
            }

        }catch(IOException e){
            throw new PrintException("Error loading file "+file);
        }

    }

}