initial commit
This commit is contained in:
@@ -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()
|
||||
Reference in New Issue
Block a user