为什么 getSupportedAttributeValues return 纸张类型

Why does getSupportedAttributeValues return Paper Types

以下代码片段应该 return 打印机可用的媒体托盘。

但是,对于某些驱动程序,特别是 Ricoh PCL6 Driver for Universal PrintHP Universal Printing PCL 6,除了打印机托盘之外,这些驱动程序还列出纸张类型,例如 RecycledThickMatte,等等

据我所知,OpenJDK 在源代码中是 properly using DC_BINNAMES when calling DeviceCapabilities. OpenJDK doesn't even seem to use DC_MEDIATYPENAMES at all,所以我不希望例如Purple Paper 甚至是可查询的 属性,但它会在从 Ricoh 驱动程序查询托盘时列出。

怎么了?这些 PCL 6 个驱动程序刚刚被窃听了吗? DeviceCapabilities有错吗?还是该错误存在于 OpenJDK 中?

import javax.print.DocFlavor;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.attribute.standard.Media;

public class TrayListing {
    public static void main(String ... args) {
        String printerName = "HP LaserJet ...";  // TODO: change this to the actual printer name
        PrintService[] allPrinters = PrintServiceLookup.lookupPrintServices(null, null);
        for(PrintService ps : allPrinters) {
            if(ps.getName().equalsIgnoreCase(printerName)) {
                // loop over media trays
                System.out.println("\n\nFound MediaTray:");

                // Some HP, Ricoh printers/drivers list items that aren't printer trays, such as paper types
                for(Media m : (Media[])ps.getSupportedAttributeValues(Media.class, DocFlavor.SERVICE_FORMATTED.PAGEABLE, null)) {
                    if (m instanceof javax.print.attribute.standard.MediaTray) {
                        System.out.println("- " + m + " (" + m.getClass().getName() + ")");
                    }
                }
            }
        }
    }
}

其他关键字:

PCL XL Feature Reference

driver 有问题。存在解决方法,但它们很复杂。

短篇:

  • Ricoh|HPPCL6|PCL 6
  • 上匹配 driver 名称
  • 过滤任何 trayId > 1000

长:

HP等部分driver打印机托盘在其他地方正常暴露,例如:

  • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers\<PRINTER_NAME>\PrinterDriverData
    • InputSlot
    • InputSlotDisplayNames

...然而,对于 driver 等理光,情况并非如此。

在检查了很多 drivers(HP、Ricoh、Xerox、Konica 等)之后,我将问题隔离为以下几点:

  • PCL6 drivers
  • HP 或 Ricoh 作为供应商

在两个供应商的情况下,DC_BINS 值始终 > 1000,即 partially explained in the PCL6 MediaSource specification,引用:

"... External input trays 1 through 248 are selected by substituting the values 8 through 255 for the enumerated values. Example, 8 = first external input tray, 9 = second external input tray, etc. ..."

虽然没有具体说明 1,000,但 Xerox 等供应商使用超过 7000 的值而没有错误。也就是说,对于有问题的供应商,观察到的是当值 > 1,000 时,它们往往是实际有效的 MediaType 值(不是 MediaSource 值),但增加了 1,000。

奇怪的是,这仅限于 HP 和 Ricoh,不适用于其他 PCL driver。例如:

  • 柯尼卡使用的托盘ID为1000 = LCT,即“大容量托盘”,有效
  • Xerox 提供 PCL6 driver,但通常使用高于 1000 的托盘 ID,例如7153 = Tray 1, 7154 = Tray 2.
  • Ricoh 在其 driver 的 PCL5 版本中使用 1025 的托盘 ID,这是 1025 = [=36] 的有效托盘值=],但他们的 PCL6 driver 似乎并非如此,其中混合了 MediaType 值。

因此,为了“解决”这个问题,我编写了一系列自定义解析来找出 driver 供应商和托盘 ID。

从Java定位trayId:

// Get default printer
PrintService ps = PrintServiceLookup.lookupDefaultPrintService();

for(Media mediaTray : (Media[])ps.getSupportedAttributeValues(Media.class, null, null)) {
   // Warning: Reflective operation on Windows-only class
   Method method = ps.getClass().getMethod("findTrayID", MediaTray.class);
   Object trayId = method.invoke(ps, new Object[]{mediaTray});
   System.out.println(trayId);
}

从Java获取driver供应商:

  • 这部分要复杂得多,需要 third-party 依赖项 JNA。出于这个原因,我省略了代码,但我将提供步骤:
  • 读取注册表就像调用一样简单Advapi32Util.registryGetStringValue(...)
  • 知道获取 driver 名称的注册表字符串值是一项复杂的操作,但以下方面会有所帮助:
    • HKLM\SYSTEM\CurrentControlSet\Control\Print\Printers\<PRINTER_NAME>\Printer Driver
    • HKLM\Software\Microsoft\Windows NT\CurrentVersion\Print\Providers\Client Side Rendering Print Provider\Servers\<PRINTER_NAME>\Printers\<GUID>

计算 driver 名称是一些细微的代码,但可以可靠地使用。有关综合代码示例,请参阅 here。特别注意keys/values.

中的特殊字符替换

找到 driver 后,使用正则表达式匹配术语 RicohHPPCL6PCL 6 将允许过滤 trayID 1,000.

通过结合上面的trayId编号、vendor匹配和关键字“PCL6”和“PCL6”的技术,可以通过编程方式过滤掉坏盘。