HydraFerret: Multi-sensor IOT with a simple interface.
↓↓ Dig deeper ↓↓
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".
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.
# 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 preamble.tmp ] ; then rm preamble.tmp ; fi # Convert pcf to bdf pcf2bdf $1 > temp.bdf # Extract and format data to intermediate form ./convbdf temp.bdf 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 awk -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
Thank you for visiting this website | Home |