I am trying to create a simple program that sends a string to a printer to print. This is what my program looks like:
import javax.print.Doc;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintException;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.SimpleDoc;
public class PrinterTest {
public static void main (String [] args) throws PrintException {
DocPrintJob job = null;
PrintService[] printServices =
PrintServiceLookup.lookupPrintServices(null, null);
System.out.println("Number of print services: " + printServices.length);
for (PrintService printer : printServices) {
System.out.println("Printer: " + printer.getName());
if (printer.getName().contains("ZM400")) {
String hello = "Hello";
DocFlavor flavor = DocFlavor.STRING.TEXT_PLAIN;
Doc doc = new SimpleDoc(hello, flavor, null);
job = printer.createPrintJob();
job.print(doc, null);
}
}
}
}
I export this as a jar file and run it on command line (Windows) using:
java -jar PrinterTest.jar
The program runs, and starts looping through all of the installed printers on the computer. But when it gets to the printer I am looking for, I then get the following error:
Exception in thread "main" sun.print.PrintJobFlavorException: invalid flavor
at sun.print.Win32PrintJob.print(Unknown Source)
at PrinterTest.main(PrinterTest.java:21)
Not really sure what I'm doing wrong here, as the printer that I am searching for does in fact show up.
-Using the following link for reference: http://docs.oracle.com/javase/7/docs/technotes/guides/jps/spec/jpsOverview.fm4.html
-Tried changing DocFlavor flavor = DocFlavor.STRING.TEXT_PLAIN
to DocFlavor flavor = DocFlavor.INPUT_STREAM.AUTOSENSE
, but I get the error IllegalArgumentException: data is not of declared type
.
-Tried changing Doc doc = new SimpleDoc(hello, flavor, null)
to Doc doc = new SimpleDoc(hello, null, null)
, but it seems like you need to add a flavor there.
-Tried changing the printer, as the original printer I was trying to call was a labeling printer, but that did not make a difference.
Any idea what I'm doing wrong here? What can I do to fix this code and make it print?
UPDATE
I got this to (somewhat) work. This is what I have so far:
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import javax.print.Doc;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintException;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.SimpleDoc;
public class PrinterTest {
public static void main (String [] args) throws PrintException, IOException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
System.out.print("Enter the name of the printer: ");
String printerName = bufferedReader.readLine();
System.out.print("Enter a short message of what you would like to print here: ");
String printerMessage = "PRINTER MESSAGE: " + bufferedReader.readLine();
boolean printerCheck = false;
DocPrintJob job = null;
PrintService[] printServices = PrintServiceLookup.lookupPrintServices(null, null);
System.out.println("Number of print services: " + printServices.length);
for (PrintService printer : printServices) {
System.out.println("Printer: " + printer.getName());
if (printer.getName().contains(printerName)) {
InputStream inputStream = new ByteArrayInputStream(printerMessage.getBytes());
DocFlavor flavor = DocFlavor.INPUT_STREAM.AUTOSENSE;
Doc doc = new SimpleDoc(inputStream, flavor, null);
job = printer.createPrintJob();
job.print(doc, null);
printerCheck = true;
}
}
if (printerCheck == false) {
System.out.println("The printer you were searching for could not be found.");
}
}
}
What I did was put the string into an input stream, and changed DocFlavor.STRING.TEXT_PLAIN
to DocFlavor.INPUT_STREAM.AUTOSENSE
.
My only hiccup now is that nothing actually prints unless something else is sent to the printer. Leaving this here for now for reference.
The exception messages are rather helpful and should help you to find a solution.
1) First, this flavor is not supported by your printer :
DocFlavor.STRING.TEXT_PLAIN;
This exception says it :
Exception in thread "main" sun.print.PrintJobFlavorException: invalid flavor
If you look in the source code of this constant value, you can see that it is declared as :
public static final STRING TEXT_PLAIN =
new STRING ("text/plain; charset=utf-16");
So, the first thing you should do is checking which flavors are supported by your printer.
To render it, change the actual code :
if (printer.getName().contains("ZM400")) {
String hello = "Hello";
DocFlavor flavor = DocFlavor.STRING.TEXT_PLAIN;
Doc doc = new SimpleDoc(hello, flavor, null);
job = printer.createPrintJob();
job.print(doc, null);
}
by :
if (printer.getName().contains("ZM400")) {
Arrays.stream(printer.getSupportedDocFlavors()).forEach(f->System.out.println(f.getMediaType() + ":" + f.getMimeType() + ":" + f.getRepresentationClassName()));
String hello = "Hello";
DocFlavor flavor = DocFlavor.STRING.TEXT_PLAIN;
Doc doc = new SimpleDoc(hello, flavor, null);
job = printer.createPrintJob();
job.print(doc, null);
}
With my printer, it produces the following output :
image:image/gif:[B image:image/gif:java.io.InputStream
image:image/gif:java.net.URL image:image/jpeg:[B
image:image/jpeg:java.io.InputStream image:image/jpeg:java.net.URL
image:image/png:[B image:image/png:java.io.InputStream
image:image/png:java.net.URL
application:application/x-java-jvm-local-objectref:java.awt.print.Pageable
application:application/x-java-jvm-local-objectref:java.awt.print.Printable
application:application/octet-stream:[B
application:application/octet-stream:java.net.URL
application:application/octet-stream:java.io.InputStream
You may notice the my printer doesn't support the
"text/plain; charset=utf-16"
flavor either.
2) By changing the flavor to DocFlavor.INPUT_STREAM.AUTOSENSE
, you don't have any longer the exception related to missing support for the DocFlavor
.
So it means that DocFlavor.INPUT_STREAM.AUTOSENSE
is supported by your printer.
But you encounter another problem as the data to print doesn't match to declared type associated to DocFlavor.INPUT_STREAM.AUTOSENSE
:
IllegalArgumentException: data is not of declared type.
In DocFlavor
, the INPUT_STREAM.AUTOSENSE
constant is declared in this way :
public static final INPUT_STREAM AUTOSENSE =
new INPUT_STREAM ("application/octet-stream");
This corresponds to the last supported flavor in the previous output :
application:application/octet-stream:java.io.InputStream
And the problem is there :
String hello = "Hello";
...
Doc doc = new SimpleDoc(hello, flavor, null);
you don't have pass a InputStream
but a String
.
You can for example provide an InputStream
in this way:
String hello = "Hello";
DocFlavor flavor = DocFlavor.INPUT_STREAM.AUTOSENSE;
Doc doc = new SimpleDoc(new ByteArrayInputStream(hello.getBytes()),
flavor, null);
Or you could also use this flavor :
application:application/octet-stream:[B
as you have not an InputStream
but a String
as input :
Here is the flavor constant to use :
DocFlavor.BYTE_ARRAY.AUTOSENSE
You could also use it in this way :
String hello = "Hello";
DocFlavor flavor = DocFlavor.BYTE_ARRAY.AUTOSENSE;
Doc doc = new SimpleDoc(hello.getBytes(), flavor, null);