Font partition supported. No time and ram is used for load smooth font.
This commit is contained in:
parent
7d85157c3c
commit
44d8aa1073
|
|
@ -6,6 +6,11 @@
|
||||||
// New anti-aliased (smoothed) font functions added below
|
// New anti-aliased (smoothed) font functions added below
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//syntax highlight enable
|
||||||
|
#ifndef TFT_ESPI_VERSION
|
||||||
|
#include "TFT_eSPI.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
/***************************************************************************************
|
/***************************************************************************************
|
||||||
** Function name: loadFont
|
** Function name: loadFont
|
||||||
** Description: loads parameters from a font vlw array in memory
|
** Description: loads parameters from a font vlw array in memory
|
||||||
|
|
@ -17,6 +22,30 @@ void TFT_eSPI::loadFont(const uint8_t array[])
|
||||||
loadFont("", false);
|
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
|
#ifdef FONT_FS_AVAILABLE
|
||||||
/***************************************************************************************
|
/***************************************************************************************
|
||||||
** Function name: loadFont
|
** Function name: loadFont
|
||||||
|
|
@ -29,6 +58,7 @@ void TFT_eSPI::loadFont(String fontName, fs::FS &ffs)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************************
|
/***************************************************************************************
|
||||||
** Function name: loadFont
|
** Function name: loadFont
|
||||||
** Description: loads parameters from a font vlw file
|
** 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
|
gFont.gCount = (uint16_t)readInt32(); // glyph count in file
|
||||||
readInt32(); // vlw encoder version - discard
|
readInt32(); // vlw encoder version - discard
|
||||||
gFont.yAdvance = (uint16_t)readInt32(); // Font size in points, not pixels
|
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.ascent = (uint16_t)readInt32(); // top of "d"
|
||||||
gFont.descent = (uint16_t)readInt32(); // bottom of "p"
|
gFont.descent = (uint16_t)readInt32(); // bottom of "p"
|
||||||
|
|
||||||
// These next gFont values might 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.maxAscent = gFont.ascent; // Determined from metrics
|
||||||
gFont.maxDescent = gFont.descent; // Determined from metrics
|
|
||||||
gFont.yAdvance = gFont.ascent + gFont.descent;
|
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;
|
fontLoaded = true;
|
||||||
|
|
||||||
// Fetch the metrics for each glyph
|
|
||||||
loadMetrics();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************************
|
static TFT_eSPI::CharMetrics _cm;
|
||||||
** Function name: loadMetrics
|
|
||||||
** Description: Get the metrics for each glyph and store in RAM
|
TFT_eSPI::CharMetrics * TFT_eSPI::getCharMetrics(uint16_t gNum)
|
||||||
*************************************************************************************x*/
|
|
||||||
//#define SHOW_ASCENT_DESCENT
|
|
||||||
void TFT_eSPI::loadMetrics(void)
|
|
||||||
{
|
{
|
||||||
uint32_t headerPtr = 24;
|
CharMetrics * cm = &_cm;
|
||||||
uint32_t bitmapPtr = headerPtr + gFont.gCount * 28;
|
|
||||||
|
|
||||||
#if defined (ESP32) && defined (CONFIG_SPIRAM_SUPPORT)
|
fontPtr = (uint8_t *)&gFont.gArray[24 + gNum * 28];
|
||||||
if ( psramFound() )
|
cm->gUnicode = (uint16_t)readInt32(); // Unicode code point value
|
||||||
{
|
cm->gHeight = (uint8_t)readInt32(); // Height of glyph
|
||||||
gUnicode = (uint16_t*)ps_malloc( gFont.gCount * 2); // Unicode 16 bit Basic Multilingual Plane (0-FFFF)
|
cm->gWidth = (uint8_t)readInt32(); // Width of glyph
|
||||||
gHeight = (uint8_t*)ps_malloc( gFont.gCount ); // Height of glyph
|
cm->gxAdvance = (uint8_t)readInt32(); // xAdvance - to move x cursor
|
||||||
gWidth = (uint8_t*)ps_malloc( gFont.gCount ); // Width of glyph
|
cm->gdY = (int16_t)readInt32(); // y delta from baseline
|
||||||
gxAdvance = (uint8_t*)ps_malloc( gFont.gCount ); // xAdvance - to move x cursor
|
cm->gdX = (int8_t)readInt32(); // x delta from cursor
|
||||||
gdY = (int16_t*)ps_malloc( gFont.gCount * 2); // offset from bitmap top edge from lowest point in any character
|
cm->gBitmap = 24 + gFont.gCount*28 + readInt32();
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef SHOW_ASCENT_DESCENT
|
return cm;
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -254,54 +200,18 @@ void TFT_eSPI::loadMetrics(void)
|
||||||
*************************************************************************************x*/
|
*************************************************************************************x*/
|
||||||
void TFT_eSPI::unloadFont( void )
|
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;
|
gFont.gArray = nullptr;
|
||||||
|
|
||||||
#ifdef FONT_FS_AVAILABLE
|
#ifdef FONT_FS_AVAILABLE
|
||||||
if (fs_font && fontFile) fontFile.close();
|
if (fs_font && fontFile) fontFile.close();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (font_handle)
|
||||||
|
{
|
||||||
|
spi_flash_munmap(font_handle);
|
||||||
|
font_handle = 0;
|
||||||
|
}
|
||||||
|
|
||||||
fontLoaded = false;
|
fontLoaded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -312,24 +222,24 @@ void TFT_eSPI::unloadFont( void )
|
||||||
*************************************************************************************x*/
|
*************************************************************************************x*/
|
||||||
uint32_t TFT_eSPI::readInt32(void)
|
uint32_t TFT_eSPI::readInt32(void)
|
||||||
{
|
{
|
||||||
uint32_t val = 0;
|
uint32_t val;
|
||||||
|
|
||||||
#ifdef FONT_FS_AVAILABLE
|
#ifdef FONT_FS_AVAILABLE
|
||||||
if (fs_font) {
|
if (fs_font)
|
||||||
val |= fontFile.read() << 24;
|
{
|
||||||
val |= fontFile.read() << 16;
|
fontFile.seek((uint32_t)fontPtr, fs::SeekSet);
|
||||||
val |= fontFile.read() << 8;
|
|
||||||
val |= fontFile.read();
|
val |= fontFile.read();
|
||||||
|
val |= fontFile.read() << 8;
|
||||||
|
val |= fontFile.read() << 16;
|
||||||
|
val |= fontFile.read() << 24;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
val |= pgm_read_byte(fontPtr++) << 24;
|
val = pgm_read_dword(fontPtr) & 0xFFFFFFFFul;
|
||||||
val |= pgm_read_byte(fontPtr++) << 16;
|
|
||||||
val |= pgm_read_byte(fontPtr++) << 8;
|
|
||||||
val |= pgm_read_byte(fontPtr++);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fontPtr += 4;
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -347,7 +257,8 @@ bool TFT_eSPI::getUnicodeIndex(uint16_t unicode, uint16_t *index)
|
||||||
int i = above / 2;
|
int i = above / 2;
|
||||||
do
|
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)
|
if (code == unicode)
|
||||||
{
|
{
|
||||||
*index = i;
|
*index = i;
|
||||||
|
|
@ -384,6 +295,56 @@ bool TFT_eSPI::getUnicodeIndex(uint16_t unicode, uint16_t *index)
|
||||||
|
|
||||||
#endif
|
#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
|
** Function name: drawGlyph
|
||||||
|
|
@ -416,28 +377,27 @@ void TFT_eSPI::drawGlyph(uint16_t code)
|
||||||
|
|
||||||
if (found)
|
if (found)
|
||||||
{
|
{
|
||||||
|
CharMetrics * cm = getCharMetrics(gNum);
|
||||||
if (textwrapX && (cursor_x + gWidth[gNum] + gdX[gNum] > width()))
|
if (textwrapX && (cursor_x + cm->gWidth + cm->gdX > width()))
|
||||||
{
|
{
|
||||||
cursor_y += gFont.yAdvance;
|
cursor_y += gFont.yAdvance;
|
||||||
cursor_x = 0;
|
cursor_x = 0;
|
||||||
}
|
}
|
||||||
if (textwrapY && ((cursor_y + gFont.yAdvance) >= height())) cursor_y = 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;
|
uint8_t* pbuffer = glyph_line_buffer;//(uint8_t*)malloc(cm->gWidth);
|
||||||
const uint8_t* gPtr = (const uint8_t*) gFont.gArray;
|
const uint8_t* gPtr = (const uint8_t*) gFont.gArray + cm->gBitmap;
|
||||||
|
|
||||||
#ifdef FONT_FS_AVAILABLE
|
#ifdef FONT_FS_AVAILABLE
|
||||||
if (fs_font)
|
if (fs_font)
|
||||||
{
|
{
|
||||||
fontFile.seek(gBitmap[gNum], fs::SeekSet); // This is taking >30ms for a significant position shift
|
fontFile.seek(cm->gBitmap, fs::SeekSet); // This is taking >30ms for a significant position shift
|
||||||
pbuffer = (uint8_t*)malloc(gWidth[gNum]);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int16_t cy = cursor_y + gFont.maxAscent - gdY[gNum];
|
int16_t cy = cursor_y + gFont.maxAscent - cm->gdY;
|
||||||
int16_t cx = cursor_x + gdX[gNum];
|
int16_t cx = cursor_x + cm->gdX;
|
||||||
|
|
||||||
int16_t xs = cx;
|
int16_t xs = cx;
|
||||||
uint32_t dl = 0;
|
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);
|
//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
|
#ifdef FONT_FS_AVAILABLE
|
||||||
if (fs_font) {
|
if (fs_font) {
|
||||||
if (spiffs)
|
if (spiffs)
|
||||||
{
|
{
|
||||||
fontFile.read(pbuffer, gWidth[gNum]);
|
fontFile.read(pbuffer, cm->gWidth);
|
||||||
//Serial.println("SPIFFS");
|
//Serial.println("SPIFFS");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
endWrite(); // Release SPI for SD card transaction
|
endWrite(); // Release SPI for SD card transaction
|
||||||
fontFile.read(pbuffer, gWidth[gNum]);
|
fontFile.read(pbuffer, cm->gWidth);
|
||||||
startWrite(); // Re-start SPI for TFT transaction
|
startWrite(); // Re-start SPI for TFT transaction
|
||||||
//Serial.println("Not SPIFFS");
|
//Serial.println("Not SPIFFS");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
#endif
|
#endif
|
||||||
for (int x = 0; x < gWidth[gNum]; x++)
|
|
||||||
{
|
{
|
||||||
#ifdef FONT_FS_AVAILABLE
|
memcpy_I(pbuffer, gPtr, cm->gWidth);
|
||||||
if (fs_font) pixel = pbuffer[x];
|
gPtr += cm->gWidth;
|
||||||
else
|
}
|
||||||
#endif
|
|
||||||
pixel = pgm_read_byte(gPtr + gBitmap[gNum] + x + gWidth[gNum] * y);
|
for (int x = 0; x < cm->gWidth; x++)
|
||||||
|
{
|
||||||
|
pixel = pbuffer[x];
|
||||||
|
|
||||||
if (pixel)
|
if (pixel)
|
||||||
{
|
{
|
||||||
|
|
@ -499,8 +461,8 @@ void TFT_eSPI::drawGlyph(uint16_t code)
|
||||||
if (dl) { drawFastHLine( xs, y + cy, dl, fg); dl = 0; }
|
if (dl) { drawFastHLine( xs, y + cy, dl, fg); dl = 0; }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pbuffer) free(pbuffer);
|
//if (pbuffer) free(pbuffer);
|
||||||
cursor_x += gxAdvance[gNum];
|
cursor_x += cm->gxAdvance;
|
||||||
endWrite();
|
endWrite();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -528,12 +490,13 @@ void TFT_eSPI::showFont(uint32_t td)
|
||||||
for (uint16_t i = 0; i < gFont.gCount; i++)
|
for (uint16_t i = 0; i < gFont.gCount; i++)
|
||||||
{
|
{
|
||||||
// Check if this will need a new screen
|
// Check if this will need a new screen
|
||||||
if (cursorX + gdX[i] + gWidth[i] >= width()) {
|
CharMetrics * cm = getCharMetrics(i);
|
||||||
cursorX = -gdX[i];
|
if (cursorX + cm->gdX + cm->gWidth >= width()) {
|
||||||
|
cursorX = -cm->gdX;
|
||||||
|
|
||||||
cursorY += gFont.yAdvance;
|
cursorY += gFont.yAdvance;
|
||||||
if (cursorY + gFont.maxAscent + gFont.descent >= height()) {
|
if (cursorY + gFont.maxAscent + gFont.descent >= height()) {
|
||||||
cursorX = -gdX[i];
|
cursorX = -cm->gdX;
|
||||||
cursorY = 0;
|
cursorY = 0;
|
||||||
delay(timeDelay);
|
delay(timeDelay);
|
||||||
timeDelay = td;
|
timeDelay = td;
|
||||||
|
|
@ -542,8 +505,8 @@ void TFT_eSPI::showFont(uint32_t td)
|
||||||
}
|
}
|
||||||
|
|
||||||
setCursor(cursorX, cursorY);
|
setCursor(cursorX, cursorY);
|
||||||
drawGlyph(gUnicode[i]);
|
drawGlyph(cm->gUnicode);
|
||||||
cursorX += gxAdvance[i];
|
cursorX += cm->gxAdvance;
|
||||||
//cursorX += printToSprite( cursorX, cursorY, i );
|
//cursorX += printToSprite( cursorX, cursorY, i );
|
||||||
yield();
|
yield();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@
|
||||||
void loadFont(String fontName, fs::FS &ffs);
|
void loadFont(String fontName, fs::FS &ffs);
|
||||||
#endif
|
#endif
|
||||||
void loadFont(String fontName, bool flash = true);
|
void loadFont(String fontName, bool flash = true);
|
||||||
|
void loadFont(const char * partitionName, esp_partition_subtype_t subtype);
|
||||||
|
|
||||||
void unloadFont( void );
|
void unloadFont( void );
|
||||||
bool getUnicodeIndex(uint16_t unicode, uint16_t *index);
|
bool getUnicodeIndex(uint16_t unicode, uint16_t *index);
|
||||||
|
|
||||||
|
|
@ -29,19 +31,31 @@
|
||||||
uint16_t maxDescent; // Maximum descent found in font
|
uint16_t maxDescent; // Maximum descent found in font
|
||||||
} fontMetrics;
|
} 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)
|
// 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
|
typedef struct
|
||||||
uint8_t* gHeight = NULL; //cheight
|
{
|
||||||
uint8_t* gWidth = NULL; //cwidth
|
uint16_t gUnicode; //UTF-16 code, the codes are searched so do not need to be sequential
|
||||||
uint8_t* gxAdvance = NULL; //setWidth
|
uint8_t gHeight; //cheight
|
||||||
int16_t* gdY = NULL; //topExtent
|
uint8_t gWidth; //cwidth
|
||||||
int8_t* gdX = NULL; //leftExtent
|
uint8_t gxAdvance; //setWidth
|
||||||
uint32_t* gBitmap = NULL; //file pointer to greyscale bitmap
|
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
|
bool fontLoaded = false; // Flags when a anti-aliased font is loaded
|
||||||
|
|
||||||
|
spi_flash_mmap_handle_t font_handle;
|
||||||
|
|
||||||
#ifdef FONT_FS_AVAILABLE
|
#ifdef FONT_FS_AVAILABLE
|
||||||
fs::File fontFile;
|
fs::File fontFile;
|
||||||
fs::FS &fontFS = SPIFFS;
|
fs::FS &fontFS = SPIFFS;
|
||||||
|
|
@ -54,7 +68,6 @@ fontMetrics gFont = { nullptr, 0, 0, 0, 0, 0, 0, 0 };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void loadMetrics(void);
|
|
||||||
uint32_t readInt32(void);
|
uint32_t readInt32(void);
|
||||||
|
|
||||||
uint8_t* fontPtr = nullptr;
|
uint8_t* fontPtr = nullptr;
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,11 @@
|
||||||
// there is a nett performance gain by using swapped bytes.
|
// 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
|
** Function name: TFT_eSprite
|
||||||
** Description: Class constructor
|
** Description: Class constructor
|
||||||
|
|
@ -45,7 +50,7 @@ TFT_eSprite::TFT_eSprite(TFT_eSPI *tft)
|
||||||
** Description: Create a sprite (bitmap) of defined width and height
|
** 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
|
// 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;
|
if ( _created ) return _img8_1;
|
||||||
|
|
@ -65,7 +70,16 @@ void* TFT_eSprite::createSprite(int16_t w, int16_t h, uint8_t frames)
|
||||||
_sh = h;
|
_sh = h;
|
||||||
_scolor = TFT_BLACK;
|
_scolor = TFT_BLACK;
|
||||||
|
|
||||||
_img8 = (uint8_t*) callocSprite(w, h, frames);
|
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_1 = _img8;
|
||||||
_img8_2 = _img8;
|
_img8_2 = _img8;
|
||||||
_img = (uint16_t*) _img8;
|
_img = (uint16_t*) _img8;
|
||||||
|
|
@ -372,17 +386,18 @@ uint16_t TFT_eSprite::getPaletteColor(uint8_t index)
|
||||||
** Function name: deleteSprite
|
** Function name: deleteSprite
|
||||||
** Description: Delete the sprite to free up memory (RAM)
|
** Description: Delete the sprite to free up memory (RAM)
|
||||||
***************************************************************************************/
|
***************************************************************************************/
|
||||||
void TFT_eSprite::deleteSprite(void)
|
void TFT_eSprite::deleteSprite(bool keep)
|
||||||
{
|
{
|
||||||
if (_colorMap != nullptr)
|
if (_colorMap != nullptr)
|
||||||
{
|
{
|
||||||
free(_colorMap);
|
free(_colorMap);
|
||||||
_colorMap = nullptr;
|
_colorMap = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_created)
|
if (_created)
|
||||||
{
|
{
|
||||||
free(_img8_1);
|
if (!keep)
|
||||||
|
free(_img8_1);
|
||||||
_img8 = nullptr;
|
_img8 = nullptr;
|
||||||
_created = false;
|
_created = false;
|
||||||
_vpOoB = true; // TFT_eSPI class write() uses this to check for valid sprite
|
_vpOoB = true; // TFT_eSPI class write() uses this to check for valid sprite
|
||||||
|
|
@ -2380,6 +2395,8 @@ int16_t TFT_eSprite::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t fo
|
||||||
|
|
||||||
|
|
||||||
#ifdef SMOOTH_FONT
|
#ifdef SMOOTH_FONT
|
||||||
|
void * memcpy_I(void * dst, const void * src, int len);
|
||||||
|
|
||||||
/***************************************************************************************
|
/***************************************************************************************
|
||||||
** Function name: drawGlyph
|
** Function name: drawGlyph
|
||||||
** Description: Write a character to the sprite cursor position
|
** Description: Write a character to the sprite cursor position
|
||||||
|
|
@ -2410,60 +2427,60 @@ void TFT_eSprite::drawGlyph(uint16_t code)
|
||||||
|
|
||||||
if (found)
|
if (found)
|
||||||
{
|
{
|
||||||
|
CharMetrics * cm = getCharMetrics(gNum);
|
||||||
|
|
||||||
bool newSprite = !_created;
|
bool newSprite = !_created;
|
||||||
|
|
||||||
if (newSprite)
|
if (newSprite)
|
||||||
{
|
{
|
||||||
createSprite(gWidth[gNum], gFont.yAdvance);
|
createSprite(cm->gWidth, gFont.yAdvance);
|
||||||
if(fg != bg) fillSprite(bg);
|
if(fg != bg) fillSprite(bg);
|
||||||
cursor_x = -gdX[gNum];
|
cursor_x = -cm->gdX;
|
||||||
cursor_y = 0;
|
cursor_y = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if( textwrapX && ((cursor_x + gWidth[gNum] + gdX[gNum]) > width())) {
|
if( textwrapX && ((cursor_x + cm->gWidth + cm->gdX) > width())) {
|
||||||
cursor_y += gFont.yAdvance;
|
cursor_y += gFont.yAdvance;
|
||||||
cursor_x = 0;
|
cursor_x = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( textwrapY && ((cursor_y + gFont.yAdvance) > height())) cursor_y = 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;
|
uint8_t* pbuffer = glyph_line_buffer;//(uint8_t*)malloc(cm->gWidth);
|
||||||
const uint8_t* gPtr = (const uint8_t*) gFont.gArray;
|
const uint8_t* gPtr = (const uint8_t*) gFont.gArray + cm->gBitmap;
|
||||||
|
|
||||||
#ifdef FONT_FS_AVAILABLE
|
#ifdef FONT_FS_AVAILABLE
|
||||||
if (fs_font) {
|
if (fs_font) {
|
||||||
fontFile.seek(gBitmap[gNum], fs::SeekSet); // This is slow for a significant position shift!
|
fontFile.seek(cm->gBitmap, fs::SeekSet); // This is slow for a significant position shift!
|
||||||
pbuffer = (uint8_t*)malloc(gWidth[gNum]);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int16_t xs = 0;
|
int16_t xs = 0;
|
||||||
uint16_t dl = 0;
|
uint16_t dl = 0;
|
||||||
uint8_t pixel = 0;
|
uint8_t pixel = 0;
|
||||||
int32_t cgy = cursor_y + gFont.maxAscent - gdY[gNum];
|
int32_t cgy = cursor_y + gFont.maxAscent - cm->gdY;
|
||||||
int32_t cgx = cursor_x + gdX[gNum];
|
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
|
#ifdef FONT_FS_AVAILABLE
|
||||||
if (fs_font) {
|
if (fs_font) {
|
||||||
fontFile.read(pbuffer, gWidth[gNum]);
|
fontFile.read(pbuffer, cm->gWidth);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
#endif
|
#endif
|
||||||
for (int32_t x = 0; x < gWidth[gNum]; x++)
|
|
||||||
{
|
{
|
||||||
#ifdef FONT_FS_AVAILABLE
|
memcpy_I(pbuffer, gPtr, cm->gWidth);
|
||||||
if (fs_font) {
|
gPtr += cm->gWidth;
|
||||||
pixel = pbuffer[x];
|
}
|
||||||
}
|
|
||||||
else
|
for (int32_t x = 0; x < cm->gWidth; x++)
|
||||||
#endif
|
{
|
||||||
pixel = pgm_read_byte(gPtr + gBitmap[gNum] + x + gWidth[gNum] * y);
|
pixel = pbuffer[x];
|
||||||
|
|
||||||
if (pixel)
|
if (pixel)
|
||||||
{
|
{
|
||||||
|
|
@ -2490,14 +2507,14 @@ void TFT_eSprite::drawGlyph(uint16_t code)
|
||||||
if (dl) { drawFastHLine( xs, y + cgy, dl, fg); dl = 0; }
|
if (dl) { drawFastHLine( xs, y + cgy, dl, fg); dl = 0; }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pbuffer) free(pbuffer);
|
//if (pbuffer) free(pbuffer);
|
||||||
|
|
||||||
if (newSprite)
|
if (newSprite)
|
||||||
{
|
{
|
||||||
pushSprite(cgx, cursor_y);
|
pushSprite(cgx, cursor_y);
|
||||||
deleteSprite();
|
deleteSprite();
|
||||||
}
|
}
|
||||||
cursor_x += gxAdvance[gNum];
|
cursor_x += cm->gxAdvance;
|
||||||
}
|
}
|
||||||
else
|
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);
|
uint16_t unicode = decodeUTF8((uint8_t*)cbuffer, &n, len - n);
|
||||||
if (getUnicodeIndex(unicode, &index))
|
if (getUnicodeIndex(unicode, &index))
|
||||||
{
|
{
|
||||||
if (n == 0) sWidth -= gdX[index];
|
CharMetrics * cm = getCharMetrics(index);
|
||||||
if (n == len-1) sWidth += ( gWidth[index] + gdX[index]);
|
if (n == 0) sWidth -= cm->gdX;
|
||||||
else sWidth += gxAdvance[index];
|
if (n == len-1) sWidth += ( cm->gWidth + cm->gdX);
|
||||||
|
else sWidth += cm->gxAdvance;
|
||||||
}
|
}
|
||||||
else sWidth += gFont.spaceWidth + 1;
|
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)
|
int16_t TFT_eSprite::printToSprite(int16_t x, int16_t y, uint16_t index)
|
||||||
{
|
{
|
||||||
bool newSprite = !_created;
|
bool newSprite = !_created;
|
||||||
int16_t sWidth = gWidth[index];
|
CharMetrics * cm = getCharMetrics(index);
|
||||||
|
int16_t sWidth = cm->gWidth;
|
||||||
|
|
||||||
if (newSprite)
|
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);
|
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();
|
deleteSprite();
|
||||||
}
|
}
|
||||||
|
|
||||||
else drawGlyph(gUnicode[index]);
|
else drawGlyph(cm->gUnicode);
|
||||||
|
|
||||||
return gxAdvance[index];
|
return cm->gxAdvance;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ class TFT_eSprite : public TFT_eSPI {
|
||||||
// - 1 nibble per pixel for 4 bit colour
|
// - 1 nibble per pixel for 4 bit colour
|
||||||
// - 1 byte per pixel for 8 bit colour
|
// - 1 byte per pixel for 8 bit colour
|
||||||
// - 2 bytes per pixel for 16 bit color depth
|
// - 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
|
// Returns a pointer to the sprite or nullptr if not created, user must cast to pointer type
|
||||||
void* getPointer(void);
|
void* getPointer(void);
|
||||||
|
|
@ -28,7 +28,7 @@ class TFT_eSprite : public TFT_eSPI {
|
||||||
bool created(void);
|
bool created(void);
|
||||||
|
|
||||||
// Delete the sprite to free up the RAM
|
// 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)
|
// Select the frame buffer for graphics write (for 2 colour ePaper and DMA toggle buffer)
|
||||||
// Returns a pointer to the Sprite frame buffer
|
// Returns a pointer to the Sprite frame buffer
|
||||||
|
|
|
||||||
|
|
@ -2777,9 +2777,10 @@ int16_t TFT_eSPI::textWidth(const char *string, uint8_t font)
|
||||||
uint16_t gNum = 0;
|
uint16_t gNum = 0;
|
||||||
bool found = getUnicodeIndex(uniCode, &gNum);
|
bool found = getUnicodeIndex(uniCode, &gNum);
|
||||||
if (found) {
|
if (found) {
|
||||||
if(str_width == 0 && gdX[gNum] < 0) str_width -= gdX[gNum];
|
CharMetrics * cm = getCharMetrics(gNum);
|
||||||
if (*string || isDigits) str_width += gxAdvance[gNum];
|
if(str_width == 0 && cm->gdX < 0) str_width -= cm->gdX;
|
||||||
else str_width += (gdX[gNum] + gWidth[gNum]);
|
if (*string || isDigits) str_width += cm->gxAdvance;
|
||||||
|
else str_width += (cm->gdX + cm->gWidth);
|
||||||
}
|
}
|
||||||
else str_width += gFont.spaceWidth + 1;
|
else str_width += gFont.spaceWidth + 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
Loading…
Reference in New Issue