I have to print a PDF file using java application. I have tried such approach:
FileInputStream psStream = new FileInputStream("<path to file>");
PrintService service = getPrinterByName("some printer name");
if (service != null) {
DocPrintJob printJob = service.createPrintJob();
Doc document = new SimpleDoc(psStream, DocFlavor.INPUT_STREAM.AUTOSENSE, null);
try {
printJob.print(document, null);
} catch (PrintException e) {
e.printStackTrace();
}
}
private PrintService[] getPrintersList() {
DocFlavor flavor = DocFlavor.INPUT_STREAM.AUTOSENSE;
PrintService[] services = PrintServiceLookup.lookupPrintServices(flavor, null);
return services;
}
private PrintService getPrinterByName(String name) {
PrintService[] list = getPrintersList();
if (list.length > 0) {
for (PrintService service : list) {
if (service.getName().contains(name)) {
return service;
}
}
}
return null;
}
When I tested this on fake printer (I used PDFCreator as a printer) everything was OK, but when I tried to print on physical printer, nothing happend.
Then I used PDFBox. Document was printed, but with strange dots between words, in places where they should not be.
So, maybe someone have experience with printing PDF from java applications and can share this information?
Sending a PDF file directly to a printer will only work for printers that support the PDF format natively. This will be supported by any virtual PDF printer, but not by most of the hardware printers out-there. If you want to print a PDF file reliably, you need to use a library to render its content into the printer.
Take look then at this question in SO:
Which Java based PDF rendering library should I use for printing?
Update:
The link above is broken but there is no replacement for it other that doing a google search. Unfortunately stack-overflow owners decided that questions related to library recommendations are not welcome.
Related
I am trying to use a Zebra label printer using Java, and I'm having some issues:
I am trying the following code, which contains code taken from here: https://github.com/w3blogfr/zebra-zpl
public static void printZpl(String zpl, String printerName) throws ZebraPrintException {
try {
PrintService psZebra = null;
String sPrinterName = null;
PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null);
for (int i = 0; i < services.length; i++) {
PrintServiceAttribute attr = services[i].getAttribute(PrinterName.class);
sPrinterName = ((PrinterName) attr).getValue();
if (sPrinterName.toLowerCase().indexOf(printerName.toLowerCase()) >= 0) {
psZebra = services[i];
break;
}
}
if (psZebra == null) {
throw new ZebraPrintNotFoundException("Zebra printer not found : " + printerName);
}
DocPrintJob job = psZebra.createPrintJob();
byte[] by = zpl.getBytes();
DocFlavor flavor = DocFlavor.BYTE_ARRAY.AUTOSENSE;
Doc doc = new SimpleDoc(by, flavor, null);
job.print(doc, null);
} catch (PrintException e) {
throw new ZebraPrintException("Cannot print label on this printer : " + printerName, e);
}
}
The string I am trying to print is this one:
^XA
^MMT
^FT0,110^FH\^FDTestString^FS
^XZ
The problem is that although I am able to connect to the printer and print something, the output is printed as plain text, it's as if the printer does not recognize that a ZDL command has been given.
The printer is a Zebra ZD220, and I have connected it to my Mac as a generic label printer, and selected the Zebra ZDL as the software to use it with.
Is there something I miss?
Note that I have been able to do this using NodeJS (so I know that this is working) using node-printer, so I know that it should work, but with Java, I cannot seem to make the printer understand that I am giving ZPL commands to it, and it prints plain characters.
I got this working by creating a socket connection with ZPL printer and writing ZPL content to output stream. Refer https://github.com/khpraful/ZPLPrint/blob/master/src/ZebraPrinter.java for more details. I tried with locally installed ZPL print emulator.
I am Working on Pdfs to Excel conversion using docparser.
But docparser is unable to process scanned pdfs properly. So I need to seperate the scanned pdfs from normal pdfs and only want to process normal pdfs through docparser(i.e API call).
Is there exit some to way to identify the pdf type(Scanned or normal) programmatically so that I could work further?
Please help if anyone knows how to tackle this problem.....
Finally, I found a solution to my question.But not a standard one(I THINK SO). Thanks to the people who commented and provide some help.
Using Pdfbox library we can extract pages of scanned pdf and will compare each page to the instance of an image object(PDImageXObject),if it comes true , the page will be count as an image and we can count those images.If images are equal to number of pages in pdf. We will say it is a scanned pdf.
here is the code...
public static String testPdf(String filename) throws IOException
{
String s = "";
int g = 0;
int gg = 0;
PDDocument doc = PDDocument.load(new File(filename));
gg = doc.getNumberOfPages();
for(PDPage page:doc.getPages())
{
PDResources resource = page.getResources();
for(COSName xObjectName:resource.getXObjectNames())
{
PDXObject xObject = resource.getXObject(xObjectName);
if (xObject instanceof PDImageXObject)
{
((PDImageXObject) xObject).getImage();
g++;
}
}
}
doc.close();
if(g==gg) // pdf pages if equal to the images
{
return "Scanned pdf";
}
else
{
return "Searchable pdf";
}
}
I've created a report and exported it as a text file, to print in a matrix printer, however, the result of the job is a blank page. I did the same in ubuntu and it is printing correctly.
Is it a Java bug?
This is a example code I did to show you the problem:
public class PrintError extends Application {
public static void main(String args[]) {
launch(args);
}
public void start(Stage stage) throws PrintException {
PrinterJob printerJob = PrinterJob.createPrinterJob();
printerJob.showPrintDialog(stage);
PrintRequestAttributeSet printRequestAttributeSet = new HashPrintRequestAttributeSet();
printRequestAttributeSet.add(new Copies(printerJob.getJobSettings().getCopies()));
printRequestAttributeSet.add(new JobName("test", Locale.getDefault()));
DocFlavor flavor = DocFlavor.INPUT_STREAM.AUTOSENSE;
Doc mydoc = new SimpleDoc(ClassLoader.class.getResourceAsStream("/should-be-printed.txt"), flavor, null);
DocPrintJob job = getPrintService(printerJob.getPrinter().getName()).createPrintJob();
job.print(mydoc, printRequestAttributeSet);
}
private PrintService getPrintService(String name) {
for (PrintService printService : java.awt.print.PrinterJob.lookupPrintServices()) {
if (name.equalsIgnoreCase(printService.getName())) {
return printService;
}
}
return null;
}
}
This example was created in JavaFx 8 and is running in Java build 1.8.0-b132 in Windows 7.
I've also created a simple project at github
From the documentation:
Recommended DocFlavors
The Java Print Service API does not define any mandatorily supported DocFlavors. …
When you have a PrintService instance, you can use the method getSupportedDocFlavors() to find out which flavors it supports.
When you find out that none of the DocFlavor. INPUT_STREAM. TEXT_PLAIN_… flavors is in the list, it doesn’t help to use AUTOSENSE as that simply means “best guess” and it’s unlikely that a PrintService will guess a type it doesn’t support, instead, it’s more likely that the data will be misinterpreted as one of the formats it supports.
On my Windows machine, none of the provided PrintServices supports printing plaintext…
If anyone else comes across a similar problem (Printing blank in Windows 7 but working in Windows 10 in my case), but the DocFlavor is set correctly (i.e. One supported by a chosen print service)...
I was able to solve my issue by updating the JRE from 32-bit 8u101 to 64-bit 8u121.
Here i have coded to get a list of devices and i will check each devices status
DocFlavor myFormat = DocFlavor.SERVICE_FORMATTED.PRINTABLE;
PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
PrintService[] services =PrintServiceLookup.lookupPrintServices(myFormat, aset);
System.out.println("The following printers are available");
for (int i=0;i<services.length;i++) {
PrintService printService = services[i];
PrintServiceAttributeSet printServiceAttributes = printService.getAttributes();
PrinterState printerState =
(PrinterState)printServiceAttributes.get(PrinterState.class);
if (printerState != null){
System.out.println(services[i].getName() + " is online");
} else {
System.out.println(services[i].getName() + " is offline");
}
}
But the problem is each and every time i got a status "Offline" even that printer is Switched on or Switched off
I recently had the same problem getting another attribute from a PrintService.
In fact, it always returns null because the method has never been implemented in the Java class, and that's the case for a lot of attributes.
If you really want to get these information, you will have to use the windows Print Spooler DLL or, if your printer is a net printer, query these informations via SNMP.
I am using Fedex ship web service to create a shipment. I am using a thermal printer to print the label (Java).
First I wanted to know what should be STOCKTYPE for printing to ZLPII printer, second question follows below.
When printing to the printer and empty label comes out but nothing print, when I use to print to PDF it works very well.
This is my Java code
PrintService pss[] = PrintServiceLookup.lookupPrintServices(DocFlavor.INPUT_STREAM.AUTOSENSE, null);
if (pss.length == 0)
System.out.println("FedExSmartPostServiceImpl::saveLabelToFile No printer services available.");
PrintService ps = null;
for (PrintService ps1 : pss) {
if (ps1.getName().indexOf("Zebra") >= 0) {
ps = ps1;
break;
}
}
System.out.println("FedExSmartPostServiceImpl::saveLabelToFile Printing to " + ps);
DocPrintJob job = ps.createPrintJob();
Doc doc = new SimpleDoc(fis, DocFlavor.INPUT_STREAM.AUTOSENSE, null);
job.print(doc, null);
fis.close();
Thanks for the help in advance.
I could able to print the label with almost same code as above, with slight change of changing the SimpleDoc as below rather using the FileInputStream.
Doc doc = new SimpleDoc(byteArr, DocFlavor.BYTE_ARRAY.AUTOSENSE, null);
Hope this helps.