Font partition supported. No time and ram is used for load smooth font.

This commit is contained in:
en.ot 2021-08-08 21:44:12 +03:00
parent 7d85157c3c
commit 44d8aa1073
8 changed files with 276 additions and 229 deletions

View File

@ -6,6 +6,11 @@
// New anti-aliased (smoothed) font functions added below
////////////////////////////////////////////////////////////////////////////////////////
//syntax highlight enable
#ifndef TFT_ESPI_VERSION
#include "TFT_eSPI.h"
#endif
/***************************************************************************************
** Function name: loadFont
** Description: loads parameters from a font vlw array in memory
@ -17,6 +22,30 @@ void TFT_eSPI::loadFont(const uint8_t array[])
loadFont("", false);
}
void TFT_eSPI::loadFont(const char * partitionName, esp_partition_subtype_t subtype)
{
const esp_partition_t* fontpart = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, subtype, partitionName);
if (!fontpart)
{
Serial.print("Font partition not found: ");
Serial.println(partitionName);
return;
}
esp_err_t err = spi_flash_mmap(fontpart->address, fontpart->size, SPI_FLASH_MMAP_INST, (const void **)&fontPtr, &font_handle);
// esp_err_t err = spi_flash_mmap(fontpart->address, 4*1024*1024, SPI_FLASH_MMAP_INST, (const void **)&fontPtr, &font_handle);
if (err)
{
Serial.print("Partition mapping error ");
Serial.println(err);
return;
}
loadFont("", false);
}
#ifdef FONT_FS_AVAILABLE
/***************************************************************************************
** Function name: loadFont
@ -29,6 +58,7 @@ void TFT_eSPI::loadFont(String fontName, fs::FS &ffs)
}
#endif
/***************************************************************************************
** Function name: loadFont
** Description: loads parameters from a font vlw file
@ -128,123 +158,39 @@ void TFT_eSPI::loadFont(String fontName, bool flash)
gFont.gCount = (uint16_t)readInt32(); // glyph count in file
readInt32(); // vlw encoder version - discard
gFont.yAdvance = (uint16_t)readInt32(); // Font size in points, not pixels
readInt32(); // discard
gFont.maxDescent = (int32_t)readInt32();
gFont.ascent = (uint16_t)readInt32(); // top of "d"
gFont.descent = (uint16_t)readInt32(); // bottom of "p"
// 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;
gFont.spaceWidth = gFont.yAdvance / 4; // Guess at space width
yield();
gFont.yAdvance = gFont.maxAscent + gFont.maxDescent;
gFont.spaceWidth = (gFont.ascent + gFont.descent) * 2/7; // Guess at space width
fontLoaded = true;
// Fetch the metrics for each glyph
loadMetrics();
}
/***************************************************************************************
** Function name: loadMetrics
** Description: Get the metrics for each glyph and store in RAM
*************************************************************************************x*/
//#define SHOW_ASCENT_DESCENT
void TFT_eSPI::loadMetrics(void)
static TFT_eSPI::CharMetrics _cm;
TFT_eSPI::CharMetrics * TFT_eSPI::getCharMetrics(uint16_t gNum)
{
uint32_t headerPtr = 24;
uint32_t bitmapPtr = headerPtr + gFont.gCount * 28;
CharMetrics * cm = &_cm;
#if defined (ESP32) && defined (CONFIG_SPIRAM_SUPPORT)
if ( psramFound() )
{
gUnicode = (uint16_t*)ps_malloc( gFont.gCount * 2); // Unicode 16 bit Basic Multilingual Plane (0-FFFF)
gHeight = (uint8_t*)ps_malloc( gFont.gCount ); // Height of glyph
gWidth = (uint8_t*)ps_malloc( gFont.gCount ); // Width of glyph
gxAdvance = (uint8_t*)ps_malloc( gFont.gCount ); // xAdvance - to move x cursor
gdY = (int16_t*)ps_malloc( gFont.gCount * 2); // offset from bitmap top edge from lowest point in any character
gdX = (int8_t*)ps_malloc( gFont.gCount ); // offset for bitmap left edge relative to cursor X
gBitmap = (uint32_t*)ps_malloc( gFont.gCount * 4); // seek pointer to glyph bitmap in the file
}
else
#endif
{
gUnicode = (uint16_t*)malloc( gFont.gCount * 2); // Unicode 16 bit Basic Multilingual Plane (0-FFFF)
gHeight = (uint8_t*)malloc( gFont.gCount ); // Height of glyph
gWidth = (uint8_t*)malloc( gFont.gCount ); // Width of glyph
gxAdvance = (uint8_t*)malloc( gFont.gCount ); // xAdvance - to move x cursor
gdY = (int16_t*)malloc( gFont.gCount * 2); // offset from bitmap top edge from lowest point in any character
gdX = (int8_t*)malloc( gFont.gCount ); // offset for bitmap left edge relative to cursor X
gBitmap = (uint32_t*)malloc( gFont.gCount * 4); // seek pointer to glyph bitmap in the file
}
fontPtr = (uint8_t *)&gFont.gArray[24 + gNum * 28];
cm->gUnicode = (uint16_t)readInt32(); // Unicode code point value
cm->gHeight = (uint8_t)readInt32(); // Height of glyph
cm->gWidth = (uint8_t)readInt32(); // Width of glyph
cm->gxAdvance = (uint8_t)readInt32(); // xAdvance - to move x cursor
cm->gdY = (int16_t)readInt32(); // y delta from baseline
cm->gdX = (int8_t)readInt32(); // x delta from cursor
cm->gBitmap = 24 + gFont.gCount*28 + readInt32();
#ifdef SHOW_ASCENT_DESCENT
Serial.print("ascent = "); Serial.println(gFont.ascent);
Serial.print("descent = "); Serial.println(gFont.descent);
#endif
#ifdef FONT_FS_AVAILABLE
if (fs_font) fontFile.seek(headerPtr, fs::SeekSet);
#endif
uint16_t gNum = 0;
while (gNum < gFont.gCount)
{
gUnicode[gNum] = (uint16_t)readInt32(); // Unicode code point value
gHeight[gNum] = (uint8_t)readInt32(); // Height of glyph
gWidth[gNum] = (uint8_t)readInt32(); // Width of glyph
gxAdvance[gNum] = (uint8_t)readInt32(); // xAdvance - to move x cursor
gdY[gNum] = (int16_t)readInt32(); // y delta from baseline
gdX[gNum] = (int8_t)readInt32(); // x delta from cursor
readInt32(); // ignored
//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)
{
// 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
Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", maxAscent = "); Serial.println(gFont.maxAscent);
#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)
{
// 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))
{
gFont.maxDescent = gHeight[gNum] - gdY[gNum];
#ifdef SHOW_ASCENT_DESCENT
Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", maxDescent = "); Serial.println(gHeight[gNum] - gdY[gNum]);
#endif
}
}
gBitmap[gNum] = bitmapPtr;
bitmapPtr += gWidth[gNum] * gHeight[gNum];
gNum++;
yield();
}
gFont.yAdvance = gFont.maxAscent + gFont.maxDescent;
gFont.spaceWidth = (gFont.ascent + gFont.descent) * 2/7; // Guess at space width
return cm;
}
@ -254,54 +200,18 @@ void TFT_eSPI::loadMetrics(void)
*************************************************************************************x*/
void TFT_eSPI::unloadFont( void )
{
if (gUnicode)
{
free(gUnicode);
gUnicode = NULL;
}
if (gHeight)
{
free(gHeight);
gHeight = NULL;
}
if (gWidth)
{
free(gWidth);
gWidth = NULL;
}
if (gxAdvance)
{
free(gxAdvance);
gxAdvance = NULL;
}
if (gdY)
{
free(gdY);
gdY = NULL;
}
if (gdX)
{
free(gdX);
gdX = NULL;
}
if (gBitmap)
{
free(gBitmap);
gBitmap = NULL;
}
gFont.gArray = nullptr;
#ifdef FONT_FS_AVAILABLE
if (fs_font && fontFile) fontFile.close();
#endif
if (font_handle)
{
spi_flash_munmap(font_handle);
font_handle = 0;
}
fontLoaded = false;
}
@ -312,24 +222,24 @@ void TFT_eSPI::unloadFont( void )
*************************************************************************************x*/
uint32_t TFT_eSPI::readInt32(void)
{
uint32_t val = 0;
uint32_t val;
#ifdef FONT_FS_AVAILABLE
if (fs_font) {
val |= fontFile.read() << 24;
val |= fontFile.read() << 16;
val |= fontFile.read() << 8;
if (fs_font)
{
fontFile.seek((uint32_t)fontPtr, fs::SeekSet);
val |= fontFile.read();
val |= fontFile.read() << 8;
val |= fontFile.read() << 16;
val |= fontFile.read() << 24;
}
else
#endif
{
val |= pgm_read_byte(fontPtr++) << 24;
val |= pgm_read_byte(fontPtr++) << 16;
val |= pgm_read_byte(fontPtr++) << 8;
val |= pgm_read_byte(fontPtr++);
val = pgm_read_dword(fontPtr) & 0xFFFFFFFFul;
}
fontPtr += 4;
return val;
}
@ -347,7 +257,8 @@ bool TFT_eSPI::getUnicodeIndex(uint16_t unicode, uint16_t *index)
int i = above / 2;
do
{
uint16_t code = gUnicode[i];
fontPtr = (uint8_t *)&gFont.gArray[24 + i * 28];
uint32_t code = readInt32(); // Unicode code point value. 32bit to prevent compiler optimisation leading to unaligned access (16 bit)
if (code == unicode)
{
*index = i;
@ -384,6 +295,56 @@ bool TFT_eSPI::getUnicodeIndex(uint16_t unicode, uint16_t *index)
#endif
//--------------------------------------------------------------------------------------
void * memcpy_I(void * dst, const void * src, int len)
{
// return memcpy(dst, src, len);
if (!len) return dst;
uint32_t d;
uint32_t dst1 = (uint32_t)dst;
uint32_t src1 = (uint32_t)src;
if (src1 & 3)
{
d = *(uint32_t*)(src1 & ~3);
d >>= 8 * (src1 & 3);
while (src1 & 3)
{
*(uint8_t *)dst1 = d & 0xFF;
d >>= 8;
src1++;
dst1++;
len--;
if (!len) return dst;
}
}
while (len > 3)
{
d = *(uint32_t *)src1;
*(uint32_t *)dst1 = d;
src1 += 4;
dst1 += 4;
len -= 4;
}
if (!len) return dst;
d = *(uint32_t *)src1;
while (len)
{
*(uint8_t *)dst1 = d & 0xFF;
d >>= 8;
src1++;
dst1++;
len--;
}
return dst;
}
/***************************************************************************************
** Function name: drawGlyph
@ -416,28 +377,27 @@ void TFT_eSPI::drawGlyph(uint16_t code)
if (found)
{
if (textwrapX && (cursor_x + gWidth[gNum] + gdX[gNum] > width()))
CharMetrics * cm = getCharMetrics(gNum);
if (textwrapX && (cursor_x + cm->gWidth + cm->gdX > width()))
{
cursor_y += gFont.yAdvance;
cursor_x = 0;
}
if (textwrapY && ((cursor_y + gFont.yAdvance) >= height())) cursor_y = 0;
if (cursor_x == 0) cursor_x -= gdX[gNum];
if (cursor_x == 0) cursor_x -= cm->gdX;
uint8_t* pbuffer = nullptr;
const uint8_t* gPtr = (const uint8_t*) gFont.gArray;
uint8_t* pbuffer = glyph_line_buffer;//(uint8_t*)malloc(cm->gWidth);
const uint8_t* gPtr = (const uint8_t*) gFont.gArray + cm->gBitmap;
#ifdef FONT_FS_AVAILABLE
if (fs_font)
{
fontFile.seek(gBitmap[gNum], fs::SeekSet); // This is taking >30ms for a significant position shift
pbuffer = (uint8_t*)malloc(gWidth[gNum]);
fontFile.seek(cm->gBitmap, fs::SeekSet); // This is taking >30ms for a significant position shift
}
#endif
int16_t cy = cursor_y + gFont.maxAscent - gdY[gNum];
int16_t cx = cursor_x + gdX[gNum];
int16_t cy = cursor_y + gFont.maxAscent - cm->gdY;
int16_t cx = cursor_x + cm->gdX;
int16_t xs = cx;
uint32_t dl = 0;
@ -447,31 +407,33 @@ void TFT_eSPI::drawGlyph(uint16_t code)
//if (fg!=bg) fillRect(cursor_x, cursor_y, gxAdvance[gNum], gFont.yAdvance, bg);
for (int y = 0; y < gHeight[gNum]; y++)
for (int y = 0; y < cm->gHeight; y++)
{
#ifdef FONT_FS_AVAILABLE
if (fs_font) {
if (spiffs)
{
fontFile.read(pbuffer, gWidth[gNum]);
fontFile.read(pbuffer, cm->gWidth);
//Serial.println("SPIFFS");
}
else
{
endWrite(); // Release SPI for SD card transaction
fontFile.read(pbuffer, gWidth[gNum]);
fontFile.read(pbuffer, cm->gWidth);
startWrite(); // Re-start SPI for TFT transaction
//Serial.println("Not SPIFFS");
}
}
#endif
for (int x = 0; x < gWidth[gNum]; x++)
{
#ifdef FONT_FS_AVAILABLE
if (fs_font) pixel = pbuffer[x];
else
#endif
pixel = pgm_read_byte(gPtr + gBitmap[gNum] + x + gWidth[gNum] * y);
{
memcpy_I(pbuffer, gPtr, cm->gWidth);
gPtr += cm->gWidth;
}
for (int x = 0; x < cm->gWidth; x++)
{
pixel = pbuffer[x];
if (pixel)
{
@ -499,8 +461,8 @@ void TFT_eSPI::drawGlyph(uint16_t code)
if (dl) { drawFastHLine( xs, y + cy, dl, fg); dl = 0; }
}
if (pbuffer) free(pbuffer);
cursor_x += gxAdvance[gNum];
//if (pbuffer) free(pbuffer);
cursor_x += cm->gxAdvance;
endWrite();
}
else
@ -528,12 +490,13 @@ void TFT_eSPI::showFont(uint32_t td)
for (uint16_t i = 0; i < gFont.gCount; i++)
{
// Check if this will need a new screen
if (cursorX + gdX[i] + gWidth[i] >= width()) {
cursorX = -gdX[i];
CharMetrics * cm = getCharMetrics(i);
if (cursorX + cm->gdX + cm->gWidth >= width()) {
cursorX = -cm->gdX;
cursorY += gFont.yAdvance;
if (cursorY + gFont.maxAscent + gFont.descent >= height()) {
cursorX = -gdX[i];
cursorX = -cm->gdX;
cursorY = 0;
delay(timeDelay);
timeDelay = td;
@ -542,8 +505,8 @@ void TFT_eSPI::showFont(uint32_t td)
}
setCursor(cursorX, cursorY);
drawGlyph(gUnicode[i]);
cursorX += gxAdvance[i];
drawGlyph(cm->gUnicode);
cursorX += cm->gxAdvance;
//cursorX += printToSprite( cursorX, cursorY, i );
yield();
}

View File

@ -9,6 +9,8 @@
void loadFont(String fontName, fs::FS &ffs);
#endif
void loadFont(String fontName, bool flash = true);
void loadFont(const char * partitionName, esp_partition_subtype_t subtype);
void unloadFont( void );
bool getUnicodeIndex(uint16_t unicode, uint16_t *index);
@ -29,19 +31,31 @@
uint16_t maxDescent; // Maximum descent found in font
} fontMetrics;
fontMetrics gFont = { nullptr, 0, 0, 0, 0, 0, 0, 0 };
fontMetrics gFont = { nullptr, 0, 0, 0, 0, 0, 0, 0 };
#define MAX_GLYPH_WIDTH 30
uint8_t glyph_line_buffer[MAX_GLYPH_WIDTH];
// These are for the metrics for each individual glyph (so we don't need to seek this in file and waste time)
uint16_t* gUnicode = NULL; //UTF-16 code, the codes are searched so do not need to be sequential
uint8_t* gHeight = NULL; //cheight
uint8_t* gWidth = NULL; //cwidth
uint8_t* gxAdvance = NULL; //setWidth
int16_t* gdY = NULL; //topExtent
int8_t* gdX = NULL; //leftExtent
uint32_t* gBitmap = NULL; //file pointer to greyscale bitmap
typedef struct
{
uint16_t gUnicode; //UTF-16 code, the codes are searched so do not need to be sequential
uint8_t gHeight; //cheight
uint8_t gWidth; //cwidth
uint8_t gxAdvance; //setWidth
int16_t gdY; //topExtent
int8_t gdX; //leftExtent
uint32_t gBitmap; //bitmap offset
} CharMetrics;
TFT_eSPI::CharMetrics * getCharMetrics(uint16_t gNum);
// uint32_t* gBitmap = NULL; //file pointer to greyscale bitmap
bool fontLoaded = false; // Flags when a anti-aliased font is loaded
spi_flash_mmap_handle_t font_handle;
#ifdef FONT_FS_AVAILABLE
fs::File fontFile;
fs::FS &fontFS = SPIFFS;
@ -54,7 +68,6 @@ fontMetrics gFont = { nullptr, 0, 0, 0, 0, 0, 0, 0 };
private:
void loadMetrics(void);
uint32_t readInt32(void);
uint8_t* fontPtr = nullptr;

View File

@ -10,6 +10,11 @@
// there is a nett performance gain by using swapped bytes.
***************************************************************************************/
//syntax highlight enable
#ifndef TFT_ESPI_VERSION
#include "TFT_eSPI.h"
#endif
/***************************************************************************************
** Function name: TFT_eSprite
** Description: Class constructor
@ -45,7 +50,7 @@ TFT_eSprite::TFT_eSprite(TFT_eSPI *tft)
** Description: Create a sprite (bitmap) of defined width and height
***************************************************************************************/
// cast returned value to (uint8_t*) for 8 bit or (uint16_t*) for 16 bit colours
void* TFT_eSprite::createSprite(int16_t w, int16_t h, uint8_t frames)
void* TFT_eSprite::createSprite(int16_t w, int16_t h, uint8_t frames, uint8_t * mem)
{
if ( _created ) return _img8_1;
@ -65,7 +70,16 @@ void* TFT_eSprite::createSprite(int16_t w, int16_t h, uint8_t frames)
_sh = h;
_scolor = TFT_BLACK;
if (!mem)
{
_img8 = (uint8_t*) callocSprite(w, h, frames);
Serial.println("error: alloc!!!!");
}
else
{
//memset(mem, 0, w*h*sizeof(uint8_t)/_bpp*8);
_img8 = mem;
}
_img8_1 = _img8;
_img8_2 = _img8;
_img = (uint16_t*) _img8;
@ -372,7 +386,7 @@ uint16_t TFT_eSprite::getPaletteColor(uint8_t index)
** Function name: deleteSprite
** Description: Delete the sprite to free up memory (RAM)
***************************************************************************************/
void TFT_eSprite::deleteSprite(void)
void TFT_eSprite::deleteSprite(bool keep)
{
if (_colorMap != nullptr)
{
@ -382,6 +396,7 @@ void TFT_eSprite::deleteSprite(void)
if (_created)
{
if (!keep)
free(_img8_1);
_img8 = nullptr;
_created = false;
@ -2380,6 +2395,8 @@ int16_t TFT_eSprite::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t fo
#ifdef SMOOTH_FONT
void * memcpy_I(void * dst, const void * src, int len);
/***************************************************************************************
** Function name: drawGlyph
** Description: Write a character to the sprite cursor position
@ -2410,60 +2427,60 @@ void TFT_eSprite::drawGlyph(uint16_t code)
if (found)
{
CharMetrics * cm = getCharMetrics(gNum);
bool newSprite = !_created;
if (newSprite)
{
createSprite(gWidth[gNum], gFont.yAdvance);
createSprite(cm->gWidth, gFont.yAdvance);
if(fg != bg) fillSprite(bg);
cursor_x = -gdX[gNum];
cursor_x = -cm->gdX;
cursor_y = 0;
}
else
{
if( textwrapX && ((cursor_x + gWidth[gNum] + gdX[gNum]) > width())) {
if( textwrapX && ((cursor_x + cm->gWidth + cm->gdX) > width())) {
cursor_y += gFont.yAdvance;
cursor_x = 0;
}
if( textwrapY && ((cursor_y + gFont.yAdvance) > height())) cursor_y = 0;
if ( cursor_x == 0) cursor_x -= gdX[gNum];
if ( cursor_x == 0) cursor_x -= cm->gdX;
}
uint8_t* pbuffer = nullptr;
const uint8_t* gPtr = (const uint8_t*) gFont.gArray;
uint8_t* pbuffer = glyph_line_buffer;//(uint8_t*)malloc(cm->gWidth);
const uint8_t* gPtr = (const uint8_t*) gFont.gArray + cm->gBitmap;
#ifdef FONT_FS_AVAILABLE
if (fs_font) {
fontFile.seek(gBitmap[gNum], fs::SeekSet); // This is slow for a significant position shift!
pbuffer = (uint8_t*)malloc(gWidth[gNum]);
fontFile.seek(cm->gBitmap, fs::SeekSet); // This is slow for a significant position shift!
}
#endif
int16_t xs = 0;
uint16_t dl = 0;
uint8_t pixel = 0;
int32_t cgy = cursor_y + gFont.maxAscent - gdY[gNum];
int32_t cgx = cursor_x + gdX[gNum];
int32_t cgy = cursor_y + gFont.maxAscent - cm->gdY;
int32_t cgx = cursor_x + cm->gdX;
for (int32_t y = 0; y < gHeight[gNum]; y++)
for (int32_t y = 0; y < cm->gHeight; y++)
{
#ifdef FONT_FS_AVAILABLE
if (fs_font) {
fontFile.read(pbuffer, gWidth[gNum]);
}
#endif
for (int32_t x = 0; x < gWidth[gNum]; x++)
{
#ifdef FONT_FS_AVAILABLE
if (fs_font) {
pixel = pbuffer[x];
fontFile.read(pbuffer, cm->gWidth);
}
else
#endif
pixel = pgm_read_byte(gPtr + gBitmap[gNum] + x + gWidth[gNum] * y);
{
memcpy_I(pbuffer, gPtr, cm->gWidth);
gPtr += cm->gWidth;
}
for (int32_t x = 0; x < cm->gWidth; x++)
{
pixel = pbuffer[x];
if (pixel)
{
@ -2490,14 +2507,14 @@ void TFT_eSprite::drawGlyph(uint16_t code)
if (dl) { drawFastHLine( xs, y + cgy, dl, fg); dl = 0; }
}
if (pbuffer) free(pbuffer);
//if (pbuffer) free(pbuffer);
if (newSprite)
{
pushSprite(cgx, cursor_y);
deleteSprite();
}
cursor_x += gxAdvance[gNum];
cursor_x += cm->gxAdvance;
}
else
{
@ -2540,9 +2557,10 @@ void TFT_eSprite::printToSprite(char *cbuffer, uint16_t len) //String string)
uint16_t unicode = decodeUTF8((uint8_t*)cbuffer, &n, len - n);
if (getUnicodeIndex(unicode, &index))
{
if (n == 0) sWidth -= gdX[index];
if (n == len-1) sWidth += ( gWidth[index] + gdX[index]);
else sWidth += gxAdvance[index];
CharMetrics * cm = getCharMetrics(index);
if (n == 0) sWidth -= cm->gdX;
if (n == len-1) sWidth += ( cm->gWidth + cm->gdX);
else sWidth += cm->gxAdvance;
}
else sWidth += gFont.spaceWidth + 1;
}
@ -2577,7 +2595,8 @@ void TFT_eSprite::printToSprite(char *cbuffer, uint16_t len) //String string)
int16_t TFT_eSprite::printToSprite(int16_t x, int16_t y, uint16_t index)
{
bool newSprite = !_created;
int16_t sWidth = gWidth[index];
CharMetrics * cm = getCharMetrics(index);
int16_t sWidth = cm->gWidth;
if (newSprite)
{
@ -2585,14 +2604,15 @@ int16_t TFT_eSprite::printToSprite(int16_t x, int16_t y, uint16_t index)
if (textcolor != textbgcolor) fillSprite(textbgcolor);
drawGlyph(gUnicode[index]);
//todo:drawGlyphIndex
drawGlyph(cm->gUnicode);
pushSprite(x + gdX[index], y, textbgcolor);
pushSprite(x + cm->gdX, y, textbgcolor);
deleteSprite();
}
else drawGlyph(gUnicode[index]);
else drawGlyph(cm->gUnicode);
return gxAdvance[index];
return cm->gxAdvance;
}
#endif

View File

@ -19,7 +19,7 @@ class TFT_eSprite : public TFT_eSPI {
// - 1 nibble per pixel for 4 bit colour
// - 1 byte per pixel for 8 bit colour
// - 2 bytes per pixel for 16 bit color depth
void* createSprite(int16_t width, int16_t height, uint8_t frames = 1);
void* createSprite(int16_t width, int16_t height, uint8_t frames = 1, uint8_t * mem = nullptr);
// Returns a pointer to the sprite or nullptr if not created, user must cast to pointer type
void* getPointer(void);
@ -28,7 +28,7 @@ class TFT_eSprite : public TFT_eSPI {
bool created(void);
// Delete the sprite to free up the RAM
void deleteSprite(void);
void deleteSprite(bool keep = false);
// Select the frame buffer for graphics write (for 2 colour ePaper and DMA toggle buffer)
// Returns a pointer to the Sprite frame buffer

View File

@ -2777,9 +2777,10 @@ int16_t TFT_eSPI::textWidth(const char *string, uint8_t font)
uint16_t gNum = 0;
bool found = getUnicodeIndex(uniCode, &gNum);
if (found) {
if(str_width == 0 && gdX[gNum] < 0) str_width -= gdX[gNum];
if (*string || isDigits) str_width += gxAdvance[gNum];
else str_width += (gdX[gNum] + gWidth[gNum]);
CharMetrics * cm = getCharMetrics(gNum);
if(str_width == 0 && cm->gdX < 0) str_width -= cm->gdX;
if (*string || isDigits) str_width += cm->gxAdvance;
else str_width += (cm->gdX + cm->gWidth);
}
else str_width += gFont.spaceWidth + 1;
}

View File

@ -0,0 +1,42 @@
import struct
inf = 'x324.vlw'
outf = 'x324.prt'
with open(inf, 'rb') as f1:
x = f1.read()
print(len(x))
gCount, ver, yAdvance, dummy, ascent, descent = struct.unpack('>llllll', x[:24])
print(gCount, ver, yAdvance, dummy, ascent, descent)
m = x[24:24+gCount*28]
bitmap = x[24+gCount*28:]
print(len(m), len(bitmap))
print(len(m)/28)
in_metrics = list(struct.iter_unpack('>lllllll', m))
print(len(in_metrics))
max_descent = 0
disp = 0
glyph_metrics = b''
for m in in_metrics:
code, height, width, xAdvance, dY, dX, dummy = m
# print(code, height, width, xAdvance, dY, dX)
s = struct.pack('<lllllll', code, height, width, xAdvance, dY, dX, disp)
glyph_metrics += s
disp += height * width
if ((code > 0x20 and code < 0xA0 and code != 0x7F) or code > 0xFF):
descent1 = height - dY
if descent1 > max_descent: max_descent = descent1
yAdvance = ascent + max_descent
font_metrics = struct.pack('<llllll', gCount, ver, yAdvance, max_descent, ascent, descent)
out_data = font_metrics + glyph_metrics + bitmap
with open(outf, 'wb') as f2:
f2.write(out_data)

View File

@ -0,0 +1,7 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x300000,
app1, app, ota_1, 0x310000,0x300000,
font1, data, fat, 0x610000,0x300000,
spiffs, data, spiffs, 0x910000,0x4F0000,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x5000
3 otadata data ota 0xe000 0x2000
4 app0 app ota_0 0x10000 0x300000
5 app1 app ota_1 0x310000 0x300000
6 font1 data fat 0x610000 0x300000
7 spiffs data spiffs 0x910000 0x4F0000

View File

@ -0,0 +1 @@
tools\esptool.exe --port COM49 --baud 2000000 write_flash -z --flash_mode dio --flash_freq 80m --flash_size detect 0x610000 data/x324.prt