Files
brother_ql/reader.py
T
Philipp Klaus d37abd6da0 initial commit
2015-12-12 00:52:11 +01:00

123 lines
5.1 KiB
Python
Executable File

#!/usr/bin/env python
import io
import logging
from PIL import Image
import numpy as np
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': ("set mode", 1, ""),
b'\x1b\x69\x41': ("cuts-settings", 1, "cut every n setting"),
b'\x1b\x69\x4B': ("cut type", 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 = {
62: 90*8,
}
def hex_format(data):
return ' '.join('{:02X}'.format(byte) for byte in data)
class BrotherReader(object):
def __init__(self, brother_file):
if type(brother_file) in (str,):
brother_file = io.open(brother_file, 'rb')
self.brother_file = brother_file
self.width, self.height = None, None
self.rows = []
self.compression = False
self.page = 1
def analyze(self):
rem_script = self.brother_file.read()
while True:
if len(rem_script) == 0: break
cmd_found = False
for command in cmds.keys():
if rem_script.startswith(command):
cmd = cmds[command]
num_bytes = len(command)
if cmd[1] > 0: num_bytes += cmd[1]
if cmd[0] == 'init':
self.width, self.height = None, 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
logger.info(" {} ({}) --> found! (payload: {})".format(cmd[0], hex_format(command), hex_format(payload)))
if cmd[0] == 'compression':
self.compression = payload[0] == 0x02
if cmd[0] == 'raster':
rpl = payload[2:] # raster payload
index = 0
row = []
if self.compression:
while True:
num = rpl[index]
if num & 0x80:
num = num - 0x100
if num < 0:
num = -num + 1
for i in range(num): row.append(rpl[index+1])
index += 2
else:
num = num + 1
for i in range(num): row.append(rpl[index+1+i])
index += 1 + num
if index >= len(rpl): break
else:
raise NotImplementedError()
self.rows.append(row)
if cmd[0] == 'media/quality':
self.height = rem_script[len(command) + 4] + rem_script[len(command) + 5]*256
self.width = rem_script[len(command) + 2] + rem_script[len(command) + 3]*256
logger.info(" width: {}mm height: {}dots".format(self.width, self.height))
if cmd[0] == 'print':
self.rows = [np.unpackbits(np.array(row, dtype=np.uint8)) for row in self.rows]
array = np.array(self.rows, dtype=np.uint8)
im = Image.fromarray(array)
im = im.point(lambda x: 0 if x == 1 else 255, '1') # -> Monocolor and invert
#plt.imshow(im)
#plt.show()
im.save('image{:04d}.png'.format(self.page))
self.page += 1
rem_script = rem_script[num_bytes:]
cmd_found = True
if cmd_found:
continue
else:
logger.error('cmd not found: {}...'.format(rem_script[0:4]))
rem_script = rem_script[1:]
if __name__ == '__main__':
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument('file', help='The file to analyze')
parser.add_argument('--loglevel', type=lambda x: getattr(logging, x), default=logging.WARNING, help='The loglevel to apply')
args = parser.parse_args()
logging.basicConfig(format='%(levelname)s: %(message)s', level=args.loglevel)
br = BrotherReader(args.file)
br.analyze()