from __future__ import division from PIL import Image, ImageDraw, ImageFont, ImageOps import re def textBox(text, font, position, limits, colour, draw_black): str = "" limit = [0, 0] limit[0] = limits[0] - position[0] limit[1] = limits[1] - position[1] words = text.split(" ") i = 0 #index of first word sizex, sizey = draw_black.multiline_textsize(str, font) #size of the textbox #while more words to be added to string AND string textbox height < height limit for word in words: sizex, sizey = draw_black.multiline_textsize(str + word, font) sizex2, sizey2 = draw_black.multiline_textsize(str, font) if sizex < limit[0]: #if width of gen textbox < width limit str += word + " " else: sizex, sizey = draw_black.multiline_textsize(str + "\n" + word, font) if(sizey > limit[1]): break else: str = str.rstrip(" ") str += "\n" + word + " " draw_black.text(position, str, font = font, fill = 0) def putImage(imagepath, maskpath, position, colour): img = Image.open(imagepath) mask = Image.open(maskpath).convert(mode='1') if colour is "black": image_black.paste(img, position, mask) if colour is "yellow": image_yellow.paste(img, position, mask) black_invert = ImageOps.invert(image_black.convert('L')) draw_yellow.bitmap((0,0), black_invert, 255) class TextWidget(): #this example widget will have a set size: 3x1 cells (one column) #an instance of this widget class can be created and pasted to canvas def __init__(self, cwidth, cheight, xy = (0, 0), dim = (1, 1), str = ""): self.width = dim[0] self.height = dim[1] self.wt = cwidth*dim[0] self.ht = cheight*dim[1] self.cellX = xy[0] self.cellY = xy[1] self.image_yellow = Image.new('1', (self.wt, self.ht), 255) #255: clear the frame self.draw_yellow = ImageDraw.Draw(self.image_yellow) self.image_black = Image.new('1', (self.wt, self.ht), 255) #255: clear the frame self.draw_black = ImageDraw.Draw(self.image_black) self.font = ImageFont.truetype('DejaVuSans.ttf', 16) self.updateWidget(str) def drawText(self, str): #define parameters for text placement position = (0,0) limit = (self.wt, self.ht) #write the string in the widget textBox(str, self.font, position, limit, "black", self.draw_black) def saveImages(self): print("saving widget images") self.image_black.save("imgBlackWidget.bmp") self.image_yellow.save("imgYellowWidget.bmp") def updateWidget(self, str): self.draw_black.rectangle((0, 0, self.wt, self.ht), fill=255) self.draw_yellow.rectangle((0, 0, self.wt, self.ht), fill=255) self.drawText(str) self.saveImages() class ImageWidget(): #this widget displays an image #needs to recieve an image file as input. Then resize and convert to monochrome. def __init__(self, cwidth, cheight, xy = (0, 0), dim = (1, 1), bwMode = "mono", scaleMode = "fill", img = ""): self.width = dim[0] self.height = dim[1] self.wt = cwidth*dim[0] self.ht = cheight*dim[1] self.cellX = xy[0] self.cellY = xy[1] self.image_yellow = Image.new('1', (self.wt, self.ht), 255) #255: clear the frame self.draw_yellow = ImageDraw.Draw(self.image_yellow) self.image_black = Image.new('1', (self.wt, self.ht), 255) #255: clear the frame self.draw_black = ImageDraw.Draw(self.image_black) self.bwMode = bwMode self.scaleMode = scaleMode self.updateWidget(Image.open(img)) def resizeImg(self, img): #scale image down until whole image fits inside the cell iRatio = img.size[0]/img.size[1] #image ratio cRatio = self.wt/self.ht #canvas ratio if cRatio > iRatio: #height is limiting dimension fixedImg = img.resize((int(self.ht*iRatio), self.ht)) print(" limited by height") return fixedImg if cRatio < iRatio: #width is limiting dimension fixedImg = img.resize((self.wt, int(self.wt/iRatio))) print(" limited by width") return fixedImg fixedImg = img print(" ratios are equal, not limited") return fixedImg def fillImg(self, img): #enlarge the image and crop to fill the widget canvas iRatio = img.size[0]/img.size[1] #image ratio cRatio = self.wt/self.ht #canvas ratio if cRatio > iRatio: print("new sizes as calcd in resize: "+str(self.wt)+" "+str(self.wt/iRatio)) fixedImg = img.resize((self.wt, int(self.wt/iRatio))) #width = wt, calc new height w/ ratio offset = 0.5*(fixedImg.size[1] - self.ht) #centre by height cropped = fixedImg.crop((0, offset, self.wt, offset+self.ht-1)) #cropped.load() print("zoomed to fill height") return cropped if cRatio < iRatio: fixedImg = img.resize((int(self.ht*iRatio), self.ht)) #height = ht, calc new width w/ ratio offset = 0.5*(fixedImg.size[0] - self.wt) #centre by width cropped = fixedImg.crop((offset, 0, offset+self.wt, self.ht-1)) #cropped.load() print("zoomed to fill width") return cropped print("not zoomed") return img.resize((self.wt, self.ht)) def autoThresholdLimit(self, img): gscale = img.convert(mode="L") gscale.save("greyscale.bmp") extrema = gscale.getextrema() print("EXTREMA: "+str(extrema)) limit = extrema[0] + 0.4*(extrema[1]-extrema[0]) print(limit) self.thresLim = limit def threshold(self, val): if(val>self.thresLim): return 1 else: return 0 def bwImg(self, img): self.autoThresholdLimit(img) if self.bwMode is "mono": return img.convert('L').point(self.threshold, '1') if self.bwMode is "dither": return img.convert(mode='1') def pasteImg(self, img): iRatio = img.size[0]/img.size[1] #image ratio cRatio = self.wt/self.ht #canvas ratio if cRatio > iRatio: #needs to be centred horizontally offset = int(0.5*(self.wt - img.size[0])) self.image_black.paste(img, (offset, 0)) if cRatio < iRatio: #needs to be centred vertically offset = int(0.5*(self.ht - img.size[1])) self.image_black.paste(img, (0, offset)) def saveImages(self): print("saving widget images") self.image_black.save("imgBlackWidget.bmp") self.image_yellow.save("imgYellowWidget.bmp") def updateWidget(self, img): if self.scaleMode is "fill": rsImg = self.fillImg(img) if self.scaleMode is "resize": rsImg = self.resizeImg(img) if self.scaleMode is "none": rsImg = img rsImg.save("rsImg.bmp") newImg = self.bwImg(rsImg) newImg.save("bwImg.bmp") print(" Dimensions are now: "+str(newImg.size[0])+"x"+str(newImg.size[1])) print(" Dimensions of widget canvas: "+str(self.wt)+"x"+str(self.ht)) self.pasteImg(newImg) self.saveImages()