Python win32print
python 调用win32print
背景
POS机打印小票含有中文, 英文, 高棉语、图片等信息,高棉语的无法正常输出。原因是大多嵌入式打印小票打印机只提供了英文字库,国产的做了中文字库的装载。而类似小国家的非常的库没有厂商愿做。
解决办法(Windows 平台)
- 适配字库, 然后调用DLL;
- 生成word docx、txt、rtf文件, 调用print 命令打印;
- win32 api把打印合成图片, 使用win32print以图片bmp格式打印;
前提是已配置好打印机,可以在word或记事本里能正常打印
HORZRES = 8
VERTRES = 10
LOGPIXELSX = 88
LOGPIXELSY = 90
PHYSICALWIDTH = 110
PHYSICALHEIGHT = 111
from PIL import ImageWin
import win32gui, win32ui, win32print, win32con, win32api
scale_factor = 20
pr_dict = dict()
paper_sizes = {
"letter": 1,
"lettersmall": 2,
"tabloid": 3,
"ledger": 4,
"legal": 5,
"statement": 6,
"executive": 7,
"a3": 8,
"a4": 9,
"envelope9": 19,
"envelope10": 20,
"envelope11": 21,
"envelope12": 22,
"envelope14": 23,
"fanfold": 39,
}
orientations = {
"portrait": 1,
"landscape": 2,
}
duplexes = {
"normal": 1,
"none": 1,
"long": 2,
"short": 3,
}
class Document:
def __init__(self, printer=None, paper_size=None, orientation=None, duplex=None):
self.dc = None
self.font = None
self.printer = printer
self.paper_size = paper_size
self.orientation = orientation
self.page = 0
self.duplex = duplex
self.pen = None
self.hdc = None
self.h_printer = None
def scale_pos(self, pos):
rc, _ = list(), self
for i in range(len(pos)):
p = pos[i]
if i % 2:
p *= -1
rc.append(int(p * scale_factor))
return tuple(rc)
def begin_document(self, name="DMallPOS print job"):
# open the printer
if self.printer is None:
self.printer = win32print.GetDefaultPrinter()
self.h_printer = win32print.OpenPrinter(self.printer)
# load default settings
dev_mode = win32print.GetPrinter(self.h_printer, 8)["pDevMode"]
# change paper size and orientation
if self.paper_size is not None:
if type(self.paper_size) is int:
dev_mode.PaperSize = self.paper_size
else:
dev_mode.PaperSize = paper_sizes[self.paper_size]
if self.orientation is not None:
dev_mode.Orientation = orientations[self.orientation]
if self.duplex is not None:
dev_mode.Duplex = duplexes[self.duplex]
# create dc using new settings
self.hdc = win32gui.CreateDC("WINSPOOL", self.printer, dev_mode)
self.dc = win32ui.CreateDCFromHandle(self.hdc)
# self.dc = win32ui.CreateDC()
# if self.printer is not None:
# self.dc.CreatePrinterDC(self.printer)
# else:
# self.dc.CreatePrinterDC()
self.dc.SetMapMode(win32con.MM_TWIPS) # hundredths of inches
self.dc.StartDoc(name)
self.dc.SetBkMode(win32con.TRANSPARENT)
self.pen = win32ui.CreatePen(0, int(scale_factor), 0)
self.dc.SelectObject(self.pen)
win32gui.SetBkMode(self.hdc, 1) # transparent
self.page = 1
def end_document(self):
if self.page == 0:
return # document was never started
self.dc.EndDoc()
del self.dc
def end_page(self):
if self.page == 0:
return # nothing on the page
# end page gets stupid if the page is completely blank
self.text((1, 1), " ")
self.dc.EndPage()
self.page += 1
def getsize(self):
if not self.page:
self.begin_document()
# returns printable (width, height) in points
width = float(self.dc.GetDeviceCaps(HORZRES)) * (72.0 / self.dc.GetDeviceCaps(LOGPIXELSX))
height = float(self.dc.GetDeviceCaps(VERTRES)) * (72.0 / self.dc.GetDeviceCaps(LOGPIXELSY))
return width, height
def line(self, from_, to):
if not self.page:
self.begin_document()
self.dc.MoveTo(self.scale_pos(from_))
self.dc.LineTo(self.scale_pos(to))
def rectangle(self, box):
if not self.page:
self.begin_document()
self.dc.MoveTo(self.scale_pos((box[0], box[1])))
self.dc.LineTo(self.scale_pos((box[2], box[1])))
self.dc.LineTo(self.scale_pos((box[2], box[3])))
self.dc.LineTo(self.scale_pos((box[0], box[3])))
self.dc.LineTo(self.scale_pos((box[0], box[1])))
def text(self, position, text):
if self.page == 0:
self.begin_document()
self.dc.TextOut(int(scale_factor * position[0]),
int(-1 * scale_factor * position[1]), text)
def set_font(self, name, size, bold=None, italic=None):
if not self.page:
self.begin_document()
wt = 400
if bold:
wt = 700
if italic:
italic = 1
else:
italic = 0
self.font = get_font(name, size, wt, italic)
self.dc.SelectObject(self.font)
def image(self, position, image, size):
"""print PIL image at position with given size"""
if ImageWin is None:
raise Exception()
if self.page == 0:
self.begin_document()
dib = ImageWin.Dib(image)
end_pos = (position[0] + size[0], position[1] + size[1])
dst = (position[0] * scale_factor, -1 * position[1] * scale_factor,
end_pos[0] * scale_factor, -1 * end_pos[1] * scale_factor)
dib.draw(self.hdc, dst)
def set_ink(self, ink):
win32gui.SetTextColor(self.hdc, win32api.RGB(*ink))
def set_fill(self, on_off):
pass
def build_dict():
global pr_dict
lst = win32print.EnumPrinters(
win32print.PRINTER_ENUM_CONNECTIONS
+ win32print.PRINTER_ENUM_LOCAL)
pr_dict = {}
for flags, description, name, comment in lst:
pr_dict[name] = {}
pr_dict[name]["flags"] = flags
pr_dict[name]["description"] = description
pr_dict[name]["comment"] = comment
def list_printers():
dft = win32print.GetDefaultPrinter()
if pr_dict is None:
build_dict()
keys = pr_dict.keys()
keys.sort()
rc = [dft]
for k in keys:
if k != dft:
rc.append(k)
return rc
def desc(name):
not pr_dict and list_printers()
return pr_dict[name]
def get_font(name, size, weight=400, italic=0):
if italic:
return win32ui.CreateFont({"name": name, "height": scale_factor * size, "weight": weight, "italic": italic,})
else:
return win32ui.CreateFont({"name": name, "height": scale_factor * size, "weight": weight, })
if __name__ == "__main__":
doc = Document(orientation="portrait")
doc.begin_document()
doc.set_font("Khmer UI", 12, bold=True)
doc.text((0, 0), "ញ្ចូលមាតិកាជាភាសាខ្មែរដែលអ្នកចង់បកប្រែខាងក្រោម")
doc.set_font("Khmer UI", 12, bold=False)
doc.text((0, 48), "ញ្ចូលមាតិកាជាភាសាខ្មែរដែលអ្នកចង់បកប្រែខាងក្រោម")
doc.set_font("宋体", 12)
doc.text((0, 48 + 48), "羅拔臣什味啫喱粉")
# doc.rectangle((72, 72, 72*6, 72*3))
# doc.line((72, 72), (72*6, 72*3))
from PIL import Image
img = Image.open("a.bmp", )
doc.image((0, 100), img, img.size)
doc.end_document()
from win32com import client
c = client.Dispatch("OPOS.CashDrawer")
c.Open("StanderU")
c.ClaimDevice(1000)
c.DeviceEnabled = True
c.OpenDrawer()
c.DeviceEnabled = False
c.Release()
c.Close()