brother_ql_write script added
This commit is contained in:
65
brother_ql/create.py
Executable file
65
brother_ql/create.py
Executable file
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import sys, argparse, logging
|
||||
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
|
||||
from brother_ql.writer import QLRaster
|
||||
|
||||
def hex_format(data):
|
||||
return ' '.join('{:02X}'.format(byte) for byte in data)
|
||||
|
||||
def multiline_hex(data, bpl):
|
||||
""" data: bytes, bpl: int (bytes to be displayed per line) """
|
||||
data = hex_format(data).split()
|
||||
data = [' '.join(data[i:i+bpl]) for i in range(0, len(data), bpl)]
|
||||
return '\n'.join(data) + '\n'
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('image')
|
||||
parser.add_argument('outfile', nargs='?', type=argparse.FileType('wb'), default=sys.stdout.buffer)
|
||||
parser.add_argument('--model', default='QL-500')
|
||||
parser.add_argument('--threshold', type=int, default=170)
|
||||
parser.add_argument('--loglevel', type=lambda x: getattr(logging, x), default=logging.WARNING)
|
||||
args = parser.parse_args()
|
||||
|
||||
logging.basicConfig(level=args.loglevel)
|
||||
|
||||
im = Image.open(args.image)
|
||||
im = im.convert("L")
|
||||
arr = np.asarray(im, dtype=np.uint8)
|
||||
arr.flags.writeable = True
|
||||
white_idx = arr[:,:] < args.threshold
|
||||
black_idx = arr[:,:] >= args.threshold
|
||||
arr[white_idx] = 1
|
||||
arr[black_idx] = 0
|
||||
|
||||
qlr = QLRaster(args.model)
|
||||
qlr.set_mode()
|
||||
qlr.set_clear_command_buffer()
|
||||
qlr.set_initialize()
|
||||
qlr.set_mode()
|
||||
qlr.mtype = 0x0A
|
||||
qlr.mwidth = 62
|
||||
qlr.mlength = 0
|
||||
qlr.set_media_and_quality(im.size[1])
|
||||
qlr.set_autocut(True)
|
||||
qlr.set_cut_every(1)
|
||||
qlr.dpi_600 = False
|
||||
qlr.cut_at_end = True
|
||||
qlr.set_expanded_mode()
|
||||
qlr.set_margins()
|
||||
qlr.set_compression(True)
|
||||
qlr.set_raster_data(arr)
|
||||
qlr.print()
|
||||
|
||||
if args.loglevel == logging.DEBUG:
|
||||
sys.stderr.write(multiline_hex(qlr.data, 16))
|
||||
|
||||
args.outfile.write(qlr.data)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -75,3 +75,34 @@ right_margin_addition = {
|
||||
'QL-1050': 44,
|
||||
'QL-1060N': 44,
|
||||
}
|
||||
|
||||
modesetting = [
|
||||
'QL-580N',
|
||||
'QL-650TD',
|
||||
'QL-1050',
|
||||
'QL-1060N',
|
||||
'QL-710W',
|
||||
'QL-720NW',
|
||||
]
|
||||
|
||||
cuttingsupport = [
|
||||
'QL-560',
|
||||
'QL-570',
|
||||
'QL-580N',
|
||||
'QL-650TD',
|
||||
'QL-700',
|
||||
'QL-1050',
|
||||
'QL-1060N',
|
||||
'QL-710W',
|
||||
'QL-720NW',
|
||||
]
|
||||
|
||||
compressionsupport = [
|
||||
'QL-570',
|
||||
'QL-580N',
|
||||
'QL-650TD',
|
||||
'QL-1050',
|
||||
'QL-1060N',
|
||||
'QL-710W',
|
||||
'QL-720NW',
|
||||
]
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import struct
|
||||
import io
|
||||
import logging
|
||||
import sys
|
||||
|
||||
from PIL import Image
|
||||
import numpy as np
|
||||
@@ -103,7 +104,9 @@ class BrotherReader(object):
|
||||
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))
|
||||
img_name = 'page{:04d}.png'.format(self.page)
|
||||
im.save(img_name)
|
||||
print('Page saved as {}'.format(img_name))
|
||||
self.page += 1
|
||||
|
||||
rem_script = rem_script[num_bytes:]
|
||||
@@ -111,7 +114,7 @@ class BrotherReader(object):
|
||||
if cmd_found:
|
||||
continue
|
||||
else:
|
||||
logger.error('cmd not found: {}...'.format(rem_script[0:4]))
|
||||
logger.error('cmd not found: {0}... ({1}...)'.format(hex_format(rem_script[0:4]), rem_script[0:4]))
|
||||
rem_script = rem_script[1:]
|
||||
|
||||
def main():
|
||||
@@ -122,7 +125,7 @@ def main():
|
||||
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)
|
||||
logging.basicConfig(stream=sys.stdout, format='%(levelname)s: %(message)s', level=args.loglevel)
|
||||
|
||||
br = BrotherReader(args.file)
|
||||
br.analyze()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
import struct
|
||||
import logging
|
||||
|
||||
import packbits
|
||||
import numpy as np
|
||||
@@ -9,7 +10,12 @@ from .devicedependent import models, \
|
||||
min_max_length_dots, \
|
||||
paper_dimensions, \
|
||||
number_bytes_per_row, \
|
||||
right_margin_addition
|
||||
right_margin_addition, \
|
||||
compressionsupport, \
|
||||
cuttingsupport, \
|
||||
modesetting
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class QLRaster(object):
|
||||
|
||||
@@ -22,14 +28,28 @@ class QLRaster(object):
|
||||
self.page_number = 0
|
||||
self.cut_at_end = True
|
||||
self.dpi_600 = False
|
||||
self.compression = True
|
||||
self._compression = False
|
||||
self.exception_on_warning = False
|
||||
|
||||
def initialize(self):
|
||||
def warn(self, problem):
|
||||
if self.exception_on_warning:
|
||||
raise QLRasterError(problem)
|
||||
else:
|
||||
logger.warning(problem)
|
||||
|
||||
def set_initialize(self):
|
||||
self.page_number = 0
|
||||
self.data += b'\x1B\x69\x61\x01' # mode setting (raster mode)
|
||||
self.data += b'\x00' * 200
|
||||
self.data += b'\x1B\x40' # init
|
||||
self.data += b'\x1B\x69\x61\x01' # mode setting (raster mode)
|
||||
|
||||
def set_mode(self):
|
||||
""" switch to raster mode """
|
||||
if self.model not in modesetting:
|
||||
self.warn("Trying to switch the operating mode on a printer that doesn't support the command.")
|
||||
return
|
||||
self.data += b'\x1B\x69\x61\x01'
|
||||
|
||||
def set_clear_command_buffer(self):
|
||||
self.data += b'\x00' * 200
|
||||
|
||||
@property
|
||||
def mtype(self): return self._mtype
|
||||
@@ -83,6 +103,9 @@ class QLRaster(object):
|
||||
self.data += bytes([n & 0xFF])
|
||||
|
||||
def set_expanded_mode(self):
|
||||
if self.model not in cuttingsupport:
|
||||
self.warn("Trying to set expanded mode on a printer that doesn't support it")
|
||||
return
|
||||
self.data += b'\x1B\x69\x4B'
|
||||
flags = 0x00
|
||||
flags |= self.cut_at_end << 3
|
||||
@@ -94,17 +117,27 @@ class QLRaster(object):
|
||||
self.data += struct.pack('<H', dots)
|
||||
|
||||
def set_compression(self, compression=True):
|
||||
self.compression = compression
|
||||
if self.model not in compressionsupport:
|
||||
self.warn("Trying to set compression on a printer that doesn't support it")
|
||||
return
|
||||
self._compression = compression
|
||||
self.data += b'\x4D'
|
||||
self.data += bytes([compression << 1])
|
||||
|
||||
def set_raster_data(self, np_array):
|
||||
""" np_array: numpy array of 1-bit values """
|
||||
np_array = np.fliplr(np_array)
|
||||
try:
|
||||
nbpr = number_bytes_per_row[self.model]
|
||||
except:
|
||||
nbpr = number_bytes_per_row['default']
|
||||
for row in np_array:
|
||||
self.data += b'\x67\x00'
|
||||
row = bytes(np.packbits(row))
|
||||
if self.compression:
|
||||
if len(row) != nbpr:
|
||||
fmt = 'Wrong number of bytes per row: {}, expected {}'
|
||||
raise QLRasterError(fmt.format(len(row), nbpr))
|
||||
if self._compression:
|
||||
row = packbits.encode(row)
|
||||
self.data += bytes([len(row)])
|
||||
self.data += row
|
||||
|
||||
5
setup.py
5
setup.py
@@ -16,7 +16,8 @@ setup(name='brother_ql',
|
||||
packages = ['brother_ql'],
|
||||
entry_points = {
|
||||
'console_scripts': [
|
||||
'brother_ql_reader = brother_ql.reader:main',
|
||||
'brother_ql_read = brother_ql.reader:main',
|
||||
'brother_ql_write = brother_ql.create:main',
|
||||
],
|
||||
},
|
||||
include_package_data = False,
|
||||
@@ -24,7 +25,7 @@ setup(name='brother_ql',
|
||||
platforms = 'any',
|
||||
install_requires = ['numpy', 'packbits', 'pillow'],
|
||||
extras_require = {
|
||||
'brother_ql_reader': ["matplotlib",],
|
||||
'brother_ql_read': ["matplotlib",],
|
||||
},
|
||||
keywords = 'Brother QL-500 QL-570 QL-710W QL-720NW',
|
||||
classifiers = [
|
||||
|
||||
Reference in New Issue
Block a user