Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python3 print landscape image/file with specified printer

I want to print a pdf file (or image) that I create on my script with a specified printer but the file is landscape orientation. I have tried the Tim Golden's python print but it is printed wrong and most of the image is not printed or I get an error message that the specified file is not found. This is the error: "pywintypes.error: (2, 'ShellExecute', 'The system cannot find the file specified.')" and the command is this: win32api.ShellExecute (0, "print", filename, '/d:"%s"' % printer_name, ".", 0). Of course filename and printer are strings and printer name is taken from win32print.EnumPrinters(2,None,1)

Here is my printing function:

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()

I don't know what else to try. Is there a way to achieve this?

like image 972
George Sp Avatar asked Sep 13 '25 22:09

George Sp


1 Answers

bmp = bmp.rotate(90)

This will crop the image. Use img.rotate(90, expand=True) to flip the image properly.

You can use SetViewportExt/SetWindowExt instead of manually calculating the bitmap ratio to printer resolution. You also need to account for printer's margin. See example below.

The system error for file not found error is separate. Use the debugger to find where it occurs.

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 )
like image 52
Barmak Shemirani Avatar answered Sep 15 '25 11:09

Barmak Shemirani