comparison zebra.py @ 29:63d1260cc64e 0.1.0

- class name is now 'Zebra' instead of 'zebra' - Fix for missing win32print module in pypi - Drop python 2 support - use setuptools instead of distutils - improve documentation - Added reset(), reset_default(), autosense(), print_config_label() and print_graphic() functions
author Ben Croston <ben@croston.org>
date Tue, 01 Sep 2020 15:57:24 +0100
parents 7c132e01c281
children f77ca0963d6d
comparison
equal deleted inserted replaced
28:172de216b85d 29:63d1260cc64e
1 #!/usr/bin/env python 1 #!/usr/bin/env python3
2 2
3 # Copyright (c) 2011-2015 Ben Croston 3 # Copyright (c) 2011-2020 Ben Croston
4 # 4 #
5 # Permission is hereby granted, free of charge, to any person obtaining a copy of 5 # Permission is hereby granted, free of charge, to any person obtaining a copy of
6 # this software and associated documentation files (the "Software"), to deal in 6 # this software and associated documentation files (the "Software"), to deal in
7 # the Software without restriction, including without limitation the rights to 7 # the Software without restriction, including without limitation the rights to
8 # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
28 import win32print 28 import win32print
29 else: 29 else:
30 IS_WINDOWS = False 30 IS_WINDOWS = False
31 import subprocess 31 import subprocess
32 32
33 class zebra(object): 33 class Zebra:
34 """A class to communicate with (Zebra) label printers using EPL2""" 34 """A class to communicate with (Zebra) label printers"""
35 35
36 def __init__(self, queue=None): 36 def __init__(self, queue=None):
37 """queue - name of the printer queue (optional)""" 37 """queue - name of the printer queue (optional)"""
38 self.queue = queue 38 self.queue = queue
39 39
45 p.communicate(commands) 45 p.communicate(commands)
46 p.stdin.close() 46 p.stdin.close()
47 47
48 def _output_win(self, commands): 48 def _output_win(self, commands):
49 if self.queue == 'zebra_python_unittest': 49 if self.queue == 'zebra_python_unittest':
50 print commands 50 print(commands)
51 return 51 return
52 hPrinter = win32print.OpenPrinter(self.queue) 52 hPrinter = win32print.OpenPrinter(self.queue)
53 try: 53 try:
54 hJob = win32print.StartDocPrinter(hPrinter, 1, ('Label',None,'RAW')) 54 hJob = win32print.StartDocPrinter(hPrinter, 1, ('Label',None,'RAW'))
55 try: 55 try:
59 finally: 59 finally:
60 win32print.EndDocPrinter(hPrinter) 60 win32print.EndDocPrinter(hPrinter)
61 finally: 61 finally:
62 win32print.ClosePrinter(hPrinter) 62 win32print.ClosePrinter(hPrinter)
63 63
64 def output(self, commands): 64 def output(self, commands, encoding='cp437'):
65 """Output EPL2 commands to the label printer 65 """Send raw commands to the label printer
66 66
67 commands - EPL2 commands to send to the printer 67 commands - commands to send to the printer. Converted to a byte string if necessary.
68 encoding - Encoding used if 'commands' is not a byte string
68 """ 69 """
69 assert self.queue is not None 70 assert self.queue is not None
70 if sys.version_info[0] == 3: 71 if type(commands) != bytes:
71 if type(commands) != bytes: 72 commands = str(commands).encode(encoding=encoding)
72 commands = str(commands).encode()
73 else:
74 commands = str(commands).encode()
75 if IS_WINDOWS: 73 if IS_WINDOWS:
76 self._output_win(commands) 74 self._output_win(commands)
77 else: 75 else:
78 self._output_unix(commands) 76 self._output_unix(commands)
77
78 def print_config_label(self):
79 """
80 Send an EPL2 command to print label(s) with current config settings
81 """
82 self.output('\nU\n')
79 83
80 def _getqueues_unix(self): 84 def _getqueues_unix(self):
81 queues = [] 85 queues = []
82 try: 86 try:
83 output = subprocess.check_output(['lpstat','-p'], universal_newlines=True) 87 output = subprocess.check_output(['lpstat','-p'], universal_newlines=True)
104 def setqueue(self, queue): 108 def setqueue(self, queue):
105 """Set the printer queue""" 109 """Set the printer queue"""
106 self.queue = queue 110 self.queue = queue
107 111
108 def setup(self, direct_thermal=None, label_height=None, label_width=None): 112 def setup(self, direct_thermal=None, label_height=None, label_width=None):
109 """Set up the label printer. Parameters are not set if they are None. 113 """Set up the label printer using EPL2. Parameters are not set if they are None.
114 Not necessary if using AutoSense (hold feed button while powering on)
110 115
111 direct_thermal - True if using direct thermal labels 116 direct_thermal - True if using direct thermal labels
112 label_height - tuple (label height, label gap) in dots 117 label_height - tuple (label height, label gap) in dots
113 label_width - in dots 118 label_width - in dots
114 """ 119 """
115 commands = '\n' 120 commands = '\n'
116 if direct_thermal: 121 if direct_thermal:
117 commands += ('OD\n') 122 commands += 'OD\n'
118 if label_height: 123 if label_height:
119 commands += ('Q%s,%s\n'%(label_height[0],label_height[1])) 124 commands += 'Q%s,%s\n'%(label_height[0],label_height[1])
120 if label_width: 125 if label_width:
121 commands += ('q%s\n'%label_width) 126 commands += 'q%s\n'%label_width
122 self.output(commands) 127 self.output(commands)
123 128
129 def reset_default(self):
130 """Reset the printer to factory settings using EPL2"""
131 self.output('\n^default\n')
132
133 def reset(self):
134 """Resets the printer using EPL2 - equivalent to switching off/on"""
135 self.output('\n^@\n')
136
137 def autosense(self):
138 """Run AutoSense by sending an EPL2 command
139 Get the printer to detect label and gap length and set the sensor levels
140 """
141 self.output('\nxa\n')
142
124 def store_graphic(self, name, filename): 143 def store_graphic(self, name, filename):
125 """Store a .PCX file on the label printer 144 """Store a 1 bit PCX file on the label printer, using EPL2.
126 145
127 name - name to be used on printer 146 name - name to be used on printer
128 filename - local filename 147 filename - local filename
129 """ 148 """
130 assert filename.lower().endswith('.pcx') 149 assert filename.lower().endswith('.pcx')
133 size = os.path.getsize(filename) 152 size = os.path.getsize(filename)
134 commands += 'GM"%s"%s\n'%(name,size) 153 commands += 'GM"%s"%s\n'%(name,size)
135 self.output(commands) 154 self.output(commands)
136 self.output(open(filename,'rb').read()) 155 self.output(open(filename,'rb').read())
137 156
157 def print_graphic(self, x, y, width, length, data, qty):
158 """Print a label from 1 bit data, using EPL2
159
160 x,y - top left coordinates of the image, in dots
161 width - width of image, in dots. Must be a multiple of 8.
162 length - length of image, in dots
163 data - raw graphical data, in bytes
164 qty - number of labels to print
165 """
166 assert type(data) == bytes
167 assert width % 8 == 0 # make sure width is a multiple of 8
168 assert (width//8) * length == len(data)
169 commands = b"\nN\nGW%d,%d,%d,%d,%s\nP%d\n"%(x, y, width//8, length, data, qty)
170 self.output(commands)
171
138 if __name__ == '__main__': 172 if __name__ == '__main__':
139 z = zebra() 173 z = Zebra()
140 print 'Printer queues found:',z.getqueues() 174 print('Printer queues found:',z.getqueues())
141 z.setqueue('zebra_python_unittest') 175 z.setqueue('zebra_python_unittest')
142 z.setup(direct_thermal=True, label_height=(406,32), label_width=609) # 3" x 2" direct thermal label 176 z.setup(direct_thermal=True, label_height=(406,32), label_width=609) # 3" x 2" direct thermal label
143 z.store_graphic('logo','logo.pcx') 177 z.store_graphic('logo','logo.pcx')
144 label = """ 178 label = """
145 N 179 N