Reworking brother_ql/reader.py
The code used in BrotherQLReader.analyse() is now is now split into a chunker() function which separates (=chunks) a data stream of bytes into individual printer instructions and into the main functionality of the analyse() method: Stating debug information about each instruction and generating images of the expected printer output.
This commit is contained in:
+56
-37
@@ -12,21 +12,21 @@ from matplotlib import pyplot as plt
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
cmds = {
|
||||
# signature name following bytes description
|
||||
b'\x00': ("preamble", 0, "Preamble, 200-300x 0x00 to clear comamnd buffer"),
|
||||
b'\x4D': ("compression", 1, ""),
|
||||
b'\x67': ("raster", -1, ""),
|
||||
b'\x0C': ("print", 0, "print intermediate page"),
|
||||
b'\x1A': ("print", 0, "print final page"),
|
||||
b'\x1b\x40': ("init", 0, "initialization"),
|
||||
b'\x1b\x69\x61': ("mode setting", 1, ""),
|
||||
b'\x1b\x69\x7A': ("media/quality", 10, "print-media and print-quality"),
|
||||
b'\x1b\x69\x4D': ("various", 1, "Auto cut flag in bit 7"),
|
||||
b'\x1b\x69\x41': ("cut-every", 1, "cut every n-th page"),
|
||||
b'\x1b\x69\x4B': ("expanded", 1, ""),
|
||||
b'\x1b\x69\x64': ("margins", 2, ""),
|
||||
b'\x1b\x69\x55\x77\x01': ('amedia',127, "Additional media information command"),
|
||||
b'\x1b\x69\x55\x4A': ('jobid', 14, "Job ID setting command"),
|
||||
# signature name following bytes description
|
||||
b'\x00': ("preamble", -1, "Preamble, 200-300x 0x00 to clear comamnd buffer"),
|
||||
b'\x4D': ("compression", 1, ""),
|
||||
b'\x67': ("raster", -1, ""),
|
||||
b'\x0C': ("print", 0, "print intermediate page"),
|
||||
b'\x1A': ("print", 0, "print final page"),
|
||||
b'\x1b\x40': ("init", 0, "initialization"),
|
||||
b'\x1b\x69\x61': ("mode setting", 1, ""),
|
||||
b'\x1b\x69\x7A': ("media/quality", 10, "print-media and print-quality"),
|
||||
b'\x1b\x69\x4D': ("various", 1, "Auto cut flag in bit 7"),
|
||||
b'\x1b\x69\x41': ("cut-every", 1, "cut every n-th page"),
|
||||
b'\x1b\x69\x4B': ("expanded", 1, ""),
|
||||
b'\x1b\x69\x64': ("margins", 2, ""),
|
||||
b'\x1b\x69\x55\x77\x01': ('amedia', 127, "Additional media information command"),
|
||||
b'\x1b\x69\x55\x4A': ('jobid', 14, "Job ID setting command"),
|
||||
}
|
||||
|
||||
dot_widths = {
|
||||
@@ -39,6 +39,41 @@ def hex_format(data):
|
||||
except ValueError: # Py2
|
||||
return ' '.join('{:02X}'.format(ord(byte)) for byte in data)
|
||||
|
||||
def chunker(data, raise_exception=False):
|
||||
"""
|
||||
Breaks data stream (bytes) into a list of bytes containing single instructions each.
|
||||
|
||||
Logs warnings for unknown commands.
|
||||
If raise_exception is set to True it raise exceptions instead.
|
||||
|
||||
returns: list of bytes
|
||||
"""
|
||||
instructions = []
|
||||
while True:
|
||||
if len(data) == 0: break
|
||||
cmd_found = False
|
||||
for command in cmds.keys():
|
||||
if data.startswith(command):
|
||||
cmd = cmds[command]
|
||||
num_bytes = len(command)
|
||||
if cmd[1] > 0: num_bytes += cmd[1]
|
||||
if cmd[0] == 'raster':
|
||||
num_bytes += data[2] + 2
|
||||
#payload = data[len(command):num_bytes]
|
||||
instructions.append(data[:num_bytes])
|
||||
data = data[num_bytes:]
|
||||
cmd_found = True
|
||||
if cmd_found:
|
||||
continue
|
||||
else:
|
||||
msg = 'unknown instruction starting with {}...)'.format(hex_format(data[0:4]))
|
||||
if raise_exception:
|
||||
raise ValueError(msg)
|
||||
else:
|
||||
logger.warning(msg)
|
||||
data = data[1:]
|
||||
return instructions
|
||||
|
||||
class BrotherQLReader(object):
|
||||
|
||||
def __init__(self, brother_file):
|
||||
@@ -52,23 +87,16 @@ class BrotherQLReader(object):
|
||||
self.page = 1
|
||||
|
||||
def analyse(self):
|
||||
rem_script = self.brother_file.read()
|
||||
while True:
|
||||
if len(rem_script) == 0: break
|
||||
cmd_found = False
|
||||
instructions = self.brother_file.read()
|
||||
for instruction in chunker(instructions):
|
||||
for command in cmds.keys():
|
||||
if rem_script.startswith(command):
|
||||
if instruction.startswith(command):
|
||||
cmd = cmds[command]
|
||||
num_bytes = len(command)
|
||||
if cmd[1] > 0: num_bytes += cmd[1]
|
||||
if cmd[0] == 'init':
|
||||
self.mwidth, self.mheight = None, None
|
||||
self.raster_no = None
|
||||
self.rows = []
|
||||
if cmd[0] == 'raster':
|
||||
num_bytes += rem_script[2] + 2
|
||||
payload = rem_script[len(command):num_bytes]
|
||||
# now num_bytes and payload are accessable
|
||||
payload = instruction[len(command):]
|
||||
logger.info(" {} ({}) --> found! (payload: {})".format(cmd[0], hex_format(command), hex_format(payload)))
|
||||
if cmd[0] == 'compression':
|
||||
self.compression = payload[0] == 0x02
|
||||
@@ -95,8 +123,8 @@ class BrotherQLReader(object):
|
||||
self.rows.append(row)
|
||||
if cmd[0] == 'media/quality':
|
||||
self.raster_no = struct.unpack('<L', payload[4:8])[0]
|
||||
self.mwidth = rem_script[len(command) + 2]
|
||||
self.mlength = rem_script[len(command) + 3]*256
|
||||
self.mwidth = instruction[len(command) + 2]
|
||||
self.mlength = instruction[len(command) + 3]*256
|
||||
fmt = " media width: {}mm, media length: {}mm, raster no: {}dots"
|
||||
logger.info(fmt.format(self.mwidth, self.mlength, self.raster_no))
|
||||
if cmd[0] == 'print':
|
||||
@@ -111,12 +139,3 @@ class BrotherQLReader(object):
|
||||
im.save(img_name)
|
||||
print('Page saved as {}'.format(img_name))
|
||||
self.page += 1
|
||||
|
||||
rem_script = rem_script[num_bytes:]
|
||||
cmd_found = True
|
||||
if cmd_found:
|
||||
continue
|
||||
else:
|
||||
logger.error('cmd not found: {0}... ({1}...)'.format(hex_format(rem_script[0:4]), rem_script[0:4]))
|
||||
rem_script = rem_script[1:]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user