From 5819a1fbb95f17dd442032a337d5981a1fecd014 Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Wed, 16 Sep 2026 04:38:08 +0200 Subject: [PATCH] Optimize big font storage with lossless packed encoding --- App/font.c | 152 ++++++++++++++++++++++++++++++++++++++++++++++++ App/font.h | 3 +- App/ui/helper.c | 5 +- 3 files changed, 156 insertions(+), 4 deletions(-) diff --git a/App/font.c b/App/font.c index d34cbd4c..e1a3194e 100644 --- a/App/font.c +++ b/App/font.c @@ -14,10 +14,14 @@ * limitations under the License. */ +#include + #include "font.h" // removed last and middle column which was all 0x00 // also the space char is not needed +// Uncompressed reference kept for byte-for-byte verification of the packed font. +#if 0 const uint8_t gFontBig[95 - 1][16 - 2] = { #if 0 @@ -214,6 +218,154 @@ const uint8_t gFontBig[95 - 1][16 - 2] = {0x08, 0x0C, 0x04, 0x0C, 0x08, 0x0C, 0x04, /*0x00,*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // '->' #endif }; +#endif + +// Each glyph contains fourteen bytes: seven columns for each display page. +// Common bytes use a four-bit page-specific dictionary index; 0xF escapes +// into the literal stream. The eighth byte of each row is its literal offset. +static const uint8_t gFontBigDictionary[2][15] = +{ + {0x00, 0xFC, 0x20, 0xE0, 0x04, 0x80, 0xC0, 0xF8, 0x44, 0x84, 0x40, 0x60, 0x30, 0x7C, 0x0C}, + {0x00, 0x0F, 0x08, 0x07, 0x0C, 0x03, 0x01, 0x06, 0x0E, 0x02, 0x09, 0x7F, 0x20, 0x48, 0x0B} +}; + +static const uint8_t gFontBigPacked[94][8] = +{ + {0x00, 0x10, 0x01, 0x00, 0x00, 0xFF, 0x00, 0x00}, + {0xF0, 0x0F, 0xF0, 0x0F, 0x00, 0x00, 0x00, 0x02}, + {0x72, 0x27, 0x77, 0x92, 0x11, 0x19, 0x91, 0x06}, + {0x7F, 0xFF, 0xFF, 0xFF, 0x24, 0xFF, 0x31, 0x06}, + {0xCC, 0x50, 0xB6, 0x4C, 0x57, 0x06, 0x44, 0x0F}, + {0xF5, 0xFD, 0xFF, 0x3A, 0x21, 0x32, 0x21, 0x0F}, + {0xF0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13}, + {0x00, 0x7F, 0x4E, 0x00, 0x50, 0x43, 0x02, 0x16}, + {0x00, 0xE4, 0xF7, 0x00, 0x20, 0x34, 0x05, 0x17}, + {0x50, 0x3F, 0x36, 0x0F, 0x90, 0x65, 0x95, 0x18}, + {0x50, 0x35, 0x53, 0x05, 0x00, 0x55, 0x00, 0x1A}, + {0x00, 0x00, 0x00, 0x00, 0xF0, 0x8F, 0x00, 0x1A}, + {0x55, 0x55, 0x55, 0x05, 0x00, 0x00, 0x00, 0x1C}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x1C}, + {0x00, 0x50, 0xB6, 0x4C, 0x57, 0x06, 0x00, 0x1C}, + {0x17, 0x44, 0x14, 0x37, 0x21, 0x22, 0x31, 0x1C}, + {0xF0, 0x1F, 0x01, 0x00, 0x22, 0x11, 0x22, 0x1C}, + {0xFF, 0x94, 0xDF, 0x4F, 0xE8, 0x2A, 0x22, 0x1E}, + {0xFF, 0x88, 0x18, 0x7F, 0x28, 0x22, 0x31, 0x22}, + {0x65, 0xCB, 0x1F, 0x61, 0x66, 0x66, 0x11, 0x25}, + {0xDD, 0x88, 0xF8, 0xF9, 0x24, 0x22, 0x31, 0x26}, + {0x7F, 0x8F, 0xF8, 0x35, 0x21, 0x22, 0x31, 0x28}, + {0x44, 0x94, 0xDF, 0x0F, 0x80, 0x61, 0x00, 0x2B}, + {0x1F, 0x88, 0x18, 0x3F, 0x21, 0x22, 0x31, 0x2D}, + {0x1F, 0x99, 0x19, 0x07, 0x22, 0x42, 0x53, 0x2F}, + {0x00, 0xC0, 0x0C, 0x00, 0x00, 0x77, 0x00, 0x30}, + {0x00, 0xC0, 0x0C, 0x00, 0x20, 0x78, 0x00, 0x30}, + {0x50, 0xB6, 0xFC, 0x0F, 0x60, 0x75, 0x24, 0x30}, + {0xAA, 0xAA, 0xAA, 0x9A, 0x99, 0x99, 0x99, 0x32}, + {0xF0, 0xCF, 0x6B, 0x05, 0x42, 0x57, 0x06, 0x32}, + {0xFF, 0x94, 0xDF, 0x0F, 0x00, 0xFF, 0x00, 0x34}, + {0x7F, 0xFF, 0x7F, 0x3F, 0x21, 0xEE, 0x6E, 0x3A}, + {0x17, 0x99, 0x19, 0x17, 0x01, 0x00, 0x11, 0x3F}, + {0x11, 0x88, 0x18, 0x1F, 0x21, 0x22, 0x31, 0x3F}, + {0x17, 0x44, 0xF4, 0x3F, 0x21, 0x22, 0x78, 0x40}, + {0x11, 0x44, 0x7E, 0x1F, 0x21, 0x42, 0x53, 0x42}, + {0x11, 0x88, 0x48, 0x14, 0x21, 0x22, 0x22, 0x43}, + {0x11, 0x88, 0x48, 0x14, 0x01, 0x00, 0x00, 0x43}, + {0x17, 0x94, 0xF9, 0x3F, 0x21, 0x22, 0x31, 0x43}, + {0x11, 0xAA, 0x1A, 0x11, 0x01, 0x00, 0x11, 0x45}, + {0x00, 0x14, 0x41, 0x00, 0x20, 0x11, 0x02, 0x45}, + {0x00, 0x40, 0x11, 0x74, 0x28, 0x12, 0x03, 0x45}, + {0x11, 0xC3, 0xEF, 0x14, 0x61, 0x75, 0x24, 0x45}, + {0x11, 0x00, 0x00, 0x10, 0x21, 0x22, 0x22, 0x46}, + {0x11, 0xFF, 0x1F, 0x11, 0x01, 0x00, 0x11, 0x46}, + {0x11, 0x6B, 0x15, 0x11, 0x01, 0x60, 0x11, 0x49}, + {0x17, 0x44, 0x14, 0x37, 0x21, 0x22, 0x31, 0x49}, + {0x11, 0x99, 0x19, 0x1F, 0x01, 0x00, 0x00, 0x49}, + {0x17, 0x44, 0x14, 0x37, 0x21, 0x44, 0xFF, 0x4A}, + {0x11, 0x99, 0x19, 0x1F, 0x61, 0x75, 0x24, 0x4C}, + {0xDF, 0x88, 0xF8, 0x7F, 0x28, 0x22, 0x31, 0x4D}, + {0x40, 0x14, 0x41, 0x04, 0x00, 0x11, 0x00, 0x50}, + {0x11, 0x00, 0x10, 0x31, 0x21, 0x22, 0x31, 0x50}, + {0x1D, 0x05, 0x15, 0x0D, 0x15, 0x14, 0x05, 0x50}, + {0x11, 0x50, 0x10, 0x11, 0x71, 0x75, 0x11, 0x50}, + {0xFE, 0x6F, 0xFF, 0x4E, 0x51, 0x50, 0x41, 0x50}, + {0xF0, 0x6D, 0xD6, 0x0F, 0x00, 0x11, 0x00, 0x54}, + {0x44, 0xF9, 0xFF, 0x8F, 0xA1, 0x22, 0x22, 0x56}, + {0x00, 0x11, 0x44, 0x00, 0x10, 0x21, 0x02, 0x5A}, + {0xFF, 0x63, 0x05, 0x00, 0x00, 0x56, 0x83, 0x5A}, + {0x00, 0x44, 0x11, 0x00, 0x20, 0x12, 0x01, 0x5C}, + {0xEF, 0xFF, 0xEF, 0x0F, 0x00, 0x00, 0x00, 0x5C}, + {0x00, 0x00, 0x00, 0xC0, 0xCC, 0xCC, 0xCC, 0x61}, + {0x00, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x00, 0x61}, + {0xF0, 0xFF, 0x3F, 0x36, 0x21, 0x22, 0x11, 0x63}, + {0x11, 0x22, 0x32, 0x16, 0x21, 0x22, 0x31, 0x67}, + {0x36, 0x22, 0xB2, 0x3A, 0x21, 0x22, 0xF4, 0x67}, + {0x36, 0x22, 0x12, 0x31, 0x21, 0x22, 0x11, 0x68}, + {0x36, 0x22, 0x32, 0x36, 0xA1, 0xAA, 0x6A, 0x68}, + {0x22, 0x17, 0xFF, 0x04, 0x10, 0x01, 0x00, 0x68}, + {0x36, 0x22, 0x32, 0x33, 0xDF, 0xDD, 0xFB, 0x6A}, + {0x11, 0x22, 0x32, 0x16, 0x01, 0x00, 0x11, 0x6C}, + {0x00, 0xF2, 0x0F, 0x00, 0x20, 0x11, 0x02, 0x6C}, + {0x00, 0x00, 0xF2, 0x0F, 0xFF, 0xFF, 0xFB, 0x6E}, + {0x11, 0x50, 0xB6, 0x12, 0x61, 0x75, 0x24, 0x75}, + {0x00, 0x14, 0x01, 0x00, 0x20, 0x11, 0x02, 0x75}, + {0x33, 0x32, 0x32, 0x16, 0x01, 0x01, 0x11, 0x75}, + {0x33, 0x22, 0x32, 0x16, 0x01, 0x00, 0x11, 0x75}, + {0x36, 0x22, 0x32, 0x36, 0x21, 0x22, 0x31, 0x75}, + {0x33, 0x22, 0x32, 0xB6, 0x2B, 0x22, 0x31, 0x75}, + {0x36, 0x22, 0x32, 0x33, 0x21, 0x22, 0xBB, 0x75}, + {0x33, 0x2B, 0x22, 0x12, 0x01, 0x00, 0x00, 0x75}, + {0x36, 0x22, 0x22, 0x22, 0xAA, 0xAA, 0x71, 0x75}, + {0x22, 0x11, 0x22, 0x00, 0x30, 0x21, 0x22, 0x75}, + {0x33, 0x00, 0x30, 0x33, 0x21, 0x22, 0x11, 0x75}, + {0x33, 0x00, 0x30, 0x03, 0x15, 0x14, 0x05, 0x75}, + {0x33, 0x50, 0x30, 0x33, 0x21, 0x21, 0x31, 0x75}, + {0x3B, 0x05, 0x35, 0x4B, 0x58, 0x56, 0x48, 0x75}, + {0x33, 0x00, 0x30, 0x33, 0xDF, 0xDD, 0xFB, 0x75}, + {0x22, 0xF2, 0xB3, 0x42, 0xE8, 0x2A, 0x22, 0x77}, + {0x00, 0x7A, 0x4F, 0x04, 0x00, 0x13, 0x22, 0x78}, + {0x00, 0xF0, 0x0F, 0x00, 0x00, 0x11, 0x00, 0x79}, + {0x40, 0xF4, 0xA7, 0x00, 0x22, 0x31, 0x00, 0x7B}, + {0xEF, 0xE4, 0xEF, 0x04, 0x00, 0x00, 0x00, 0x7C} +}; + +static const uint8_t gFontBigLiterals[126] = +{ + 0x0D, 0x0D, 0x0F, 0x1F, 0x1F, 0x0F, 0x70, 0x88, 0x8E, 0x8E, 0x98, 0x10, 0x04, 0x38, + 0x38, 0xD8, 0xE4, 0xBC, 0xD8, 0x10, 0x1F, 0x0F, 0xF0, 0xF0, 0xA0, 0xA0, 0x10, 0x1E, + 0x10, 0x18, 0x18, 0x1C, 0xC4, 0x38, 0x18, 0x1C, 0xB8, 0x18, 0xC4, 0x04, 0xF0, 0x4C, + 0xC4, 0xE4, 0x1C, 0xB8, 0xB8, 0x78, 0x18, 0x08, 0x08, 0x18, 0x38, 0x3C, 0xC4, 0x38, + 0x0D, 0x0D, 0xF0, 0x08, 0xC8, 0xC8, 0xF0, 0xB8, 0x1C, 0x18, 0xF0, 0x9C, 0x98, 0x18, + 0x18, 0x70, 0x18, 0x78, 0x1F, 0x17, 0x78, 0x38, 0xCC, 0x88, 0x3C, 0xF0, 0xF0, 0x3C, + 0x3C, 0x3C, 0xC4, 0x64, 0x3C, 0x1C, 0x38, 0x70, 0x08, 0x06, 0x03, 0x06, 0x08, 0x03, + 0x07, 0xA0, 0xA0, 0xA0, 0xA0, 0x04, 0x24, 0x24, 0x4F, 0x3F, 0xEC, 0xEC, 0xEC, 0xEC, + 0x30, 0x70, 0x40, 0x40, 0x3F, 0x4F, 0x3F, 0xA0, 0xBC, 0xBC, 0xBC, 0xBC, 0x08, 0x08 +}; + +static_assert(sizeof(gFontBigPacked) / sizeof(gFontBigPacked[0]) == 94u); +static_assert(sizeof(gFontBigPacked[0]) == 8u); +static_assert(sizeof(gFontBigLiterals) == 126u); + +void FONT_DrawBigGlyph(uint8_t glyph, uint8_t *top, uint8_t *bottom) +{ + // The caller maps validated ASCII '!'..'~' to glyph 0..93. Packed byte 7 + // is the literal offset; regenerated data must keep every 0xF escape within + // gFontBigLiterals. The table dimensions are checked above at compile time. + const uint8_t *encoded = gFontBigPacked[glyph]; + uint8_t literal = encoded[7]; + + for (uint8_t i = 0; i < 14; i++) + { + const uint8_t packed = encoded[i >> 1]; + const uint8_t code = (packed >> ((i & 1u) * 4u)) & 0x0Fu; + const uint8_t value = code == 0x0Fu + ? gFontBigLiterals[literal++] + : gFontBigDictionary[i >= 7u][code]; + + if (i < 7u) + top[i] = value; + else + bottom[i - 7u] = value; + } +} #if 0 // original font diff --git a/App/font.h b/App/font.h index 8972aabf..0e339a97 100644 --- a/App/font.h +++ b/App/font.h @@ -20,7 +20,7 @@ #include -extern const uint8_t gFontBig[95 - 1][16 - 2]; +void FONT_DrawBigGlyph(uint8_t glyph, uint8_t *top, uint8_t *bottom); extern const uint8_t gFontBigDigits[11][26 - 6]; extern const uint8_t gFont3x5[96][3]; extern const uint8_t gFontSmall[95 - 1][6]; @@ -29,4 +29,3 @@ extern const uint8_t gFontSmall[95 - 1][6]; #endif #endif - diff --git a/App/ui/helper.c b/App/ui/helper.c index ca4392b2..ef67f018 100644 --- a/App/ui/helper.c +++ b/App/ui/helper.c @@ -75,8 +75,9 @@ void UI_PrintString(const char *pString, uint8_t Start, uint8_t End, uint8_t Lin if (pString[i] > ' ' && pString[i] < 127) { const unsigned int index = pString[i] - ' ' - 1; - memcpy(gFrameBuffer[Line + 0] + ofs, &gFontBig[index][0], 7); - memcpy(gFrameBuffer[Line + 1] + ofs, &gFontBig[index][7], 7); + FONT_DrawBigGlyph(index, + gFrameBuffer[Line + 0] + ofs, + gFrameBuffer[Line + 1] + ofs); } } }