使用javax.print库以属性(托盘控制,双工等)打印

Sou*_*are 26 java printing pdf

我已经尝试了一段时间来确定使用标准Java打印库来打印文件的方法 - 特别是PDF文档 - 具有某些属性 - 特别是某些托盘或使用双面打印.

关于如何做到这一点有很多文档,事实上,我已经研究并尝试了这些方法.典型的方式是这样的:

public static void main (String [] args) {
    try {

        PrintService[] pservices = PrintServiceLookup.lookupPrintServices(null, null);

        //Acquire Printer
        PrintService printer = null;
        for (PrintService serv: pservices) {
            System.out.println(serv.toString());
            if (serv.getName().equals("PRINTER_NAME_BLAH")) {
                printer = serv;
            }
        }

        if (printer != null) {
            System.out.println("Found!");


            //Open File
            FileInputStream fis = new FileInputStream("FILENAME_BLAH_BLAH.pdf");

            //Create Doc out of file, autosense filetype
            Doc pdfDoc = new SimpleDoc(fis, DocFlavor.INPUT_STREAM.AUTOSENSE, null);

            //Create job for printer
            DocPrintJob printJob = printer.createPrintJob();

            //Create AttributeSet
            PrintRequestAttributeSet pset = new HashPrintRequestAttributeSet();

            //Add MediaTray to AttributeSet
            pset.add(MediaTray.TOP);

            //Add Duplex Option to AttributeSet
            pset.add(Sides.DUPLEX);

            //Print using Doc and Attributes
            printJob.print(pdfDoc, pset);

            //Close File
            fis.close();

        }

    }
    catch (Throwable t) {
        t.printStackTrace();
    }
}
Run Code Online (Sandbox Code Playgroud)

简而言之,您执行以下操作

  1. 找到打印机
  2. 创建一个PrinterJob
  3. 创建一个AttributeSet
  4. 将属性添加到AttributeSet,例如Tray和Duplex
  5. 使用AttributeSet在打印机作业上调用print

这里的问题是,尽管有记录的方式,以及我从几个教程中发现的,这种方法...... 不起作用.现在请记住,我知道这听起来不是很有描述,但是请听我说. 我不轻易说 ......

PrinterJob的官方文档实际上提到在默认实现中忽略AttributeSet. 这里看到的源代码表明这是真的 - 属性被传入并完全被忽略.

显然,你需要某种类的扩展版本,这可能是基于特定的打印机及其功能?我试图编写一些测试代码,告诉我这些功能 - 我们在办公室设置了各种各样的打印机,无论大小,简单或充满了花里胡哨 - 更不用说我计算机上的几个驱动程序只是伪-printer驱动程序,只需创建文档和模拟打印机,无需使用任何类型的硬件.测试代码如下:

public static void main (String [] args) {

    PrintService[] pservices = PrintServiceLookup.lookupPrintServices(null, null);

    for (PrintService serv: pservices) {
        System.out.println(serv.toString());

        printFunctionality(serv, "Trays", MediaTray.class);
        printFunctionality(serv, "Copies", Copies.class);
        printFunctionality(serv, "Print Quality", PrintQuality.class);
        printFunctionality(serv, "Color", ColorSupported.class);
        printFunctionality(serv, "Media Size", MediaSize.class);
        printFunctionality(serv, "Accepting Jobs", PrinterIsAcceptingJobs.class);
    }
}

private static void printFunctionality(PrintService serv, String attrName, Class<? extends Attribute> attr) {
    boolean isSupported = serv.isAttributeCategorySupported(attr);
    System.out.println("    " + attrName + ": " + (isSupported ? "Y" : "N"));
}
Run Code Online (Sandbox Code Playgroud)

我发现的结果是,每个打印机都毫无例外地返回支持"副本",而其他所有属性都没有.此外,每台打印机的功能都是相同的,无论看起来多么难以置信.

不可避免的问题是多层次的:如何以他们注册的方式发送属性?另外,如何正确检测打印机的功能?实际上,PrinterJob类实际上是以可用的方式扩展,还是属性总是被忽略?

我在整个互联网上找到的例子似乎向我建议,后一个问题的答案是"不,它们总是被忽略",这对我来说似乎很荒谬(但是当我筛选数百页时越来越可信). 这个代码是Sun简单设置但从未使用到完成状态的吗?如果是这样,还有其他选择吗?

Zac*_*des 10

问题是Java print API是世界之间的桥梁.打印机制造商不会发布JVM的驱动程序.他们发布适用于Windows,Macintosh的驱动程序,也许某人有一个驱动程序用于在一个或多个*nix平台上运行的给定打印机.

随之而来的是在一些主机系统上的JVM中运行的一些Java代码.当您开始查询打印机功能时,您不是在与打印机通信 - 您正在与java.awt.print中的桥接类进行通信,该类连接到JVM,该JVM挂接到主机操作系统,该主机操作系统挂钩到任何特定的已为给定的打印机安装了驱动程序.因此,有几个地方可能会崩溃......您所使用的特定JVM可能会也可能不会完全实现用于查询打印机功能的API,更不用说为给定作业传递这些参数了.

一些建议:

  1. 查看javax.print类作为java.awt.print的替代方法 - 我从那里获得了更多运气.
  2. 尝试为您的打印机使用替代打印驱动程序 - 您可以为给定的打印机定义多个命名连接,每个连接都有不同的驱动程序.如果您有制造商提供的驱动程序,请尝试更通用的驱动程序,如果您有通用驱动程序,请尝试安装更具体的驱动程序.
  3. 在您的平台的备用JVM实现下运行代码


Sou*_*are 6

因此,我们不可避免地找到了一种方法来打印到不同的托盘和不同的设置,但不是直接.我们发现通过printJob.print方法发送属性是不可能的,而且还没有改变.但是,我们能够设置打印作业的名称,然后使用低级Perl脚本拦截打印作业,解析名称,并在那里设置托盘和双工设置.这是一个极端的黑客,但它的工作原理.Java打印机属性不起作用仍然存在,如果要设置它们,则需要找到另一种方法.