def rasterize(encoded_image_data): for i in range(0, len(encoded_image_data), CHUNK_SIZE): buffer = bytearray() chunk = encoded_image_data[i:i + CHUNK_SIZE] if chunk == ZERO_CHUNK: buffer += ZERO_COMMAND else: packed_chunk = packbits.encode(chunk) buffer += RASTER_COMMAND buffer += len(packed_chunk).to_bytes(2, "little") buffer += packbits.encode(chunk) yield buffer
def printImg(img, end=False): "Sends a PIL image object to printer after converting it to the proper format." imgW, imgH = img.size img = img.transpose(Image.ROTATE_270) ##Rotate to fit in the printer img = img.transpose(Image.FLIP_LEFT_RIGHT) ilist = list(img.getdata()) img.save("rot.png") img.close() ##Below is the starting string for a Brother 710-W printer with no cut after kid_b1 = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x001B\x40\x1B\x69\x61\x01\x1B\x69\x55\x4A\x00\x0C\xD4\x3D\x7E\xBE\x4D\x36\x00\x00\x0A\x00\x00\x00\x1B\x69\x7A\x8E\x0B\x3E\x64\x55\x04\x00\x00\x00\x00\x1B\x69\x4D\x00\x1B\x69\x4B\x00\x1B\x69\x64\x00\x00\x4D\x02' ##This is the starting string with a cut after parent_b1 = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x001B\x40\x1B\x69\x61\x01\x1B\x69\x55\x4A\x00\x0C\xD4\x3D\x7E\xBE\x4D\x36\x00\x00\x09\x00\x00\x00\x1B\x69\x7A\x8E\x0B\x3E\x64\x55\x04\x00\x00\x00\x00\x1B\x69\x4D\x00\x1B\x69\x4B\x08\x1B\x69\x64\x00\x00\x4D\x02' b2 = b"" b3 = b"\x1a" ##Finish and cut paper header = b"\x67\x00" ##This loop converts the pixels into the bytes the printer can read ##hopefully as fast as possible. for x in range(0, imgW): r = ilist[x * 720:((x * 720) + 720)] row = __convert(r) row = packbits.encode(row) ##This replaces an empty row with the code for an empty road if row == b"\xA7\x00": b2 += b'Z' else: b2 += header + chr(len(row)).encode() + row if end: b1 = parent_b1 else: b1 = kid_b1 return (b''.join([b1, b2, b3]))
def add_raster_data(self, image, second_image=None): """ image: Pillow Image() """ logger.info("raster_image_size: {0}x{1}".format(*image.size)) if image.size[0] != self.get_pixel_width(): fmt = 'Wrong pixel width: {}, expected {}' raise BrotherQLRasterError(fmt.format(image.size[0], self.get_pixel_width())) images = [image] if second_image: if image.size != second_image.size: fmt = "First and second image don't have the same dimesions: {} vs {}." raise BrotherQLRasterError(fmt.format(image.size, second_image.size)) images.append(second_image) frames = [] for image in images: image = image.transpose(Image.FLIP_LEFT_RIGHT) image = image.convert("1") frames.append(bytes(image.tobytes(encoder_name='raw'))) frame_len = len(frames[0]) row_len = images[0].size[0]//8 start = 0 file_str = BytesIO() while start + row_len <= frame_len: for i, frame in enumerate(frames): row = frame[start:start+row_len] if second_image: file_str.write(b'\x77\x01' if i == 0 else b'\x77\x02') else: file_str.write(b'\x67\x00') if self._compression: row = packbits.encode(row) file_str.write(bytes([len(row)])) file_str.write(row) start += row_len self.data += file_str.getvalue()
def compress_constant_rle( fd, # type: BinaryIO value, # type: int width, # type: int rows, # type: int depth, # type: int version # type: int ): # type: (...) -> None """ Write a virtual image containing a constant to a runlength-encoded stream. {} """ if depth == 1: # pragma: no cover raise ValueError("rle compression is not supported for 1-bit images") row = _make_constant_row(value, width, depth) packed = packbits.encode(row.tobytes()) if version == 1: lengths = np.full((rows, ), len(packed), dtype='>u2') else: lengths = np.full((rows, ), len(packed), dtype='>u4') fd.write(lengths.tobytes()) for i in range(rows): fd.write(packed)
def encode_raster_transfer(data): """ Encode 1 bit per pixel image data for transfer over serial to the printer """ buf = bytearray() # Send in chunks of 1 line (128px @ 1bpp = 16 bytes) # This mirrors the official app from Brother. Other values haven't been tested. chunk_size = 16 for i in range(0, len(data), chunk_size): chunk = data[i:i + chunk_size] # Encode as tiff packed_chunk = packbits.encode(chunk) # Write header buf.append(TRANSFER_COMMAND) # Write number of bytes to transfer (n1 + n2*256) length = len(packed_chunk) buf.append(int(length % 256)) buf.append(int(length / 256)) # Write data buf.extend(packed_chunk) return buf
def encode_packbits(data, width, height, depth, version): row_size = width * depth // 8 with io.BytesIO(data) as fp: rows = [packbits.encode(fp.read(row_size)) for _ in range(height)] bytes_counts = array.array(('H', 'I')[version - 1], map(len, rows)) encoded = b''.join(rows) with io.BytesIO() as fp: write_be_array(fp, bytes_counts) fp.write(encoded) result = fp.getvalue() return result
def compress_rle( fd, # type: BinaryIO image, # type: np.ndarray depth, # type: int version # type: int ): # type: (...) -> None """ Write a Numpy array to a run length encoded stream. {} """ if depth == 1: # pragma: no cover raise ValueError("rle compression is not supported for 1-bit images") start = fd.tell() if version == 1: fd.seek(image.shape[0] * 2, 1) lengths = np.empty((len(image), ), dtype='>u2') else: fd.seek(image.shape[0] * 4, 1) lengths = np.empty((len(image), ), dtype='>u4') if util.needs_byteswap(image): for i, row in enumerate(image): row = util.do_byteswap(row) packed = packbits.encode(row) lengths[i] = len(packed) fd.write(packed) else: for i, row in enumerate(image): packed = packbits.encode(row) lengths[i] = len(packed) fd.write(packed) end = fd.tell() fd.seek(start) fd.write(lengths.tobytes()) fd.seek(end)
def add_raster_data(self, np_array): """ np_array: numpy array of 1-bit values """ np_array = np.fliplr(np_array) logger.info("raster_image_size: {1}x{0}".format(*np_array.shape)) if np_array.shape[1] != self.get_pixel_width(): fmt = 'Wrong pixel width: {}, expected {}' raise BrotherQLRasterError(fmt.format(np_array.shape[0], self.get_pixel_width())) for row in np_array: self.data += b'\x67\x00' row = bytes(np.packbits(row)) if self._compression: row = packbits.encode(row) self.data += bytes([len(row)]) self.data += row
def add_raster_data(self, image, second_image=None): """ Add the image data to the instructions. The provided image has to be binary (every pixel is either black or white). :param PIL.Image.Image image: The image to be converted and added to the raster instructions :param PIL.Image.Image second_image: A second image with a separate color layer (red layer for the QL-800 series) """ logger.debug("raster_image_size: {0}x{1}".format(*image.size)) if image.size[0] != self.get_pixel_width(): fmt = 'Wrong pixel width: {}, expected {}' raise BrotherQLRasterError( fmt.format(image.size[0], self.get_pixel_width())) images = [image] if second_image: if image.size != second_image.size: fmt = "First and second image don't have the same dimesions: {} vs {}." raise BrotherQLRasterError( fmt.format(image.size, second_image.size)) images.append(second_image) frames = [] for image in images: image = image.transpose(Image.FLIP_LEFT_RIGHT) image = image.convert("1") frames.append(bytes(image.tobytes(encoder_name='raw'))) frame_len = len(frames[0]) row_len = images[0].size[0] // 8 start = 0 file_str = BytesIO() while start + row_len <= frame_len: for i, frame in enumerate(frames): row = frame[start:start + row_len] if self._compression: row = packbits.encode(row) translen = len(row) # number of bytes to be transmitted if self.model.startswith('PT'): file_str.write(b'\x47') file_str.write(bytes([translen % 256, translen // 256])) else: if second_image: file_str.write(b'\x77\x01' if i == 0 else b'\x77\x02') else: file_str.write(b'\x67\x00') file_str.write(bytes([translen])) file_str.write(row) start += row_len self.data += file_str.getvalue()
def processFrame(self, start, row_len, frame_len, frame, index, g_data): file_str = BytesIO() 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) g_data[index] = file_str.getvalue()
def encode_packbits(data, width, height, depth, version): bytes_counts = array.array(('H', 'I')[version - 1]) encoded = b'' with io.BytesIO(data) as fp: row_size = width * depth // 8 for index in range(height): row = packbits.encode(fp.read(row_size)) bytes_counts.append(len(row)) encoded += row with io.BytesIO() as fp: write_be_array(fp, bytes_counts) fp.write(encoded) result = fp.getvalue() return result
def encode_line(bitmap_line: bytes, tape_info: TapeInfo) -> bytes: # The number of bits we need to add left or right is not always a multiple # of 8, so we need to convert our line into an int, shift it over by the # left margin and convert it to back again, padding to 16 bytes. line_int = int.from_bytes(bitmap_line, byteorder='big') line_int <<= tape_info.rmargin padded = line_int.to_bytes(16, byteorder='big') # pad to 16 bytes compressed = packbits.encode(padded) logger.debug("original bitmap: %s", bitmap_line) logger.debug("padded bitmap %s", padded) logger.debug("packbits compressed %s", compressed) # <h: big endian short (2 bytes) prefix = struct.pack("<H", len(compressed)) return prefix + compressed
def add_raster_data(self, image): """ image: Pillow Image() """ logger.info("raster_image_size: {0}x{1}".format(*image.size)) image = image.transpose(Image.FLIP_LEFT_RIGHT) image = image.convert("1") if image.size[0] != self.get_pixel_width(): fmt = 'Wrong pixel width: {}, expected {}' raise BrotherQLRasterError( fmt.format(image.size[0], self.get_pixel_width())) frame = bytes(image.tobytes(encoder_name='raw')) frame_len = len(frame) row_len = image.size[0] // 8 start = 0 file_str = BytesIO() while start + row_len <= frame_len: row = frame[start:start + row_len] start += row_len file_str.write(b'\x67\x00') if self._compression: row = packbits.encode(row) file_str.write(bytes([len(row)])) file_str.write(row) self.data += file_str.getvalue()
def test_encode_long_raw2(): data = b'12345678' * 16 encoded = packbits.encode(data) assert packbits.decode(encoded) == data
def test_encode_switching_rle(): encoded = packbits.encode(b'1122') assert packbits.decode(encoded) == b'1122'
def test_encode_long_raw(): data = b'12345678' * 17 encoded = packbits.encode(data) print(encoded) assert packbits.decode(encoded) == data
def test_encode2(): encoded = packbits.encode(b"112112") assert packbits.decode(encoded) == b"112112"
def test_encode_single(): encoded = packbits.encode(b"X") assert encoded == b"\x00X" assert packbits.decode(encoded) == b"X"
def test_encode_decode(): encoded = packbits.encode(RESULT) decoded = packbits.decode(encoded) assert decoded == RESULT
def test_restart_rle(): data = b"1" * 127 + b"foo" encoded = packbits.encode(data) assert packbits.decode(encoded) == data
def test_encode_single(): encoded = packbits.encode(b'X') assert encoded == b'\x00X' assert packbits.decode(encoded) == b'X'
def test_encode_long(): data = b'1' * 128 + b'12345678' * 17 encoded = packbits.encode(data) assert packbits.decode(encoded) == data
def test_raw(): encoded = packbits.encode(b'123') assert encoded == b'\x02123' assert packbits.decode(encoded) == b'123'
def test_encode_long_raw(): data = b'12345678' * 16 encoded = packbits.encode(data) assert packbits.decode(encoded) == data
def test_restart_rle(): data = b'1' * 127 + b'foo' encoded = packbits.encode(data) assert packbits.decode(encoded) == data
def test_encode_long_rle3(): data = b'1' * 128 encoded = packbits.encode(data) assert packbits.decode(encoded) == data
def test_encode_empty(): assert packbits.encode(b'') == b''
def test_encode2(): encoded = packbits.encode(b'112112') assert packbits.decode(encoded) == b'112112'
def test_encode_long_raw(): data = b"12345678" * 17 encoded = packbits.encode(data) print(encoded) assert packbits.decode(encoded) == data
def test_encode_long_rle2(): data = b"1" * 127 encoded = packbits.encode(data) assert packbits.decode(encoded) == data
def test_raw(): encoded = packbits.encode(b"123") assert encoded == b"\x02123" assert packbits.decode(encoded) == b"123"
def add_raster_data(self, image, cores=1): """ image: Pillow Image() """ logger.info("raster_image_size: {0}x{1}".format(*image.size)) image = image.transpose(Image.FLIP_LEFT_RIGHT) image = image.convert("1") if image.size[0] != self.get_pixel_width(): fmt = 'Wrong pixel width: {}, expected {}' raise BrotherQLRasterError(fmt.format(image.size[0], self.get_pixel_width())) frame = bytes(image.tobytes(encoder_name='raw')) frame_len = len(frame) row_len = image.size[0]//8 start = 0 file_str = BytesIO() if cores > 1: len_prop = float(float(frame_len) / (float(row_len) * float(cores))) len_check = len_prop.is_integer() logger.debug("Using " + str(cores) + " cores in add_raster_data.") processes = {} manager = Manager() g_data = manager.list(['']*cores) #Check if we can equally assign subframes to processes, or adjust their length to fit. if len_check: subframe_len = int(frame_len/cores) for i in range(0, cores): subframe_start =int(subframe_len * i) subframe_limit = int(subframe_len * (i+1)) subframe = frame[subframe_start:subframe_limit] processes[i] = Process(target=self.processFrame, args=(0, row_len, subframe_len, subframe, i, g_data,)) processes[i].start() else: num_rows = int(float(frame_len) / (float(row_len) * float(cores))) last_limit = 0 subframe_len = int(row_len * num_rows) for i in range(0, cores - 1): subframe_start =int(subframe_len * i) subframe_limit = int(subframe_len * (i+1)) last_limit = subframe_limit subframe = frame[subframe_start:subframe_limit] processes[i] = Process(target=self.processFrame, args=(0, row_len, subframe_len, subframe, i, g_data,)) processes[i].start() subframe = frame[last_limit:frame_len] processes[cores - 1] = Process(target=self.processFrame, args=(0, row_len, frame_len - last_limit, subframe, cores - 1, g_data,)) processes[cores-1].start() for i in range(0, cores): processes[i].join() for i in range(0, cores): self.data += g_data[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 file_str.write(b'\x67\x00') if self._compression: row = packbits.encode(row) file_str.write(bytes([len(row)])) file_str.write(row) self.data += file_str.getvalue()