I have few lines of code to send job to my printer using pywin32
but when i send this command the content for the new line it doesn't appear on it row on the paper (newline)
after printing but continue to follows the first row the content.
When i print this to the terminal it print like what i desire but not when i send the job to the printer.
Have been searching on this site on how am going to arrange my content when sending it printed but to no avail.
import win32con
import win32print
import win32ui
def text():
rows = (("PETER PAUL", "MALE", "100000"), ("MARGARET ", "FEMALE", "1000"), ("MICHAEL JORDAN", "MALE", "1"),("AGNES", "FEMALE", "200"))
return '\r\n'.join('{:20} {:8} {}'.format(*row) for row in rows)
print(text())
def printer():
dc = win32ui.CreateDC()
printername = win32print.GetDefaultPrinter()
dc.CreatePrinterDC(printername)
dc.SetMapMode(win32con.MM_TWIPS)
scale_factor = 20
dc.StartDoc('Win32print ')
pen = win32ui.CreatePen(0, int(scale_factor), 0)
dc.SelectObject(pen)
font = win32ui.CreateFont({
"name": "Lucida Console",
"height": int(scale_factor * 10),
"weight": 400,
})
dc.SelectObject(font)
dc.TextOut(scale_factor * 72, -1 * scale_factor * 72, text())
dc.EndDoc()
printer()
Note: [GitHub]: mhammond/pywin32 - Python for Windows (pywin32) Extensions doesn't have an official doc (or at least I couldn't find any), so I'll be using the 2nd best thing available: ActiveState (I could only find references for the ancient Python2.4, but generally they are OK)
[ActiveState.Docs]: PyCDC.TextOut wraps [MS.Docs]: TextOutW function. The function doesn't handle \r\n (and definitely other special chars) like print does (the doc doesn't say anything about this), but instead it just ignores them (it doesn't have the concept of line). That means that in order to achieve print - like functionality, the user is responsible for outputting each line individually (of course at a different Y coordinate - to avoid outputting on top of the previous one).
To better illustrate the behavior, I created an example (based on your code).
code.py:
#!/usr/bin/env python3
import sys
import time
import win32ui
import win32con
import win32print
def get_data_strings():
rows = (("PETER PAUL", "MALE", "100000"), ("MARGARET ", "FEMALE", "1000"), ("MICHAEL JORDAN", "MALE", "1"),("AGNES", "FEMALE", "200"))
return ["{:20} {:8} {}".format(*row) for row in rows]
def text():
return "\r\n".join(get_data_strings())
def paint_dc(dc, printer_dc, paint_each_string=True):
scale_factor = 20
if printer_dc:
x_y = 100, 0 # TopLeft of the page. In order to move away from the point, X increases to positives, while Y to negatives
font_scale = 10
y_direction_scale = -1 # For printers, the Y axis is "reversed"
y_ellipsis = -100
else:
x_y = 100, 150 # TopLeft from wnd's client area
font_scale = 1
y_direction_scale = 1
y_ellipsis = 100
font0 = win32ui.CreateFont(
{
"name": "Lucida Console",
"height": scale_factor * font_scale,
"weight": 400,
})
font1 = win32ui.CreateFont(
{
"name": "algerian",
"height": scale_factor * font_scale,
"weight": 400,
})
fonts = [font0, font1]
dc.SelectObject(font0)
dc.SetTextColor(0x0000FF00) # 0BGR
#dc.SetBkColor(0x000000FF)
dc.SetBkMode(win32con.TRANSPARENT)
if paint_each_string:
for idx, txt in enumerate(get_data_strings()):
dc.SelectObject(fonts[idx % len(fonts)])
dc.TextOut(x_y[0], x_y[1] + idx * scale_factor * font_scale * y_direction_scale, txt)
else:
dc.TextOut(*x_y, text())
pen = win32ui.CreatePen(0, 0, 0)
dc.SelectObject(pen)
dc.Ellipse((50, y_ellipsis, *x_y))
def paint_wnd(wnd, paint_each_string=True):
dc = wnd.GetWindowDC()
paint_dc(dc, False, paint_each_string=paint_each_string)
wnd.ReleaseDC(dc)
def paint_prn(printer_name, paint_each_string=True):
printer_name = printer_name or win32print.GetDefaultPrinter()
dc = win32ui.CreateDC()
dc.CreatePrinterDC(printer_name)
dc.SetMapMode(win32con.MM_TWIPS)
dc.StartDoc("Win32print")
#dc.StartPage()
paint_dc(dc, True, paint_each_string=paint_each_string)
#dc.EndPage()
dc.EndDoc()
def main():
print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
print(text())
time.sleep(0.1)
if len(sys.argv) > 1:
if sys.argv[1] == "window":
paint_func = paint_wnd
paint_func_dc_arg = win32ui.GetForegroundWindow()
else:
paint_func = paint_prn
paint_func_dc_arg = sys.argv[1]
else:
paint_func = paint_prn
paint_func_dc_arg = None
paint_func(paint_func_dc_arg, paint_each_string=True)
if __name__ == "__main__":
main()
Notes:
dc.SetBkColor
), and text color (dc.SetTextColor
), but I left it there and drew an ellipse (just for fun)time.sleep
is required there because outputting to HDC happens a lot faster than print (because of buffering), so even if according to code it happens after print, actually its effect happens before, and print "pushes" the window content (including our graphic output) up, so when the graphic output will go outside the visible area, it will be invalidated and that zone will be repainted, making it disappear. Output:
@EDIT0:
Added some printer specific functionality. Also, changed the behavior:
Output:
@EDIT1: