You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过pycups获取打印选项键?求更高效实现方案

问题与需求

我通过反复试错并查看PPD文件,写出了能实现多纸盒打印的脚本,在PPD里找到了job-options对应的正确键值名称。但仅靠conn.getPrinterAttributes(printer)['media-source-supported']没法清晰获取这些选项。我觉得肯定有比直接查看PPD文件更好的方法来获取所有打印作业选项,但没找到相关文档;另外因为pycups底层基于C语言,我对它的Python与C绑定机制也不太清楚。执行pip show pycups只找到cupshelpers和pycups的相关信息,以及以下文件:

cups.cpython-310-x86_64-linux-gnu.so
cupsext.cpython-310-x86_64-linux-gnu.so
cupshelpers/
cupshelpers-1.0-py3.10.egg-info
pycups-2.0.1.egg-info

没找到具体的绑定细节。为了更好地使用pycups并理解其底层绑定机制,特此提问,附上参考代码:

#!/usr/bin/env python3
import cups

def list_printers():
    conn = cups.Connection()
    printers = conn.getPrinters()

    print("Available printers:")
    for printer in printers:
        print(f"Printer: {printer}")
        print("Supported options:")
        options = conn.getPrinterAttributes(printer)['media-source-supported']
        for option in options:
            cleaned_option = ''.join(c for c in option if c.isalnum()).upper()
            print(f"  {cleaned_option}")
        print()


def print_document(printer_name, document_path, tray_option):
    conn = cups.Connection()
    printers = conn.getPrinters()

    if printer_name not in printers:
        print(f"Printer '{printer_name}' not found.")
        return

    job_options = {
        'InputSlot': tray_option,
    }
    print(job_options)

    with open(document_path, 'rb') as document:
        print_job_id = conn.printFile(printer_name, document_path, "Print Job", job_options)
        print(f"Document '{document_path}' sent to '{printer_name}' with Job ID: {print_job_id}")

if __name__ == "__main__":
    # Specify the printer name, document paths, and tray options
    printer_name = "Kyocera-ECOSYS-P3055dn-KPDL"

    document1_path = "Tray1.pdf"
    document2_path = "Tray2.pdf"

    options = ["PF430A", "PF430B"]

    for option in options:
        print_document(printer_name, f"{option}.pdf", option)

一、获取完整打印作业选项的替代方法

1. 使用CUPS命令行工具

直接执行lpoptions -p <打印机名称> -l命令,可直接列出打印机支持的所有作业选项及可选值,输出格式更直观,无需手动解析PPD文件。比如针对你的打印机:

lpoptions -p Kyocera-ECOSYS-P3055dn-KPDL -l

示例输出:

InputSlot/Media Source: *Auto PF430A PF430B
MediaSize/Media Size: *A4 Letter Legal

你可以在Python中通过subprocess模块调用该命令,解析输出结果得到结构化的选项列表,比仅依赖media-source-supported更全面。

2. 利用cupshelpers封装库

pycups附带的cupshelpers模块提供了上层封装,能更友好地处理打印机选项。比如用cupshelpers.getPrinterOptions方法获取包含选项名称、可选值的字典:

from cupshelpers import getPrinterOptions
import cups

conn = cups.Connection()
printer = "Kyocera-ECOSYS-P3055dn-KPDL"
options = getPrinterOptions(conn, printer)
# 打印所有支持的选项及对应值
for opt_name, opt_info in options.items():
    print(f"{opt_name}: {opt_info['choices']}")

该方法会自动处理PPD中的选项映射,返回结果比直接调用getPrinterAttributes更清晰。


二、理解pycups的Python与C绑定机制

pycups的底层绑定通过SWIG(Simplified Wrapper and Interface Generator)生成,它负责将CUPS的C API转换为Python可调用的接口。你看到的.so文件是编译后的C扩展模块,承载了Python与CUPS C库之间的调用逻辑。

1. 绑定细节的查找方式

pycups源码仓库中包含SWIG接口定义文件(如cups.i),里面明确了哪些CUPS C函数被暴露给Python,以及参数、返回值的转换规则。若想深入了解,可下载pycups源码包,查看其中的cups.i、setup.py等文件——setup.py包含编译C扩展的配置,能看到SWIG生成的代码如何被编译为.so模块。

2. pip安装文件说明

  • cups.cpython-310-x86_64-linux-gnu.so和cupsext.cpython-310-x86_64-linux-gnu.so:编译后的C扩展,直接实现Python到CUPS C API的调用;
  • cupshelpers/:纯Python编写的辅助模块,封装常用打印机操作,无需直接对接C接口;
  • .egg-info文件:pip用于管理包信息的元数据文件,与绑定机制无关。

优化后的参考代码

结合上述方法,优化后的代码可自动获取并使用正确的纸盒选项:

#!/usr/bin/env python3
import cups
from cupshelpers import getPrinterOptions
import subprocess

def list_printers_with_options():
    conn = cups.Connection()
    printers = conn.getPrinters()

    print("可用打印机及其支持的选项:")
    for printer in printers:
        print(f"\n打印机: {printer}")
        # 使用cupshelpers获取选项
        options = getPrinterOptions(conn, printer)
        if 'InputSlot' in options:
            print("支持的纸盒选项:")
            for choice in options['InputSlot']['choices']:
                print(f"  {choice}")
        # 或者用lpoptions命令获取完整选项
        print("\n通过lpoptions获取的完整选项:")
        result = subprocess.run(
            ['lpoptions', '-p', printer, '-l'],
            capture_output=True, text=True
        )
        print(result.stdout)

def print_document(printer_name, document_path, tray_option):
    conn = cups.Connection()
    printers = conn.getPrinters()

    if printer_name not in printers:
        print(f"未找到打印机 '{printer_name}'")
        return

    job_options = {
        'InputSlot': tray_option,
    }
    print(f"打印选项: {job_options}")

    try:
        print_job_id = conn.printFile(printer_name, document_path, "打印任务", job_options)
        print(f"文档 '{document_path}' 已发送到 '{printer_name}',任务ID: {print_job_id}")
    except cups.IPPError as e:
        print(f"打印失败: {e}")

if __name__ == "__main__":
    printer_name = "Kyocera-ECOSYS-P3055dn-KPDL"
    # 先列出所有选项确认
    list_printers_with_options()

    # 示例打印任务
    options = ["PF430A", "PF430B"]
    for option in options:
        print_document(printer_name, f"{option}.pdf", option)

内容的提问来源于stack exchange,提问作者Xaver

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 00:10:59