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

我一直在努力确定一种方法来使用标准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(); } } 

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

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

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

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

显然,你需要某种类的扩展版本,这可能是基于特定的打印机及其function? 我试图编写一些测试代码来告诉我这些function – 我们在办公室设置了大量的打印机,无论大小,简单还是充满了花里胡哨 – 更不用说我计算机上的几个驱动程序只是伪-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 attr) { boolean isSupported = serv.isAttributeCategorySupported(attr); System.out.println(" " + attrName + ": " + (isSupported ? "Y" : "N")); } 

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

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

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

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

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

一些建议:

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

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

我们有类似的要求打印PDF并希望将一些页面发送到特定托盘,并且还希望对文档进行装订。 我们使用Java代码+ ghost脚本组合首先将PDF转换为ghost脚本,然后将PJL(打印作业语言)命令添加到ghost脚本文件中以选择托盘并装订文档。 然后将编辑后的ghost脚本文件发送到打印机。

这是用Java编写的完整示例

http://reddymails.blogspot.com/2014/07/how-to-print-documents-using-java-how.html

-内存

这是它在javafx中的样子托盘可能会有所不同,它也会打印出所有可用的托盘只需更改托盘名称

 private void printImage(Node node) { PrinterJob job = PrinterJob.createPrinterJob(); if (job != null) { JobSettings js = job.getJobSettings(); PaperSource papersource = js.getPaperSource(); System.out.println("PaperSource=" + papersource); PrinterAttributes pa = printer.getPrinterAttributes(); Set s = pa.getSupportedPaperSources(); System.out.println("# of papersources=" + s.size()); if (s != null) { for (PaperSource newPaperSource : s) { System.out.println("newpapersource= " + newPaperSource); //Here is where you would put the tray name that is appropriate //in the contains section if(newPaperSource.toString().contains("Tray 2")) js.setPaperSource(newPaperSource); } } job.getJobSettings().setJobName("Whatever"); ObjectProperty sources = job.getJobSettings().paperSourceProperty(); System.out.println(sources.toString()); boolean success = job.printPage(node); if (success) { System.out.println("PRINTING FINISHED"); job.endJob(); //Stage mainStage = (Stage) root.getScene().getWindow(); //mainStage.close(); } } } 

这是我的输出:

 PaperSource=Paper source : Automatic # of papersources=6 newpapersource= Paper source : newpapersource= Paper source : Manual Feed in Tray 1 newpapersource= Paper source : Printer auto select newpapersource= Paper source : Tray 1 newpapersource= Paper source : Tray 2 newpapersource= Paper source : Form-Source ObjectProperty [bean: Collation = UNCOLLATED Copies = 1 Sides = ONE_SIDED JobName = Whatever Page ranges = null Print color = COLOR Print quality = NORMAL Print resolution = Feed res=600dpi. Cross Feed res=600dpi. Paper source = Paper source : Tray 2 Page layout = Paper=Paper: Letter size=8.5x11.0 INCH Orient=PORTRAIT leftMargin=54.0 rightMargin=54.0 topMargin=54.0 bottomMargin=54.0, name: paperSource, value: Paper source : Tray 2] PRINTING FINISHED