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 渲染软件(例如 Adobe 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);
}
}
}
我正在使用 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
extendsFilterOutputStream
extendsOutputStream
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, aPrintStream
never throws anIOException
; instead, exceptional situations merely set an internal flag that can be tested via thecheckError
method. Optionally, aPrintStream
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 渲染软件(例如 Adobe 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);
}
}
}