def main(): parser = ArgumentParser( description="Print an illustration for a proxy by ID") parser.add_argument("id", help="ID of the proxy to print") parser.add_argument("-d", "--database-path", help="Path to RandomProxyPrinter basic database", required=True, dest="database_path") parser.add_argument("-p", "--printer", help="Path to printer device", required=True) parser.add_argument("-r", "--printer-baudrate", help="Printer baudrate", default=19200, dest="baudrate") args = parser.parse_args() printer = Serial(args.printer, baudrate=args.baudrate) connection = connect(args.database_path) connection.row_factory = Row cursor = connection.cursor() cursor.execute("SELECT illustration FROM proxies WHERE id = ?", (args.id, )) row = cursor.fetchone() printer.image(Image.open(BytesIO(row["illustration"])), impl="bitImageColumn")
class bonprinter: def __init__(self, logger, config, printq): self.logger = logger self.cf = config self.printq = printq #self.p = None self.p = Serial(devfile='/dev/ttyUSB1', baudrate=38400, bytesize=8, parity='N', stopbits=1, timeout=1.00, dsrdtr=False, profile="TM-T88II") self.pprint = printerpreter(self.p) # pretty printer def brrr(self, context): for item in self.printq: if item['printed'] is False: context.bot.send_message(chat_id=item['id'], text=printing_text) self.printq.update(tdbop.set("printed", True), Query().date == item['date']) # mark as printed so errors dont result in infinite loops if item['text'] is not None: self.pprint.printbon(item['text']) if item['image'] is not None: self.p.image(item['image'], impl='bitImageRaster') self.p.text("\n------------------------------------------\n") if self.cf['auto_cut'] is True: self.p.cut(mode='FULL', feed=True, lines=4) if item['image'] is not None: sleep(2) # timeout so printer can cool down
class Imprimir: def __init__(self, porta_serial): self.p = Serial(porta_serial) self.p.charcode("MULTILINGUAL") self.nome_serial = porta_serial def imprimir_texto(self, texto): self.p.text(str(texto)) self.p.cut() def imprimir_imagem(self, imagem): self.p.image(str(imagem)) self.p.cut() def imprimir_qr_code(self, texto): self.p.qr(str(texto)) self.p.cut() def retornar_impressora(self): return str(self.nome_serial)
class printout: """Print stuff from Twitter""" def __init__(self, printerConf): self.p = Serial(devfile=printerConf['dev'], baudrate=[ int(printerConf['baudrate']) if 'baudrate' in printerConf else 9600 ][0]) self.p.open() self.printerWidth = printerConf['printerWidth'] self.basedir = dirname(realpath(__file__)) + sep + pardir + sep self.printerConf = printerConf def imBox(self, width, height): """Create a white rectangle""" img = Image.new("1", (width, height)) draw = ImageDraw.Draw(img) bgColor = 255 draw.rectangle((0, 0) + img.size, fill=bgColor) return img def imText(self, text, align="left", textSize=None, rotate=None, bgColor=255, fontColor=0, scale=None, leading=0.25, txtWidth=None): """Render an image using a truetype font. Text may be be a list of string objects (one object per line). If a line is too wide the function will try to line wrap. Arg. 'leading' is the interline spacing in as a proportion of the height of a line. Arg. 'scale' is the proportion of the width of the paper.""" if not textSize: textSize = int(self.printerConf['textSize']) if not txtWidth: txtWidth = self.printerConf['printerWidth'] font = ImageFont.truetype(self.printerConf['fontFile'], textSize) def splitList(txtWidth, txtList, font, newlineSplitOnly=False): """Each str/unicode in txtList equals one line when printet. Split at newlines and furthermore split if a line is too wide.""" # First of search for newlines and split the list if a newline is found withoutNewlines = [] for txt in txtList: withoutNewlines.extend(txt.split("\n")) txtList = withoutNewlines if newlineSplitOnly: return txtList txtListWrapped = [] for txt in txtList: # If the whole line is too wide, remove words until we are good if font.getsize(txt)[0] > txtWidth: txtLen = len(txt) for i in range(txtLen)[::-1]: if font.getsize(txt[:i + 1])[0] <= txtWidth: whitespaceEtc = [" ", "\t", "-"] if txt[i] in whitespaceEtc: txtSplit = [txt[:i + 1].rstrip(), txt[i + 1:]] if font.getsize(txtSplit[1])[0] > txtWidth: txtSplit = splitList( txtWidth, txtSplit, font) break else: break # If there are no whitespaces etc. then split the word elif not any(w in txt[:i + 1] for w in whitespaceEtc): if font.getsize(txt[:i + 1] + "-")[0] <= txtWidth: txtSplit = [ txt[:i + 1].rstrip() + "-", txt[i + 1:] ] if font.getsize(txtSplit[1])[0] > txtWidth: txtSplit = splitList( txtWidth, txtSplit, font) break else: break else: continue else: txtSplit = [txt] txtListWrapped.extend(txtSplit) return txtListWrapped # If txtList is a simple string make it a list if type(text) is list: txtList = text else: txtList = [text] # Spacing between lines as a proportion of the width of a danish letter for the current text size. leadingDots = int(font.getsize(u"Å")[0] * leading) if rotate in [90, 270]: # Don't wrap lines based on width when turned 90 or 270 degrees txtList = splitList(txtWidth, txtList, font, newlineSplitOnly=True) else: # Do wordwrapping etc. txtList = splitList(txtWidth, txtList, font) # Determine the size of the resulting text image size = [0, 0] lineHeight = font.getsize("a")[1] size = [0, (leadingDots + lineHeight) * len(txtList) + leadingDots] # Find the width if rotate is 180: # Avoid right alignment of rotated text, if a line is less wide than the paper / printerConf['printerWidth'] size[0] = self.printerConf['printerWidth'] else: for txt in txtList: maxWidth = font.getsize(txt)[0] if maxWidth > size[0]: size[0] = maxWidth # Create the actual image containing the text img = Image.new("1", size) draw = ImageDraw.Draw(img) draw.rectangle((0, 0) + img.size, fill=bgColor) pointer = [0, 0] # For each line.. for txt in txtList: txtPxWidth = font.getsize(txt)[0] if align == "left": pointer[0] = 0 elif align == "right": pointer[0] = size[0] - txtPxWidth elif align == "center": pointer[0] = (size[0] - txtPxWidth) / 2 draw.text(pointer, txt, font=font, fill=fontColor) pointer[1] += lineHeight + leadingDots if rotate: angles = [0, 90, 180, 270] if rotate in angles: img = img.rotate(rotate, expand=True) else: raise ValueError("rotate must be part of %s if set " % str(angles)) if rotate in [90, 270]: if img.size[0] > self.printerConf['printerWidth'] and not scale: raise Exception( "The textSize is too large to print. Use either a smaller textSize or the scale parameter" ) else: if img.size[0] > self.printerConf['printerWidth']: raise Exception( "Could not print the text. One or more lines are too wide. Did you choose a very large font?" ) if align is not "left": imgOld = img img = Image.new("1", (txtWidth, imgOld.size[1])) draw = ImageDraw.Draw(img) draw.rectangle((0, 0) + img.size, fill=bgColor) pointer = [0, 0] if align is "center": i = 2 else: i = 1 img.paste(imgOld, ((txtWidth - imgOld.size[0]) / i, 0)) return img def printLine(self, pxWidth=False, width=1.0, pxThickness=4, pxHeading=10, pxTrailing=10): """Prints a horisontal line. If width is set then pxWidth is ignored. width higher than 1.0 is ignored.""" # calculate dimensions if not pxWidth: pxWidth = int(self.printerConf['printerWidth'] * width) pxHeight = pxHeading + pxThickness + pxTrailing img = Image.new("1", (self.printerConf['printerWidth'], pxHeight)) draw = ImageDraw.Draw(img) draw.rectangle((0, 0, self.printerConf['printerWidth'], pxHeight), fill=255) draw.rectangle( ((self.printerConf['printerWidth'] - pxWidth) / 2, pxHeading, (self.printerConf['printerWidth'] - pxWidth) / 2 + pxWidth, pxHeading + pxThickness), fill=0) return img def combinePILObjects(self, imgArray, doPrint=True, multiCol=False, ignoreRotate=False): """Combine objects and print them""" if multiCol: # Multiple columns object (e.g. printing wearther forecast). imgArray is then an array of arrays. imArray = [ self.combinePILObjects(i, doPrint=False, ignoreRotate=True) for i in imgArray ] # Determine height pre multicol orgMaxHeight = 0 for im in imArray: h = im[0].size[1] if h > orgMaxHeight: orgMaxHeight = h numCols = len(imArray) imgMaster = self.imBox(self.printerConf['printerWidth'], orgMaxHeight / numCols) # Paste the columns together offset = 0 numCols = len(imArray) colWidth = self.printerConf['printerWidth'] / numCols for i in imArray: imgMaster.paste( i[0].resize([colWidth, int(i[0].size[1] * 1. / numCols)]), (offset, 0)) offset += colWidth else: # Calculate height height = 0 imgTooWide = False for i in range(len(imgArray)): img = imgArray[i] # If an image is too large if img.size[0] > self.printerConf['printerWidth']: # resize image imgArray[i] = img.resize([ self.printerConf['printerWidth'], int(img.size[1] * float(self.printerConf['printerWidth']) / img.size[0]) ]) height += imgArray[i].size[1] # Create imgMaster = self.imBox(self.printerConf['printerWidth'], height) offset = 0 for img in imgArray: imgMaster.paste(img, (0, offset)) offset += img.size[1] if self.printerConf['rotate'] and not ignoreRotate: imgMaster = imgMaster.rotate(180) height = imgMaster.size[1] bytes_io = BytesIO() imgMaster.save(bytes_io, format="PNG") bytes_io.seek(0) imgData = bytes_io.read() if doPrint: bytes_io.seek(0) self.p.image(bytes_io, impl=self.printerConf['printType']) # return: PIL-object, height (int), PNG-file return (imgMaster, height, imgData) def qrIcon(self, url, size=120): iconHeight = size qr = qrcode.QRCode( version=1, error_correction=qrcode.constants.ERROR_CORRECT_M, box_size=10, border=4, ) qr.add_data(url) qr.make(fit=True) img = qr.make_image() return img.resize((iconHeight, iconHeight)) def commonPrint(self, conn, srcType): try: dbPrinter = conn.cursor() dbPrinter.execute( """SELECT printout.id, printout.jdoc FROM printout INNER JOIN srcType ON srcType.id = printout.srcType WHERE srcType.shortName = %s AND printed = 0 ORDER BY printout.id ASC LIMIT 1""", (srcType, )) row = dbPrinter.fetchone() # if there is something unprinted waiting for us for the given srcType if row is not None: data = json.loads(row[1]) printFunc = getattr(self, srcType.lower()) printData = printFunc(data) # Hmm. one could argue that if printing something fails, # then the message should not be marked as printed in the db.. dbPrinter.execute( """UPDATE printout SET height = %s, printed = 1, printedImg = _binary %s, printedImgRotated = %s, printedImgMimeType = %s WHERE id=%s""", (str(printData[0]), printData[1], str( printData[2]), printData[3], str(row[0]))) dbPrinter.close() except Exception, e: print(e) try: print( "The id for the failed message in the printout table: %i" % row[0]) except: pass else:
area = (0, STRIP_WIDTH * i, img_w, STRIP_WIDTH * (i + 1)) strips[i] = image.crop(area) if img_h % STRIP_WIDTH != 0: strips[-1] = strips[-1].crop((0, 0, img_w, img_h % STRIP_WIDTH)) # Dump strips into a temporary directory if not os.path.exists('.temp'): os.mkdir('.temp') for i in range(num_strips): strips[i].save(os.path.join('.temp', "strip{0:03}.png".format(i))) # Do the printing p = Serial(devfile='COM5', baudrate=9600, parity='N', stopbits=1, timeout=1.00, dsrdtr=True) p.text("\033@") # Reset p.text("\033C\20") # Set sheet eject length p.text("\0331") # Select 1/8-inch line spacing p.text("\033$\000\000") # Set left margin p.text("\033a\001") # Center align for i in range(num_strips): p.image(os.path.join('.temp', "strip{0:03}.png".format(i))) p.text("\033a\000") # Left align #p.cut()
parity='N', stopbits=1, timeout=1.00, dsrdtr=True) p.text("\033@") # Reset p.text("\033C\100") # Set sheet eject length p.text("\0331") # Select 1/8-inch line spacing p.text("\033$\000\030") # Set left margin p.text("\033a\000") # Left align p.text("See back of receipt for your chance\n") p.text("to win $1000 ID #:7N77MVS1VUY\n") p.text("\033a\001") # Center align p.image("C:\\Users\\Alexander\\Desktop\\download.jpg") p.text("978-851-6265 Mgr:BETH WATERHOUSE\n") p.text("333 MAIN ST\n") p.text("TEWKSBURY MA 01876\n") p.text("\033a\000") # Left align p.text("ST# 02222 OP# 009056 TE# 56 TR# 00079\n") p.text("PRNCS DIA RING 00128182447 F 52000.00 T\n") p.text("PRNCS DIA RING 00128182447 F 52000.00 T\n") p.text("PRNCS DIA RING 00128182447 F 52000.00 T\n") p.text("PRNCS DIA RING 00128182447 F 52000.00 T\n") p.text("PRNCS DIA RING 00128182447 F 52000.00 T\n") p.text("PRNCS DIA RING 00128182447 F 52000.00 T\n") p.text("PRNCS DIA RING 00128182447 F 52000.00 T\n") p.text("PRNCS DIA RING 00128182447 F 52000.00 T\n")