【问题标题】:python3 print landscape image/file with specified printerpython3使用指定的打印机打印横向图像/文件
【发布时间】:2019-02-04 18:22:46
【问题描述】:

我想使用指定的打印机打印我在脚本上创建的 pdf 文件(或图像),但该文件是横向的。我尝试了Tim Golden's python print,但它打印错误并且大部分图像没有打印,或者我收到一条错误消息,指出找不到指定的文件。这是错误:"pywintypes.error: (2, 'ShellExecute', '系统找不到指定的文件。')" 命令是这样的:win32api.ShellExecute (0, "print", filename, '/d:"%s"' % printer_name, ".", 0) .当然 filenameprinter 是字符串,打印机名称取自 win32print.EnumPrinters(2,None,1)

这是我的打印功能:

def programA_printer():
    global name
    global printer_name
    global event2
    # time.sleep(3)
    i=0
    while True:
        if not event2.is_set():
            try:
                img = Image.open("Program_A_graph.png", 'r')
                if (time.time()-(os.path.getmtime("Program_A_graph.png")) < 1.75):
                    break
            except OSError as identifier:
                i = i+1
                print(identifier)
                time.sleep(1)
                if i>5:
                    print("Υπήρξε πρόβλημα, δεν εκτυπώνω και συνεχίζω στο επόμενο σετ!")
                    return


    serial_number_message = int(time.time())

    # img.show(title="Final Result")
    img.convert('RGB').save('./εκτυπώσεις/'+str(serial_number_message)+'.pdf', format="PDF", resolution=100.0)

#win32api.ShellExecute (0, "print", './εκτυπώσεις/'+str(serial_number_message)+'.pdf', '/d:"%s"' % printer_name, ".",0)
#win32api.ShellExecute (0, "print", './εκτυπώσεις/'+str(serial_number_message)+'.pdf', '/d:"%s"' % printer_name, "./εκτυπώσεις",0)
    HORZRES = 10
    VERTRES = 10

    PHYSICALWIDTH = 110
    PHYSICALHEIGHT = 111

    PHYSICALOFFSETX = 112
    PHYSICALOFFSETY = 113

    hDC = win32ui.CreateDC()
    hDC.CreatePrinterDC(printer_name)
    printable_area = hDC.GetDeviceCaps(HORZRES), hDC.GetDeviceCaps(VERTRES)
    printer_size = hDC.GetDeviceCaps(PHYSICALWIDTH), hDC.GetDeviceCaps(PHYSICALHEIGHT)
    printer_margins = hDC.GetDeviceCaps(PHYSICALOFFSETX), hDC.GetDeviceCaps(PHYSICALOFFSETY)

    bmp = img
    if bmp.size[0] > bmp.size[1]:
        bmp = bmp.rotate(90)

    ratios = [1.0 * printable_area[0] / bmp.size[0], 1.0 * printable_area[1] / bmp.size[1]]
    scale = min(ratios)

    hDC.StartDoc("Result")
    hDC.StartPage()

    dib = ImageWin.Dib(bmp)
    scaled_width, scaled_height = [int(scale * i) for i in bmp.size]
    x1 = int((printer_size[0] - scaled_width) / 2)
    y1 = int((printer_size[1] - scaled_height) / 2)
    x2 = x1 + scaled_width
    y2 = y1 + scaled_height
    dib.draw(hDC.GetHandleOutput(), (x1, y1, x2, y2))

    hDC.EndPage()
    hDC.EndDoc()
    hDC.DeleteDC()

我不知道还能尝试什么。有没有办法做到这一点?

【问题讨论】:

  • 请发布导致此错误的代码以及错误的完整堆栈跟踪。您提供的参考资料提供了六种不同的方法。您要求我们猜测您选择了哪个,想象您的代码,然后提出其中可能存在的问题。
  • @BoarGules 我添加了代码,使用 win32api.ShellExecute 的注释行是我尝试打印我创建的 pdf 文件而不是来自 PIL 的图像的其他方式。

标签: python python-3.x windows printing pywin32


【解决方案1】:
bmp = bmp.rotate(90)

这将裁剪图像。使用img.rotate(90, expand=True)正确翻转图片。

您可以使用SetViewportExt/SetWindowExt 而不是手动计算位图与打印机分辨率的比率。您还需要考虑打印机的边距。请参见下面的示例。

文件未找到错误的系统错误是单独的。使用调试器查找它发生的位置。

import win32ui, win32con
from PIL import Image, ImageWin

def print_test(printer_name):

    try:
        filename = "Program_A_graph.png"
        img = Image.open(filename, 'r')
    except:
        print("error")
        return

    hdc = win32ui.CreateDC()
    hdc.CreatePrinterDC(printer_name)

    horzres = hdc.GetDeviceCaps(win32con.HORZRES)
    vertres = hdc.GetDeviceCaps(win32con.VERTRES)

    landscape = horzres > vertres

    if landscape:
        if img.size[1] > img.size[0]:
            print('Landscape mode, tall image, rotate bitmap.')
            img = img.rotate(90, expand=True)
    else:
        if img.size[1] < img.size[0]:
            print('Portrait mode, wide image, rotate bitmap.')
            img = img.rotate(90, expand=True)

    img_width = img.size[0]
    img_height = img.size[1]

    if landscape:
        #we want image width to match page width
        ratio = vertres / horzres
        max_width = img_width
        max_height = (int)(img_width * ratio)
    else:
        #we want image height to match page height
        ratio = horzres / vertres
        max_height = img_height
        max_width = (int)(max_height * ratio)

    #map image size to page size
    hdc.SetMapMode(win32con.MM_ISOTROPIC)
    hdc.SetViewportExt((horzres, vertres));
    hdc.SetWindowExt((max_width, max_height))

    #offset image so it is centered horizontally
    offset_x = (int)((max_width - img_width)/2)
    offset_y = (int)((max_height - img_height)/2)
    hdc.SetWindowOrg((-offset_x, -offset_y)) 

    hdc.StartDoc('Result')
    hdc.StartPage()

    dib = ImageWin.Dib(img)
    dib.draw(hdc.GetHandleOutput(), (0, 0, img_width, img_height))

    hdc.EndPage()
    hdc.EndDoc()
    hdc.DeleteDC()

    print( 'Debug info:' )
    print( 'Landscape: %d' % landscape )
    print( 'horzres: %d' % horzres )
    print( 'vertres: %d' % vertres )

    print( 'img_width: %d' % img_width )
    print( 'img_height: %d' % img_height )

    print( 'max_width: %d' % max_width )
    print( 'max_height: %d' % max_height )

    print( 'offset_x: %d' % offset_x )
    print( 'offset_y: %d' % offset_y )

【讨论】:

  • 这很好,我可以看到您对此了解得更多,但是现在如果打印出来的图像会从左上角的纸张中挤出来。我该如何解决这个问题?
  • 请参阅编辑。我忘记了边距。这应该拉伸/居中到最大可打印区域。
  • 我试过了,它把图像拉伸得比纸张尺寸 (A4) 还多,所以现在左右两边都离开了纸。我能做些什么?另外,我犯了一个错误,图像方向正确(横向),因此不需要旋转。只是为了使图像适合纸张大小而不改变纵横比。很抱歉混淆了。
  • 请尝试我所做的第三次更新。它还打印“调试信息”。编辑问题并显示这些值的结果。至少显示位图的大小。打印纸尺寸与此代码无关。
【解决方案2】:

上面的@Barmak Shemirani 应该对下面的大部分代码给予充分的评价。我只是添加了一个允许您选择页面大小和/或强制方向的部分。您现在还可以轻松地使用 win32con 中的 devmode 来根据需要推送图像。

def print_test(filename, page_size="11x17", page_orientation="landscape", printer_name = win32print.GetDefaultPrinter()):

    try:
        img = Image.open(filename, 'r')
    except:
        print("error")
        return

    # open the printer.
    hprinter = win32print.OpenPrinter(printer_name)

    # retrieve default settings.  this code does not work on
    devmode = win32print.GetPrinter(hprinter, 2)["pDevMode"]

    # change paper size and orientation
    # all numbers can be found here -
    # https://github.com/SublimeText/Pywin32/blob/master/lib/x64/win32/lib/win32con.py
    if page_size == "letter":
        devmode.PaperSize = 1 # 11x17 = 17, letter = 1
    elif page_size == "11x17":
        devmode.PaperSize = 17 # 11x17 = 17, letter = 1

    # 1 = portrait, 2 = landscape
    if page_orientation == "portait":
        devmode.Orientation = 2
    elif page_orientation == "landscape":
        devmode.Orientation = 2

    # create dc using new settings
    # first get the integer hDC value - note that we need the name
    hdc = win32gui.CreateDC("WINSPOOL", printer_name, devmode)
    # next create a PyCDC from the hDC.
    hdc = win32ui.CreateDCFromHandle(hdc)


    horzres = hdc.GetDeviceCaps(win32con.HORZRES)
    vertres = hdc.GetDeviceCaps(win32con.VERTRES)

    landscape = horzres > vertres

    if landscape:
        if img.size[1] > img.size[0]:
            print('Landscape mode, tall image, rotate bitmap.')
            img = img.rotate(90, expand=True)
    else:
        if img.size[1] < img.size[0]:
            print('Portrait mode, wide image, rotate bitmap.')
            img = img.rotate(90, expand=True)

    img_width = img.size[0]
    img_height = img.size[1]

    if landscape:
        #we want image width to match page width
        ratio = vertres / horzres
        max_width = img_width
        max_height = (int)(img_width * ratio)
    else:
        #we want image height to match page height
        ratio = horzres / vertres
        max_height = img_height
        max_width = (int)(max_height * ratio)

    #map image size to page size
    hdc.SetMapMode(win32con.MM_ISOTROPIC)
    hdc.SetViewportExt((horzres, vertres));
    hdc.SetWindowExt((max_width, max_height))

    #offset image so it is centered horizontally
    offset_x = (int)((max_width - img_width)/2)
    offset_y = (int)((max_height - img_height)/2)
    hdc.SetWindowOrg((-offset_x, -offset_y)) 

    hdc.StartDoc('Result')
    hdc.StartPage()

    dib = ImageWin.Dib(img)
    dib.draw(hdc.GetHandleOutput(), (0, 0, img_width, img_height))

    hdc.EndPage()
    hdc.EndDoc()
    hdc.DeleteDC()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-07
    • 1970-01-01
    • 2014-07-22
    • 2011-12-23
    • 1970-01-01
    • 1970-01-01
    • 2011-09-07
    • 1970-01-01
    相关资源
    最近更新 更多