简体   繁体   English

在 Java 中打印到特定打印机(IPP URI)

[英]Print to specific printer (IPP URI) in Java

Is there any way in Java to print to a specific IPP printer? Java中有什么方法可以打印到特定的IPP打印机吗? 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.就我而言,我想通过其 URI 查找打印机,但PrintServiceLookup似乎不支持这一点。 I've tried using a PrintServiceAttributeSet , instead of PrintRequestAttributeSet , and adding a PrinterURI attribute, but that doesn't return any printers.我尝试使用PrintServiceAttributeSet而不是PrintRequestAttributeSet并添加PrinterURI属性,但这不会返回任何打印机。 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.我怀疑查找服务正在寻找可以更改其目标 URI 的打印机,而不是寻找具有该 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.作为最后的手段,我考虑只枚举lookupPrintServices返回的所有PrintService ,但 URI 不在任何属性中。 The printer name is there, but I need the URI.打印机名称在那里,但我需要 URI。

For background, my webapp needs to print a barcode to a specific printer, based on the current user.对于背景,我的 webapp 需要根据当前用户将条形码打印到特定的打印机。 Each user is associated with a printer URI, which points to a printer on a CUPS server.每个用户都与一个打印机 URI 相关联,该 URI 指向 CUPS 服务器上的打印机。 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.打印机 URI 是我拥有的唯一信息,我无法限制打印机名称以匹配 URI 或 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.编辑:澄清一下,我不需要渲染数据,我只需要将 blob 复制到给定的打印机。 The part I can't figure out is how to identify a printer by its IPP URI.我无法弄清楚的部分是如何通过其 IPP URI 识别打印机。

I finally found a way to do this, by using jipsi :我终于找到了一种方法,通过使用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.我不得不承认,我对不得不使用 3rd-party 库来做一些看似简单的事情(比如打印到特定打印机)感到很失望。

UPDATE更新

DR points out in the comments that jipsi has a new home , and a new name. DR 在评论中指出 jipsi 有一个新家和一个新名称。

Cups4J is a nice alternative, but as the name implies it may not work correctly if the destination is not a CUPS server. Cups4J是一个不错的选择,但顾名思义,如果目标不是 CUPS 服务器,它可能无法正常工作。 I have had good results using Cups4J to print directly to a Zebra thermal printer.使用 Cups4J 直接打印到 Zebra 热敏打印机时,我取得了很好的效果。

I do not think you can get a printer the way you would like to (I think the Java Print mechanism predates IPP).我不认为您可以按照自己想要的方式获得打印机(我认为 Java 打印机制早于 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".但是,如果我没记错的话,您可以在本地渲染您的打印作业,然后“手动”将输出流的字节发送到目标 CUPS 服务器。 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 将 PDF 等可打印文档格式提交到打印机(或 CUPS),此代码提供了一个没有依赖关系的简约实现。 ipp-printjob-java has basic support for decoding the ipp response. 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));
  }

}

Using this ipp-client you can submit a PDF file to a printer (or CUPS) which supports this document format:使用此ipp-client ,您可以将 PDF 文件提交到支持此文档格式的打印机(或 CUPS):

new IppPrinter(URI.create("ipp://myprinter")).printJob(
    File("mydocument.pdf"), documentFormat("application/pdf")
);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM