From d37abd6da08ac2500fe06f5e21e53c1f1ac4fead Mon Sep 17 00:00:00 2001 From: Philipp Klaus Date: Sat, 12 Dec 2015 00:52:11 +0100 Subject: [PATCH] initial commit --- reader.py | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100755 reader.py diff --git a/reader.py b/reader.py new file mode 100755 index 0000000..6813953 --- /dev/null +++ b/reader.py @@ -0,0 +1,122 @@ +#!/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()