Speed improvements.
This commit is contained in:
@@ -5,11 +5,14 @@ from __future__ import division
|
|||||||
import sys, argparse, logging
|
import sys, argparse, logging
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
import PIL.ImageOps
|
||||||
|
|
||||||
from brother_ql.raster import BrotherQLRaster
|
from brother_ql.raster import BrotherQLRaster
|
||||||
from brother_ql.devicedependent import models, label_type_specs, ENDLESS_LABEL, DIE_CUT_LABEL, ROUND_DIE_CUT_LABEL
|
from brother_ql.devicedependent import models, label_type_specs, ENDLESS_LABEL, DIE_CUT_LABEL, ROUND_DIE_CUT_LABEL
|
||||||
from brother_ql import BrotherQLError, BrotherQLUnsupportedCmd, BrotherQLUnknownModel
|
from brother_ql import BrotherQLError, BrotherQLUnsupportedCmd, BrotherQLUnknownModel
|
||||||
|
|
||||||
|
import multiprocessing
|
||||||
|
|
||||||
try:
|
try:
|
||||||
stdout = sys.stdout.buffer
|
stdout = sys.stdout.buffer
|
||||||
except:
|
except:
|
||||||
@@ -23,6 +26,9 @@ except:
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
||||||
|
defaultCores = multiprocessing.cpu_count()
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument('image', help='The image file to create a label from.')
|
parser.add_argument('image', help='The image file to create a label from.')
|
||||||
parser.add_argument('outfile', nargs='?', type=argparse.FileType('wb'), default=stdout, help='The file to write the instructions to. Defaults to stdout.')
|
parser.add_argument('outfile', nargs='?', type=argparse.FileType('wb'), default=stdout, help='The file to write the instructions to. Defaults to stdout.')
|
||||||
@@ -32,6 +38,7 @@ def main():
|
|||||||
parser.add_argument('--threshold', '-t', type=float, default=70.0, help='The threshold value (in percent) to discriminate between black and white pixels.')
|
parser.add_argument('--threshold', '-t', type=float, default=70.0, help='The threshold value (in percent) to discriminate between black and white pixels.')
|
||||||
parser.add_argument('--no-cut', dest='cut', action='store_false', help="Don't cut the tape after printing the label.")
|
parser.add_argument('--no-cut', dest='cut', action='store_false', help="Don't cut the tape after printing the label.")
|
||||||
parser.add_argument('--loglevel', type=lambda x: getattr(logging, x), default=logging.WARNING, help='Set to DEBUG for verbose debugging output to stderr.')
|
parser.add_argument('--loglevel', type=lambda x: getattr(logging, x), default=logging.WARNING, help='Set to DEBUG for verbose debugging output to stderr.')
|
||||||
|
parser.add_argument('--cores', '-c', type=int, default=defaultCores, help='The number of cores to use on creating the bin file.')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
logging.basicConfig(level=args.loglevel)
|
logging.basicConfig(level=args.loglevel)
|
||||||
@@ -51,11 +58,14 @@ def main():
|
|||||||
|
|
||||||
qlr.exception_on_warning = True
|
qlr.exception_on_warning = True
|
||||||
|
|
||||||
create_label(qlr, args.image, args.label_size, threshold=args.threshold, cut=args.cut, rotate=args.rotate)
|
coresMessage = "Attempting to create using " + str(args.cores) + " cores."
|
||||||
|
logger.debug(coresMessage)
|
||||||
|
|
||||||
|
create_label(qlr, args.image, args.label_size, cores=args.cores, threshold=args.threshold, cut=args.cut, rotate=args.rotate)
|
||||||
|
|
||||||
args.outfile.write(qlr.data)
|
args.outfile.write(qlr.data)
|
||||||
|
|
||||||
def create_label(qlr, image, label_size, threshold=70, cut=True, **kwargs):
|
def create_label(qlr, image, label_size, cores, threshold=70, cut=True, **kwargs):
|
||||||
|
|
||||||
label_specs = label_type_specs[label_size]
|
label_specs = label_type_specs[label_size]
|
||||||
dots_printable = label_specs['dots_printable']
|
dots_printable = label_specs['dots_printable']
|
||||||
@@ -100,6 +110,7 @@ def create_label(qlr, image, label_size, threshold=70, cut=True, **kwargs):
|
|||||||
new_im.paste(im, (device_pixel_width-im.size[0]-right_margin_dots, 0))
|
new_im.paste(im, (device_pixel_width-im.size[0]-right_margin_dots, 0))
|
||||||
im = new_im
|
im = new_im
|
||||||
|
|
||||||
|
im = PIL.ImageOps.invert(im)
|
||||||
threshold = min(255, max(0, int(threshold/100.0 * 255))) # from percent to pixel val
|
threshold = min(255, max(0, int(threshold/100.0 * 255))) # from percent to pixel val
|
||||||
im = im.point(lambda x: 0 if x < threshold else 255, mode="1")
|
im = im.point(lambda x: 0 if x < threshold else 255, mode="1")
|
||||||
|
|
||||||
@@ -142,7 +153,7 @@ def create_label(qlr, image, label_size, threshold=70, cut=True, **kwargs):
|
|||||||
qlr.add_compression(True)
|
qlr.add_compression(True)
|
||||||
except BrotherQLUnsupportedCmd:
|
except BrotherQLUnsupportedCmd:
|
||||||
pass
|
pass
|
||||||
qlr.add_raster_data(im)
|
qlr.add_raster_data(im, cores)
|
||||||
qlr.add_print()
|
qlr.add_print()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
+90
-12
@@ -6,6 +6,7 @@ import logging
|
|||||||
|
|
||||||
import packbits
|
import packbits
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
import io
|
||||||
|
|
||||||
from .devicedependent import models, \
|
from .devicedependent import models, \
|
||||||
min_max_feed, \
|
min_max_feed, \
|
||||||
@@ -19,6 +20,12 @@ from .devicedependent import models, \
|
|||||||
|
|
||||||
from . import BrotherQLError, BrotherQLUnsupportedCmd, BrotherQLUnknownModel, BrotherQLRasterError
|
from . import BrotherQLError, BrotherQLUnsupportedCmd, BrotherQLUnknownModel, BrotherQLRasterError
|
||||||
|
|
||||||
|
import multiprocessing, ctypes
|
||||||
|
|
||||||
|
from multiprocessing import Process, Manager, Array
|
||||||
|
|
||||||
|
from cStringIO import StringIO
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class BrotherQLRaster(object):
|
class BrotherQLRaster(object):
|
||||||
@@ -168,7 +175,7 @@ class BrotherQLRaster(object):
|
|||||||
nbpr = number_bytes_per_row['default']
|
nbpr = number_bytes_per_row['default']
|
||||||
return nbpr*8
|
return nbpr*8
|
||||||
|
|
||||||
def add_raster_data(self, image):
|
def add_raster_data(self, image, cores):
|
||||||
""" image: Pillow Image() """
|
""" image: Pillow Image() """
|
||||||
logger.info("raster_image_size: {0}x{1}".format(*image.size))
|
logger.info("raster_image_size: {0}x{1}".format(*image.size))
|
||||||
image = image.transpose(Image.FLIP_LEFT_RIGHT)
|
image = image.transpose(Image.FLIP_LEFT_RIGHT)
|
||||||
@@ -177,23 +184,94 @@ class BrotherQLRaster(object):
|
|||||||
fmt = 'Wrong pixel width: {}, expected {}'
|
fmt = 'Wrong pixel width: {}, expected {}'
|
||||||
raise BrotherQLRasterError(fmt.format(image.size[0], self.get_pixel_width()))
|
raise BrotherQLRasterError(fmt.format(image.size[0], self.get_pixel_width()))
|
||||||
frame = bytes(image.tobytes(encoder_name='raw'))
|
frame = bytes(image.tobytes(encoder_name='raw'))
|
||||||
# The above command directly returns the 1-bit image packed
|
|
||||||
# into bits. (The cast to bytes is needed for Py2 compatibility.)
|
|
||||||
frame = bytes([2**8 + ~byte for byte in frame]) # invert b/w
|
|
||||||
frame_len = len(frame)
|
frame_len = len(frame)
|
||||||
row_len = image.size[0]//8
|
row_len = image.size[0]//8
|
||||||
start = 0
|
start = 0
|
||||||
while start + row_len <= frame_len:
|
|
||||||
row = frame[start:start+row_len]
|
file_str = StringIO()
|
||||||
start += row_len
|
|
||||||
self.data += b'\x67\x00' # g 0x00
|
logger.debug("Frame " + str(frame_len) + " Row " + str(row_len))
|
||||||
if self._compression:
|
|
||||||
row = packbits.encode(row)
|
#If the rowLen to subframeLen prop isn't and int, data would be lost.
|
||||||
self.data += bytes([len(row)])
|
if cores > 1:
|
||||||
self.data += row
|
|
||||||
|
lCheck = float(float(frame_len) / (float(row_len) * float(cores))).is_integer()
|
||||||
|
logger.debug("Using " + str(cores) + " cores in add_raster_data.")
|
||||||
|
processes = {}
|
||||||
|
manager = Manager()
|
||||||
|
gData = manager.list(['']*cores)
|
||||||
|
|
||||||
|
if lCheck:
|
||||||
|
subFrameLen = int(frame_len/cores)
|
||||||
|
for i in range(0, cores):
|
||||||
|
|
||||||
|
subFrameStart =int(subFrameLen * i)
|
||||||
|
subframeLimit = int(subFrameLen * (i+1))
|
||||||
|
subframe = frame[subFrameStart:subframeLimit]
|
||||||
|
processes[i] = Process(target=self.processFrame, args=(0, row_len, subFrameLen, subframe, i, gData,))
|
||||||
|
processes[i].start()
|
||||||
|
else:
|
||||||
|
numRows = int(float(frame_len) / (float(row_len) * float(cores)))
|
||||||
|
lastNum = 0
|
||||||
|
subFrameLen = int(row_len * numRows)
|
||||||
|
for i in range(0, cores - 1):
|
||||||
|
|
||||||
|
subFrameStart =int(subFrameLen * i)
|
||||||
|
subframeLimit = int(subFrameLen * (i+1))
|
||||||
|
lastNum = subframeLimit
|
||||||
|
subframe = frame[subFrameStart:subframeLimit]
|
||||||
|
processes[i] = Process(target=self.processFrame, args=(0, row_len, subFrameLen, subframe, i, gData,))
|
||||||
|
processes[i].start()
|
||||||
|
|
||||||
|
subframe = frame[lastNum:frame_len]
|
||||||
|
processes[cores - 1] = Process(target=self.processFrame, args=(0, row_len, frame_len - lastNum, subframe, cores - 1, gData,))
|
||||||
|
processes[cores-1].start()
|
||||||
|
|
||||||
|
for i in range(0, cores):
|
||||||
|
processes[i].join()
|
||||||
|
|
||||||
|
for i in range(0, cores):
|
||||||
|
self.data += gData[i]
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
logger.debug("Using 1 core in add_raster_data (" + str(cores) + " given).")
|
||||||
|
|
||||||
|
while start + row_len <= frame_len:
|
||||||
|
row = frame[start:start+row_len]
|
||||||
|
start += row_len
|
||||||
|
#self.data += b'\x67\x00' # g 0x00
|
||||||
|
file_str.write(b'\x67\x00')
|
||||||
|
if self._compression:
|
||||||
|
row = packbits.encode(row)
|
||||||
|
#self.data += bytes([len(row)])
|
||||||
|
#self.data += row
|
||||||
|
file_str.write(bytes([len(row)]))
|
||||||
|
file_str.write(row)
|
||||||
|
|
||||||
|
self.data += file_str.getvalue()
|
||||||
|
|
||||||
def add_print(self, last_page=True):
|
def add_print(self, last_page=True):
|
||||||
if last_page:
|
if last_page:
|
||||||
self.data += b'\x1A' # 0x1A = ^Z = SUB; here: EOF = End of File
|
self.data += b'\x1A' # 0x1A = ^Z = SUB; here: EOF = End of File
|
||||||
else:
|
else:
|
||||||
self.data += b'\x0C' # 0x0C = FF = Form Feed
|
self.data += b'\x0C' # 0x0C = FF = Form Feed
|
||||||
|
|
||||||
|
|
||||||
|
def processFrame(self, start, row_len, frame_len, frame, index, gData):
|
||||||
|
|
||||||
|
file_str = StringIO()
|
||||||
|
while start + row_len <= frame_len:
|
||||||
|
row = frame[start:start+row_len]
|
||||||
|
start += row_len
|
||||||
|
#self.data += b'\x67\x00' # g 0x00
|
||||||
|
file_str.write(b'\x67\x00')
|
||||||
|
if self._compression:
|
||||||
|
row = packbits.encode(row)
|
||||||
|
#self.data += bytes([len(row)])
|
||||||
|
#self.data += row
|
||||||
|
file_str.write(bytes([len(row)]))
|
||||||
|
file_str.write(row)
|
||||||
|
|
||||||
|
gData[index] = file_str.getvalue()
|
||||||
|
|||||||
Reference in New Issue
Block a user