为什么 getSupportedAttributeValues return 纸张类型
Why does getSupportedAttributeValues return Paper Types
以下代码片段应该 return 打印机可用的媒体托盘。
但是,对于某些驱动程序,特别是 Ricoh PCL6 Driver for Universal Print
和 HP Universal Printing PCL 6
,除了打印机托盘之外,这些驱动程序还列出纸张类型,例如 Recycled
、Thick
、 Matte
,等等
据我所知,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|HP
和 PCL6|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 后,使用正则表达式匹配术语 Ricoh
、HP
、PCL6
和 PCL 6
将允许过滤 trayID 1,000.
通过结合上面的trayId编号、vendor匹配和关键字“PCL6”和“PCL6”的技术,可以通过编程方式过滤掉坏盘。
以下代码片段应该 return 打印机可用的媒体托盘。
但是,对于某些驱动程序,特别是 Ricoh PCL6 Driver for Universal Print
和 HP Universal Printing PCL 6
,除了打印机托盘之外,这些驱动程序还列出纸张类型,例如 Recycled
、Thick
、 Matte
,等等
据我所知,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|HP
和PCL6|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
through248
are selected by substituting the values8
through255
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 后,使用正则表达式匹配术语 Ricoh
、HP
、PCL6
和 PCL 6
将允许过滤 trayID 1,000.
通过结合上面的trayId编号、vendor匹配和关键字“PCL6”和“PCL6”的技术,可以通过编程方式过滤掉坏盘。