I’ve been using this python3 script (originally by @drummyfish, some modifications by me) to make custom fonts. The script takes a .png charmap and prints the font data which you can copy to your my_font.h file.
fontconv.py
#!/usr/bin/env python3
# Convert bitmap font to array. Usage:
#
# python3 fontconv.py charmap.png [only caps] [monospace width]
#
# original author: Miloslav Ciz
# modified by: jpfli
# license: CC0 1.0
import sys
from PIL import Image
# Configuration
firstChar = ord(' ')
lastChar = ord('\x7f')
lastCharCaps = ord(']')
indent = 4
# Command line parameters
if len(sys.argv) < 2:
print("Usage: "+sys.argv[0]+" charmap.png [only caps] [monospace width]")
exit(0)
onlyCaps = len(sys.argv) >= 3 and int(sys.argv[2]) != 0
monospaceWidth = 0 if len(sys.argv) < 4 else int(sys.argv[3])
image = Image.open(sys.argv[1])
pixels = image.load()
numChars = 1 + (lastCharCaps if onlyCaps else lastChar) - firstChar
charDiv = (image.size[0] + 1) // numChars
fontH = image.size[1]
fontHRound = ((fontH + 7)//8)*8
startCol = charDiv
endCol = 0
charArray = []
for i in range(numChars):
columns = []
for x in range(charDiv):
bitcol = [0]*fontHRound
for y in range(fontH):
bitcol[y] = 1 if pixels[i*charDiv + x, y][0] == 0 else 0
if sum(bitcol) != 0:
if x + 1 > endCol:
endCol = x + 1
if x < startCol:
startCol = x
column = []
while len(bitcol) >= 8:
column.append(sum([bitcol[j]<<j for j in range(8)]))
bitcol = bitcol[8:]
columns.append(column)
charArray.append(columns)
fontW = monospaceWidth if monospaceWidth > 0 else endCol - startCol
print(' '*indent + str(fontW) + ", " + str(fontH) + ", " + str(firstChar) + ", " + ('1' if onlyCaps else '0') + ", // width, height, start char, only caps")
for i in range(len(charArray)):
columns = charArray[i]
if len(columns) < fontW:
columns += [[0]]*(fontW - len(columns))
charW = monospaceWidth
if monospaceWidth > 0:
# strip empty columns from left side
columns = columns[startCol:] + [[0]*(fontHRound//8)]*startCol
else:
nonZeroIndices = [index for index,value in enumerate([sum(col) for col in columns]) if value != 0]
if len(nonZeroIndices) > 0:
tmp = columns
# strip empty columns from left side
columns = columns[nonZeroIndices[0]:] + [[0]*(fontHRound//8)]*nonZeroIndices[0]
charW = 1 + nonZeroIndices[-1] - nonZeroIndices[0]
else:
charW = fontW//2
line = ""
for x in range(fontW):
for col in columns[x]:
line += "0x" + format(col, '02X') + ", "
line = "0x" + format(charW, '02X') + ", " + line
line += " // " + str(firstChar + i) + ": '" + chr(firstChar + i) + "'"
print(' '*indent + line)
Example charmap:
What comes to the problem with font height, I took a look in PokittoLib and there is a height limit of 16 pixels in the draw function bufferChar(x, y, index)
(in PokittoFrameBuffer.cpp). But if you are having problems even with smaller font heights then there is some other problem.
Anyway, below is a version of the bufferChar(x, y, index)
function that can handle any font height.
PokittoFrameBuffer.cpp bufferChar(x, y, index) function
int Display::bufferChar(int16_t x, int16_t y, uint16_t index){
uint8_t w = font[0];
uint8_t h = font[1];
uint8_t hbytes=((h + 7)>>3); //GLCD fonts are arranged w+1 times h/8 bytes
const uint8_t* bitmap = font + 4 + index*(1 + w*hbytes); //add an offset to the pointer
int8_t i, j;
uint8_t charW = *bitmap; //first byte of char is char width
++bitmap;
// GLCD fonts are arranged LSB = topmost pixel of char, so its easy to just shift through the column
uint32_t bitcolumn; //16 bits for 2x8 bit high characters
if( fontSize != 2 ) fontSize = 1;
void (*drawPixelFG)(int16_t,int16_t, uint8_t) = &Display::drawPixelNOP;
void (*drawPixelBG)(int16_t,int16_t, uint8_t) = &Display::drawPixelNOP;
if( x>=0 && y >= 0 && x+w*fontSize<width && y+(h+1)*fontSize<height ){
if( color != invisiblecolor )
drawPixelFG = &Display::drawPixelRaw;
if( bgcolor != invisiblecolor )
drawPixelBG = &Display::drawPixelRaw;
}else{
if( color != invisiblecolor )
drawPixelFG = &Display::drawPixel;
if( bgcolor != invisiblecolor )
drawPixelBG = &Display::drawPixel;
}
void (*drawPixel[])(int16_t,int16_t, uint8_t) = {drawPixelBG, drawPixelFG};
uint8_t colors[] = {static_cast<uint8_t>(bgcolor), static_cast<uint8_t>(color)};
#if PROJ_ARDUBOY > 0
#else
if( fontSize != 2 ){
#endif
for (i = 0; i < charW; ++i) {
for(uint32_t byteNum = 0; byteNum < hbytes; ++byteNum) {
bitcolumn = *bitmap;
++bitmap;
uint32_t endRow = (8 + 8*byteNum < h) ? (8 + 8*byteNum) : h;
for (j = 8*byteNum; j < endRow; ++j) { // was j<=h
uint8_t c = colors[ bitcolumn & 1 ];
#if PROJ_ARDUBOY > 0
drawPixel[ bitcolumn&1 ](x, y + 7 - j,c);
#elif PROJ_SUPPORT_FONTROTATION > 0
// if font flipping & rotation is allowed - do not slow down old programs!
if (flipFontVertical) {
drawPixel[ bitcolumn&1 ](x, y + h - j,c);
} else {
drawPixel[ bitcolumn&1 ](x, y + j,c);
}
#else
// "Normal" case
drawPixel[ bitcolumn&1 ](x, y + j,c);
#endif // PROJ_ARDUBOY
bitcolumn>>=1;
}
}
#if PROJ_SUPPORT_FONTROTATION > 0
if (flipFontVertical) x--;
else x++;
#else
x++;
#endif
}
#if PROJ_SUPPORT_FONTROTATION > 0
if (flipFontVertical) return -charW-adjustCharStep;
else return charW+adjustCharStep; // for character stepping
#else
return charW+adjustCharStep;
#endif
#if PROJ_ARDUBOY > 0
#else
}else{
for (i = 0; i < charW; ++i) {
for(uint32_t byteNum = 0; byteNum < hbytes; ++byteNum) {
bitcolumn = *bitmap;
++bitmap;
uint32_t endRow = (8 + 8*byteNum < h) ? (8 + 8*byteNum) : h;
for (j = 8*byteNum; j < endRow; ++j) { // was j<=h
uint8_t c = colors[ bitcolumn & 1 ];
drawPixel[ bitcolumn&1 ](x + (i<<1) , y + (j<<1), c);
drawPixel[ bitcolumn&1 ](x + (i<<1)+1, y + (j<<1), c);
drawPixel[ bitcolumn&1 ](x + (i<<1) , y + (j<<1)+1, c);
drawPixel[ bitcolumn&1 ](x + (i<<1)+1, y + (j<<1)+1, c);
bitcolumn>>=1;
}
}
}
return (charW+adjustCharStep)<<1;
}
#endif // PROJ_ARDUBOY
}
With that fix, I tried the text outline method mentioned in another thread using a 50px high font on top of a 52px high outline font.
Source code: bigfont.zip (32.1 KB)