-
Notifications
You must be signed in to change notification settings - Fork 2
/
printer_tspl.py
131 lines (100 loc) · 3.63 KB
/
printer_tspl.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#!/usr/bin/env python3
import io
import usb.core
import usb.util
import multiprocessing
class PrinterTSPL():
def __init__(self, vid, pid):
dev = usb.core.find(idVendor=vid, idProduct=pid)
if dev is None:
raise ValueError('PrinterVretti420B: device not found')
self.dev = dev
self.print_proc = None
if dev.is_kernel_driver_active(0):
dev.detach_kernel_driver(0)
dev.set_configuration()
cfg = dev.get_active_configuration()
intf = cfg[(0,0)]
self.ep_out = usb.util.find_descriptor(intf,
# match the first OUT endpoint
custom_match = \
lambda e: \
usb.util.endpoint_direction(e.bEndpointAddress) == \
usb.util.ENDPOINT_OUT)
self.ep_in = usb.util.find_descriptor(intf,
# match the first IN endpoint
custom_match = \
lambda e: \
usb.util.endpoint_direction(e.bEndpointAddress) == \
usb.util.ENDPOINT_IN)
assert (self.ep_out is not None) and (self.ep_in is not None)
@property
def dpi(self):
return 203
# In mm, (left, top, right, bottom)
def padding(self):
return (3, 0, 3, 0)
def write_command(self, command_str):
buf = bytes(f"\r\n{command_str}\r\n", "utf-8")
self.ep_out.write(buf)
def calibrate(self, label_mm, gap_mm):
label_dots = int(label_mm * 8)
gap_dots = int(gap_mm * 8)
self.write_command(f"GAPDETECT {label_dots},{gap_dots}")
def form_feed(self):
self.write_command("FORMFEED")
def home(self):
self.write_command("HOME")
def backfeed(self, distance_mm):
dots = int(distance_mm * 8)
self.write_command(f"BACKUP {dots}")
def close(self):
usb.util.dispose_resources(self.dev)
self.dev = None
def __print_image(self, width, height, image_data):
nbytes = (width + 7) // 8
buf = io.BytesIO()
# TODO: I don't know why x offset of 70 is needed
buf.write(bytes(f"\r\nBITMAP 70,0,{nbytes},{height},0,", "utf-8"))
for row in range(height):
line = bytearray(nbytes)
for byte, _ in enumerate(line):
b = 0xff
for bit in range(8):
col = (byte * 8) + bit
if col >= width:
break
idx = row * width + col
v = image_data[idx]
if v == 0:
b &= ~(1 << (7 - bit))
line[byte] = b
buf.write(line)
buf.write(b"\r\n")
self.write_command(f"SIZE {height},{width}")
self.write_command("DIRECTION 0")
self.write_command("CLS")
self.ep_out.write(buf.getvalue())
self.write_command("PRINT 1,1")
def print_image(self, image, thread=False):
# Always wait for any previous print job
if self.print_proc:
self.print_proc.join()
self.print_proc = None
width = image.width
height = image.height
image_data = image.getdata()
if thread:
self.print_proc = multiprocessing.Process(target=self.__print_image,
args=(width, height, image_data))
self.print_proc.start()
else:
self.__print_image(width, height, image_data)
class PrinterVretti420B(PrinterTSPL):
def __init__(self):
super().__init__(0x2d84, 0x71a9)
def main():
printer = PrinterVretti420B()
printer.calibrate(89, 5)
if __name__ == "__main__":
main()