Skip to content

Commit 61dfb2b

Browse files
committed
Extended character set suport for Adafruit_GFX format fonts
Supports Adafruit_GFX compatible font format with characters in the range 32-255. Note that the font rendering functions expect UTF-8 encoded characters/strings.
1 parent 7479f7e commit 61dfb2b

File tree

6 files changed

+3618
-21
lines changed

6 files changed

+3618
-21
lines changed

Extensions/Smooth_font.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ void TFT_eSPI::unloadFont( void )
246246
** Function name: decodeUTF8
247247
** Description: Line buffer UTF-8 decoder with fall-back to extended ASCII
248248
*************************************************************************************x*/
249+
/* Function moved to TFT_eSPI.cpp
249250
#define DECODE_UTF8
250251
uint16_t TFT_eSPI::decodeUTF8(uint8_t *buf, uint16_t *index, uint16_t remaining)
251252
{
@@ -273,11 +274,13 @@ uint16_t TFT_eSPI::decodeUTF8(uint8_t *buf, uint16_t *index, uint16_t remaining)
273274
274275
return c; // fall-back to extended ASCII
275276
}
277+
*/
276278

277279
/***************************************************************************************
278280
** Function name: decodeUTF8
279281
** Description: Serial UTF-8 decoder with fall-back to extended ASCII
280282
*************************************************************************************x*/
283+
/* Function moved to TFT_eSPI.cpp
281284
uint16_t TFT_eSPI::decodeUTF8(uint8_t c)
282285
{
283286
@@ -329,6 +332,7 @@ uint16_t TFT_eSPI::decodeUTF8(uint8_t c)
329332
decoderState = 0;
330333
return (uint16_t)c; // fall-back to extended ASCII
331334
}
335+
*/
332336

333337

334338

TFT_eSPI.cpp

Lines changed: 123 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
Bodmer: Added RPi 16 bit display support
1414
****************************************************/
1515

16+
1617
#include "TFT_eSPI.h"
1718

1819
#if defined (ESP32)
@@ -85,7 +86,7 @@ inline void TFT_eSPI::spi_end_read(void){
8586
#if !defined(ESP32_PARALLEL)
8687
spi.setFrequency(SPI_FREQUENCY);
8788
#endif
88-
CS_H;
89+
if(!inTransaction) CS_H;
8990
#endif
9091
#ifdef ESP8266
9192
SPI1U = SPI1U_WRITE;
@@ -342,17 +343,6 @@ void TFT_eSPI::init(uint8_t tc)
342343
writecommand(TFT_SWRST); // Software reset
343344
#endif
344345

345-
#if defined (TFT_BL) && defined (TFT_BACKLIGHT_ON)
346-
digitalWrite(TFT_BL, TFT_BACKLIGHT_ON);
347-
pinMode(TFT_BL, OUTPUT);
348-
#else
349-
#if defined (TFT_BL) && defined (M5STACK)
350-
// Turn on the back-light LED
351-
digitalWrite(TFT_BL, HIGH);
352-
pinMode(TFT_BL, OUTPUT);
353-
#endif
354-
#endif
355-
356346
spi_end();
357347

358348
delay(150); // Wait for reset to complete
@@ -407,6 +397,17 @@ void TFT_eSPI::init(uint8_t tc)
407397
spi_end();
408398

409399
setRotation(rotation);
400+
401+
#if defined (TFT_BL) && defined (TFT_BACKLIGHT_ON)
402+
digitalWrite(TFT_BL, TFT_BACKLIGHT_ON);
403+
pinMode(TFT_BL, OUTPUT);
404+
#else
405+
#if defined (TFT_BL) && defined (M5STACK)
406+
// Turn on the back-light LED
407+
digitalWrite(TFT_BL, HIGH);
408+
pinMode(TFT_BL, OUTPUT);
409+
#endif
410+
#endif
410411
}
411412

412413

@@ -2324,7 +2325,7 @@ int16_t TFT_eSPI::textWidth(const char *string, uint8_t font)
23242325
{
23252326
while (*string)
23262327
{
2327-
uniCode = *(string++);
2328+
uniCode = decodeUTF8(*string++);
23282329
if ((uniCode >= (uint8_t)pgm_read_byte(&gfxFont->first)) && (uniCode <= (uint8_t)pgm_read_byte(&gfxFont->last )))
23292330
{
23302331
uniCode -= pgm_read_byte(&gfxFont->first);
@@ -3895,6 +3896,95 @@ void TFT_eSPI::invertDisplay(boolean i)
38953896
}
38963897

38973898

3899+
/***************************************************************************************
3900+
** Function name: decodeUTF8
3901+
** Description: Serial UTF-8 decoder with fall-back to extended ASCII
3902+
*************************************************************************************x*/
3903+
#define DECODE_UTF8 // Test only, comment out to stop decoding
3904+
uint16_t TFT_eSPI::decodeUTF8(uint8_t c)
3905+
{
3906+
#ifdef DECODE_UTF8
3907+
// 7 bit Unicode Code Point
3908+
if ((c & 0x80) == 0x00) {
3909+
decoderState = 0;
3910+
return (uint16_t)c;
3911+
}
3912+
3913+
if (decoderState == 0)
3914+
{
3915+
// 11 bit Unicode Code Point
3916+
if ((c & 0xE0) == 0xC0)
3917+
{
3918+
decoderBuffer = ((c & 0x1F)<<6);
3919+
decoderState = 1;
3920+
return 0;
3921+
}
3922+
3923+
// 16 bit Unicode Code Point
3924+
if ((c & 0xF0) == 0xE0)
3925+
{
3926+
decoderBuffer = ((c & 0x0F)<<12);
3927+
decoderState = 2;
3928+
return 0;
3929+
}
3930+
// 21 bit Unicode Code Point not supported so fall-back to extended ASCII
3931+
if ((c & 0xF8) == 0xF0) return (uint16_t)c;
3932+
}
3933+
else
3934+
{
3935+
if (decoderState == 2)
3936+
{
3937+
decoderBuffer |= ((c & 0x3F)<<6);
3938+
decoderState--;
3939+
return 0;
3940+
}
3941+
else
3942+
{
3943+
decoderBuffer |= (c & 0x3F);
3944+
decoderState = 0;
3945+
return decoderBuffer;
3946+
}
3947+
}
3948+
3949+
decoderState = 0;
3950+
#endif
3951+
3952+
return (uint16_t)c; // fall-back to extended ASCII
3953+
}
3954+
3955+
3956+
/***************************************************************************************
3957+
** Function name: decodeUTF8
3958+
** Description: Line buffer UTF-8 decoder with fall-back to extended ASCII
3959+
*************************************************************************************x*/
3960+
uint16_t TFT_eSPI::decodeUTF8(uint8_t *buf, uint16_t *index, uint16_t remaining)
3961+
{
3962+
byte c = buf[(*index)++];
3963+
//Serial.print("Byte from string = 0x"); Serial.println(c, HEX);
3964+
3965+
#ifdef DECODE_UTF8
3966+
// 7 bit Unicode
3967+
if ((c & 0x80) == 0x00) return c;
3968+
3969+
// 11 bit Unicode
3970+
if (((c & 0xE0) == 0xC0) && (remaining > 1))
3971+
return ((c & 0x1F)<<6) | (buf[(*index)++]&0x3F);
3972+
3973+
// 16 bit Unicode
3974+
if (((c & 0xF0) == 0xE0) && (remaining > 2))
3975+
{
3976+
c = ((c & 0x0F)<<12) | ((buf[(*index)++]&0x3F)<<6);
3977+
return c | ((buf[(*index)++]&0x3F));
3978+
}
3979+
3980+
// 21 bit Unicode not supported so fall-back to extended ASCII
3981+
// if ((c & 0xF8) == 0xF0) return c;
3982+
#endif
3983+
3984+
return c; // fall-back to extended ASCII
3985+
}
3986+
3987+
38983988
/***************************************************************************************
38993989
** Function name: write
39003990
** Description: draw characters piped through serial stream
@@ -4008,6 +4098,8 @@ size_t TFT_eSPI::write(uint8_t utf8)
40084098
} // Custom GFX font
40094099
else
40104100
{
4101+
uniCode = (uint8_t)decodeUTF8(utf8);
4102+
if (!uniCode) return 1;
40114103

40124104
if(utf8 == '\n') {
40134105
cursor_x = 0;
@@ -4046,14 +4138,17 @@ size_t TFT_eSPI::write(uint8_t utf8)
40464138
** Function name: drawChar
40474139
** Description: draw a Unicode onto the screen
40484140
***************************************************************************************/
4049-
int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y)
4141+
int16_t TFT_eSPI::drawChar(uint16_t utf8, int32_t x, int32_t y)
40504142
{
4051-
return drawChar(uniCode, x, y, textfont);
4143+
return drawChar(utf8, x, y, textfont);
40524144
}
40534145

4054-
int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font)
4146+
int16_t TFT_eSPI::drawChar(uint16_t utf8, int32_t x, int32_t y, uint8_t font)
40554147
{
40564148

4149+
uint16_t uniCode = decodeUTF8(utf8);
4150+
if (!uniCode) return 0;
4151+
40574152
if (font==1)
40584153
{
40594154
#ifdef LOAD_GLCD
@@ -4458,7 +4553,12 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8
44584553
{
44594554
cheight = (glyph_ab + glyph_bb) * textsize;
44604555
// Get the offset for the first character only to allow for negative offsets
4461-
uint8_t c2 = *string;
4556+
uint8_t c2 = 0;
4557+
uint16_t len = strlen(string);
4558+
uint16_t n = 0;
4559+
4560+
while (n < len && c2 == 0) c2 = decodeUTF8((uint8_t*)string, &n, len - n);
4561+
44624562
if((c2 >= pgm_read_byte(&gfxFont->first)) && (c2 <= pgm_read_byte(&gfxFont->last) ))
44634563
{
44644564
c2 -= pgm_read_byte(&gfxFont->first);
@@ -4498,8 +4598,12 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8
44984598
}
44994599
else
45004600
#endif
4501-
while (*string) sumX += drawChar(*(string++), poX+sumX, poY, font);
4502-
4601+
Serial.print("sumX=");
4602+
while (*string) {
4603+
sumX += drawChar(*(string++), poX+sumX, poY, font);
4604+
Serial.print(sumX);
4605+
}
4606+
Serial.println();
45034607
//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv DEBUG vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
45044608
// Switch on debugging for the padding areas
45054609
//#define PADDING_DEBUG
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/*
2+
Example for TFT_eSPI library
3+
4+
This example shows the use of a Adafruit_GFX custom font with a
5+
character code range of 32 - 255, this means accented characters
6+
(amongst others) are available.
7+
8+
The custom font file is attached to this sketch as a header file. The
9+
font data has been created following the instructions here:
10+
https://www.youtube.com/watch?v=L8MmTISmwZ8
11+
12+
Note that online converters for Adafruit_GFX compatible fonts are
13+
available but these typically only use characters in the range 32-127,
14+
and thus do not include the accented characters. These online converters
15+
can however still be used with this sketch but the example characters
16+
used must be changed.
17+
18+
The Arduino IDE uses UTF8 encoding for these characters. The TFT_eSPI
19+
library also expects characters in the range 128 to 255 to be UTF-8
20+
encoded. See link here for details:
21+
22+
https://playground.arduino.cc/Code/UTF-8
23+
24+
To sumarise, UTF-8 characters are encoded as mor than 1 byte so care must
25+
be taken:
26+
27+
char c = 'µ'; // Wrong
28+
char bad[4] = "5µA"; // Wrong
29+
char good[] = "5µA"; // Good
30+
String okay = "5µA"; // Good
31+
32+
Created by Bodmer 08/02/19
33+
34+
Make sure LOAD_GFXFF is defined in the used User_Setup file
35+
within the library folder.
36+
37+
#########################################################################
38+
###### DON'T FORGET TO UPDATE THE User_Setup.h FILE IN THE LIBRARY ######
39+
###### TO SELECT YOUR DISPLAY TYPE, PINS USED AND ENABLE FONTS ######
40+
#########################################################################
41+
*/
42+
43+
#define TEST_TEXT "ßäöü ñâàå" // Text that will be printed on screen in the font
44+
//#define TEST_TEXT "Hello" // Text that will be printed on screen in the font
45+
46+
#include "SPI.h"
47+
#include "TFT_eSPI.h"
48+
#include "TFT_eFEX.h"
49+
50+
// The custom font file attached to this sketch must be included
51+
#include "MyFont.h"
52+
53+
// Stock font and GFXFF reference handle
54+
#define GFXFF 1
55+
56+
// Easily remembered name for the font
57+
#define MYFONT32 &myFont32pt8b
58+
59+
// Use hardware SPI
60+
TFT_eSPI tft = TFT_eSPI();
61+
TFT_eFEX fex = TFT_eFEX(&tft);
62+
63+
void setup(void) {
64+
65+
Serial.begin(250000);
66+
67+
tft.begin();
68+
69+
tft.setRotation(1);
70+
71+
}
72+
73+
void loop() {
74+
75+
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
76+
// Show custom fonts
77+
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
78+
79+
// Where font sizes increase the screen is not cleared as the larger fonts overwrite
80+
// the smaller one with the background colour.
81+
82+
// We can set the text datum to be Top, Middle, Bottom vertically and Left, Centre
83+
// and Right horizontally. These are the text datums that can be used:
84+
// TL_DATUM = Top left (default)
85+
// TC_DATUM = Top centre
86+
// TR_DATUM = Top right
87+
// ML_DATUM = Middle left
88+
// MC_DATUM = Middle centre <<< This is used below
89+
// MR_DATUM = Middle right
90+
// BL_DATUM = Bottom left
91+
// BC_DATUM = Bottom centre
92+
// BR_DATUM = Bottom right
93+
// L_BASELINE = Left character baseline (Line the 'A' character would sit on)
94+
// C_BASELINE = Centre character baseline
95+
// R_BASELINE = Right character baseline
96+
97+
//Serial.println();
98+
99+
// Set text datum to middle centre (MC_DATUM)
100+
tft.setTextDatum(MC_DATUM);
101+
102+
// Set text colour to white with black background
103+
// Unlike the stock Adafruit_GFX library, the TFT_eSPI library DOES optionally draw
104+
// the background colour for the custom and Free Fonts when using drawString()
105+
tft.setTextColor(TFT_WHITE, TFT_BLACK); // White characters on black background
106+
//tft.setTextColor(TFT_WHITE); // or white characters, no background
107+
108+
tft.fillScreen(TFT_BLUE); // Clear screen
109+
tft.setFreeFont(MYFONT32); // Select the font
110+
tft.drawString("MyFont 32", 160, 60, GFXFF); // Print the name of the font
111+
tft.setFreeFont(MYFONT32); // Select the font
112+
tft.drawString(TEST_TEXT, 160, 140, GFXFF); // Print the test text in the custom font
113+
delay(2000);
114+
fex.screenServer();
115+
// Setting textDatum does nothing when using tft.print
116+
tft.fillScreen(TFT_BLUE); // Clear screen
117+
tft.setCursor(0,60); // To be compatible with Adafruit_GFX the cursor datum is always bottom left
118+
tft.print("âäàå"); // Using tft.print means text background is NEVER rendered
119+
delay(2000);
120+
121+
// Reset text padding to zero (default)
122+
tft.setTextPadding(0);
123+
}

0 commit comments

Comments
 (0)