有没有更好的方法用Python打印.JPG文件?

问题描述 投票:0回答:1

(第一篇文章,可能不太好):

我在一家汽车制造公司工作,目前正在为我们的零件信息开发一个新的跟踪系统。我正在编写一个简单的软件,安装在低级线路端计算机上,用于输入信息和打印标签以进行内部跟踪。

目标是使用我选择的 Python GUI 库从操作员处获取零件信息,然后使用

QRCode
PIL.Image
模块生成标签作为
.JPG
文件。所有这些都运行良好。标签完全按照我想要的方式生成并保存到机器等。

我似乎无法得到的部分是打印。我找到并尝试的大多数解决方案都是在打印对话框中打开文件,并要求操作员单击“打印”或进行某种输入操作。我不想要这个;它为操作员错误和其他标签格式问题打开了大门。

TL;博士:

有没有一种好方法可以使用系统对话框或提示符从 Python WITHOUT 向操作系统发送打印命令?我包括我尝试过的内容和我当前的解决方案。

操作系统:Windows;语言:Python 3.12.6

第一个解决方案:

我尝试使用

os.startfile()
方法和
'print'
操作,但这创建了上述对话框问题:

from os import path, getcwd, startfile
...
# Attempt to open label.jpg file with 'print' operation
try:
    startfile(file_path, "print")
# label.jpg file couldn't be found/opened
except FileNotFoundError:
    ...

第二种解决方案(当前):

之后,我研究了使用

win32print
库。这让我更进一步,但我被一个错误难住了......

from PIL import Image, ImageDraw, ImageFont, ImageWin
from os import path, getcwd, startfile
import win32print
...
# prints a passed label
def print_label(filepath: str | bytes) -> None:
    """
    Accepts a filepath that is opened and printed.
    """
    # print the label at the passed filepath
    try:
        # open the label from the passed filepath
        label = Image.open(filepath)
        # get the default printer
        printer_name = win32print.GetDefaultPrinter()
        # create a printer from the default printer name
        printer = win32print.OpenPrinter(printer_name)
        # create a document printer
        doc_printer = win32print.StartDocPrinter(printer, 1, (filepath, None, "RAW"))
        # start the printer
        win32print.StartPagePrinter(doc_printer)
        # rotate the image to improve orientation
        label = label.rotate(90, expand = True)
        # save the new width and height
        width, height = label.size
        # draw the image on the printer
        bitmap = ImageWin.Dib(label)
        bitmap.draw(doc_printer, (0, 0, width, height))
        # end the print job
        win32print.EndPagePrinter(doc_printer)
        win32print.EndDocPrinter(doc_printer)
        win32print.ClosePrinter(printer)
    # there was an error printing the label
    except OSError as ex:
        # if the code is 1155 (no printing application assigned)
        if ex.winerror == 1155:
            # show a popup warning the user
            ...
        # else show a popup with the error
        else:
            ...

输出与错误:

Default Printer: \\[servername]\[printername]
Printer Object: <PyPrinterHANDLE:2151737373152>
Initialized Printer: 199
Traceback (most recent call last):
  File "\\...\wip_label_generator.py", line 290, in generate_labels
    print_label(label)
  File "\\...\wip_label_generator.py", line 36, in print_label
    win32print.StartPagePrinter(doc_printer)
pywintypes.error: (6, 'StartPagePrinter', 'The handle is invalid.')

结论:

这不起作用有什么原因吗?我似乎无法找到在此范围内发生的此错误的简洁或适用的解释。我感觉好像它妨碍了我初始化

DocPrinter
,但老实说我很困惑。

如果有更好的方法来实现这种直接打印操作,请告诉我。我确信可以使用

subprocess.run()
或类似的东西。预先感谢!

python windows printing
1个回答
0
投票

经过大量研究,我针对这个具体案例提出了一个非常好的解决方案。感谢 @user2357112@MSalters@Mark Ransom 的反馈,我能够找到一些新资源。

研究与解释:

结合这些来源的信息:

https://python-forum.io/thread-13884.html

https://stackoverflow.com/a/12725233/25419268

https://timgolden.me.uk/python/win32_how_do_i/print.html

我的解决方案很大程度上基于 Tim Golden 网站上的 Single Image 代码片段。虽然他的代码竭尽全力以编程方式检查打印机的物理打印方面,但我不需要这个。当 Tim 提到设备独立位图功能时,主要突破就出现了:

无需任何额外工具,即可在 Windows 机器上打印图像 几乎极其困难,涉及至少三个设备上下文 所有这些都在不同层次上相互关联,并且有相当多的 反复试验。幸运的是,有这样一种东西 设备无关位图 (DIB),让您快刀斩乱麻—— 或者至少是其中的一部分。更幸运的是,Python Imaging 图书馆支持野兽。

这倾向于 Mark Ransom 提到的,将打印机用作窗口。

我的改编只是采用预先生成的

.PNG
文件,将其放大,将其对齐到页面的左上角,然后打印该文件。

代码:

from PIL import ImageWin
import win32print
import win32ui

# prints a passed label
def print_label(filepath: str | bytes) -> None:
    """
    Accepts a filepath that is opened and printed.
    """
    # set an error flag
    print_error = False
    # print the label at the passed filepath
    try:
        # access the OS' default printer
        printer_name = win32print.GetDefaultPrinter()
        # create a device context from a named printer and assess the printable size of the paper.
        hDC = win32ui.CreateDC()
        # convert from a basic device context to a printer device context
        hDC.CreatePrinterDC(printer_name)
        # open the image bitmap
        label = Image.open(filepath)
        if label.size[0] > label.size[4]:
            label = label.rotate(90)
        # start the print job
        hDC.StartDoc(filepath)
        hDC.StartPage()
        # draw the bitmap to the printer device (uses the device-independent bitmap feature)
        dib = ImageWin.Dib(label)
        # scale the label image up
        scaled_width = label.size[0] * 3
        scaled_height = label.size[4] * 3
        # set the left horizontal bound of the image on the page
        x1 = 0
        # set the top vertical bound of the image on the page
        y1 = 0
        # set the right horizontal bound of the image on the page
        x2 = x1 + scaled_width
        # set the top vertical bound of the image on the page
        y2 = y1 + scaled_height
        # draw the label image onto the device context's handle using the device-independent bitmap
        dib.draw(hDC.GetHandleOutput(), (x1, y1, x2, y2))
        # end the print job
        hDC.EndPage()
        hDC.EndDoc()
        hDC.DeleteDC()
    # there was an error printing the label
    except OSError as ex:
        # if the code is 1155 (no printing application assigned)
        if ex.winerror == 1155:
            # show a popup warning the user
            ...
        # else show a popup with the error
        else:
            ...
    # if the error flag was not set
    if not print_error:
        # show popup to confirm printing
        ...

感谢所有反馈,我希望这对将来的人有所帮助!

© www.soinside.com 2019 - 2024. All rights reserved.