Reputation: 572
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?
Upvotes: 4
Views: 3698
Reputation: 581
@Barmak Shemirani above deserves full credit for most of the code below. I simply added a section which allows you to choose the page size and/or force the orientation. You can also use the devmode in the win32con easily now to push the image around as needed.
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()
Upvotes: 0
Reputation: 31599
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 )
Upvotes: 5