繁体   English   中英

从命令行打印图像并等待 Windows 上的打印作业完成

[英]print an image from command line and await print job completion on Windows

我需要编写一个解决方案来写入数据,然后批量打印 RFID 标签,每个标签都从模板 python 脚本和从数据库或 excel 文件中获取的数据生成 as.png 图像。

要打印程序,只需调用相关系统实用程序(unix 系统上的 CUPS),使用subprocess.check_call(print_cmd)传递图像文件(保存在 ram 安装的文件系统上,以尽量减少磁盘使用)

现在,它还需要在 Windows 系统上运行,但实际上并没有一个像样的系统实用程序,以及类似问题的打印图片命令行工具下的解决方案? 不要考虑打印作业的完成情况,或者如果作业导致错误,则页边距都被拧紧并且图像由于某种原因总是旋转 90 度。

如何使用 Windows 中的命令或脚本理智地打印图像并等待它成功完成或在作业出错时返回错误? 可能没有依赖关系

如果您可以安装依赖项,则有许多程序可以提供开箱即用的解决方案。


我能找到解决这个问题的唯一明智的方法是创建一个powershell脚本来解决这个问题

[CmdletBinding()]
param (
    [string]    $file = $(throw "parameter is mandatory"),
    [string]    $printer = "EXACT PRINTER NAME HERE"
)

$ERR = "UserIntervention|Error|Jammed"

$status = (Get-Printer -Name $printer).PrinterStatus.ToString()
if ($status -match $ERR){ exit 1 }

# https://stackoverflow.com/a/20402656/17350905
# only sends the print job to the printer
rundll32 C:\Windows\System32\shimgvw.dll,ImageView_PrintTo $file $printer

# wait until printer is in printing status
do {
    $status = (Get-Printer -Name $printer).PrinterStatus.ToString()
    if ($status -match $ERR){ exit 1 }
    Start-Sleep -Milliseconds 100
} until ( $status -eq "Printing" )

# wait until printing is done
do {
    $status = (Get-Printer -Name $printer).PrinterStatus.ToString()
    if ($status -match $ERR){ exit 1 }
    Start-Sleep -Milliseconds 100
} until ( $status -eq "Normal" )

然后我需要稍微修改打印子进程调用

powershell -File "path\to\print.ps1" "C:\absolute\path\to\file.png"

然后是几个必要的设置步骤:

(免责声明,我不使用英语 windows,所以我不知道应该如何称呼英语 thigs。我将使用草书

  1. 创建示例图像,右键单击然后 select打印

    • 从打开的打印对话框中,然后为您要使用的特定打印机设置所有您想要的默认选项,例如方向、页边距、纸张类型等。
  2. Go到打印机设置,工具下然后编辑打印机状态监控

    • 监控频率编辑为“仅在打印作业期间” 它应该默认禁用
    • 在下一个选项卡中,将轮询频率修改为可用的最小值,打印作业期间为 100 毫秒(您可以在不打印选项时使用较低的频率

假设如下:

  • 只有你的程序在运行这个脚本
  • 对于给定的打印机,一次总是只有 1 个打印作业
  • 打印机驱动程序不是猴子写的,它们实际上报告了当前正确的打印机状态

这个小技巧将允许从命令打印图像并等待作业完成,并进行错误管理; 并且仅使用 windows 预装软件

可以通过保持 powershell 子进程处于活动状态并仅以& "path\to\print.ps1" "C:\absolute\path\to\file.png"格式向其传递脚本来完成进一步优化,等待标准 output 报告一个OK 或 KO; 但前提是需要大量印刷。

不得不再次处理这个问题,只是想使用pywin32 package 在“纯”python 中添加一个更简单的解决方案

import time
import subprocess
from typing import List
try:
    import win32print as wprint

    PRINTERS: List[str] = [p[2] for p in wprint.EnumPrinters(wprint.PRINTER_ENUM_LOCAL)]
    PRINTER_DEFAULT = wprint.GetDefaultPrinter()
    WIN32_SUPPORTED = True
except:
    print("[!!] an error occured while retrieving printers")
    # you could throw an exception or whatever

# bla bla do other stuff
if "WIN32_SUPPORTED" in globals():
  __printImg_win32(file, printer_name)

def __printImg_win32(file: str, printer: str = ""):
    if not printer:
      printer = PRINTER_DEFAULT
    # verify prerequisites here

    # i still do prefer to print calling rundll32 directly,
    #  because of the default printer settings shenaningans
    #  and also because i've reliably used it to spool millions of jobs
    subprocess.check_call(
        [
            "C:\\Windows\\System32\\rundll32",
            "C:\\Windows\\System32\\shimgvw.dll,ImageView_PrintTo",
            file,
            printer,
        ]
    )
    __monitorJob_win32(printer)
    pass

def __monitorJob_win32(printer: str, timeout=16.0):
    p = wprint.OpenPrinter(printer)

    # wait for job to be sheduled
    t0 = time.time()
    while (time.time()-t0) < timeout:
        ptrr = wprint.GetPrinter(p, 2)
        # unsure about those flags, but definitively not errors.
        #  it seems they are "moving paper forward"
        if ptrr["Status"] != 0 and ptrr["Status"] not in [1024,1048576]:
            raise Error("Printer is in error (status %d)!" % ptrr["Status"])
        if ptrr["cJobs"] > 0:
            break
        time.sleep(0.1)
    else:
        raise Error("Printer timeout sheduling job!")

    # await job completion
    t0 = time.time()
    while (time.time()-t0) < timeout:
        ptrr = wprint.GetPrinter(p, 2)
        if ptrr["Status"] != 0 and ptrr["Status"] not in [1024,1048576]:
            raise Error("Printer is in error (status %d)!" % ptrr["Status"])
        if ptrr["cJobs"] == 0 and ptrr["Status"] == 0:
            break
        time.sleep(0.1)
    else:
        raise Error("Printer timeout waiting for completion!")

    wprint.ClosePrinter(p)
    return


有用的额外资源

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM