feat(color): Compress font data with LZ4 (#4366)

This commit is contained in:
philmoz
2023-12-09 13:04:29 +10:00
committed by GitHub
parent b4f5ed5720
commit ecd50cf5e0
45 changed files with 98766 additions and 273255 deletions
+165 -27
View File
@@ -19,47 +19,185 @@
* GNU General Public License for more details.
*/
#include "libopenui_defines.h"
#include <stdio.h>
#include <stdlib.h>
#include "font.h"
#include "libopenui/thirdparty/lz4/lz4.h"
#include "libopenui_defines.h"
#include "lz4_fonts.h"
#if !defined(BOOT)
#define FONT_TABLE(name) \
extern const etxLz4Font lv_font_##name##_bold_16; \
extern const etxLz4Font lv_font_##name##_9; \
extern const etxLz4Font lv_font_##name##_13; \
extern const etxLz4Font lv_font_##name##_24; \
extern const etxLz4Font lv_font_##name##_bold_32; \
extern const etxLz4Font lv_font_##name##_bold_64; \
static const etxLz4Font* lz4FontTable[FONTS_COUNT] = { \
nullptr, /* FONT_STD_INDEX */ \
&lv_font_##name##_bold_16, /* FONT_BOLD_INDEX */ \
&lv_font_##name##_9, /* FONT_XXS_INDEX */ \
&lv_font_##name##_13, /* FONT_XS_INDEX */ \
&lv_font_##name##_24, /* FONT_L_INDEX */ \
&lv_font_##name##_bold_32, /* FONT_XL_INDEX */ \
&lv_font_##name##_bold_64, /* FONT_XXL_INDEX */ \
}; \
static const lv_font_t* lvglFontTable[FONTS_COUNT] = { \
LV_FONT_DEFAULT, /* FONT_STD_INDEX */ \
&lv_font_ ## name ## _bold_16, /* FONT_BOLD_INDEX */ \
&lv_font_ ## name ## _9, /* FONT_XXS_INDEX */ \
&lv_font_ ## name ## _13, /* FONT_XS_INDEX */ \
&lv_font_ ## name ## _24, /* FONT_L_INDEX */ \
&lv_font_ ## name ## _bold_32, /* FONT_XL_INDEX */ \
&lv_font_ ## name ## _bold_64, /* FONT_XXL_INDEX */ \
LV_FONT_DEFAULT, /* FONT_STD_INDEX */ \
nullptr, /* FONT_BOLD_INDEX */ \
nullptr, /* FONT_XXS_INDEX */ \
nullptr, /* FONT_XS_INDEX */ \
nullptr, /* FONT_L_INDEX */ \
nullptr, /* FONT_XL_INDEX */ \
nullptr, /* FONT_XXL_INDEX */ \
}
#if defined(TRANSLATIONS_CN)
FONT_TABLE(noto_cn);
FONT_TABLE(noto_cn);
#elif defined(TRANSLATIONS_TW)
FONT_TABLE(noto_tw);
FONT_TABLE(noto_tw);
#elif defined(TRANSLATIONS_JP)
FONT_TABLE(noto_jp);
FONT_TABLE(noto_jp);
#elif defined(TRANSLATIONS_HE)
FONT_TABLE(arimo_he);
FONT_TABLE(arimo_he);
#elif defined(TRANSLATIONS_RU)
FONT_TABLE(arimo_ru);
FONT_TABLE(arimo_ru);
#else
FONT_TABLE(roboto);
FONT_TABLE(roboto);
#endif
#endif // BOOT
/*
Decompress an LZ4 font and build LVGL font structures.
*/
void decompressFont(int idx)
{
// Check if already decompressed
if (lvglFontTable[idx]) return;
// used to set the line height to the line heights used in Edgetx < 2.7 and OpenTX
static const int8_t FontHeightCorrection[FONTS_COUNT] {
-2, // STD
-2, // BOLD
-2, // XXS
-2, // XS
-3, // L
-5, // XL
-2, // XXL
const etxLz4Font* etxFont = lz4FontTable[idx];
// Calculate size of memory block to allocate for uncompressed data plus LVGL
// font structures.
int size = etxFont->uncomp_size + sizeof(lv_font_t) +
sizeof(lv_font_fmt_txt_dsc_t) +
sizeof(lv_font_fmt_txt_glyph_cache_t) +
etxFont->cmap_num * sizeof(lv_font_fmt_txt_cmap_t);
if (etxFont->kern_classes) size += sizeof(lv_font_fmt_txt_kern_classes_t);
uint8_t* data = (uint8_t*)malloc(size);
if (data) {
memset(data, 0, size);
// Pointer to next free area in data block
uint8_t* next = data;
// 'Create' lv_font_t structure
lv_font_t* lvglFont = (lv_font_t*)next;
next += sizeof(lv_font_t);
// 'Create' lv_font_fmt_txt_dsc_t structure
lv_font_fmt_txt_dsc_t* lvglFontDsc = (lv_font_fmt_txt_dsc_t*)next;
next += sizeof(lv_font_fmt_txt_dsc_t);
// 'Create' lv_font_fmt_txt_glyph_cache_t structure
lv_font_fmt_txt_glyph_cache_t* lvglCache =
(lv_font_fmt_txt_glyph_cache_t*)next;
next += sizeof(lv_font_fmt_txt_glyph_cache_t);
// 'Create' lv_font_fmt_txt_kern_classes_t structure (optional)
lv_font_fmt_txt_kern_classes_t* lvglKernClasses = nullptr;
if (etxFont->kern_classes) {
lvglKernClasses = (lv_font_fmt_txt_kern_classes_t*)next;
next += sizeof(lv_font_fmt_txt_kern_classes_t);
}
// 'Create' lv_font_fmt_txt_cmap_t structure array
lv_font_fmt_txt_cmap_t* lvglCmaps = (lv_font_fmt_txt_cmap_t*)next;
next += sizeof(lv_font_fmt_txt_cmap_t) * etxFont->cmap_num;
// Decompress the compressed data into the remaining space
// 'next' is now the start of the uncompressed data
LZ4_decompress_safe((const char*)etxFont->compressed, (char*)next,
etxFont->comp_size, etxFont->uncomp_size);
// Rebuild the lv_font_t structure
// Relocate pointers
lvglFont->get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt;
lvglFont->get_glyph_bitmap = lv_font_get_bitmap_fmt_txt;
lvglFont->dsc = lvglFontDsc;
// Fill in other properties
lvglFont->line_height = etxFont->line_height;
lvglFont->base_line = etxFont->base_line;
lvglFont->subpx = etxFont->subpx;
lvglFont->underline_position = etxFont->underline_position;
lvglFont->underline_thickness = etxFont->underline_thickness;
// Rebuild the lv_font_fmt_txt_dsc_t structure
// Relocate pointers
lvglFontDsc->glyph_bitmap = &next[etxFont->glyph_bitmap];
lvglFontDsc->glyph_dsc = (lv_font_fmt_txt_glyph_dsc_t*)&next[0];
lvglFontDsc->cmaps = lvglCmaps;
lvglFontDsc->kern_dsc = lvglKernClasses;
lvglFontDsc->kern_classes = etxFont->kern_classes;
lvglFontDsc->bitmap_format = etxFont->bitmap_format;
lvglFontDsc->cache = lvglCache;
// Fill in other properties
lvglFontDsc->kern_scale = etxFont->kern_scale;
lvglFontDsc->cmap_num = etxFont->cmap_num;
lvglFontDsc->bpp = etxFont->bpp;
// Rebuild the lv_font_fmt_txt_kern_classes_t structure
if (etxFont->kern_classes) {
// Relocate pointers
lvglKernClasses->class_pair_values =
(int8_t*)&next[etxFont->class_pair_values];
lvglKernClasses->left_class_mapping = &next[etxFont->left_class_mapping];
lvglKernClasses->right_class_mapping =
&next[etxFont->right_class_mapping];
// Fill in other properties
lvglKernClasses->left_class_cnt = etxFont->left_class_cnt;
lvglKernClasses->right_class_cnt = etxFont->right_class_cnt;
}
// Rebuild the lv_font_t lv_font_fmt_txt_cmap_t structure array
for (int i = 0; i < etxFont->cmap_num; i += 1) {
// Relocate pointers
if (etxFont->cmaps[i].unicode_list)
lvglCmaps[i].unicode_list =
(uint16_t*)&next[etxFont->cmaps[i].unicode_list];
if (etxFont->cmaps[i].glyph_id_ofs_list)
lvglCmaps[i].glyph_id_ofs_list =
&next[etxFont->cmaps[i].glyph_id_ofs_list];
// Fill in other properties
lvglCmaps[i].range_start = etxFont->cmaps[i].range_start;
lvglCmaps[i].range_length = etxFont->cmaps[i].range_length;
lvglCmaps[i].glyph_id_start = etxFont->cmaps[i].glyph_id_start;
lvglCmaps[i].list_length = etxFont->cmaps[i].list_length;
lvglCmaps[i].type = etxFont->cmaps[i].type;
}
// Save LVGL font to lookup array
lvglFontTable[idx] = lvglFont;
} else {
TRACE("No memory to decompress font %d", idx);
lvglFontTable[idx] = lvglFontTable[0];
}
}
#endif // BOOT
// used to set the line height to the line heights used in Edgetx < 2.7 and
// OpenTX
static const int8_t FontHeightCorrection[FONTS_COUNT] = {
-2, // ST
-2, // BOLD
-2, // XXS
-2, // XS
-3, // L
-5, // XL
-2, // XXL
};
const lv_font_t* getFont(LcdFlags flags)
@@ -69,6 +207,7 @@ const lv_font_t* getFont(LcdFlags flags)
#else
auto fontIndex = FONT_INDEX(flags);
if (fontIndex >= FONTS_COUNT) return LV_FONT_DEFAULT;
decompressFont(fontIndex);
return lvglFontTable[fontIndex];
#endif
}
@@ -81,11 +220,10 @@ uint8_t getFontHeight(LcdFlags flags)
uint8_t getFontHeightCondensed(LcdFlags flags)
{
auto font = getFont(flags);
return lv_font_get_line_height(font) + FontHeightCorrection[FONT_INDEX(flags)];
return getFontHeight(flags) + FontHeightCorrection[FONT_INDEX(flags)];
}
int getTextWidth(const char * s, int len, LcdFlags flags)
int getTextWidth(const char* s, int len, LcdFlags flags)
{
auto font = getFont(flags);
lv_coord_t letter_space = 0;
+80
View File
@@ -0,0 +1,80 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#pragma once
#include <stdint.h>
/*
Structures for handling LZ4 compressed versions of LVGL fonts
Compressed data is uncompressed at runtime and these strucutres
then used to rebuild the LVGL font structures.
Note: this is dependant on the LVGL font structure formats. If
the LVGL version changes, re-check the LVGL font structures.
*/
typedef struct {
// Properties used to reconstitute the LVGL 'cmaps' array
uint16_t range_start; // lv_font_fmt_txt_cmap_t.range_start
uint16_t range_length; // lv_font_fmt_txt_cmap_t.range_length
uint16_t glyph_id_start; // lv_font_fmt_txt_cmap_t.glyph_id_start
uint16_t list_length; // lv_font_fmt_txt_cmap_t.list_length
uint16_t type; // lv_font_fmt_txt_cmap_t.type
// Offsets into uncompressed data to relocate pointers at runtime
uint32_t unicode_list; // lv_font_fmt_txt_cmap_t.unicode_list
uint32_t glyph_id_ofs_list; // lv_font_fmt_txt_cmap_t.glyph_id_ofs_list
} etxFontCmap;
typedef struct {
uint32_t uncomp_size; // Uncompressed data size
uint32_t comp_size; // Compressed data size
// Properties used to reconstitute the various LVGL font structures
uint8_t line_height; // lv_font_t.line_height
uint8_t base_line; // lv_font_t.base_line
uint8_t subpx; // lv_font_t.subpx
int8_t underline_position; // lv_font_t.underline_position
int8_t underline_thickness; // lv_font_t.underline_thickness
uint8_t kern_scale; // lv_font_fmt_txt_dsc_t.kern_scale
uint8_t cmap_num; // lv_font_fmt_txt_dsc_t.cmap_num
uint8_t bpp; // lv_font_fmt_txt_dsc_t.bpp
uint8_t kern_classes; // lv_font_fmt_txt_dsc_t.kern_classes
uint8_t bitmap_format; // lv_font_fmt_txt_dsc_t.bitmap_format
uint8_t left_class_cnt; // lv_font_fmt_txt_kern_classes_t.left_class_cnt
uint8_t right_class_cnt; // lv_font_fmt_txt_kern_classes_t.right_class_cnt
// Offsets into uncompressed data to relocate pointers at runtime
// Note: lv_font_fmt_txt_dsc_t.glyph_dsc is always at the start of the uncompressed data
uint32_t glyph_bitmap; // lv_font_fmt_txt_dsc_t.glyph_bitmap
uint32_t class_pair_values; // lv_font_fmt_txt_kern_classes_t.class_pair_values
uint32_t left_class_mapping; // lv_font_fmt_txt_kern_classes_t.left_class_mapping
uint32_t right_class_mapping; // lv_font_fmt_txt_kern_classes_t.right_class_mapping
// Pointers to cmaps and compressed data
const etxFontCmap* cmaps;
const uint8_t* compressed;
} etxLz4Font;