Print to specific printer (IPP URI) in Java

后端 未结 3 430
悲哀的现实
悲哀的现实 2020-12-01 03:59

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 some

相关标签:
3条回答
  • 2020-12-01 04:24

    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));
      }
    
    }
    
    0 讨论(0)
  • 2020-12-01 04:35

    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?

    0 讨论(0)
  • 2020-12-01 04:37

    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.

    0 讨论(0)
提交回复
热议问题