#http://stackoverflow.com/questions/5747739/python-render-non-anti-aliased-font-to-internal-image #Author: Pavel Brychta from PIL import Image from PIL import ImageFont, ImageDraw import sys import ast def character(fontname, fontsize, bitsperpixel, char): """ Vykresli znak do vnitrniho povrchu a nasledne ho prevede do pole elementu intenzit, ktere ma vzdy 4 bity/bod (intenzita 0-15). Vraci [rozmer obrazku v ose X, rozmer obrazku v ose Y, Prvni radek obrazku, ktery nese obrazovou informaci (offset od 0), Posledni radek obrazku, ktery nese obrazovou informaci, [pole elementu] """ result = [] usr_font = ImageFont.truetype(fontname, fontsize) imagexsize, imageysize = usr_font.getsize(char) image = Image.new("RGB", (imagexsize, imageysize), "Black") #image = Image.new("RGB", (320, 320), "Black") # print(imagexsize, imageysize) d_usr = ImageDraw.Draw(image) if bitsperpixel > 1: d_usr.fontmode = "L" # Zapneme antialiasovani else: d_usr.fontmode = "1" # Vypneme antialiasovani (pro fonty o hloubce 1bit/pixel) #imagexsize, imageysize = d_usr.textsize(char, usr_font) d_usr.text((0, 0), char, "White", font=usr_font) #print "Imageinfosize:", ord(char), imagexsize, imageysize #image.save('test_' + str(ord(char)) + '.png', 'PNG') pix = image.load() firstimageline = 1000 lastimageline = -1 for x in range(imagexsize): for y in range(imageysize): R, G, B = pix[x, y] if R < 0x08: outpix = 0 elif R < 0x18: outpix = 1 elif R < 0x28: outpix = 2 elif R < 0x38: outpix = 3 elif R < 0x48: outpix = 4 elif R < 0x58: outpix = 5 elif R < 0x68: outpix = 6 elif R < 0x78: outpix = 7 elif R < 0x88: outpix = 8 elif R < 0x98: outpix = 9 elif R < 0xa8: outpix = 10 elif R < 0xb8: outpix = 11 elif R < 0xc8: outpix = 12 elif R < 0xd8: outpix = 13 elif R < 0xe8: outpix = 14 else: outpix = 15 result.append(outpix), if outpix != 0: if firstimageline > y: firstimageline = y if lastimageline < y: lastimageline = y if firstimageline == 1000: firstimageline = imageysize >> 1 lastimageline = firstimageline return imagexsize, imageysize, firstimageline, lastimageline, result def encodechar(chardata, bitsperpixel, firstline, height): """ Prevede zadanou bitovou mapu s rozsahem 0-15 do binarniho tvaru s orezem na viditelnou cast za pomoci firstline a height parametru """ result = [] w, h, rawdata = chardata # print(rawdata) # print(chardata) # print(firstline, w, len(rawdata)) # print(firstline, h, height, len(rawdata)) index = 0 for x in range(w): posBit = 0 outdata = 0 for y in range(h): if (y >= firstline) and (y <= (height + firstline)): data = rawdata[index] >> 3 mask = data << posBit outdata |= mask posBit += 1 if posBit > 7: result.append(outdata) posBit = 0 outdata = 0 index += 1 if posBit != 0: result.append(outdata) # optimalizace dat (odstraneni poslednich bytu, ktere jsou nulove) while len(result) > 1 and result[-1] == 0: del result[-1] return result def buildfontname(fontname, ptsize, charfrom, charto, bitsperpixel, reduceheight, codepage): """ Build ID of the font """ result = "Font" result += fontname.split(".")[0] + "_" result += "{0}pt_".format(ptsize) result += "{0:02X}_".format(charfrom) result += "{0:02X}_".format(charto) return result def createfont(fontname, ptsize, charfrom, charto, bitsperpixel, reduceheight, codepage): """ Write Font file """ fontminline = 65535 fontmaxline = 0 fontrawdata = [] fontheight = 0 fontvaliddata = [] fontoffsets = [] fontsizes = [] actualoffset = 0 fontmonospacewidth = 0 for c in range(charfrom, charto + 1): encchar = chr(c) fchar = character(fontname, ptsize, bitsperpixel, encchar) w, h, ymin, ymax, dummy = fchar if w > fontmonospacewidth: fontmonospacewidth = w # znak je zatim nejsirsi - zapamatujeme si jeho sirku pro monospace vystup fontrawdata.append((w, h, dummy)) if ymin < fontminline: fontminline = ymin # znak zacina drive nez predchozi (ve vyssim bode), zapamatujeme si pocatek if ymax > fontmaxline: fontmaxline = ymax # znak konci pozdeji nez predchozi (v nizsim bode), zapamatujeme si konec if reduceheight: fontheight = fontmaxline - fontminline + 1 # vypocitame si vysku skutecneho pismena else: fontminline = 0 fontheight = h for c in fontrawdata: fontoffsets.append(actualoffset) fontchar = encodechar(c, bitsperpixel, fontminline, fontheight) fontvaliddata.append(fontchar) fontsizes.append(len(fontchar)) actualoffset += len(fontchar) OutFile = open(buildfontname(fontname, ptsize, charfrom, charto, 1, reduceheight, codepage) + ".c", 'w') OutFile.write("/* Font resource created by fontconv.py (c) 2020 by Pavel Brychta (1 bit per pixel)*/\n") OutFile.write("const uint8_t " + buildfontname(fontname, ptsize, charfrom, charto, 1, reduceheight, codepage) + "[] PROGMEM =\n{\n") OutFile.write("\t{0}, /* width for monospace output */\n".format(fontmonospacewidth)) OutFile.write("\t{0}, /* font height */\n".format(fontheight)) OutFile.write("\t{0}, /* first char ID */\n".format(charfrom)) OutFile.write("\t{0}, /* number of characters */\n".format(charto - charfrom + 1)) OutFile.write("\t/* index table: offset MSB, offset LSB, length, width */\n") ptr = 0 for o in fontoffsets: f = fontrawdata[ptr] OutFile.write("\t0x{0:02X},".format((o >> 8) & 0xff)) # MSB OutFile.write("0x{0:02X},".format(o & 0xff)) # LSB OutFile.write("0x{0:02X},".format(fontsizes[ptr])) # length OutFile.write("0x{0:02X},".format(f[0])) # width OutFile.write("\n") ptr += 1 OutFile.write("\t/* glyph raw */") count = 0 for c in fontvaliddata: for u in c: if 0 == count: OutFile.write("\n\t") OutFile.write("0x{0:02X}".format(u)) count += 1 if 20 == count: count = 0 OutFile.write(",") OutFile.write("\n};\n") OutFile.close() def main(argv): if len(argv) != 8: sys.stderr.write("Invalid number of parameters.") return 1 else: fontname = argv[1] # jmeno fontu fontsize = int(argv[2]) # velikost fontu (vyska v bodech) charfrom = ast.literal_eval(argv[3]) # kod prvniho znaku, ktery bude ve vyslednem fontu ulozeny charto = ast.literal_eval(argv[4]) # kod posledniho znaku, ktery bude ve vyslednem fontu ulozeny bitsperpixel = int(argv[5]) # pocet bitu/pixel. Platne hodnoty jsou 1, 2, 4 reduceheight = int(argv[6]) # priznak, zda do vysledneho fontu neukladat "mrtve" oblasti (spocita skutecnou vysku nejvyssiho znaku a na tuto vysku prepocita vsechny ostatni znaky) codepage = argv[7] # pouzita kodova stranka pro narodni znaky (diakritiku) createfont(fontname, fontsize, charfrom, charto, bitsperpixel, reduceheight, codepage) return 0 if __name__ == "__main__": sys.exit(main(sys.argv))