def consoleStuff(): degreesSomething = os.popen("vcgencmd measure_temp").readline() degreesSomething = degreesSomething.replace("temp=", "") enterCount = Sub.select().where(Sub.status == entered).count() placeCount = Sub.select().where(Sub.status == placed).count() readyCount = Sub.select().where(Sub.status == gcode).count() burntCount = Sub.select().where(Sub.status == burnt).count() print(t.clear()) print(t.bold("Main: ") + thread1) print(t.bold("PubSub: ") + thread2) print(t.bold("Placer: ") + thread3) print(t.bold("Maker: ") + thread4) print(t.bold("Sender: ") + thread5) #stat readout print( str(enterCount) + " en | " + str(placeCount) + " pl | " + str(readyCount) + " rdy | " + str(burntCount) + " burnd") print(degreesSomething) #time at bottom of screen #want this to be uptime but meh now = datetime.utcnow() print(str(now)) #no more of this billion thread crap #garbage = Timer(1, consoleStuff).start() time.sleep(1)
def deraLict(): noNotGd = Sub.select().where(Sub.status == placed).count() if noNotGd > 0: print("main: found un-gcoded stuff, fixing") gList = Sub.select().where(Sub.status == placed) for name in gList: makeGcode(name)
def deraLict(): noNotGd = Sub.select().where(Sub.status == placed).count() if noNotGd > 0: consoleClass.thread1 = "found " + str( noNotGd) + " un-gcoded names, fixing" gList = Sub.select().where(Sub.status == placed) for name in gList: makeGcode(name)
def testies(testicalNum): while not threadQuit: entriesNo = Sub.select().where(Sub.status >= placed).count() consoleClass.thread1 = str(entriesNo) + " of " + str( testicalNum) + " names processed" if testicalNum == entriesNo: endTheDamnTest()
def makeDb(): fileName = open("subscriberListTest.txt") count = 0 for entry in fileName: entry = entry.strip() #fast dateTime = datetime.utcnow() + timedelta(seconds=count) count += 1 dbEntry = Sub.create(userName=entry, entryTime=dateTime) dbEntry.save() consoleClass.thread2 = str(count) + " entered to db" #slow #consoleClass.thread4 = "added " + entry #time.sleep(random.randint(10,100)) #up to 10 seconds for testing #time.sleep(0.2) consoleClass.thread2 = str(count) + " entered to db, done you f**k" fileName.close() return count
def testies(testicalNum): lineNo = makeDb() + testicalNum print("test: added " + str(lineNo) + ' to db, done txt') while not threadQuit: entriesNo = Sub.select().where(Sub.status >= placed).count() if lineNo == entriesNo: endTheDamnTest()
def makeOnePng(): #I changed this to use the nice looking board backing #the main code uses the center.png regular from settings.py center = Image.open("centerFancy.png") backing = Image.new('RGBA', (board_l, board_h), color=(255, 255, 255, 255)) draw = ImageDraw.Draw(backing) #overlay center keepout consoleClass.thread3 = "making backing for png" center_l, center_h = center.size centerPos_l = int((board_l / 2) - (center_l / 2)) centerPos_h = int((board_h / 2) - (center_h / 2)) backing.alpha_composite(center, (centerPos_l, centerPos_h)) #create backing image based on db nameWasPlaced = (Sub.select().where(Sub.status >= placed).order_by( Sub.entryTime)) #i = 0 #filename = "sequence png/sequence%03d.png" % (i,) #reBacking = backing.resize(size,Image.LANCZOS) #nuBacking = Image.new('RGBA', (1920,1080), color=(0,0,0,0)) #nuBacking.alpha_composite(reBacking, (0,305)) #nuDraw = ImageDraw.Draw(nuBacking) #userNumText = "Entries: 000" #nuFont = ImageFont.truetype(ttfFont, 72) #nuDraw.text((5,800), userNumText, (255,255,255), font = nuFont) #nuBacking.save(filename) #reBacking.save(filename) #backing.save("sequence png/sequence_unscale.png") #i = 1 for place in nameWasPlaced: font = ImageFont.truetype(ttfFont, place.fontSize) draw.text((place.positionX, place.positionY), place.userName, (0, 0, 0), font=font) #write the test image of the board #print("printing output") #filename = "sequence png/sequence%03d.png" % (i,) #reBacking = backing.resize(size,Image.LANCZOS) #nuBacking = Image.new('RGBA', (1920,1080), color=(48,48,48,255)) #nuBacking.alpha_composite(reBacking, (0,305)) #nuDraw = ImageDraw.Draw(nuBacking) #userNumText = "Entries: %03d" % (i,) #nuFont = ImageFont.truetype(ttfFont, 72) #nuDraw.text((5,800), userNumText, (255,255,255), font = nuFont) #l,h = nuFont.getsize(place.userName) #position = (1920 - 5) - l #nuDraw.text((position, 800), place.userName, (255,255,255), font = nuFont, anchor = 'Right') #nuBacking.save(filename) #i += 1 consoleClass.thread3 = "printing output png" filename = "output.png" backing.save(filename)
def main(): #change when parking lot is generated for visual. center = Image.open('center.png') backing = Image.new('RGBA', (board_l, board_h), color=(255, 255, 255, 255)) draw = ImageDraw.Draw(backing) center_l, center_h = center.size centerPos_l = int((board_l / 2) - (center_l / 2)) centerPos_h = int((board_h / 2) - (center_h / 2)) backing.alpha_composite(center, (centerPos_l, centerPos_h)) nameToPlace = (Sub.select().where(Sub.status >= 0)) for sub in nameToPlace: print("placing: " + sub.userName) font = ImageFont.truetype(fontFile, sub.fontSize) draw.text((sub.positionX, sub.positionY), sub.userName, (0, 0, 0), font=font) #write the test image of the board print("printing output") backing.save("test.png")
def gSend(): # Initialize s = serial.Serial(serialLoc, speed) #maybe open this in BTS main, pass it into gSend print("burning: initializing grbl...") s.write(b'\r\n\r\n') # Wait for grbl to initialize and flush startup text in serial input time.sleep(2) s.flushInput() #search db for entry, in order names = Sub.select().where(Sub.status == gcode) #header gBurn(homeCmd + unitsCmd + modeCmd + feedCmd, s) for name in names: print("burner: " + name.userName) gBurn(name.gCode, s, True) name.status = burnt name.save() #footer gBurn(stopCmd + pulloffCmd, s) print('burner: done burning!') s.close() return True
def gSend(): # Initialize s = serial.Serial(serialLoc, speed) #maybe open this in BTS main, pass it into gSend consoleClass.thread5 = "initializing grbl..." s.write(b'\r\n\r\n') # Wait for grbl to initialize and flush startup text in serial input time.sleep(2) s.flushInput() #search db for entry, in order names = Sub.select().where(Sub.status == gcode) #header consoleClass.thread5 = "homing" gBurn(homeCmd + unitsCmd + modeCmd + feedCmd, s) for name in names: consoleClass.thread5 = name.userName gBurn(name.gCode, s, True) name.status = burnt name.save() #footer gBurn(stopCmd + pulloffCmd, s) consoleClass.thread5 = name.userName + " done" s.close() return True
def enterDb(entry): #console consoleClass.thread2 = entry + " received" dateInfo = datetime.utcnow() dbEntry = Sub.create( userName = entry, entryTime = dateInfo ) dbEntry.save()
def testies(): while not threadQuit: #number of names to process for the test entriesNo = Sub.select().where(Sub.status >= placed).count() #display number of names to process for the test consoleClass.thread1 = str(entriesNo) + " of " + str( testicalNum) + " names processed" #when all names have been placed end the test if testicalNum == entriesNo: endTheDamnTest()
def unParsify(): output = open(outputFile, "a") nameToMake = (Sub.select().where(Sub.status >= placed).order_by( Sub.entryTime)) for sub in nameToMake: print("gcodifying: " + sub.userName) output.write("(Block-name: " + sub.userName + ")\n") output.write(sub.gCode) output.close()
def virtualSub(): #virtual pubsub consoleClass.thread2 = "disabled for test" try: consoleClass.thread1 = "test: initiated. looking for db entries" chromazomes = Sub.select().where(Sub.status >= placed).count() except: consoleClass.thread1 = "test: making new db" chromazomes = 0 chromazomes += makeDb() consoleClass.thread1 = "test: done adding names"
def makeDb(): fileName = open("subscriberListTest.txt") count = 0 for entry in fileName: entry = entry.strip() dateTime = datetime.utcnow() count += 1 dbEntry = Sub.create(userName=entry, entryTime=dateTime) dbEntry.save() print("dbmaker: " + entry) #time.sleep(random.randint(10,100)) #up to 10 seconds for testing print("dbMaker: done, you f**k.") fileName.close() return count
def runBurner(): while not threadQuit: readyCount = Sub.select().where(Sub.status == gcode).count() #console will update separately since this gets stuck in gSend. if readyCount > 0: if readyCount >= 10: LED_Grn.blink() if readyCount < 10: LED_Grn.on() if streamerToggle: gSend() else: LED_Grn.off()
def runBurner(): global gDone while not threadQuit: tomGreen = Sub.select().where(Sub.status == gcode).count() if tomGreen > 0: if tomGreen >= 10: LED_Grn.blink() else: LED_Grn.on() if streamerToggle: gDone = False gSend() gDone = True else: LED_Grn.off()
consoleClass.thread1 = "Octo special Burn the Subs started" try: Thread.daemon = True consoleClass.consoleStuff() #check if there are derelict entries #deraLict() #pubSub #webSocketInit() #virtual pubsub try: consoleClass.thread4 = "looking for db entries" chromazomes = Sub.select().where(Sub.status >= placed).count() except: consoleClass.thread4 = "making new db" chromazomes = 0 chromazomes += makeDb() consoleClass.thread4 = "done adding names" #placer #runPlace() Thread(target=runPlace).start() #thread trap testies(chromazomes) #Thread(target=testies).start() #Thread.daemon = True
def main(): try: center = Image.open(centerFile) except: print("placer: couldn't open center PNG") #sys exit, shut down threads? backing = Image.new('RGBA', (board_l, board_h), color=(255, 255, 255, 255)) draw = ImageDraw.Draw(backing) #overlay center keepout print("placer: making virtual backing, secretly") center_l, center_h = center.size centerPos_l = int((board_l / 2) - (center_l / 2)) centerPos_h = int((board_h / 2) - (center_h / 2)) backing.alpha_composite(center, (centerPos_l, centerPos_h)) #create backing image based on db nameWasPlaced = (Sub.select().where(Sub.status >= gcode).order_by( Sub.entryTime)) i = 0 filename = "sequence png/sequence%03d.png" % (i, ) reBacking = backing.resize(size, Image.LANCZOS) nuBacking = Image.new('RGBA', (1920, 1080), color=(0, 0, 0, 0)) nuBacking.alpha_composite(reBacking, (0, 305)) nuDraw = ImageDraw.Draw(nuBacking) userNumText = "Entries: 000" nuFont = ImageFont.truetype(ttfFont, 72) nuDraw.text((5, 800), userNumText, (255, 255, 255), font=nuFont) nuBacking.save(filename) #reBacking.save(filename) #backing.save("sequence png/sequence_unscale.png") i = 1 for place in nameWasPlaced: font = ImageFont.truetype(ttfFont, place.fontSize) draw.text((place.positionX, place.positionY), place.userName, (0, 0, 0), font=font) #write the test image of the board print("printing output") filename = "sequence png/sequence%03d.png" % (i, ) reBacking = backing.resize(size, Image.LANCZOS) nuBacking = Image.new('RGBA', (1920, 1080), color=(48, 48, 48, 255)) nuBacking.alpha_composite(reBacking, (0, 305)) nuDraw = ImageDraw.Draw(nuBacking) userNumText = "Entries: %03d" % (i, ) nuFont = ImageFont.truetype(ttfFont, 72) nuDraw.text((5, 800), userNumText, (255, 255, 255), font=nuFont) l, h = nuFont.getsize(place.userName) position = (1920 - 5) - l nuDraw.text((position, 800), place.userName, (255, 255, 255), font=nuFont, anchor='Right') nuBacking.save(filename) i += 1
def runPlace(): while not threadQuit: noNotPlaced = Sub.select().where(Sub.status == entered).count() if noNotPlaced > 0: placeNames()
def placeNames(): try: center = Image.open(centerFile) except: print("placer: couldn't open center PNG") #sys exit, shut down threads? backing = Image.new('RGBA', (board_l, board_h), color=(255, 255, 255, 255)) draw = ImageDraw.Draw(backing) #overlay center keepout print("placer: making virtual backing, secretly") center_l, center_h = center.size centerPos_l = int((board_l / 2) - (center_l / 2)) centerPos_h = int((board_h / 2) - (center_h / 2)) backing.alpha_composite(center, (centerPos_l, centerPos_h)) #create backing image based on db nameWasPlaced = (Sub.select().where(Sub.status >= placed)) for place in nameWasPlaced: font = ImageFont.truetype(ttfFont, place.fontSize) draw.text((place.positionX, place.positionY), place.userName, (0, 0, 0), font=font) backing_bits = imageToBits(backing) #check database for names to place # WARNING: we must convert this to a list from the default lazy iterator, # or the value of totalEntries won't update due to SQL isolation weirdness nameToPlace = list(Sub.select().where(Sub.status == entered).order_by( Sub.entryTime)) totalEntries = Sub.select().where(Sub.status >= placed).count() for sub in nameToPlace: #LED_TYel.on() fontSize = fscale(fontMin, fontMax, totalEntries, curve) blurRad = int(fontSize / bScale) #pixel radius of blur fail = True #debug print("DEBUG: read totalEntries = %i" % totalEntries) #print("placer: " + sub.userName) #this should be a function for font choice based on number of existing names #the database population function/module/program should do this font = ImageFont.truetype(ttfFont, fontSize) l, h = font.getsize(sub.userName) l += (blurRad * 2) h += (blurRad * 2) textBox = Image.new('RGBA', (l, h), color=(255, 255, 255, 255)) draw1 = ImageDraw.Draw(textBox) draw1.text((blurRad, blurRad), sub.userName, (0, 0, 0), font=font) # must be the same as what we finally draw to the image or stuff breaks textBox_noblur_bits = imageToBits(textBox) textBox = textBox.filter(ImageFilter.GaussianBlur(radius=blurRad)) textBox_bits = imageToBits(textBox) #for testing the bitmap vs non-bitmap #new_backing_bits = imageToBits(backing) #assert backing_bits == new_backing_bits failcount = 0 start_time = time.perf_counter() while fail == True: #instead just do a random location for test board_l2 = board_l - l board_h2 = board_h - h pixOffset = border * pixMM Rboard_l = random.randint((0 + pixOffset), (board_l2 - pixOffset)) Rboard_h = random.randint((0 + pixOffset), (board_h2 - pixOffset)) fail = False #look for collision shift_by = board_l - l - Rboard_l for i in range(0, h, 1): # align the images by chopping off pixels from the right of backing if ((backing_bits[i + Rboard_h] >> shift_by) & textBox_bits[i]) != 0: failcount += 1 runtime = time.perf_counter() - start_time if (failcount % 2000) == 0: print("placer: %s :failfish: #%i, %f sec (avg %f)" % (sub.userName, failcount, runtime, runtime / failcount)) #LED_TYel.blink() fail = True break if fail: continue """ # try the old check too, just in case for i in range(0, l, 1): for j in range(0, h, 1): shift_l = i + Rboard_l shift_h = j + Rboard_h r, g, b, a = backing.getpixel((shift_l, shift_h)) r1, g1, b1, a1 = textBox.getpixel((i, j)) #compare backing to text for overlap if (r,g,b,a) != (255,255,255,255) and (r1,g1,b1,a1) != (255,255,255,255): #print("placer: :failfish:") #LED_TYel.blink() failcount += 1 runtime = time.perf_counter() - start_time print("placer: OH NO SURPRISE %s :failfish: #%i at (%i, %i) in %f sec (avg %f)" % (sub.userName, failcount, i, j, runtime, runtime / failcount)) fail = True assert(False) break if fail == True: break """ runtime = time.perf_counter() - start_time print("placer: placed %s in %i attempts and %f seconds" % (sub.userName, failcount + 1, runtime)) #now overlay that onto the board draw.text((Rboard_l + blurRad, Rboard_h + blurRad), sub.userName, (0, 0, 0), font=font) for i in range(0, h, 1): backing_bits[i + Rboard_h] |= textBox_noblur_bits[i] << shift_by #update db with good location #sub.transaction(lock_type=None) sub.positionX = Rboard_l + blurRad sub.positionY = Rboard_h + blurRad sub.fontSize = fontSize sub.status = placed sub.save() totalEntries += 1
def placeNames(): center = Image.open(centerFile) backing = Image.new('RGBA', (board_l, board_h), color=(255, 255, 255, 255)) draw = ImageDraw.Draw(backing) #overlay center keepout consoleClass.thread3 = "making mask" center_l, center_h = center.size centerPos_l = int((board_l / 2) - (center_l / 2)) centerPos_h = int((board_h / 2) - (center_h / 2)) backing.alpha_composite(center, (centerPos_l, centerPos_h)) #create backing image based on db nameWasPlaced = Sub.select().where(Sub.status >= placed) for place in nameWasPlaced: font = ImageFont.truetype(ttfFont, place.fontSize) draw.text((place.positionX, place.positionY), place.userName, (0, 0, 0), font=font) backing_bits = imageToBits(backing) #check database for names to place # WARNING: we must convert this to a list from the default lazy iterator, # or the value of totalEntries won't update due to SQL isolation weirdness nameToPlace = list(Sub.select().where(Sub.status == entered).order_by( Sub.entryTime)) totalEntries = Sub.select().where(Sub.status >= placed).count() consoleClass.thread3 = str(totalEntries) + " to place" for sub in nameToPlace: LED_TYel.on() fontSize = fscale(fontMin, fontMax, totalEntries, curve) blurRad = int(fontSize / bScale) #pixel radius of blur fail = True #debug #print("placer: " + sub.userName) consoleClass.thread3 = sub.userName + " placing" #font would change based on size here, but tracing the interior #of the avenir font lets us use the same one throughout font = ImageFont.truetype(ttfFont, fontSize) l, h = font.getsize(sub.userName) l += (blurRad * 2) h += (blurRad * 2) textBox = Image.new('RGBA', (l, h), color=(255, 255, 255, 255)) draw1 = ImageDraw.Draw(textBox) draw1.text((blurRad, blurRad), sub.userName, (0, 0, 0), font=font) # must be the same as what we finally draw to the image or stuff breaks textBox_noblur_bits = imageToBits(textBox) textBox = textBox.filter(ImageFilter.GaussianBlur(radius=blurRad)) textBox_bits = imageToBits(textBox) failcount = 0 start_time = time.perf_counter() while fail == True: #instead just do a random location for test board_l2 = board_l - l board_h2 = board_h - h pixOffset = border * pixMM Rboard_l = random.randint((0 + pixOffset), (board_l2 - pixOffset)) Rboard_h = random.randint((0 + pixOffset), (board_h2 - pixOffset)) fail = False #look for collision shift_by = board_l - l - Rboard_l for i in range(0, h, 1): # align the images by chopping off pixels from the right of backing if ((backing_bits[i + Rboard_h] >> shift_by) & textBox_bits[i]) != 0: failcount += 1 runtime = time.perf_counter() - start_time if (failcount % 2000) == 0: consoleClass.thread3 = sub.userName + " placing. Fail" + str( failcount) + " times, avg: " + str( runtime / failcount) #print("placer: %s :failfish: #%i, %f sec (avg %f)" % (sub.userName, failcount, runtime, runtime / failcount)) LED_TYel.blink() fail = True break if fail: continue runtime = time.perf_counter() - start_time consoleClass.thread3 = sub.userName + " placed in " + str(runtime) #print("placer: placed %s in %i attempts and %f seconds" % (sub.userName, failcount+1, runtime)) #now overlay that onto the board draw.text((Rboard_l + blurRad, Rboard_h + blurRad), sub.userName, (0, 0, 0), font=font) for i in range(0, h, 1): backing_bits[i + Rboard_h] |= textBox_noblur_bits[i] << shift_by #update db with good location #sub.transaction(lock_type=None) sub.positionX = Rboard_l + blurRad sub.positionY = Rboard_h + blurRad sub.fontSize = fontSize sub.status = placed sub.save() totalEntries += 1 LED_TYel.off() makeGcode(sub)
def makeGcode(): print("gCode Maker Running") #open the font file searchFile = open(fontFile, "r") stringFile = searchFile.read() glyphs = [c for c in re.finditer(r'unicode="([^"]+)"', stringFile)] #get constants from font file #graphics design exchange says "vert origin x" value is a thing in ttf #but no evidence of that in the svg conversion so, using ascent. will tweak. ascentEm = float(re.search(r'cap-height="([^"]+)"', stringFile).group(1)) #default horiz adv advanceEm = float(re.search(r'horiz-adv-x="([^"]+)"', stringFile).group(1)) #units-per-em unitsEm = float(re.search(r'units-per-em="([^"]+)"', stringFile).group(1)) #list of names nameToMake = (Sub.select().where(Sub.status == 1).order_by(Sub.entryTime)) #if nameToMake == None: #print("didn't find nobody") for sub in nameToMake: #define gcode block in output file print("making gcode for: " + sub.userName) entryString = "" #do some math #em2MM = (sub.fontSize * point) / unitsEm em2MM = (sub.fontSize * mm2pix) / unitsEm #the y position based on pixel to mm conversion #ascent is needed because PIL places in the upper left of the text #yCursor = (absBoardY) + (sub.positionY * mm2pix) - (ascentEm * em2MM) yCursor = ( (-1) * sub.positionY * mm2pix) - (ascentEm * em2MM) + yPosCal xCursor = (absBoardX) + (sub.positionX * mm2pix) + xPosCal lastChar = None hkern = None for c in sub.userName: #define our letter in Gcode becaus reasons entryString += ("(char = \"" + c + "\")\n") #find c in the font file x = [x for x in range(len(glyphs)) if glyphs[x].group(1) == c] x = int(x[0]) #this is annoying #we need this specifically later but its a location basis to get the gcode lines glyphStartPos = glyphs[x].start() horizPattern = re.compile(r'horiz-adv-x="([^"]+)"') #what position in the massive string is the start and end of gcode block startPos_Gglyph = stringFile.find('\n', glyphStartPos) + 1 #what about '_' (last char before hkern lines in file) #cue: find g and h find the minimum gPos = stringFile.find('g', startPos_Gglyph) - 2 hPos = stringFile.find('h', startPos_Gglyph) - 2 #I could put this in the above but whatever, readability endPos_Gglyph = min(gPos, hPos) #special kern spacing between specific chars at end of file if lastChar != None: #build string and regex it eg: hkern u1="Y" u2="v" k="55" #float(re.search(r"hkern u1=\"Y\" u2=\"v\" k=\"([^\"]+)\"", stringFile).group(1)) #build regex as a string regString = r"hkern u1=\"" + lastChar + "\" u2=\"" + c + "\" k=\"([^\"]+)\"" try: hkern = re.search(regString, stringFile).group(1) xCursor -= float( hkern.group(1)) * em2MM #move cursor back no of mm except: pass #iterate line by line from location to location in the string for line in stringFile[startPos_Gglyph:endPos_Gglyph].split('\n'): #print(line) sLine = line.strip() if sLine: g = GParseQuick(sLine) #scale g.set("X", round((g.get("X") * em2MM), decimalPlaces)) g.set("Y", round((g.get("Y") * em2MM), decimalPlaces)) #translate g.set("X", round((xCursor + g.get("X")), decimalPlaces)) g.set("Y", round((yCursor + g.get("Y")), decimalPlaces)) if g.get("G") == "02" or g.get("G") == "03": g.set("I", round((g.get("I") * em2MM), decimalPlaces)) g.set("J", round((g.get("J") * em2MM), decimalPlaces)) #for the sake of testing entryString += g.unparse() + "\n" else: #handle blank lines entryString += "\n" #move the cursor horizontally for next char, use default if no special space try: advanceX = horizPattern.search(stringFile, glyphStartPos, startPos_Gglyph).group(1) xCursor += (float(advanceX) * em2MM) except: xCursor += (advanceEm * em2MM) #store for next loop lastChar = c #done with sub sub.gCode = entryString sub.status = 2 sub.save() #close the font file print("gCode maker finished") searchFile.close()
def enterDb(entry): print("pubSub: entering " + entry) dateInfo = datetime.utcnow() dbEntry = Sub.create(userName=entry, entryTime=dateInfo) dbEntry.save()
def placeNames(): try: center = Image.open(centerFile) except: print("couldn't open center PNG") #sys exit, shut down threads? backing = Image.new('RGBA', (board_l,board_h), color=(255,255,255,255)) draw = ImageDraw.Draw(backing) #overlay center keepout print("making virtual backing, secretly") center_l, center_h = center.size centerPos_l = int((board_l / 2) - (center_l / 2)) centerPos_h = int((board_h / 2) - (center_h / 2)) backing.alpha_composite(center, (centerPos_l, centerPos_h)) #create backing image based on db nameWasPlaced = (Sub .select() .where(Sub.status >= 1) ) for placed in nameWasPlaced: font = ImageFont.truetype(fontFile, placed.fontSize) draw.text((placed.positionX,placed.positionY), placed.userName, (0,0,0), font = font) #check database for names to place nameToPlace = (Sub .select() .where(Sub.status == 0) .order_by(Sub.entryTime) ) for sub in nameToPlace: totalEntries = Sub.select().where(Sub.status >= 1).count() fontSize = fscale(fontMin, fontMax, totalEntries, curve) blurRad = int(fontSize/bScale) #pixel radius of blur fail = True print("Placer is placing: " + sub.userName) #this should be a function for font choice based on number of existing names #the database population function/module/program should do this font = ImageFont.truetype(fontFile, fontSize) l,h = font.getsize(sub.userName) l += (blurRad * 2) h += (blurRad * 2) textBox = Image.new('RGBA', (l,h), color=(255,255,255,255)) draw1 = ImageDraw.Draw(textBox) draw1.text((blurRad,blurRad), sub.userName, (0,0,0), font = font) textBox = textBox.filter(ImageFilter.GaussianBlur(radius=blurRad)) while fail == True: #instead just do a random location for test board_l2 = board_l - l board_h2 = board_h - h Rboard_l = random.randint(0,board_l2) Rboard_h = random.randint(0,board_h2) fail = False #look for collision for i in range(0, l, 1): for j in range(0, h, 1): shift_l = i + Rboard_l shift_h = j + Rboard_h r, g, b, a = backing.getpixel((shift_l, shift_h)) r1, g1, b1, a1 = textBox.getpixel((i, j)) #compare backing to text for overlap if (r,g,b,a) != (255,255,255,255) and (r1,g1,b1,a1) != (255,255,255,255): print(":failfish:") fail = True break if fail == True: break #now overlay that onto the board draw.text((Rboard_l+blurRad,Rboard_h+blurRad), sub.userName, (0,0,0), font = font) #update db with good location #sub.transaction(lock_type=None) sub.positionX = Rboard_l + blurRad sub.positionY = Rboard_h + blurRad sub.status = 1 sub.fontSize = fontSize sub.save()