Java printing PDF with options (staple, duplex, etc)

守給你的承諾、 提交于 2019-12-20 06:20:05

问题


I have a java program that prints PDFs. It uses Apache PDFBox to create a PDDocument object (from a pdf document or from a stream in some cases) and then sends it to the printer using the javax.print API:

private boolean print(File pdf, String printer)
{
    boolean success = false;

    try (PDDocument document = PDDocument.load(pdf))
    {
        PrintService[] printServices = PrinterJob.lookupPrintServices();
        PrintService printService = PrintServiceLookup.lookupDefaultPrintService();
        PrinterJob job = PrinterJob.getPrinterJob();
        job.setPageable(new PDFPageable(document));

        // set printer
        if (printer != null)
        {
            for (PrintService selected : printServices)
            {
                if (selected.getName().equals(printer))
                {
                    printService = selected;
                    break;
                }
            }
        }
        job.setPrintService(printService);
        job.print();
        success = true;
    }
    catch (Exception e)
    {
        myLog.error("Printer error.", e);
    }
    return success;
}

Now I need to be able to tell the printer to staple the thing...


I am familiar with the javax.print.attributes API and use this successfully for specifying the tray or setting duplex, e.g.:

// this works fine
if (duplex != null)
{               
    if (duplex.equalsIgnoreCase("short"))
    {
        myLog.debug("Setting double-sided: Short");
        attr.add(Sides.TWO_SIDED_SHORT_EDGE);
    }
    else
    {
        myLog.debug("Setting double-sided: Long");
        attr.add(Sides.TWO_SIDED_LONG_EDGE);
    }
}

I know there is an attribute for stapling:

attr.add(javax.print.attribute.standard.Finishings.STAPLE);

I have a Xerox Versalink B7035 with a Finisher XL attachment that fully supports stapling (i.e. it works from MS Office document settings) however the printer disregards the STAPLE attribute set from Java. I tried all other variants of staple attributes but soon found that the printer did not support ANY Java finishing attributes.

Or to put it in code, the following prints NO results:

DocFlavor flavor = DocFlavor.SERVICE_FORMATTED.PRINTABLE;
Object finishings = myPrinter.getSupportedAttributeValues(Finishings.class, flavor, null);
if (finishings != null && o.getClass().isArray())
{
    for (Finishings finishing : (Finishings[]) finishings)
    {
        System.out.println(finishing.getValue() + " : " + finishing);
    }
}

After reading this and trying a few different things I concluded the printer will not accept the STAPLE attribute because the finisher is an attachment or simply because Xerox doesn't like Java or something. So now I am attempting to solve this by prepending PJL commands to the pdf before sending it, as covered here. *PJL = Print Job Language

E.g:

<ESC>%-12345X@PJL<CR><LF>
@PJL SET STAPLE=LEFTTOP<CR><LF>
@PJL ENTER LANGUAGE = PDF<CR><LF>
[... all bytes of the PDF file, starting with '%PDF-1.' ...]
[... all bytes of the PDF file ............................]
[... all bytes of the PDF file ............................]
[... all bytes of the PDF file, ending with '%%EOF' .......]
<ESC>%-12345X

At first I assumed there would just be some method in the Apache PDFBox library to do just this, but no luck. Then I checked out the API for Ghost4J and saw nothing for prepending. Has anyone else solved this already?


回答1:


Reverting to Java socket printing makes PJL a thing:

// this works, it also printed faster than javax.print when tested
private static void print(File document, String printerIpAddress, boolean staple)
{
    try (Socket socket = new Socket(printerIpAddress, 9100))
    {
        DataOutputStream out = new DataOutputStream(socket.getOutputStream());
        byte[] bytes = Files.readAllBytes(document.toPath());

        out.write(27); //esc
        out.write("%-12345X@PJL\n".getBytes());
        out.write("@PJL SET DUPLEX=ON\n".getBytes());

        if (staple) 
        {
            out.write("@PJL SET STAPLEOPTION=ONE\n".getBytes());
        }
        out.write("@PJL ENTER LANGUAGE=PDF\n".getBytes());
        out.write(bytes);
        out.write(27); //esc
        out.write("%-12345X".getBytes());
        out.flush();
        out.close();
    }
    catch (Exception e)
    {
        System.out.println(e);
    }
}

The needed PJL commands came from this Xerox datasheet.

It should be noted that the same PJL commands worked for two different Xerox models and a Lexmark printer, that's all I had handy to test with. Dunno if other models will want something different.

Do not need the Apache PDFBox library anymore. Or any external libraries at all.

This might work for other types of documents, aside from PDFs.



来源:https://stackoverflow.com/questions/55777889/java-printing-pdf-with-options-staple-duplex-etc

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!