Using the lcdgfx library

Enfield Cat's Blog: Arduino and other projects.


One display library to rule them all?

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.


How are fixed width fonts configured?

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:

0x000x00 = fixed width font, 0x02 = variable width
0x0AFont width, 0x0A = 10 pixels wide
0x18Font height, 0x18 = 24 pixels high
0x20The 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.

comic_sans_font24x32_123

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



       *
      **
     ***
    ****
   *****
   ****
   ****
   ****
   ****
   *****
    ****
    ****
     ***
      **
    ****
   *****
  ******
  *****
   **





*****
******
*******
********
    ****
     ***
      **
       *
      **
    ****
  ******
********
*******
*****
********
********
********
   *****









*
**  ****
********
********
********
*****
*****
 *******
  ******
   *****
     ***
*
*












*
**
***
****    
****
****
****
***
***
**








Extract A Font from Linux

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.

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.cloudHome