You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
181 lines
7.1 KiB
181 lines
7.1 KiB
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()
|