Печать на определенный принтер (IPP URI) в Java
Есть ли способ в Java для печати на определенный принтер IPP? Все примеры кода и учебники, которые я нашел, фокусируются на том, как напечатать документ определенного типа, используя что-то вроде следующего:
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) {
}
}
Этот фрагмент просто печатает на первом найденном принтере, который способен печатать документ. В моем случае я хочу найти принтер по его URI, но PrintServiceLookup
кажется, не поддерживает это. Я пытался использовать PrintServiceAttributeSet
, вместо PrintRequestAttributeSet
и добавив PrinterURI
атрибут, но это не возвращает никаких принтеров. Я подозреваю, что служба поиска ищет принтер, который может изменить свой URI назначения, вместо того, чтобы искать принтер с этим URI.
В крайнем случае я подумал о том, чтобы просто перечислить все PrintService
с возвращено lookupPrintServices
, но URI отсутствует ни в одном из атрибутов. Имя принтера там, но мне нужен URI.
В качестве фона моему веб-приложению необходимо распечатать штрих-код на определенном принтере в зависимости от текущего пользователя. Каждый пользователь связан с URI принтера, который указывает на принтер на сервере CUPS. URI принтера - единственная информация, которую я имею, и я не могу ограничить имя принтера, чтобы оно совпадало с URI или подстрокой URI.
Изменить: Чтобы уточнить немного, мне не нужно визуализировать данные, мне просто нужно скопировать BLOB-объект на данный принтер. Часть, которую я не могу понять, это как идентифицировать принтер по IP-адресу URI.
4 ответа
Я наконец нашел способ сделать это, используя 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);
Я должен признать, что разочарован тем, что мне пришлось использовать стороннюю библиотеку, чтобы сделать что-то настолько простое, как печать на конкретном принтере.
ОБНОВИТЬ
DR отмечает в комментариях, что у jipsi есть новый дом и новое имя.
Cups4J - хорошая альтернатива, но, как следует из названия, она может работать некорректно, если местом назначения не является сервер CUPS. У меня были хорошие результаты при использовании Cups4J для печати напрямую на термопринтер Zebra.
Чтобы отправить только печатный формат документа, такой как PDF, через IPP на принтер (или в CUPS), этот код обеспечивает минималистичную реализацию без зависимостей. ipp-printjob-java базовая поддержка для декодирования ответа ipp.
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));
}
}
Я не думаю, что вы можете получить принтер так, как вы хотели бы (я думаю, что механизм Java Print предшествует IPP).
Однако вы можете, если я правильно помню, иметь возможность визуализировать ваше задание на печать локально, а затем пересылать байты выходного потока на целевой сервер CUPS "вручную". Будет ли это "достаточно хорошо" для вас?
Используя этот ipp-клиент, вы можете отправить файл PDF на принтер (или CUPS), который поддерживает этот формат документа:
new IppPrinter(URI.create("ipp://myprinter")).printJob(
File("mydocument.pdf"), documentFormat("application/pdf")
);