import argparse import sys import os import six from random import randint from PIL import Image, ImageOps ESC = b'\x1B' ETX = b'\x03' SO = b'\x0E' GRAPHIC = b'\x1B'+b'\x2A'+b'\x01' #1B 2A LINE_FEED = b'\n' CARIDGE_RET = b'\x0D' DATA = bytearray() COLUMNS = 2000 H = COLUMNS // 256 L = COLUMNS % 256 def _to_column_format(im, line_height): """ Extract slices of an image as equal-sized blobs of column-format data. :param im: Image to extract from :param line_height: Printed line height in dots """ width_pixels, height_pixels = im.size top = 0 left = 0 blobs = [] while left < width_pixels: remaining_pixels = width_pixels - left box = (left, top, left + line_height, top + height_pixels) #transform: (size, method, data=None, resample=0, fill=1) slice = im.transform((line_height, height_pixels), Image.EXTENT, box) bytes = slice.tobytes() blobs.append(bytes) left += line_height return blobs def _int_low_high(inp_number, out_bytes): """ Generate multiple bytes for a number: In lower and higher parts, or more parts as needed. to generate the H and L value :param inp_number: Input number :param out_bytes: The number of bytes to output (1 - 4). """ max_input = (256 << (out_bytes * 8) - 1); if not 1 <= out_bytes <= 4: raise ValueError("Can only output 1-4 byes") if not 0 <= inp_number <= max_input: raise ValueError("Number too large. Can only output up to {0} in {1} byes".format(max_input, out_bytes)) outp = b''; for _ in range(0, out_bytes): outp += six.int2byte(inp_number % 256) inp_number = inp_number // 256 return outp def print(filename, getlines=False): im = Image.open(filename) basewidth = 350 # Initial rotate. mirror, and extract blobs for each 8 or 24-pixel row # Convert to black & white via greyscale (so that bits can be inverted) im = im.transpose(Image.ROTATE_270).transpose(Image.FLIP_LEFT_RIGHT) height_pixels, width_pixels = im.size if width_pixels > basewidth: wpercent = (basewidth/float(im.size[0])) hsize = int((float(im.size[1])*float(wpercent))) im = im.resize((basewidth,hsize), Image.NEAREST) height_pixels, width_pixels = im.size im = im.resize((height_pixels,int(width_pixels*1.5)), Image.ANTIALIAS) im = im.convert("L") # Invert: Only works on 'L' images im = ImageOps.invert(im) # Bits are sent with 0 = white, 1 = black in ESC/POS im = im.convert("1") # Pure black and white #im.show() line_height = 1 blobs = _to_column_format (im, line_height * 8); height_pixels, width_pixels = im.size if getlines: return len(blobs) else: with open('/dev/usb/lp0', 'wb') as fp: fp.write(ESC+b"@") fp.write(ESC+b"\x7B"+b"\x41") #fp.write(ESC + b"3" + six.int2byte(22)); # Adjust line-feed size fp.write(ESC + b"\x33" + bytes([22])); #fp.write(ESC + ) fp.write(CARIDGE_RET) for blob in blobs: fp.write(GRAPHIC + _int_low_high( width_pixels, 2 ) + blob) fp.write(LINE_FEED) #fp.write(GRAPHIC + bytes([L,H]) + DATA) fp.write(ESC + b"2"); # Reset line-feed size