|
2 | 2 | from .pixel_sans.charset import charset |
3 | 3 | from .ESCPOS_constants import * |
4 | 4 | import socket |
| 5 | +from PIL import Image |
5 | 6 |
|
6 | 7 |
|
7 | 8 | class Printer: |
@@ -137,3 +138,70 @@ def print_charset(self): |
137 | 138 | ] |
138 | 139 | ) |
139 | 140 | self.print_text(char_string_split) |
| 141 | + |
| 142 | + # from https://github.com/vivier/phomemo-tools |
| 143 | + def print_image(self, image_path): |
| 144 | + """ |
| 145 | + Print an image |
| 146 | +
|
| 147 | + Args: |
| 148 | + image_path (str): Path to an image file to print |
| 149 | + """ |
| 150 | + image = Image.open(image_path) |
| 151 | + if image.width > image.height: |
| 152 | + image = image.transpose(Image.ROTATE_90) |
| 153 | + |
| 154 | + # width 384 dots |
| 155 | + IMAGE_WIDTH_BYTES = 70 |
| 156 | + IMAGE_WIDTH_BITS = IMAGE_WIDTH_BYTES * 8 |
| 157 | + image = image.resize( |
| 158 | + size=(IMAGE_WIDTH_BITS, int(image.height * IMAGE_WIDTH_BITS / image.width)) |
| 159 | + ) |
| 160 | + |
| 161 | + # black&white printer: dithering |
| 162 | + image = image.convert(mode="1") |
| 163 | + |
| 164 | + self._print_bytes(HEADER) |
| 165 | + for start_index in range(0, image.height, 256): |
| 166 | + end_index = ( |
| 167 | + start_index + 256 if image.height - 256 > start_index else image.height |
| 168 | + ) |
| 169 | + line_height = end_index - start_index |
| 170 | + |
| 171 | + BLOCK_MARKER = ( |
| 172 | + GSV0 |
| 173 | + + bytes([IMAGE_WIDTH_BYTES]) |
| 174 | + + b"\x00" |
| 175 | + + bytes([line_height - 1]) |
| 176 | + + b"\x00" |
| 177 | + ) |
| 178 | + self._print_bytes(BLOCK_MARKER) |
| 179 | + |
| 180 | + image_lines = [] |
| 181 | + for image_line_index in range(line_height): |
| 182 | + image_line = b"" |
| 183 | + for byte_start in range(int(image.width / 8)): |
| 184 | + byte = 0 |
| 185 | + for bit in range(8): |
| 186 | + if ( |
| 187 | + image.getpixel( |
| 188 | + (byte_start * 8 + bit, image_line_index + start_index) |
| 189 | + ) |
| 190 | + == 0 |
| 191 | + ): |
| 192 | + byte |= 1 << (7 - bit) |
| 193 | + # 0x0a breaks the rendering |
| 194 | + # 0x0a alone is processed like LineFeed by the printe |
| 195 | + if byte == 0x0A: |
| 196 | + byte = 0x14 |
| 197 | + # self._print_bytes(byte.to_bytes(1, 'little')) |
| 198 | + image_line += byte.to_bytes(1, "little") |
| 199 | + |
| 200 | + image_lines.append(image_line) |
| 201 | + |
| 202 | + for l in image_lines: |
| 203 | + self._print_bytes(l) |
| 204 | + |
| 205 | + self._print_bytes(PRINT_FEED) |
| 206 | + self._print_bytes(PRINT_FEED) |
| 207 | + self._print_bytes(FOOTER) |
0 commit comments