Add new callback for smooth font antialiasing

Callback allows anitaliased fonts to be rendered over colour gradients
or images.
"Smooth_font_reading_TFT" example added
"Smooth_font_gradient" example added
Minor changes to avoid signed/unsigned comparison warnings.
This commit is contained in:
Bodmer
2019-11-10 02:23:22 +00:00
parent d28e43574b
commit 5bb14ba2d8
16 changed files with 369 additions and 46 deletions

View File

@@ -370,7 +370,6 @@ uint16_t TFT_eSPI::decodeUTF8(uint8_t c)
*/
/***************************************************************************************
** Function name: alphaBlend
** Description: Blend foreground and background and return new colour
@@ -509,6 +508,7 @@ void TFT_eSPI::drawGlyph(uint16_t code)
else drawFastHLine( xs, y + cy, dl, fg);
dl = 0;
}
if (getColor) bg = getColor(x + cx, y + cy);
drawPixel(x + cx, y + cy, alphaBlend(pixel, fg, bg));
}
else

View File

@@ -566,21 +566,21 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_
int32_t xs = x;
int32_t ys = y;
uint32_t ws = w;
uint32_t hs = h;
int32_t ws = w;
int32_t hs = h;
if (x < 0) { xo = -x; ws += x; xs = 0; }
if (y < 0) { yo = -y; hs += y; ys = 0; }
if (xs + ws >= _iwidth) ws = _iwidth - xs;
if (ys + hs >= _iheight) hs = _iheight - ys;
if (xs + ws >= (int32_t)_iwidth) ws = _iwidth - xs;
if (ys + hs >= (int32_t)_iheight) hs = _iheight - ys;
if (_bpp == 16) // Plot a 16 bpp image into a 16 bpp Sprite
{
for (uint32_t yp = yo; yp < yo + hs; yp++)
for (int32_t yp = yo; yp < yo + hs; yp++)
{
x = xs;
for (uint32_t xp = xo; xp < xo + ws; xp++)
for (int32_t xp = xo; xp < xo + ws; xp++)
{
uint16_t color = data[xp + yp * w];
if(!_iswapBytes) color = color<<8 | color>>8;
@@ -592,10 +592,10 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_
}
else if (_bpp == 8) // Plot a 16 bpp image into a 8 bpp Sprite
{
for (uint32_t yp = yo; yp < yo + hs; yp++)
for (int32_t yp = yo; yp < yo + hs; yp++)
{
x = xs;
for (uint32_t xp = xo; xp < xo + ws; xp++)
for (int32_t xp = xo; xp < xo + ws; xp++)
{
uint16_t color = data[xp + yp * w];
if(_iswapBytes) color = color<<8 | color>>8;
@@ -662,21 +662,21 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const u
int32_t xs = x;
int32_t ys = y;
uint32_t ws = w;
uint32_t hs = h;
int32_t ws = w;
int32_t hs = h;
if (x < 0) { xo = -x; ws += x; xs = 0; }
if (y < 0) { yo = -y; hs += y; ys = 0; }
if (xs + ws >= _iwidth) ws = _iwidth - xs;
if (ys + hs >= _iheight) hs = _iheight - ys;
if (xs + ws >= (int32_t)_iwidth) ws = _iwidth - xs;
if (ys + hs >= (int32_t)_iheight) hs = _iheight - ys;
if (_bpp == 16) // Plot a 16 bpp image into a 16 bpp Sprite
{
for (uint32_t yp = yo; yp < yo + hs; yp++)
for (int32_t yp = yo; yp < yo + hs; yp++)
{
x = xs;
for (uint32_t xp = xo; xp < xo + ws; xp++)
for (int32_t xp = xo; xp < xo + ws; xp++)
{
uint16_t color = pgm_read_word(data + xp + yp * w);
if(!_iswapBytes) color = color<<8 | color>>8;
@@ -689,10 +689,10 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const u
else if (_bpp == 8) // Plot a 16 bpp image into a 8 bpp Sprite
{
for (uint32_t yp = yo; yp < yo + hs; yp++)
for (int32_t yp = yo; yp < yo + hs; yp++)
{
x = xs;
for (uint32_t xp = xo; xp < xo + ws; xp++)
for (int32_t xp = xo; xp < xo + ws; xp++)
{
uint16_t color = pgm_read_word(data + xp + yp * w);
if(_iswapBytes) color = color<<8 | color>>8;
@@ -733,7 +733,7 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const u
uint8_t pbyte = pgm_read_byte(pdata++);
for (uint8_t xc = 0; xc < 8; xc++)
{
if (xp+xc<w) drawPixel(x+xp+xc, y+yp, (pbyte<<xc) & 0x80);
if (xp+xc<(uint32_t)w) drawPixel(x+xp+xc, y+yp, (pbyte<<xc) & 0x80);
}
}
}

View File

@@ -49,6 +49,8 @@ uint8_t readByte(void);
// GPIO parallel input/output control
void busDir(uint32_t mask, uint8_t mode);
void gpioMode(uint8_t gpio, uint8_t mode);
inline void TFT_eSPI::spi_begin(void){
#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(ESP32_PARALLEL)
if (locked) {locked = false; spi.beginTransaction(SPISettings(SPI_FREQUENCY, MSBFIRST, TFT_SPI_MODE)); CS_L;}
@@ -377,6 +379,8 @@ void TFT_eSPI::init(uint8_t tc)
spi_begin();
tc = tc; // Supress warning
// This loads the driver specific initialisation code <<<<<<<<<<<<<<<<<<<<< ADD NEW DRIVERS TO THE LIST HERE <<<<<<<<<<<<<<<<<<<<<<<
#if defined (ILI9341_DRIVER)
#include "TFT_Drivers/ILI9341_Init.h"
@@ -711,6 +715,11 @@ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0)
#else // Not ESP32_PARALLEL
// This function can get called during antialiased font rendering
// so a transaction may be in progress
bool wasInTransaction = inTransaction;
if (inTransaction) { inTransaction= false; spi_end();}
spi_begin_read();
readAddrWindow(x0, y0, 1, 1); // Sets CS low
@@ -748,11 +757,19 @@ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0)
spi_end_read();
// Reinstate the transaction if one was in progress
if(wasInTransaction) { spi_begin(); inTransaction = true; }
return color565(r, g, b);
#endif
}
void TFT_eSPI::setCallback(getColorCallback getCol)
{
getColor = getCol;
}
/***************************************************************************************
** Function name: read byte - supports class functions
** Description: Read a byte from ESP32 8 bit data port
@@ -785,29 +802,45 @@ uint8_t readByte(void)
}
/***************************************************************************************
** Function name: masked GPIO direction control - supports class functions
** Description: Set masked ESP32 GPIO pins to input or output
** Function name: GPIO direction control - supports class functions
** Description: Set parallel bus to input or output
***************************************************************************************/
void busDir(uint32_t mask, uint8_t mode)
{
#ifdef ESP32_PARALLEL
void busDir(uint32_t mask, uint8_t mode)
{//*
gpioMode(TFT_D0, mode);
gpioMode(TFT_D1, mode);
gpioMode(TFT_D2, mode);
gpioMode(TFT_D3, mode);
gpioMode(TFT_D4, mode);
gpioMode(TFT_D5, mode);
gpioMode(TFT_D6, mode);
gpioMode(TFT_D7, mode);
return; //*/
// Supports GPIO 0 - 31 on ESP32 only
gpio_config_t gpio;
gpio.pin_bit_mask = mask;
gpio.mode = GPIO_MODE_INPUT;
gpio.pull_up_en = GPIO_PULLUP_ENABLE;
gpio.pull_down_en = GPIO_PULLDOWN_DISABLE;
gpio.intr_type = GPIO_INTR_DISABLE;
if (mode == OUTPUT) gpio.mode = GPIO_MODE_OUTPUT;
gpio_config(&gpio);
#endif
/*
// Arduino generic native function, but slower
pinMode(TFT_D0, mode);
pinMode(TFT_D1, mode);
pinMode(TFT_D2, mode);
pinMode(TFT_D3, mode);
pinMode(TFT_D4, mode);
pinMode(TFT_D5, mode);
pinMode(TFT_D6, mode);
pinMode(TFT_D7, mode);
return; //*/
}
// Set ESP32 GPIO pin to input or output
void gpioMode(uint8_t gpio, uint8_t mode)
{
if(mode == INPUT) GPIO.enable_w1tc = ((uint32_t)1 << gpio);
else GPIO.enable_w1ts = ((uint32_t)1 << gpio);
ESP_REG(DR_REG_IO_MUX_BASE + esp32_gpioMux[gpio].reg) = ((uint32_t)2 << FUN_DRV_S) | (FUN_IE) | ((uint32_t)2 << MCU_SEL_S);
GPIO.pin[gpio].val = 0;
}
#endif
/***************************************************************************************
** Function name: read rectangle (for SPI Interface II i.e. IM [3:0] = "1101")
** Description: Read 565 pixel colours from a defined area

View File

@@ -15,7 +15,7 @@
#ifndef _TFT_eSPIH_
#define _TFT_eSPIH_
#define TFT_ESPI_VERSION "1.4.20"
#define TFT_ESPI_VERSION "1.4.21"
//#define ESP32 //Just used to test ESP32 options
@@ -656,6 +656,7 @@ const PROGMEM fontinfo fontdata [] = {
#endif
};
typedef uint16_t (*getColorCallback)(uint16_t x, uint16_t y);
// Class functions and variables
class TFT_eSPI : public Print {
@@ -740,6 +741,7 @@ class TFT_eSPI : public Print {
// Read the colour of a pixel at x,y and return value in 565 format
uint16_t readPixel(int32_t x0, int32_t y0);
void setCallback(getColorCallback getCol);
// The next functions can be used as a pair to copy screen blocks (or horizontal/vertical lines) to another location
// Read a block of pixels to a data buffer, buffer is 16 bit and the array size must be at least w * h
@@ -872,6 +874,7 @@ class TFT_eSPI : public Print {
uint32_t lastColor = 0xFFFF;
getColorCallback getColor = nullptr;
protected:

View File

@@ -38,11 +38,11 @@
#########################################################################
*/
#include "Free_Fonts.h" // Include the header file attached to this sketch
#include "SPI.h"
#include "TFT_eSPI.h"
#include "Free_Fonts.h" // Include the header file attached to this sketch
// Use hardware SPI
TFT_eSPI tft = TFT_eSPI();

View File

@@ -39,8 +39,6 @@
//
// tft.setFreeFont(NULL); // Set font to GLCD
#define LOAD_GFXFF
#ifdef LOAD_GFXFF // Only include the fonts if LOAD_GFXFF is defined in User_Setup.h
// Use these when printing or drawing text in GLCD and high rendering speed fonts
@@ -264,6 +262,8 @@
#define FONT7 7
#define FONT8 8
#define TT1 1
#define FF0 1
#define FF1 1
#define FF2 1

View File

@@ -23,11 +23,11 @@
#########################################################################
*/
#include "Free_Fonts.h" // Include the header file attached to this sketch
#include <TFT_eSPI.h> // Hardware-specific library
#include <SPI.h>
#include "Free_Fonts.h" // Include the header file attached to this sketch
TFT_eSPI tft = TFT_eSPI(); // Invoke custom library with default width and height
unsigned long drawTime = 0;

View File

@@ -39,7 +39,6 @@
//
// tft.setFreeFont(NULL); // Set font to GLCD
#define LOAD_GFXFF
#ifdef LOAD_GFXFF // Only include the fonts if LOAD_GFXFF is defined in User_Setup.h
@@ -265,6 +264,8 @@
#define FONT7 7
#define FONT8 8
#define TT1 1
#define FF0 1
#define FF1 1
#define FF2 1

View File

@@ -0,0 +1,121 @@
/*
This sketch is based on Font Demo 1. It introduces a method for rendering
anti-aliased fonts on a graded background. This is acheived by telling the
TFT_eSPI library the pixel color at each point on the screen. In this sketch
a graded background is drawn, the color of each pixel can therefore be
determined. The TFT does not need to support reading of the graphics memory.
The sketch could be adapted so only part of the screen is gas a color gradient.
The TFT_eSPI library must be given the name of the function in the sketch
that will return the pixel xolor at a position x,y on the TFT. In this
sketch that function is called gradientColor, so this line is included:
tft.setCallback(gradientColor);
TFT_eSPI will call this function during the rendering of the anti-aliased
font to blend the edges of each character with the returned color.
If the TFT supports reading the screen RAM then the returned value can be
tft.readPixel(x,y) and anti-aliased text can the be drawn over any screen
image. See "Smooth_font_over_image" example.
*/
// The fonts used are in the sketch data folder, press Ctrl+K to view.
// Upload the fonts and icons to SPIFFS (must set at least 1M for SPIFFS) using the
// "Tools" "ESP8266 (or ESP32) Sketch Data Upload" menu option in the IDE.
// To add this option follow instructions here for the ESP8266:
// https://github.com/esp8266/arduino-esp8266fs-plugin
// or for the ESP32:
// https://github.com/me-no-dev/arduino-esp32fs-plugin
// Close the IDE and open again to see the new menu option.
// A processing sketch to create new fonts can be found in the Tools folder of TFT_eSPI
// https://github.com/Bodmer/TFT_eSPI/tree/master/Tools/Create_Smooth_Font/Create_font
// This sketch uses font files created from the Noto family of fonts:
// https://www.google.com/get/noto/
#define AA_FONT_SMALL "NotoSansBold15"
#define AA_FONT_LARGE "NotoSansBold36"
// Font files are stored in SPIFFS, so load the library
#include <FS.h>
#include <SPI.h>
#include <TFT_eSPI.h> // Hardware-specific library
TFT_eSPI tft = TFT_eSPI();
#define TOP_COLOR TFT_RED
#define BOTTOM_COLOR TFT_BLACK
#define GRADIENT_HEIGHT (9 + tft.fontHeight() * 5) // Gradient over 5 lines
#define OUTSIDE_GRADIENT TFT_BLUE
uint16_t gradientColor(uint16_t x, uint16_t y)
{
if (y > GRADIENT_HEIGHT) return OUTSIDE_GRADIENT; // Outside gradient area
uint8_t alpha = (255 * y) / GRADIENT_HEIGHT; // alpha is a value in the range 0-255
return tft.alphaBlend(alpha, BOTTOM_COLOR, TOP_COLOR);
}
void fillGradient() {
uint16_t w = tft.width();
for (uint16_t y = 0; y < tft.height(); ++y) {
uint16_t color = gradientColor(0, y); // x not used here
tft.drawFastHLine(0, y, w, color);
}
}
void setup(void) {
Serial.begin(115200);
tft.begin();
tft.setCallback(gradientColor); // Switch on color callback for anti-aliased fonts
//tft.setCallback(nullptr); // Switch off callback (off by default)
tft.setRotation(1);
if (!SPIFFS.begin()) {
Serial.println("SPIFFS initialisation failed!");
while (1) yield(); // Stay here twiddling thumbs waiting
}
Serial.println("\r\nSPIFFS available!");
// ESP32 will crash if any of the fonts are missing
bool font_missing = false;
if (SPIFFS.exists("/NotoSansBold15.vlw") == false) font_missing = true;
if (SPIFFS.exists("/NotoSansBold36.vlw") == false) font_missing = true;
if (font_missing)
{
Serial.println("\r\nFont missing in SPIFFS, did you upload it?");
while (1) yield();
}
else Serial.println("\r\nFonts found OK.");
}
void loop() {
// Select a font size comensurate with screen size
if (tft.width()>= 320)
tft.loadFont(AA_FONT_LARGE);
else
tft.loadFont(AA_FONT_SMALL);
fillGradient(); // Put here after selecting the font so fontHeight() is already set
tft.setTextColor(TFT_WHITE); // Background color is ignored in gradient area
tft.setCursor(0, 10); // Set cursor at top left of screen
uint32_t t = millis();
tft.println(" Ode to a small\n lump of green\n putty I found\n in my armpit\n one midsummer\n morning ");
Serial.println(t = millis()-t);
tft.unloadFont(); // Remove the font to recover memory used
delay(2000);
}

View File

@@ -0,0 +1,165 @@
/*
This sketch is based on Font Demo 1. It introduces a method for rendering
anti-aliased fonts on an arbitrary background. This is acheived by reading
the pixel color at each point on the screen. The TFT must support reading
the graphics RAM of the screen memory. This sketch has been tested with
ILI9241 and ILI9481 serial and parallel screens. Other screens may or may
not work!
The TFT_eSPI library must be given the name of the function in the sketch
that will return the pixel color at a position x,y on the TFT. In this
sketch that function is called pixelColor, so this line is included:
tft.setCallback(pixelColor);
TFT_eSPI will call this function during the rendering of the anti-aliased
font and use it to blend the edges of each character with the screen color.
*/
// The fonts used are in the sketch data folder, press Ctrl+K to view.
// Upload the fonts and icons to SPIFFS (must set at least 1M for SPIFFS) using the
// "Tools" "ESP8266 (or ESP32) Sketch Data Upload" menu option in the IDE.
// To add this option follow instructions here for the ESP8266:
// https://github.com/esp8266/arduino-esp8266fs-plugin
// or for the ESP32:
// https://github.com/me-no-dev/arduino-esp32fs-plugin
// Close the IDE and open again to see the new menu option.
// A processing sketch to create new fonts can be found in the Tools folder of TFT_eSPI
// https://github.com/Bodmer/TFT_eSPI/tree/master/Tools/Create_Smooth_Font/Create_font
// This sketch uses font files created from the Noto family of fonts:
// https://www.google.com/get/noto/
#define AA_FONT_SMALL "NotoSansBold15"
#define AA_FONT_LARGE "NotoSansBold36"
// Font files are stored in SPIFFS, so load the library
#include <FS.h>
#include <SPI.h>
#include <TFT_eSPI.h> // Hardware-specific library
TFT_eSPI tft = TFT_eSPI();
// Callback function to provide the pixel color at x,y
uint16_t pixelColor(uint16_t x, uint16_t y) { return tft.readPixel(x, y); }
void setup(void) {
Serial.begin(115200);
tft.begin();
tft.setCallback(pixelColor); // The callback is only used durung font rendering
//tft.setCallback(nullptr); // Switch off callback (off by default)
tft.setRotation(1);
if (!SPIFFS.begin()) {
Serial.println("SPIFFS initialisation failed!");
while (1) yield(); // Stay here twiddling thumbs waiting
}
Serial.println("\r\nSPIFFS available!");
// ESP32 will crash if any of the fonts are missing, so check
bool font_missing = false;
if (SPIFFS.exists("/NotoSansBold15.vlw") == false) font_missing = true;
if (SPIFFS.exists("/NotoSansBold36.vlw") == false) font_missing = true;
if (font_missing)
{
Serial.println("\r\nFont missing in SPIFFS, did you upload it?");
while (1) yield();
}
else Serial.println("\r\nFonts found OK.");
}
void loop() {
rainbow_fill(); // Fill the screen with rainbow colours
// Select a font size comensurate with screen size
if (tft.width()>= 320)
tft.loadFont(AA_FONT_LARGE);
else
tft.loadFont(AA_FONT_SMALL);
tft.setTextColor(TFT_BLACK, TFT_WHITE); // Background color is ignored if callback is set
tft.setCursor(0, 10); // Set cursor at top left of screen
uint32_t t = millis();
tft.println(" Ode to a small\n lump of green\n putty I found\n in my armpit\n one midsummer\n morning ");
Serial.println(t = millis()-t);
tft.unloadFont(); // Remove the font to recover memory used
delay(2000);
}
// #########################################################################
// Fill screen with a rainbow pattern
// #########################################################################
byte red = 31;
byte green = 0;
byte blue = 0;
byte state = 0;
unsigned int colour = red << 11; // Colour order is RGB 5+6+5 bits each
void rainbow_fill()
{
// The colours and state are not initialised so the start colour changes each time the funtion is called
for (int i = 319; i >= 0; i--) {
// Draw a vertical line 1 pixel wide in the selected colour
tft.drawFastHLine(0, i, tft.width(), colour); // in this example tft.width() returns the pixel width of the display
// This is a "state machine" that ramps up/down the colour brightnesses in sequence
switch (state) {
case 0:
green ++;
if (green == 64) {
green = 63;
state = 1;
}
break;
case 1:
red--;
if (red == 255) {
red = 0;
state = 2;
}
break;
case 2:
blue ++;
if (blue == 32) {
blue = 31;
state = 3;
}
break;
case 3:
green --;
if (green == 255) {
green = 0;
state = 4;
}
break;
case 4:
red ++;
if (red == 32) {
red = 31;
state = 5;
}
break;
case 5:
blue --;
if (blue == 255) {
blue = 0;
state = 0;
}
break;
}
colour = red << 11 | green << 5 | blue;
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "TFT_eSPI",
"version": "1.4.20",
"version": "1.4.21",
"keywords": "tft, ePaper, display, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9486, ST7789, RM68140",
"description": "A TFT and ePaper SPI graphics library for ESP8266 and ESP32",
"repository":

View File

@@ -1,5 +1,5 @@
name=TFT_eSPI
version=1.4.20
version=1.4.21
author=Bodmer
maintainer=Bodmer
sentence=A fast TFT graphics library for ESP8266 and ESP32 processors for the Arduino IDE