Commit 1e1e888f authored by Bodmer's avatar Bodmer

Support extended font formats

Adafruit_GFX font support extended to Unidode Basic Multilingual Plane
Print stream deocdes UTF-8
Smooth font ascent and descent (affects line spacing) changed to rely on
metrics provided by Processing IDE (issue #303)
Bug fix for font rendering with no background on RLE native fonts
parent 6a42e4b1
......@@ -97,7 +97,7 @@ void TFT_eSPI::loadFont(String fontName)
gFont.ascent = (uint16_t)readInt32(); // top of "d"
gFont.descent = (uint16_t)readInt32(); // bottom of "p"
// These next gFont values will be updated when the Metrics are fetched
// These next gFont values might be updated when the Metrics are fetched
gFont.maxAscent = gFont.ascent; // Determined from metrics
gFont.maxDescent = gFont.descent; // Determined from metrics
gFont.yAdvance = gFont.ascent + gFont.descent;
......@@ -147,11 +147,19 @@ void TFT_eSPI::loadMetrics(uint16_t gCount)
gdX[gNum] = (int8_t)readInt32(); // x delta from cursor
readInt32(); // ignored
// Different glyph sets have different ascent values not always based on "d", so get maximum glyph ascent
//Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", gHeight = "); Serial.println(gHeight[gNum]);
//Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", gWidth = "); Serial.println(gWidth[gNum]);
//Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", gxAdvance = "); Serial.println(gxAdvance[gNum]);
//Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", gdY = "); Serial.println(gdY[gNum]);
// Different glyph sets have different ascent values not always based on "d", so we could get
// the maximum glyph ascent by checking all characters. BUT this method can generate bad values
// for non-existant glyphs, so we will reply on processing for the value and disable this code for now...
/*
if (gdY[gNum] > gFont.maxAscent)
{
// Avoid UTF coding values and characters that tend to give duff values
if (((gUnicode[gNum] > 0x20) && (gUnicode[gNum] < 0xA0) && (gUnicode[gNum] != 0x7F)) || (gUnicode[gNum] > 0xFF))
// Try to avoid UTF coding values and characters that tend to give duff values
if (((gUnicode[gNum] > 0x20) && (gUnicode[gNum] < 0x7F)) || (gUnicode[gNum] > 0xA0))
{
gFont.maxAscent = gdY[gNum];
#ifdef SHOW_ASCENT_DESCENT
......@@ -159,6 +167,7 @@ void TFT_eSPI::loadMetrics(uint16_t gCount)
#endif
}
}
*/
// Different glyph sets have different descent values not always based on "p", so get maximum glyph descent
if (((int16_t)gHeight[gNum] - (int16_t)gdY[gNum]) > gFont.maxDescent)
......
......@@ -8,9 +8,6 @@
void unloadFont( void );
bool getUnicodeIndex(uint16_t unicode, uint16_t *index);
uint16_t decodeUTF8(uint8_t *buf, uint16_t *index, uint16_t remaining);
uint16_t decodeUTF8(uint8_t c);
uint16_t alphaBlend(uint8_t alpha, uint16_t fgc, uint16_t bgc);
virtual void drawGlyph(uint16_t code);
......@@ -44,9 +41,6 @@ fontMetrics gFont = { 0, 0, 0, 0, 0, 0, 0 };
String _gFontFilename;
uint8_t decoderState = 0; // UTF8 decoder state
uint16_t decoderBuffer; // Unicode code-point buffer
bool fontLoaded = false; // Flags when a anti-aliased font is loaded
private:
......
......@@ -1312,13 +1312,16 @@ void TFT_eSprite::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t
*************************************************************************************x*/
size_t TFT_eSprite::write(uint8_t utf8)
{
uint16_t uniCode = decodeUTF8(utf8);
if (!uniCode) return 1;
if (utf8 == '\r') return 1;
#ifdef SMOOTH_FONT
if(this->fontLoaded)
{
uint16_t unicode = decodeUTF8(utf8);
if (unicode < 32 && utf8 != '\n') return 1;
if (uniCode < 32 && utf8 != '\n') return 1;
//fontFile = SPIFFS.open( _gFontFilename, "r" );
//fontFile = SPIFFS.open( this->_gFontFilename, "r" );
......@@ -1330,7 +1333,8 @@ size_t TFT_eSprite::write(uint8_t utf8)
//}
//Serial.print("Decoded Unicode = 0x");Serial.println(unicode,HEX);
drawGlyph(unicode);
drawGlyph(uniCode);
//fontFile.close();
return 1;
}
......@@ -1338,10 +1342,8 @@ size_t TFT_eSprite::write(uint8_t utf8)
if (!_created ) return 1;
uint8_t uniCode = utf8; // Work with a copy
if (utf8 == '\n') uniCode+=22; // Make it a valid space character to stop errors
else if (utf8 < 32) return 1;
if (uniCode == '\n') uniCode+=22; // Make it a valid space character to stop errors
else if (uniCode < 32) return 1;
uint16_t width = 0;
uint16_t height = 0;
......@@ -1362,7 +1364,7 @@ size_t TFT_eSprite::write(uint8_t utf8)
if (textfont == 2)
{
if (utf8 > 127) return 1;
// This is 20us faster than using the fontdata structure (0.443ms per character instead of 0.465ms)
width = pgm_read_byte(widtbl_f16 + uniCode-32);
height = chr_hgt_f16;
// Font 2 is rendered in whole byte widths so we must allow for this
......@@ -1380,7 +1382,6 @@ size_t TFT_eSprite::write(uint8_t utf8)
{
if (utf8 > 127) return 1;
// Uses the fontinfo struct array to avoid lots of 'if' or 'switch' statements
// A tad slower than above but this is not significant and is more convenient for the RLE fonts
width = pgm_read_byte( (uint8_t *)pgm_read_dword( &(fontdata[textfont].widthtbl ) ) + uniCode-32 );
height= pgm_read_byte( &fontdata[textfont].height );
}
......@@ -1420,15 +1421,14 @@ size_t TFT_eSprite::write(uint8_t utf8)
} // Custom GFX font
else
{
if(utf8 == '\n') {
this->cursor_x = 0;
this->cursor_y += (int16_t)textsize * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
} else {
if (uniCode > (uint8_t)pgm_read_byte(&gfxFont->last )) return 1;
if (uniCode < (uint8_t)pgm_read_byte(&gfxFont->first)) return 1;
if (uniCode > pgm_read_word(&gfxFont->last )) return 1;
if (uniCode < pgm_read_word(&gfxFont->first)) return 1;
uint8_t c2 = uniCode - pgm_read_byte(&gfxFont->first);
uint8_t c2 = uniCode - pgm_read_word(&gfxFont->first);
GFXglyph *glyph = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c2]);
uint8_t w = pgm_read_byte(&glyph->width),
h = pgm_read_byte(&glyph->height);
......@@ -1456,7 +1456,7 @@ size_t TFT_eSprite::write(uint8_t utf8)
** Function name: drawChar
** Description: draw a single character in the Adafruit GLCD or freefont
*************************************************************************************x*/
void TFT_eSprite::drawChar(int32_t x, int32_t y, unsigned char c, uint32_t color, uint32_t bg, uint8_t size)
void TFT_eSprite::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32_t bg, uint8_t size)
{
if (!_created ) return;
......@@ -1466,6 +1466,7 @@ void TFT_eSprite::drawChar(int32_t x, int32_t y, unsigned char c, uint32_t color
((y + 8 * size - 1) < 0)) // Clip top
return;
if (c < 32) return;
#ifdef LOAD_GLCD
//>>>>>>>>>>>>>>>>>>
#ifdef LOAD_GFXFF
......@@ -1534,15 +1535,15 @@ void TFT_eSprite::drawChar(int32_t x, int32_t y, unsigned char c, uint32_t color
#ifdef LOAD_GFXFF
// Filter out bad characters not present in font
if ((c >= (uint8_t)pgm_read_byte(&gfxFont->first)) && (c <= (uint8_t)pgm_read_byte(&gfxFont->last )))
if ((c >= pgm_read_word(&gfxFont->first)) && (c <= pgm_read_word(&gfxFont->last )))
{
//>>>>>>>>>>>>>>>>>>>>>>>>>>>
c -= pgm_read_byte(&gfxFont->first);
c -= pgm_read_word(&gfxFont->first);
GFXglyph *glyph = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c]);
uint8_t *bitmap = (uint8_t *)pgm_read_dword(&gfxFont->bitmap);
uint16_t bo = pgm_read_word(&glyph->bitmapOffset);
uint32_t bo = pgm_read_word(&glyph->bitmapOffset);
uint8_t w = pgm_read_byte(&glyph->width),
h = pgm_read_byte(&glyph->height);
//xa = pgm_read_byte(&glyph->xAdvance);
......@@ -1597,15 +1598,19 @@ void TFT_eSprite::drawChar(int32_t x, int32_t y, unsigned char c, uint32_t color
** Function name: drawChar
** Description: draw a unicode onto the screen
*************************************************************************************x*/
// Any UTF-8 decoding must be done before calling drawChar()
int16_t TFT_eSprite::drawChar(uint16_t uniCode, int32_t x, int32_t y)
{
return drawChar(uniCode, x, y, textfont);
}
// Any UTF-8 decoding must be done before calling drawChar()
int16_t TFT_eSprite::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font)
{
if (!_created ) return 0;
if (!uniCode) return 0;
if (font==1)
{
#ifdef LOAD_GLCD
......@@ -1630,9 +1635,9 @@ int16_t TFT_eSprite::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t fo
}
else
{
if((uniCode >= pgm_read_byte(&gfxFont->first)) && (uniCode <= pgm_read_byte(&gfxFont->last) ))
if((uniCode >= pgm_read_word(&gfxFont->first)) && (uniCode <= pgm_read_word(&gfxFont->last) ))
{
uint8_t c2 = uniCode - pgm_read_byte(&gfxFont->first);
uint16_t c2 = uniCode - pgm_read_word(&gfxFont->first);
GFXglyph *glyph = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c2]);
return pgm_read_byte(&glyph->xAdvance) * textsize;
}
......
......@@ -31,7 +31,7 @@ class TFT_eSprite : public TFT_eSPI {
void drawPixel(int32_t x, int32_t y, uint32_t color);
void drawChar(int32_t x, int32_t y, unsigned char c, uint32_t color, uint32_t bg, uint8_t size),
void drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32_t bg, uint8_t size),
fillSprite(uint32_t color),
......
......@@ -12,7 +12,7 @@
#ifdef LOAD_GFXFF
typedef struct { // Data stored PER GLYPH
uint16_t bitmapOffset; // Pointer into GFXfont->bitmap
uint32_t bitmapOffset; // Pointer into GFXfont->bitmap
uint8_t width, height; // Bitmap dimensions in pixels
uint8_t xAdvance; // Distance to advance cursor (x axis)
int8_t xOffset, yOffset; // Dist from cursor pos to UL corner
......@@ -21,7 +21,7 @@ typedef struct { // Data stored PER GLYPH
typedef struct { // Data stored for FONT AS A WHOLE:
uint8_t *bitmap; // Glyph bitmaps, concatenated
GFXglyph *glyph; // Glyph array
uint8_t first, last; // ASCII extents
uint16_t first, last; // ASCII extents
uint8_t yAdvance; // Newline distance (y axis)
} GFXfont;
......
......@@ -2272,21 +2272,22 @@ int16_t TFT_eSPI::textWidth(const char *string)
int16_t TFT_eSPI::textWidth(const char *string, uint8_t font)
{
int32_t str_width = 0;
int32_t str_width = 0;
uint16_t uniCode = 0;
#ifdef SMOOTH_FONT
if(fontLoaded)
{
while (*string)
{
uint16_t unicode = decodeUTF8(*string++);
if (unicode)
uniCode = decodeUTF8(*string++);
if (uniCode)
{
if (unicode == 0x20) str_width += gFont.spaceWidth;
if (uniCode == 0x20) str_width += gFont.spaceWidth;
else
{
uint16_t gNum = 0;
bool found = getUnicodeIndex(unicode, &gNum);
bool found = getUnicodeIndex(uniCode, &gNum);
if (found)
{
if(str_width == 0 && gdX[gNum] < 0) str_width -= gdX[gNum];
......@@ -2302,18 +2303,15 @@ int16_t TFT_eSPI::textWidth(const char *string, uint8_t font)
}
#endif
unsigned char uniCode;
char *widthtable;
if (font>1 && font<9)
{
widthtable = (char *)pgm_read_dword( &(fontdata[font].widthtbl ) ) - 32; //subtract the 32 outside the loop
char *widthtable = (char *)pgm_read_dword( &(fontdata[font].widthtbl ) ) - 32; //subtract the 32 outside the loop
while (*string)
{
uniCode = *(string++);
if (uniCode > 31 && uniCode < 128)
str_width += pgm_read_byte( widthtable + uniCode); // Normally we need to subract 32 from uniCode
str_width += pgm_read_byte( widthtable + uniCode); // Normally we need to subtract 32 from uniCode
else str_width += pgm_read_byte( widthtable + 32); // Set illegal character = space width
}
}
......@@ -2326,9 +2324,9 @@ int16_t TFT_eSPI::textWidth(const char *string, uint8_t font)
while (*string)
{
uniCode = decodeUTF8(*string++);
if ((uniCode >= (uint8_t)pgm_read_byte(&gfxFont->first)) && (uniCode <= (uint8_t)pgm_read_byte(&gfxFont->last )))
if ((uniCode >= pgm_read_word(&gfxFont->first)) && (uniCode <= pgm_read_word(&gfxFont->last )))
{
uniCode -= pgm_read_byte(&gfxFont->first);
uniCode -= pgm_read_word(&gfxFont->first);
GFXglyph *glyph = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[uniCode]);
// If this is not the last character or is a digit then use xAdvance
if (*string || isDigits) str_width += pgm_read_byte(&glyph->xAdvance);
......@@ -2393,7 +2391,7 @@ int16_t TFT_eSPI::fontHeight(void)
** Function name: drawChar
** Description: draw a single character in the Adafruit GLCD font
***************************************************************************************/
void TFT_eSPI::drawChar(int32_t x, int32_t y, unsigned char c, uint32_t color, uint32_t bg, uint8_t size)
void TFT_eSPI::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32_t bg, uint8_t size)
{
if ((x >= _width) || // Clip right
(y >= _height) || // Clip bottom
......@@ -2498,17 +2496,17 @@ void TFT_eSPI::drawChar(int32_t x, int32_t y, unsigned char c, uint32_t color, u
#ifdef LOAD_GFXFF
// Filter out bad characters not present in font
if ((c >= (uint8_t)pgm_read_byte(&gfxFont->first)) && (c <= (uint8_t)pgm_read_byte(&gfxFont->last )))
if ((c >= pgm_read_word(&gfxFont->first)) && (c <= pgm_read_word(&gfxFont->last )))
{
spi_begin();
inTransaction = true;
//>>>>>>>>>>>>>>>>>>>>>>>>>>>
c -= pgm_read_byte(&gfxFont->first);
c -= pgm_read_word(&gfxFont->first);
GFXglyph *glyph = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c]);
uint8_t *bitmap = (uint8_t *)pgm_read_dword(&gfxFont->bitmap);
uint16_t bo = pgm_read_word(&glyph->bitmapOffset);
uint32_t bo = pgm_read_word(&glyph->bitmapOffset);
uint8_t w = pgm_read_byte(&glyph->width),
h = pgm_read_byte(&glyph->height);
//xa = pgm_read_byte(&glyph->xAdvance);
......@@ -3991,18 +3989,18 @@ uint16_t TFT_eSPI::decodeUTF8(uint8_t *buf, uint16_t *index, uint16_t remaining)
***************************************************************************************/
size_t TFT_eSPI::write(uint8_t utf8)
{
uint16_t uniCode = decodeUTF8(utf8);
if (!uniCode) return 1;
if (utf8 == '\r') return 1;
#ifdef SMOOTH_FONT
if(fontLoaded)
{
uint16_t unicode = decodeUTF8(utf8);
//Serial.print("UniCode="); Serial.println(unicode);
//Serial.print("UniCode="); Serial.println(uniCode);
//Serial.print("UTF8 ="); Serial.println(utf8);
if (!unicode) return 1;
//fontFile = SPIFFS.open( _gFontFilename, "r" );
//if(!fontFile)
......@@ -4011,16 +4009,15 @@ size_t TFT_eSPI::write(uint8_t utf8)
// return 1;
//}
drawGlyph(unicode);
drawGlyph(uniCode);
//fontFile.close();
return 1;
}
#endif
uint8_t uniCode = utf8; // Work with a copy
if (utf8 == '\n') uniCode+=22; // Make it a valid space character to stop errors
else if (utf8 < 32) return 1;
if (uniCode == '\n') uniCode+=22; // Make it a valid space character to stop errors
else if (uniCode < 32) return 1;
uint16_t width = 0;
uint16_t height = 0;
......@@ -4040,8 +4037,8 @@ size_t TFT_eSPI::write(uint8_t utf8)
#ifdef LOAD_FONT2
if (textfont == 2)
{
if (utf8 > 127) return 1;
// This is 20us faster than using the fontdata structure (0.443ms per character instead of 0.465ms)
if (uniCode > 127) return 1;
width = pgm_read_byte(widtbl_f16 + uniCode-32);
height = chr_hgt_f16;
// Font 2 is rendered in whole byte widths so we must allow for this
......@@ -4057,9 +4054,8 @@ size_t TFT_eSPI::write(uint8_t utf8)
{
if ((textfont>2) && (textfont<9))
{
if (utf8 > 127) return 1;
if (uniCode > 127) return 1;
// Uses the fontinfo struct array to avoid lots of 'if' or 'switch' statements
// A tad slower than above but this is not significant and is more convenient for the RLE fonts
width = pgm_read_byte( (uint8_t *)pgm_read_dword( &(fontdata[textfont].widthtbl ) ) + uniCode-32 );
height= pgm_read_byte( &fontdata[textfont].height );
}
......@@ -4098,18 +4094,15 @@ size_t TFT_eSPI::write(uint8_t utf8)
} // Custom GFX font
else
{
uniCode = (uint8_t)decodeUTF8(utf8);
if (!uniCode) return 1;
if(utf8 == '\n') {
cursor_x = 0;
cursor_y += (int16_t)textsize *
(uint8_t)pgm_read_byte(&gfxFont->yAdvance);
} else {
if (uniCode > (uint8_t)pgm_read_byte(&gfxFont->last )) return 1;
if (uniCode < (uint8_t)pgm_read_byte(&gfxFont->first)) return 1;
if (uniCode > pgm_read_word(&gfxFont->last )) return 1;
if (uniCode < pgm_read_word(&gfxFont->first)) return 1;
uint8_t c2 = uniCode - pgm_read_byte(&gfxFont->first);
uint16_t c2 = uniCode - pgm_read_word(&gfxFont->first);
GFXglyph *glyph = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c2]);
uint8_t w = pgm_read_byte(&glyph->width),
h = pgm_read_byte(&glyph->height);
......@@ -4136,17 +4129,17 @@ size_t TFT_eSPI::write(uint8_t utf8)
/***************************************************************************************
** Function name: drawChar
** Description: draw a Unicode onto the screen
** Description: draw a Unicode glyph onto the screen
***************************************************************************************/
int16_t TFT_eSPI::drawChar(uint16_t utf8, int32_t x, int32_t y)
// Any UTF-8 decoding must be done before calling drawChar()
int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y)
{
return drawChar(utf8, x, y, textfont);
return drawChar(uniCode, x, y, textfont);
}
int16_t TFT_eSPI::drawChar(uint16_t utf8, int32_t x, int32_t y, uint8_t font)
// Any UTF-8 decoding must be done before calling drawChar()
int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font)
{
uint16_t uniCode = decodeUTF8(utf8);
if (!uniCode) return 0;
if (font==1)
......@@ -4173,9 +4166,9 @@ int16_t TFT_eSPI::drawChar(uint16_t utf8, int32_t x, int32_t y, uint8_t font)
}
else
{
if((uniCode >= pgm_read_byte(&gfxFont->first)) && (uniCode <= pgm_read_byte(&gfxFont->last) ))
if((uniCode >= pgm_read_word(&gfxFont->first)) && (uniCode <= pgm_read_word(&gfxFont->last) ))
{
uint8_t c2 = uniCode - pgm_read_byte(&gfxFont->first);
uint16_t c2 = uniCode - pgm_read_word(&gfxFont->first);
GFXglyph *glyph = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c2]);
return pgm_read_byte(&glyph->xAdvance) * textsize;
}
......@@ -4197,7 +4190,6 @@ int16_t TFT_eSPI::drawChar(uint16_t utf8, int32_t x, int32_t y, uint8_t font)
#ifdef LOAD_FONT2
if (font == 2)
{
// This is faster than using the fontdata structure
flash_address = pgm_read_dword(&chrtbl_f16[uniCode]);
width = pgm_read_byte(widtbl_f16 + uniCode);
height = chr_hgt_f16;
......@@ -4211,7 +4203,6 @@ int16_t TFT_eSPI::drawChar(uint16_t utf8, int32_t x, int32_t y, uint8_t font)
{
if ((font>2) && (font<9))
{
// This is slower than above but is more convenient for the RLE fonts
flash_address = pgm_read_dword( pgm_read_dword( &(fontdata[font].chartbl ) ) + uniCode*sizeof(void *) );
width = pgm_read_byte( (uint8_t *)pgm_read_dword( &(fontdata[font].widthtbl ) ) + uniCode );
height= pgm_read_byte( &fontdata[font].height );
......@@ -4309,6 +4300,7 @@ int16_t TFT_eSPI::drawChar(uint16_t utf8, int32_t x, int32_t y, uint8_t font)
// Font is not 2 and hence is RLE encoded
{
spi_begin();
inTransaction = true;
w *= height; // Now w is total number of pixels in the character
if ((textsize != 1) || (textcolor == textbgcolor)) {
......@@ -4360,6 +4352,7 @@ int16_t TFT_eSPI::drawChar(uint16_t utf8, int32_t x, int32_t y, uint8_t font)
}
}
inTransaction = false;
spi_end();
}
else // Text colour != background && textsize = 1
......@@ -4442,7 +4435,7 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY)
return drawString(string, poX, poY, textfont);
}
// With font number
// With font number. Note: font number is over-ridden if a smooth font is loaded
int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8_t font)
{
int16_t sumX = 0;
......@@ -4553,15 +4546,15 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8
{
cheight = (glyph_ab + glyph_bb) * textsize;
// Get the offset for the first character only to allow for negative offsets
uint8_t c2 = 0;
uint16_t c2 = 0;
uint16_t len = strlen(string);
uint16_t n = 0;
while (n < len && c2 == 0) c2 = decodeUTF8((uint8_t*)string, &n, len - n);
if((c2 >= pgm_read_byte(&gfxFont->first)) && (c2 <= pgm_read_byte(&gfxFont->last) ))
if((c2 >= pgm_read_word(&gfxFont->first)) && (c2 <= pgm_read_word(&gfxFont->last) ))
{
c2 -= pgm_read_byte(&gfxFont->first);
c2 -= pgm_read_word(&gfxFont->first);
GFXglyph *glyph = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c2]);
xo = pgm_read_byte(&glyph->xOffset) * textsize;
// Adjust for negative xOffset
......@@ -4576,6 +4569,9 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8
}
#endif
uint16_t len = strlen(string);
uint16_t n = 0;
#ifdef SMOOTH_FONT
if(fontLoaded)
{
......@@ -4584,14 +4580,13 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8
//drawLine(poX, poY - 5, poX, poY + 5, TFT_GREEN);
//fontFile = SPIFFS.open( _gFontFilename, "r");
if(!fontFile) return 0;
uint16_t len = strlen(string);
uint16_t n = 0;
setCursor(poX, poY);
while (n < len)
{
uint16_t unicode = decodeUTF8((uint8_t*)string, &n, len - n);
drawGlyph(unicode);
uint16_t uniCode = decodeUTF8((uint8_t*)string, &n, len - n);
drawGlyph(uniCode);
}
sumX += cwidth;
//fontFile.close();
......@@ -4599,7 +4594,11 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8
else
#endif
{
while (*string) sumX += drawChar(*(string++), poX+sumX, poY, font);
while (n < len)
{
uint16_t uniCode = decodeUTF8((uint8_t*)string, &n, len - n);
sumX += drawChar(uniCode, poX+sumX, poY, font);
}
}
//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv DEBUG vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
......@@ -4669,7 +4668,7 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8
#endif
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ DEBUG ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
return sumX;
return sumX + poX;
}
......@@ -4782,7 +4781,7 @@ int16_t TFT_eSPI::drawFloat(float floatNumber, uint8_t dp, int32_t poX, int32_t
// No chance of overflow from here on
// Get integer part
unsigned long temp = (unsigned long)floatNumber;
uint32_t temp = (uint32_t)floatNumber;
// Put integer part into array
ltoa(temp, str + ptr, 10);
......@@ -4830,7 +4829,7 @@ void TFT_eSPI::setFreeFont(const GFXfont *f)
glyph_ab = 0;
glyph_bb = 0;
uint8_t numChars = pgm_read_byte(&gfxFont->last) - pgm_read_byte(&gfxFont->first);
uint16_t numChars = pgm_read_word(&gfxFont->last) - pgm_read_word(&gfxFont->first);
// Find the biggest above and below baseline offsets
for (uint8_t c = 0; c < numChars; c++)
......
......@@ -668,7 +668,7 @@ class TFT_eSPI : public Print {
// These are virtual so the TFT_eSprite class can override them with sprite specific functions
virtual void drawPixel(int32_t x, int32_t y, uint32_t color),
drawChar(int32_t x, int32_t y, unsigned char c, uint32_t color, uint32_t bg, uint8_t size),
drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32_t bg, uint8_t size),
drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t color),
drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color),
drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color),
......@@ -813,6 +813,8 @@ class TFT_eSPI : public Print {
void writeColor(uint16_t color, uint32_t len); // Write colours without transaction overhead
void endWrite(void); // End SPI transaction
uint16_t decodeUTF8(uint8_t *buf, uint16_t *index, uint16_t remaining);
uint16_t decodeUTF8(uint8_t c);
size_t write(uint8_t);
#ifdef TFT_SDA_READ
......@@ -838,6 +840,9 @@ class TFT_eSPI : public Print {
int16_t _xpivot; // x pivot point coordinate
int16_t _ypivot; // x pivot point coordinate
uint8_t decoderState = 0; // UTF8 decoder state
uint16_t decoderBuffer; // Unicode code-point buffer
private:
inline void spi_begin() __attribute__((always_inline));
......
// This is a Processing sketch, see https://processing.org/ to download the IDE
// Select the character range in the user configure section starting at line 100
// Select the font, size and character ranges in the user configuration section
// of this sketch, which starts at line 120. Instructions start at line 50.
/*
Software License Agreement (FreeBSD License)
......@@ -36,47 +38,61 @@ Software License Agreement (FreeBSD License)
////////////////////////////////////////////////////////////////////////////////////////////////
// This is a processing sketch to create font files for the TFT_eSPI library:
// https://github.com/Bodmer/TFT_eSPI
// Coded by Bodmer January 2018
// Coded by Bodmer January 2018, updated 10/2/19
// Version 0.8
// See comments below in code for specifying the font parameters
// (point size, unicode blocks to include etc). Ranges of characers or
// specific individual unicodes can be included in the created font file/
// >>>>>>>>>>>>>>>>>>>> INSTRUCTIONS <<<<<<<<<<<<<<<<<<<<
// See comments below in code for specifying the font parameters (point size,
// unicode blocks to include etc). Ranges of characters (glyphs) and specific
// individual glyphs can be included in the created "*.vlw" font file.
// Created fonts are saved in the sketches "FontFiles" folder. Press Ctrl+K to
// see that folder.
// see that folder location.
// 16 bit unicodes in the range 0x0000 - 0xFFFF are supported.
// 16 bit Unicode point codes in the range 0x0000 - 0xFFFF are supported.
// Codes 0-31 are control codes such as "tab" and "carraige return" etc.
// and 32 is a "space", these should NOT be included.
// The sketch will convert True Type (a .ttf or .otf file) file stored in the
// sketches "Data" folder as well as your computers system fonts.
// sketches "Data" folder as well as your computers' system fonts.
// To maximise rendering performance and the memory consumed only include the characters
// you will use. Characters at the start of the file will render faster than those at
// the end due to the buffering and file seeking overhead.
// To maximise rendering performance only include the characters you will use.
// Characters at the start of the file will render faster than those at the end.
// The inclusion of "non-existant" characters in a font may give unpredicatable results
// when rendering with the TFT_eSPI library. The Processing sketch window that pops up
// to show the font characters will print "boxes" (also known as Tofu!) for non existant
// characters.
// Once created the files must be loaded into the ESP32 or ESP8266 SPIFFS memory
// using the Arduino IDE plugin detailed here:
// https://github.com/esp8266/arduino-esp8266fs-plugin
// https://github.com/me-no-dev/arduino-esp32fs-plugin
// The sketch list all the available PC fonts to the console, you may need to increase
// console line count (in preferences.txt) to stop some fonts scrolling out of view.
// When the sketch is run it will generate a file called "System_Font_List.txt" in the
// sketch "FontFiles" folder, press Ctrl+K to see it. Open the file in a text editor to
// view it. This list provides the font reference number needed below to locate that
// font on your system.
// The sketch also lists all the available system fonts to the console, you can increase
// the console line count (in preferences.txt) to stop some fonts scrolling out of view.
// See link in File>Preferences to locate "preferences.txt" file. You must close
// Processing then edit the file lines. If Processing is not closed first then the
// edits will be overwritten by defaults! Edit "preferences.txt" as follows for
// 1000 lines, then save, then run Processing again:
// 3000 lines, then save, then run Processing again:
// console.length=3000; // Line 4 in file
// console.scrollback.lines=3000; // Line 7 in file
/*
console.length=1000 // Line 4 in file
console.scrollback.lines=1000 // Line 7 in file
*/
// Useful links:
/*
/*
https://en.wikipedia.org/wiki/Unicode_font
......@@ -86,33 +102,39 @@ Software License Agreement (FreeBSD License)
http://savannah.gnu.org/projects/freefont/
http://www.google.com/get/noto/
https://github.com/Bodmer/TFT_eSPI
https://github.com/esp8266/arduino-esp8266fs-plugin
https://github.com/me-no-dev/arduino-esp32fs-plugin
*/
////////////////////////////////////////////////////////////////////////////////////////////////
>>>>>>>>>>>>>>>>>>>> END OF INSTRUCTIONS <<<<<<<<<<<<<<<<<<<< */
import java.awt.Desktop; // Required to allow sketch to open file windows
import java.awt.Desktop;
////////////////////////////////////////////////////////////////////////////////////////////////
// >>>>>>>>>> USER CONFIGURED PARAMETERS START HERE <<<<<<<<<<
// Use font number or name, -1 for fontNumber means use fontName below, a value >=0 means use system font number from list.
// When the sketch is run it will generate a file called "systemFontList.txt" in the sketch folder, press Ctrl+K to see it.
// Open the "systemFontList.txt" in a text editor to view the font files and reference numbers for your system.
int fontNumber = -1; // << Use [Number] in brackets from the fonts listed.
// Use font name for ttf files placed in the "Data" folder or the font number seen in IDE Console for system fonts
// OR use font name for ttf files placed in the "Data" folder or the font number seen in IDE Console for system fonts
// the font numbers are listed when the sketch is run.
// | 1 2 | Maximum filename size for SPIFFS is 32 including leading /
// | 1 2 | Maximum filename size for SPIFFS is 31 including leading /
// 1234567890123456789012345 and added point size and .vlw extension, so max is 25
String fontName = "Final-Frontier"; //Manually crop the filename length later after creation if needed
String fontType = ".ttf"; //SPIFFS does not accept underscore in filename!
String fontName = "Final-Frontier"; // Manually crop the filename length later after creation if needed
// Note: SPIFFS does NOT accept underscore in a filename!
String fontType = ".ttf";
//String fontType = ".otf";
// Use font number instead of name, -1 means use name above, or a value >=0 means use system font number from list.
int fontNumber = -1; // << Use [Number] in brackets from the fonts listed in console window
// Define the font size in points for the created font file
int fontSize = 28;
// Define the font size in points for the TFT_eSPI font file
int fontSize = 20;
// Font size to use in the Processing sketch display window that pops up (can be different to above)
int displayFontSize = 28;
......@@ -125,7 +147,7 @@ int displayFontSize = 28;
static final int[] unicodeBlocks = {
// The list below has been created from the table here: https://en.wikipedia.org/wiki/Unicode_block
// Remove // at start of lines below to include that unicode block, different code ranges can also be specified by
// editting the start and end of range values. Multiple lines from the list below can be included, limited only by
// editting the start and end-of-range values. Multiple lines from the list below can be included, limited only by
// the final font file size!
// Block range, //Block name, Code points, Assigned characters, Scripts
......@@ -298,20 +320,20 @@ static final int[] unicodeBlocks = {
//0x0061, 0x007A, //Example custom range (Lower case a-z)
};
// Here we specify specific individual Unicodes to be included (appended at end of selected range)
// Here we specify particular individual Unicodes to be included (appended at end of selected range)
static final int[] specificUnicodes = {
// Commonly used codes, add or remove // in next line
// 0x00A3, 0x00B0, 0x00B5, 0x03A9, 0x20AC, // £ ° µ Ω €
// Numbers and characters for showing time, change next line to //* to use
/*
/*
0x002B, 0x002D, 0x002E, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, // - + . 0 1 2 3 4
0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x0061, 0x006D, // 5 6 7 8 9 : a m
0x0070, // p
//*/
//*/
// More characters, change next line to //* to use
// More characters for TFT_eSPI test sketches, change next line to //* to use
/*
0x0102, 0x0103, 0x0104, 0x0105, 0x0106, 0x0107, 0x010C, 0x010D,
0x010E, 0x010F, 0x0110, 0x0111, 0x0118, 0x0119, 0x011A, 0x011B,
......@@ -337,8 +359,8 @@ static final int[] specificUnicodes = {
//*/
};
// >>>>>>>>>> USER CONFIGURED PARAMETERS END HERE <<<<<<<<<<
////////////////////////////////////////////////////////////////////////////////////////////////
// Variable to hold the inclusive Unicode range (16 bit values only for this sketch)
......@@ -347,7 +369,10 @@ int lastUnicode = 0;
PFont myFont;
PrintWriter logOutput;
void setup() {
logOutput = createWriter("FontFiles/System_Font_List.txt");
size(1000, 800);
......@@ -355,6 +380,15 @@ void setup() {
String[] fontList = PFont.list();
printArray(fontList);
// Save font list to file
for (int x = 0; x < fontList.length; x++)
{
logOutput.print("[" + x + "] ");
logOutput.println(fontList[x]);
}
logOutput.flush(); // Writes the remaining data to the file
logOutput.close(); // Finishes the file
// Set the fontName from the array number or the defined fontName
if (fontNumber >= 0)
{
......@@ -410,19 +444,19 @@ void setup() {
}
}
// loading the range specified
// loading the specific point codes
for (int i = 0; i < specificUnicodes.length; i++) {
charset[index] = Character.toChars(specificUnicodes[i])[0];
index++;
}
// Make font smooth
// Make font smooth (anti-aliased)
boolean smooth = true;
// Create the font in memory
myFont = createFont(fontName+fontType, displayFontSize, smooth, charset);
// Print a few characters to the sketch window
// Print characters to the sketch window
fill(0, 0, 0);
textFont(myFont);
......@@ -444,10 +478,10 @@ void setup() {
int unicode = charset[index];
float cwidth = textWidth((char)unicode) + 2;
if ( (x + cwidth) > (width - gapx) ) break;
// Draw the letter to the screen
// Draw the glyph to the screen
text(new String(Character.toChars(unicode)), x, y);
// Move cursor
x += cwidth;
// Increment the counter
......@@ -458,12 +492,12 @@ void setup() {
}
// creating font
// creating font to save as a file
PFont font;
font = createFont(fontName+fontType, fontSize, smooth, charset);
println("Created font " + fontName + str(fontSize) + ".vlw");
println("Created font " + fontName + str(fontSize) + ".vlw");
// creating file
try {
......@@ -486,4 +520,4 @@ void setup() {
catch(IOException e) {
println("Doh! Failed to create the file");
}
}
\ No newline at end of file
}
......@@ -41,8 +41,8 @@ void loop(void) {
tft.getSetup(user); //
Serial.printf("\n[code]\n");
String ver = user.version;
Serial.println("TFT_eSPI ver = " + ver +"\n");
Serial.printf("TFT_eSPI ver = " + user.version) +"\n");
Serial.printf("Processor = ESP%i\n", user.esp, HEX);
Serial.printf("Frequency = %i MHz\n", ESP.getCpuFreqMHz());
#ifdef ESP8266
......
{
"name": "TFT_eSPI",
"version": "1.4.3",
"version": "1.4.4",
"keywords": "tft, ePaper, display, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9486, ST7789",
"description": "A TFT and ePaper SPI graphics library for ESP8266 and ESP32",
"repository":
......
name=TFT_eSPI
version=1.4.3
version=1.4.4
author=Bodmer
maintainer=Bodmer
sentence=A fast TFT graphics library for ESP8266 and ESP32 processors for the Arduino IDE
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment