Files
PrecIR/tools_python/img2dm.py
Furrtek 405e27f69a Moved files, added ESL Blaster protocol info
Removed line used for debug in ESL Blaster FW
2019-07-25 08:38:11 +02:00

179 lines
4.4 KiB
Python

# Converts, compresses and transmits images to dot matrix ESLs
# 2018 furrtek - furrtek.org
# See LICENSE
import pr
import tx
from imageio import imread
import sys
def record_run(run_count):
# Convert to binary
del bits[:]
while run_count:
bits.insert(0, run_count & 1)
run_count >>= 1
# Zero length coding
for b in bits[1:]:
compressed.append(0)
if len(bits):
compressed.extend(bits)
def usage():
print("img2dm - Transmits image to Dot Matrix ESL\n")
print("Usage:")
print("img2dm.py port image barcode page (x y)\n")
print(" port: serial port name (0 for ESL Blaster)")
print(" image: image file")
print(" barcode: 17-character barcode data")
print(" page: page number to update (0~15)")
print(" x y: top-left position of image, default: 0 0")
exit()
arg_count = len(sys.argv)
if arg_count < 5:
usage()
port = sys.argv[1]
# Search for connected ESL Blaster if required
if (port == "0"):
blaster_port = tx.search_esl_blaster()
if (blaster_port == "0"):
exit()
# Open image file
image = imread(sys.argv[2])
width = image.shape[1]
height = image.shape[0]
if width > 208 or height > 112:
print("Image should be 208*112 pixels or less.")
exit()
# Get PLID from barcode string
PLID = pr.get_plid(sys.argv[3])
page = int(sys.argv[4])
if page < 0 or page > 15:
print("Page can only be between 0 and 15.")
exit()
if arg_count > 5:
pos_x = int(sys.argv[5])
else:
pos_x = 0
if arg_count > 6:
pos_y = int(sys.argv[6])
else:
pos_y = 0
bits = []
size_raw = width * height
# Convert image to 1-bit
pixels = []
for row in image:
for rgb in row:
pixels.append(int(round((0.21 * rgb[0] + 0.72 * rgb[1] + 0.07 * rgb[2]) / 255)))
print("Compressing %i pixels..." % size_raw)
# First pixel
compressed = []
run_pixel = pixels[0]
run_count = 1
compressed.append(run_pixel)
for pixel in pixels[1:]:
if pixel == run_pixel:
# Add to run
run_count += 1
else:
# Record run
record_run(run_count)
run_count = 1
run_pixel = pixel
# Record last run
if run_count > 1:
record_run(run_count)
size_compressed = len(compressed)
# Decide on compression or not
if size_compressed < size_raw:
print("Compression ratio: %.1f%%" % (100 - ((size_compressed * 100) / float(size_raw))))
data = compressed
compression_type = 2
else:
print("Compression ratio suxx, using raw data")
data = pixels
compression_type = 0
# Pad data to multiple of bits_per_frame
bits_per_frame = 20 * 8
data_size = len(data)
padding = bits_per_frame - (data_size % bits_per_frame)
for b in range(0, padding):
data.append(0)
padded_data_size = len(data)
frame_count = padded_data_size // bits_per_frame
frames = []
# Ping frame
frames.append(pr.make_ping_frame(PLID, 400))
print("Generating %i data frames..." % frame_count)
# Parameters frame
frame = pr.make_mcu_frame(PLID, 0x05)
pr.append_word(frame, data_size // 8) # Byte count
frame.append(0x00) # Unused
frame.append(compression_type)
frame.append(page)
pr.append_word(frame, width)
pr.append_word(frame, height)
pr.append_word(frame, pos_x)
pr.append_word(frame, pos_y)
pr.append_word(frame, 0x0000) # Keycode
frame.append(0x88) # 0x80 = update, 0x08 = set base page
pr.append_word(frame, 0x0000) # Enabled pages (bitmap)
frame.extend([0x00, 0x00, 0x00, 0x00])
pr.terminate_frame(frame, 1)
frames.append(frame)
# Data frames
i = 0
for fr in range(0, frame_count):
frame = pr.make_mcu_frame(PLID, 0x20)
pr.append_word(frame, fr)
for by in range(0, 20):
v = 0
# Bit string to byte
for bi in range(0, 8):
v <<= 1
v += data[i + bi]
frame.append(v)
i += 8
pr.terminate_frame(frame, 1)
frames.append(frame)
# Refresh frame
frames.append(pr.make_refresh_frame(PLID))
# DEBUG
#f = open("out.txt", "w")
#for fr in frames:
# for b in fr:
# f.write(format(b, '02X') + " ")
# f.write("\n")
#exit()
# Send data to IR transmitter
if (port == "0"):
tx.transmit_esl_blaster(frames, blaster_port)
else:
tx.transmit_serial(frames, port)
print("Done. Please allow a few seconds for the ESL to refresh.")