142 lines
4.3 KiB
Python
142 lines
4.3 KiB
Python
import seekablebitmap
|
|
|
|
import gc
|
|
import os
|
|
import struct
|
|
import time
|
|
|
|
import board
|
|
import digitalio
|
|
import keypad
|
|
import ulab.numpy as np
|
|
|
|
import adafruit_ble
|
|
from adafruit_ble import BLERadio
|
|
from adafruit_ble.advertising import Advertisement
|
|
|
|
from thermalprinter import CatPrinter
|
|
from seekablebitmap import imageopen
|
|
|
|
ble = BLERadio() # pylint: disable=no-member
|
|
|
|
buttons = keypad.Keys([board.BUTTON_A, board.BUTTON_B], value_when_pressed=False)
|
|
|
|
def pnmopen(filename):
|
|
"""
|
|
Scan for netpbm format info, skip over comments, and read header data.
|
|
|
|
Return the format, header, and the opened file positioned at the start of
|
|
the bitmap data.
|
|
"""
|
|
# pylint: disable=too-many-branches
|
|
image_file = open(filename, "rb")
|
|
magic_number = image_file.read(2)
|
|
image_file.seek(2)
|
|
pnm_header = []
|
|
next_value = bytearray()
|
|
while True:
|
|
# We have all we need at length 3 for formats P2, P3, P5, P6
|
|
if len(pnm_header) == 3:
|
|
return image_file, magic_number, pnm_header
|
|
|
|
if len(pnm_header) == 2 and magic_number in [b"P1", b"P4"]:
|
|
return image_file, magic_number, pnm_header
|
|
|
|
next_byte = image_file.read(1)
|
|
if next_byte == b"":
|
|
raise RuntimeError("Unsupported image format {}".format(magic_number))
|
|
if next_byte == b"#": # comment found, seek until a newline or EOF is found
|
|
while image_file.read(1) not in [b"", b"\n"]: # EOF or NL
|
|
pass
|
|
elif not next_byte.isdigit(): # boundary found in header data
|
|
if next_value:
|
|
# pull values until space is found
|
|
pnm_header.append(int("".join(["%c" % char for char in next_value])))
|
|
next_value = bytearray() # reset the byte array
|
|
else:
|
|
next_value += next_byte # push the digit into the byte array
|
|
|
|
def wait_for_press(kbd):
|
|
"""
|
|
Wait for a keypress and return the event
|
|
"""
|
|
while True:
|
|
event = kbd.events.get()
|
|
if event and event.pressed:
|
|
return event
|
|
|
|
def show(s):
|
|
"""
|
|
Display a message on the screen
|
|
"""
|
|
board.DISPLAY.auto_refresh = False
|
|
print("\n" * 24)
|
|
print(s)
|
|
board.DISPLAY.auto_refresh = True
|
|
|
|
def show_error(s):
|
|
"""
|
|
Display a message on the screen and wait for a button press
|
|
"""
|
|
show(s + "\nPress a button to continue")
|
|
wait_for_press(buttons)
|
|
|
|
def find_cat_printer(radio):
|
|
"""
|
|
Connect to the cat printer device using BLE
|
|
"""
|
|
while True:
|
|
show("Scanning for GB02 device...")
|
|
for adv in radio.start_scan(Advertisement):
|
|
complete_name = getattr(adv, 'complete_name')
|
|
if complete_name is not None:
|
|
print(f"Saw {complete_name}")
|
|
if complete_name == 'GB02':
|
|
radio.stop_scan()
|
|
return radio.connect(adv, timeout=10)[CatPrinter]
|
|
|
|
image_files = [i for i in os.listdir('/') if i.lower().endswith(".pbm") or i.lower().endswith(".bmp")]
|
|
image_files.sort(key=lambda filename: filename.lower())
|
|
|
|
def select_image():
|
|
i = 0
|
|
while True:
|
|
show(f"Select image file\nA: next image\nB: print this image\n\n{image_files[i]}")
|
|
event = wait_for_press(buttons)
|
|
if event.key_number == 0: # button "A"
|
|
i = (i + 1) % len(image_files)
|
|
if event.key_number == 1: # button "B"
|
|
return image_files[i]
|
|
|
|
printer = find_cat_printer(ble)
|
|
|
|
while True:
|
|
try:
|
|
filename = select_image()
|
|
|
|
show(f"Loading {filename}")
|
|
|
|
image = imageopen(filename)
|
|
if image.width != 384:
|
|
raise ValueError("Invalid image. Must be 384 pixels wide")
|
|
if image.bits_per_pixel != 1:
|
|
raise ValueError("Invalid image. Must be 1 bit per pixel (black & white)")
|
|
|
|
invert_image = image.palette and image.palette[0] == 0
|
|
|
|
show(f"Printing {filename}")
|
|
|
|
for i in range(image.height):
|
|
row_data = image.get_row(i)
|
|
if invert_image:
|
|
row_data = ~np.frombuffer(row_data, dtype=np.uint8)
|
|
printer.print_bitmap_row(row_data)
|
|
|
|
# Print blank lines until the paper can be torn off
|
|
for i in range(80):
|
|
printer.print_bitmap_row(b'\0' * 48)
|
|
|
|
except Exception as e:
|
|
show_error(str(e))
|
|
image_files.remove(filename)
|
|
continue
|