Nastroj pro generovani fontu (neuplny!!!)
This commit is contained in:
		
							
								
								
									
										205
									
								
								tools/fontconv.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										205
									
								
								tools/fontconv.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,205 @@ | |||||||
|  | #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)) | ||||||
							
								
								
									
										1
									
								
								tools/requirements.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tools/requirements.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | PIL | ||||||
							
								
								
									
										7
									
								
								tools/test_fontconv.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								tools/test_fontconv.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | # python3 fontconv.py "built titling lt.ttf" 25 0x30 0xff 1 1 cp852 | ||||||
|  | # python3 fontconv.py "built_titling_lt.ttf" 25 0x20 0x3f 1 1 cp852 | ||||||
|  | # python3 fontconv.py "built_titling_lt.ttf" 60 0x30 0x39 1 1 cp852 | ||||||
|  | # python3 fontconv.py "built_titling_sb.ttf" 60 0x30 0x39 1 1 cp852 | ||||||
|  | #python3 fontconv.py "built_titling_sb.ttf" 60 0x20 0x23 1 1 cp852 | ||||||
|  | #python3 fontconv.py "built_titling_sb.ttf" 60 0x23 0x24 1 1 cp852 | ||||||
|  | python3 fontconv.py "built_titling_sb.ttf" 60 0x30 0x39 1 1 cp852 | ||||||
		Reference in New Issue
	
	Block a user