Enfield Cat's Blog: Arduino and other projects.
The Arduino "lcdgfx" looks really good and like it covers most small LCD displays used in the Arduino world. It is relatively easy to set up in a project and use. This ease of use and support for many different display types is what has made lcdgfx attractive to projects such as miniThrottle.
The comments here refer to how fonts are created for "lcdgfx" library only. Other libraries may store their font representations differently.
Each font is a string of bytes representing the font. The 1st 4 bytes give some "dimensional" data, followed by a bit-map for each character. The dimensional data used, looks as follows:
0x00 | 0x00 = fixed width font, 0x02 = variable width |
0x0A | Font width, 0x0A = 10 pixels wide |
0x18 | Font height, 0x18 = 24 pixels high |
0x20 | The ASCII value of the first character represented, 0x20 = 32 = space |
To explore the bit map we'll take a large font which will demonstrate the princples used. For this a 24 pixel wide by 32 high "Comic Sans" font is used, but we will just examine one character: ampersand (&). Next by dumping out a bit map of each byte, such that binary zeros become spaces and binary ones become asterisks, we find the pattern in the table below. What we observe is as a 24 bit wide pixel, the first 24 bytes represent a band 8 pixels high at the top of the character. The next 24 bytes a second band of 8 pixels high, and so on. The result is a character that appears to be lying on its side - rotated ninety degrees clockwise.
Note: The documentation includes a note that some of the bigger fonts (which would be useful on larger displays) only work on one display type. (ssd1306) Your usage of these larger fonts may be limited in the current version of the library.
NB: the right to left rendering here, with the least significant bit furthest right. This bit is the top left hand bit of the displayed character.
4th 24x8 bits | 3rd 24x8 bits | 2nd 24x8 bits | 1st 24x8 bits |
---|---|---|---|
* ** *** **** ***** **** **** **** **** ***** **** **** *** ** **** ***** ****** ***** ** | ***** ****** ******* ******** **** *** ** * ** **** ****** ******** ******* ***** ******** ******** ******** ***** | * ** **** ******** ******** ******** ***** ***** ******* ****** ***** *** * * | * ** *** **** **** **** **** *** *** ** |
While lcdgfx comes with several fonts, is it possible to take a font from Linux (say for example from /usr/share/fonts/X11/misc/) and use that? It would appear so. However, the answer is "Yes, But".
g++ -O -o convdbf convbdf.cpp
Taking the above into account the following is a work-around to extract the font from Linux and rewrite it in lcdgfx format. Maybe not efficient or elegant, but good enough for somthing that is only occasionally run.
Some prerequisites are required. Assuming you are using Ubuntu, then addition to the C++ compiler, you will need the following to convert ungzipped pcf files to an intermediate bdf format and a version of awk that does bitwise "and" operations:apt-get install pcf2bdf gawk
Then the conversion code, eg place in font2ino.sh:
# Initial checks if [ "${1}" = "" ] ; then echo "$0 <source-font> [output-file [font-name]]" exit 0 fi if [ "${2}" = "" ] ; then fileName="font.c" else fileName="${2}" fi if [ "${3}" = "" ] ; then fontName="new_font" else fontName="${3}" fi if [ -f temp.bdf ] ; then rm temp.bdf fi if [ -f preamble.tmp ] ; then rm preamble.tmp ; fi # Convert pcf to bdf - comment out this line if using dbf sources pcf2bdf $1 > temp.bdf # Extract and format data to intermediate form # Allow for dynamic switch between pcf conversion and bdf if [ -f temp.bdf ] ; then sourceFile="temp.bdf" else sourceFile=$1 fi # do the extraction ./convbdf "${sourceFile}" temp | egrep -v "namespace|static const|#include|^$|\};|Advance:|Box:|^\/\/$" | awk -v fontName="${fontName}" -v inFile="${1}" ' BEGIN { mode = 0 print "// Comments represent source data information, not extracted font information" > "header.tmp" print "//###########################################################################" >> "header.tmp" print "//" >> "header.tmp" print "// Contents are extracted from " inFile >> "header.tmp" print "//" >> "header.tmp" print "//###########################################################################" >> "header.tmp" print "//" >> "header.tmp" printf ("\nconst PROGMEM uint8_t %s[] = {\n", fontName) >> "header.tmp" printf ("0x00, // Fixed width font\n" ) >> "header.tmp" } /\/\/ Font information:/ { mode = 3 } /\/\/ Bounding box/ { split ($2, part, ",") printf ("FontWidth=%d\n", part[1]) >> "preamble.tmp" split ($3, part, ",") printf ("FontHeight=%d\n", part[1]) >> "preamble.tmp" } /Character / { if ($3 < 32) mode = 0 if ((mode == 0 || mode==3) && $3 == 32) { mode = 1 printf ("FirstChar=%d\n", $3) >> "preamble.tmp" } if ($3>127) mode = 2 } { if (mode==1) { if (substr($1,1,1) == "/") print $0 else for (a=1; a<=NF; a++) { if (substr($a,1,2) == "0x") { nu = 0 for (b=3; b<5; b++) { nu = nu * 16 val = substr($a,b,1) if (val >= "0" && val <= "9") nu = nu + val else { if (val == "A") bar = 10 else if (val == "B") bar = 11 else if (val == "C") bar = 12 else if (val == "D") bar = 13 else if (val == "E") bar = 14 else if (val == "F") bar = 15 nu = nu + bar } } print nu } else print $a } } if (mode==3 && $1=="//") print $0 >> "header.tmp" } # END { # printf ("0x00 };\n") # } ' > "${fileName}.bat" . ./preamble.tmp gawk -v FirstChar="${FirstChar}" -v FontWidth="${FontWidth}" -v FontHeight="${FontHeight}" ' BEGIN { inputWidth=int(FontWidth/8) if (FontWidth%8 > 0) inputWidth++ outputWidth=int(FontHeight/8) if (FontHeight%8 > 0) outputWidth++ inheight=0 inwidth=0 ol="" po[0] = 128 po[1] = 64 po[2] = 32 po[3] = 16 po[4] = 8 po[5] = 4 po[6] = 2 po[7] = 1 printf ("0x%02x, // Font Width\n", FontWidth) printf ("0x%02x, // Font Height\n", FontHeight) printf ("0x%02x, // First Character\n", FirstChar) } { if (substr($1,1,1) == "/") print $0 else { for (n=0; n<8; n++) { if ( and((po[n]+0), ($1+0)) ) val = "*" else val = " " ol = sprintf ("%s%s", ol, val) } if (++inwidth >= inputWidth) { inwidth = 0 inheight++ pixLine[inheight] = ol if (inheight == FontHeight) { inheight = 0 for (inline=0; inline<FontHeight; inline+=8) { lineoffset = inline + 8 if (lineoffset > FontHeight) lineoffset = FontHeight for (coloffset=1; coloffset<=FontWidth; coloffset++) { outval = 0 zs = lineoffset for (j=0; j<8; j++) { outval = outval * 2 if (zs > inline && substr(pixLine[zs], coloffset, 1) == "*") { outval = outval + 1 } zs-- } printf ("0x%02x, ", outval) } } printf ("\n") } ol = "" } } } END { printf ("0x00 }; \n") } ' "${fileName}.bat" > "${fileName}.tmp" cat header.tmp "${fileName}.tmp" > "${fileName}" if [ -f "${fileName}.bat" ] ; then rm "${fileName}.bat" fi if [ -f "${fileName}.tmp" ] ; then rm "${fileName}.tmp" fi if [ -f "header.tmp" ] ; then rm "header.tmp" fi if [ -f "preamble.tmp" ] ; then rm "preamble.tmp" fi if [ -f "temp.bdf" ] ; then rm "temp.bdf" fi
Using fonts from an archive, such as the https://github.com/masaeedu/bitmap-fonts mentioned previously, a variant of the above script could be used as follows:
./font2ino.sh ./bitmap-fonts/bitmap/spleen/spleen-16x32.bdf a_font_16x32.ino spleen cp a_font_16x32.ino ../Arduino/ESP32_miniThrottle/a_font_16x32.ino
Please check if there are any copyrights on the fonts and then use or avoid as appropriate.
Thank you for visiting camelthorn.cloud | Home |