Is there any way in Java to print to a specific IPP printer? All of the sample code and tutorials I've found focus on how to print a particular type of document, using something like the following:
DocFlavor flavor = DocFlavor.INPUT_STREAM.POSTSCRIPT;
PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
aset.add(MediaSizeName.ISO_A4);
PrintService[] pservices =
PrintServiceLookup.lookupPrintServices(flavor, aset);
if (pservices.length > 0) {
DocPrintJob pj = pservices[0].createPrintJob();
try {
FileInputStream fis = new FileInputStream("test.ps");
Doc doc = new SimpleDoc(fis, flavor, null);
pj.print(doc, aset);
} catch (FileNotFoundException fe) {
} catch (PrintException e) {
}
}
This snippet simply prints to the first printer found that is capable of printing the document. In my case, I want to lookup a printer by its URI, but PrintServiceLookup
doesn't seem to support this. I've tried using a PrintServiceAttributeSet
, instead of PrintRequestAttributeSet
, and adding a PrinterURI
attribute, but that doesn't return any printers. I suspect the lookup service is looking for a printer that can change its destination URI, rather than looking for the printer with that URI.
As a last resort, I thought about just enumerating through all of the PrintService
s returned by lookupPrintServices
, but the URI is not in any of the attributes. The printer name is there, but I need the URI.
For background, my webapp needs to print a barcode to a specific printer, based on the current user. Each user is associated with a printer URI, which points to a printer on a CUPS server. The printer URI is the only information I have, and I can't constrain the printer name to match the URI or a substring of the URI.
Edit: To clarify a bit, I don't need to render the data, I just need to copy a blob to a given printer. The part I can't figure out is how to identify a printer by its IPP URI.
Select [Connect to a printer on the Internet or on a home or office network]. Enter [URL]. Enter "http://<the IP address or name of the printer>/ipp." When you want to perform IPPS printing using SSL encrypted communication, enter "https://<the IP address or name of the printer>/ipp."
Setting flow IPP printing uses the Internet Printing Protocol (IPP) and prints information via the network. IPP that is extended HTTP is used to forward printing data, enabling you to print data on a printer on a distance location via the Internet.
This single-valued attribute specifies the Uniform Resource Identifier (URI) of the remote Internet Printing Protocol (IPP) server that is running either in a printer or host system. This attribute is required if you create a printer definition and protocol-type=ipp.
IPP stands for Internet Printing Protocol... It allows programs to send one or more print jobs to the printer or print server and perform administration such as querying the status of a printer, obtaining the status of print jobs, or cancelling individual print jobs.
I finally found a way to do this, by using jipsi
:
URI printerURI = new URI("ipp://SERVER:631/printers/PRINTER_NAME");
IppPrintService svc = new IppPrintService(printerURI);
InputStream stream = new BufferedInputStream(new FileInputStream("image.epl"));
DocFlavor flavor = DocFlavor.INPUT_STREAM.AUTOSENSE;
Doc myDoc = new SimpleDoc(stream, flavor, null);
DocPrintJob job = svc.createPrintJob();
job.print(myDoc, null);
I have to admit I'm disappointed at having to use a 3rd-party library to do something so seemingly simple as printing to a specific printer.
UPDATE
DR points out in the comments that jipsi has a new home, and a new name.
Cups4J is a nice alternative, but as the name implies it may not work correctly if the destination is not a CUPS server. I have had good results using Cups4J to print directly to a Zebra thermal printer.
I do not think you can get a printer the way you would like to (I think the Java Print mechanism predates IPP).
You may, however, if I recall correctly be able to render your print job locally and then ship the bytes of the output stream to the target CUPS server "by hand". Would this be "good enough" for you?
To only submit a printable document format like PDF via IPP to a printer (or to CUPS) this code provides a minimalistic implementation without dependencies. ipp-printjob-java has basic support for decoding the ipp response.
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
public class IppPrintJob {
public static void main(String args[]) throws Exception {
URI printerURI = URI.create("http://colorjet:631/ipp/printer");
File file = new File("A4-blank.pdf");
short status = new IppPrintJob()
.printDocument(printerURI, new FileInputStream(file));
System.out.println(String.format("ipp status: %04X", status));
}
short printDocument(
URI uri, InputStream documentInputStream
) throws IOException {
HttpURLConnection httpURLConnection =
(HttpURLConnection) uri.toURL().openConnection();
httpURLConnection.setDoOutput(true);
httpURLConnection.setRequestProperty("Content-Type", "application/ipp");
OutputStream outputStream = httpURLConnection.getOutputStream();
DataOutputStream dataOutputStream =
new DataOutputStream(httpURLConnection.getOutputStream());
dataOutputStream.writeShort(0x0101); // ipp version
dataOutputStream.writeShort(0x0002); // print job operation
dataOutputStream.writeInt(0x002A); // request id
dataOutputStream.writeByte(0x01); // operation group tag
writeAttribute(dataOutputStream, 0x47, "attributes-charset", "utf-8");
writeAttribute(dataOutputStream, 0x48, "attributes-natural-language", "en");
writeAttribute(dataOutputStream, 0x45, "printer-uri", uri.toString());
dataOutputStream.writeByte(0x03); // end tag
documentInputStream.transferTo(outputStream);
dataOutputStream.close();
outputStream.close();
if (httpURLConnection.getResponseCode() == 200) {
DataInputStream dataInputStream =
new DataInputStream(httpURLConnection.getInputStream());
System.out.println(String.format("ipp version %d.%s",
dataInputStream.readByte(), dataInputStream.readByte()
));
return dataInputStream.readShort();
} else {
throw new IOException(String.format("post to %s failed with http status %d",
uri, httpURLConnection.getResponseCode()
));
}
}
void writeAttribute(
DataOutputStream dataOutputStream, int tag, String name, String value
) throws IOException
{
Charset charset = StandardCharsets.UTF_8;
dataOutputStream.writeByte(tag);
dataOutputStream.writeShort(name.length());
dataOutputStream.write(name.getBytes(charset));
dataOutputStream.writeShort(value.length());
dataOutputStream.write(value.getBytes(charset));
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With