Windows Printing using win32print
Geoffrey Gerrietts
geoff at homegain.com
Tue Jun 26 16:10:14 EDT 2001
It's funny, I was asking a question about printing thru a different
mechanism prior to this discussion coming up. I'm using the Windows GDI
calls to paint text on printer device context.
I've been writing code to dump a simple text file to the printer. I think
that I've seen a half-dozen people talking about ways to do it, but none of
them are very simple or straightforward.
The solution I arrived at is below -- it's pretty easy to change the
file.readlines() call to a string.split() call and make this print multiline
strings for you. It's not elegant code, or even something I particularly
want my name associated with just yet, but it does do the trick.
The big "issue" right now is that it seems to underrun its pages somewhat,
and nobody seems able to tell me how to retrieve the page dimensions from
the device context.
Anyone who can help with /that/, I'd appreciate greatly. :)
(code follows .sig)
Thanks,
--G.
---
Geoff Gerrietts <geoff at homegain.com>
Software Engineer, HomeGain.com
510-655-0800 x4320
import win32ui, win32con
import math, string, sys
# 20 TWIPS per point
# 72 points per inch
# 1440 TWIPS per inch
INCH = 1440
MAXW = int(INCH * 8.5)
BUFW = INCH / 4
MAXH = int(INCH * 11)
BUFH = INCH / 4
fonts = {}
metrics = {}
files = []
def createFonts():
global fonts
normal = {
'name': 'Courier New',
'size': 12,
'weight': 400
}
bold = {
'name': 'Courier New',
'size': 12,
'weight': 700
}
italic = {
'name': 'Courier New',
'size': 12,
'weight': 400,
'italic': 1
}
for i in ['normal', 'bold', 'italic']:
d = locals().get(i)
f = win32ui.CreateFont(d)
fonts[i] = f
def prepareDevice():
global metrics
fonts['orig'] = dc.SelectObject(fonts['normal'])
m = dc.GetTextMetrics()
metrics['width'] = w = m['tmMaxCharWidth']
metrics['height'] = h = m['tmHeight']
lines = int((MAXH - (2 * BUFH))/ (h * 1.5))
lines = lines - 4
cols = (MAXW - (2 * BUFW)) / w
metrics['lines'] = lines
metrics['cols'] = cols
def processFile(file):
global pages, metrics
col = metrics['cols']
lin = metrics['lines']
# in a real app we wouldn't use bigtext
# we'd use readlines here
lines = file.readlines()
formlines = []
# here we break our input into page-oriented lines.
# if we were going to do line numbering and such, this would be the
# place to do it.
for line in lines:
line = line[:-1] # snip the end of line
while len(line) > col:
try:
idx = string.rindex(line," ",0,col-1)
except ValueError:
idx = col-1
formlines.append(line[:idx])
line = line[idx:]
# repeat shortening line until it fits on one line
formlines.append(line)
# do this for all lines in the input
# clean up our memory
del lines
# now paginate
totlines = len(formlines)
pagecount = int(math.ceil(totlines/float(lin)))
pages = []
for i in range(0,pagecount*lin,lin):
page = formlines[i:i+lin]
pages.append(page)
# subtract 'height' increments, and textout at BUFW.
def setup():
global dc, fn, oldfn
dc = win32ui.CreateDC()
dc.CreatePrinterDC()
dc.SetMapMode(win32con.MM_TWIPS)
createFonts()
prepareDevice()
def printPage(page, header):
dc.StartPage()
# would do the page header & footer here ordinarily...
h = metrics['height']
hpos = int((BUFH + (h * 1.5)) * -1)
f = dc.SelectObject(fonts['bold'])
dc.TextOut(BUFW, hpos, header)
dc.SelectObject(f)
# body starts 2 lines + bufh + h down the page
pos = ((h * 3) + BUFH + h) * -1
for line in page:
# print in bufw chars
dc.TextOut(BUFW, pos, line)
pos = pos - int(h * 1.5)
dc.EndPage()
def printDocument(name):
global pages
dc.StartDoc(name)
# calculate the length (in chars) of the page info
s = "%d" % len(pages)
plen = (2 * len(s)) + 4
# make a dict: space reserved for name, and for page info
d = {'name': metrics['cols'] - plen, 'page': plen }
# create a header template based on that
hdrtmpl = "%%-%(name)d.%(name)ds %%%(page)d.%(page)ds" % d
pp = "%d of " + str(len(pages))
for pageno in range(len(pages)):
page = pages[pageno]
p = pp % (pageno + 1)
hdr = hdrtmpl % (name, p)
printPage(page, hdr)
dc.EndDoc()
def openFiles():
global files
flist = sys.argv[1:]
for file in flist:
try:
f = open(file)
files.append(f)
except:
print "Could not open %s" % f
# setup opens the dc, creates the fonts, calculates the metrics
# processFile reads file, handles linebreaks, and paginates
# printDocument prints a parsed document
setup()
openFiles()
for file in files:
processFile(file)
printDocument(file.name)
More information about the Python-list
mailing list