I receive an ESC/P protocol from a device via a serial interface. The device is actually intended to be connected to a dot matrix printer. Since we do not want to use printers, I am currently working on a solution to receive the stream with a software and save it in a BMP file for further use. I have been searching the web for a long time for a library for Python or other solutions on this topic and have unfortunately not found anything. So I read up on the ESC/P protocol and tried to write my own Python routine. In case others have the same problem, I'll post my solution here. I would be very happy about feedback or suggestions for improvement.
from PIL import Image
import struct, io
def parse_ESCP_bytes(data):
image_list = []
while data:
# Search for the start character (ESC) and the ASCII asterisk
start_index = data.find(b'\x1b*')
if start_index != -1:
# Extract the number of columns with the low and high bytes
num_columns_low, num_columns_high = struct.unpack('>BB', data[start_index+3:start_index+5])
num_columns = (num_columns_high << 8) + num_columns_low
# Read all bytes of the image data
image_data = struct.unpack('>' + 'B' * num_columns, data[start_index + 5:start_index + 5 + num_columns])
# The image data has the following format:
# [0, 7, 15, ...] each 8-bit value represents a column with 8 rows.
# 0 = No pixels, 7 = pixels 6, 7, 8 of this column are set (counted from the top).
# Thus, for each image data row we read, 8 new image rows are added to our list
for i in range(7, -1, -1):
image_list.append([col >> i & 1 for col in image_data])
# Update the data for the next iteration
data = data[start_index + 5 + num_columns + 2:]
# Control characters for DPI or paper feed or carriage return are not considered here.
else:
break
# Define the width and height of the pixel matrix
width, height = len(image_list), len(image_list[0])
# Create the binary black and white image
img = Image.new('1', (width, height))
# Set the pixels based on the pixel matrix
img.putdata([int(pixel) for row in image_list for pixel in row])
img_byte_arr = io.BytesIO()
img.save(img_byte_arr, format='BMP')
return img_byte_arr.getvalue()
with open("ESCP", "rb") as file:
raw_serial = file.read()
image_bytes = parse_ESCP_bytes(raw_serial)
with open("output.bmp", 'wb') as file:
file.write(image_bytes)