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
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+251
View File
@@ -0,0 +1,251 @@
/*
* 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.
*/
/*
Tool to convert an LVGL font (in 'lvgl' format) to an LZ4 compressed format
that can be uncompressed and reconstituted at runtime.
The font to be compressed must be in the file 'lv_font.inc'.
Usage:
Create the lv_font.inc file using the lv_font_conv program
Compile this program with GCC
Run this program with the font name as the first argument
Designed to be used by the make_fonts.sh tool, not run standalone.
Overview:
The font to be compressed is read from the structures in the lv_font.inc file.
Including and compiling with this files saves the effort of writing a parser
for the 'lvgl' font data.
Data that can be compressed is collected into a byte array and then LZ4 compressed.
The remaining data, and offsets needed to rebuild the LVGL font structures are
collected into custom structures (see lz4_fonts.h).
Everything is then written back out to the argv[1].c file to be compiled into
the EdgeTx firmware.
Note:
This is dependant on the LVGL font structure formats. If the LVGL version is
changed re-check that the font structure are still compatible.
*/
#include <stdio.h>
#include <stdlib.h>
#include "../../lv_conf.h"
#define LV_CONF_SKIP 1
#include "lv_font.inc"
#include "lz4/lz4hc.h"
#include "../../gui/colorlcd/lz4_fonts.h"
// Need this to allow lvgl to compile.
bool lv_font_get_glyph_dsc_fmt_txt(const lv_font_t* font,
lv_font_glyph_dsc_t* dsc_out,
uint32_t unicode_letter,
uint32_t unicode_letter_next)
{
return true;
}
// Need this to allow lvgl to compile.
const uint8_t * lv_font_get_bitmap_fmt_txt(const lv_font_t * font, uint32_t letter)
{
return nullptr;
}
int main(int argc, char* argv[])
{
int uncomp_size = 0;
int comp_size = 0;
// Pointers to base LVGL font strucures
const lv_font_t* font = &lv_font;
lv_font_fmt_txt_dsc_t* dsc = (lv_font_fmt_txt_dsc_t*)font->dsc;
// Calculate size of data to compress
uncomp_size = sizeof(glyph_bitmap) + sizeof(glyph_dsc);
if (dsc->kern_classes) {
uncomp_size += sizeof(kern_class_values) + sizeof(kern_left_class_mapping) + sizeof(kern_right_class_mapping);
}
for (int i = 0; i < dsc->cmap_num; i += 1) {
if (dsc->cmaps[i].unicode_list)
uncomp_size += dsc->cmaps[i].list_length * sizeof(uint16_t);
if (dsc->cmaps[i].glyph_id_ofs_list)
uncomp_size += dsc->cmaps[i].list_length * sizeof(uint8_t);
}
// Create custom strucutre to hold font data
etxLz4Font etx_font;
memset(&etx_font, 0, sizeof(etxLz4Font));
// Copy font propeties
etx_font.line_height = font->line_height;
etx_font.base_line = font->base_line;
etx_font.subpx = font->subpx;
etx_font.underline_position = font->underline_position;
etx_font.underline_thickness = font->underline_thickness;
etx_font.kern_scale = dsc->kern_scale;
etx_font.cmap_num = dsc->cmap_num;
etx_font.bpp = dsc->bpp;
etx_font.kern_classes = dsc->kern_classes;
etx_font.bitmap_format = dsc->bitmap_format;
if (dsc->kern_classes) {
etx_font.left_class_cnt = kern_classes.left_class_cnt;
etx_font.right_class_cnt = kern_classes.right_class_cnt;
}
// Create custom cmap structure array
etxFontCmap* etx_cmaps = nullptr;
if (dsc->cmap_num > 0) {
etx_cmaps = (etxFontCmap*)malloc(dsc->cmap_num * sizeof(etxFontCmap));
memset(etx_cmaps, 0, dsc->cmap_num * sizeof(etxFontCmap));
// Copy properties
for (int i = 0; i < dsc->cmap_num; i += 1) {
etx_cmaps[i].range_start = dsc->cmaps[i].range_start;
etx_cmaps[i].range_length = dsc->cmaps[i].range_length;
etx_cmaps[i].glyph_id_start = dsc->cmaps[i].glyph_id_start;
etx_cmaps[i].list_length = dsc->cmaps[i].list_length;
etx_cmaps[i].type = dsc->cmaps[i].type;
}
}
// Allocate data blob
uint8_t* data = (uint8_t*)malloc(uncomp_size);
// Pointer to next available space in data blob
uint8_t* next = data;
memset(data, 0, uncomp_size);
// Copy compressable data and save offsets to each section
// glyph_dsc is always first at offset 0 - no offset needed
memcpy(next, glyph_dsc, sizeof(glyph_dsc));
next += sizeof(glyph_dsc);
// Copy cmaps array
for (int i = 0; i < dsc->cmap_num; i += 1) {
if (dsc->cmaps[i].unicode_list) {
memcpy(next, dsc->cmaps[i].unicode_list, dsc->cmaps[i].list_length * sizeof(uint16_t));
etx_cmaps[i].unicode_list = next - data;
next += dsc->cmaps[i].list_length * sizeof(uint16_t);
}
if (dsc->cmaps[i].glyph_id_ofs_list) {
memcpy(next, dsc->cmaps[i].glyph_id_ofs_list, dsc->cmaps[i].list_length * sizeof(uint8_t));
etx_cmaps[i].glyph_id_ofs_list = next - data;
next += dsc->cmaps[i].list_length * sizeof(uint8_t);
}
}
// Copy glyph_bitmap
memcpy(next, glyph_bitmap, sizeof(glyph_bitmap));
etx_font.glyph_bitmap = next - data;
next += sizeof(glyph_bitmap);
// Copy kern_classes (optional)
if (dsc->kern_classes) {
memcpy(next, kern_class_values, sizeof(kern_class_values));
etx_font.class_pair_values = next - data;
next += sizeof(kern_class_values);
memcpy(next, kern_left_class_mapping, sizeof(kern_left_class_mapping));
etx_font.left_class_mapping = next - data;
next += sizeof(kern_left_class_mapping);
memcpy(next, kern_right_class_mapping, sizeof(kern_right_class_mapping));
etx_font.right_class_mapping = next - data;
next += sizeof(kern_right_class_mapping);
}
// Allocate array and LZ4 compress data
uint8_t* lz4_data = (uint8_t*)malloc(uncomp_size);
comp_size = LZ4_compress_HC((const char*)data, (char*)lz4_data, uncomp_size, uncomp_size, 12);
// Write data to file
int i;
char filename[100];
snprintf(filename, 100,"%s.c",argv[1]);
FILE* fp = fopen(filename,"w");
fprintf(fp, "#include \"lz4_fonts.h\"\n\n");
// Compressed data
fprintf(fp, "static const uint8_t lz4FontData[] ={\n");
for (i = 0; i < comp_size; i += 1) {
fprintf(fp,"0x%02x,",lz4_data[i]);
if ((i & 0x0F) == 0x0F)
fprintf(fp, "\n");
}
if ((i & 0x0F) != 0)
fprintf(fp, "\n");
fprintf(fp, "};\n\n");
// Cmaps
if (dsc->cmap_num > 0) {
fprintf(fp, "static const etxFontCmap cmaps[] = {\n");
for (int i = 0; i < dsc->cmap_num; i += 1) {
fprintf(fp,"{ .range_start = %d, .range_length = %d, .glyph_id_start = %d, .list_length = %d, .type = %d, .unicode_list = %d, .glyph_id_ofs_list = %d },\n",
etx_cmaps[i].range_start, etx_cmaps[i].range_length, etx_cmaps[i].glyph_id_start, etx_cmaps[i].list_length,
etx_cmaps[i].type, etx_cmaps[i].unicode_list, etx_cmaps[i].glyph_id_ofs_list
);
}
fprintf(fp, "};\n\n");
}
// Custom font structure
fprintf(fp,"const etxLz4Font %s = {\n", argv[1]);
fprintf(fp,".uncomp_size = %d,\n",uncomp_size);
fprintf(fp,".comp_size = %d,\n",comp_size);
fprintf(fp,".line_height = %d,\n",etx_font.line_height);
fprintf(fp,".base_line = %d,\n",etx_font.base_line);
fprintf(fp,".subpx = %d,\n",etx_font.subpx);
fprintf(fp,".underline_position = %d,\n",etx_font.underline_position);
fprintf(fp,".underline_thickness = %d,\n",etx_font.underline_thickness);
fprintf(fp,".kern_scale = %d,\n",etx_font.kern_scale);
fprintf(fp,".cmap_num = %d,\n",etx_font.cmap_num);
fprintf(fp,".bpp = %d,\n",etx_font.bpp);
fprintf(fp,".kern_classes = %d,\n",etx_font.kern_classes);
fprintf(fp,".bitmap_format = %d,\n",etx_font.bitmap_format);
fprintf(fp,".left_class_cnt = %d,\n",etx_font.left_class_cnt);
fprintf(fp,".right_class_cnt = %d,\n",etx_font.right_class_cnt);
fprintf(fp,".glyph_bitmap = %d,\n",etx_font.glyph_bitmap);
fprintf(fp,".class_pair_values = %d,\n",etx_font.class_pair_values);
fprintf(fp,".left_class_mapping = %d,\n",etx_font.left_class_mapping);
fprintf(fp,".right_class_mapping = %d,\n",etx_font.right_class_mapping);
fprintf(fp,".cmaps = cmaps,\n");
fprintf(fp,".compressed = lz4FontData,\n");
fprintf(fp, "};\n");
fclose(fp);
printf("%s %d %d %d%%\n",argv[1],uncomp_size,comp_size,(comp_size * 100) / uncomp_size);
}
+33 -5
View File
@@ -43,6 +43,29 @@ function make_font() {
--format lvgl -o lv_font_${name}_${size}.c --force-fast-kern-format ${arg}
}
function compress_font() {
local name=$1
gcc -I ../../thirdparty/libopenui/thirdparty lz4_font.cpp ../../thirdparty/libopenui/thirdparty/lz4/lz4hc.c ../../thirdparty/libopenui/thirdparty/lz4/lz4.c -o lz4_font
./lz4_font ${name}
}
function make_font_lz4() {
local name=$1
local ttf=$2
local size=$3
local chars=$4
local arg=$5
lv_font_conv --no-prefilter --bpp 4 --size ${size} \
--font ${TTF_DIR}${ttf} -r ${ASCII},${DEGREE},${BULLET},${COMPARE}${chars} \
--font EdgeTX/extra.ttf -r ${EXTRA_SYM} \
--font ${ARROWS_FONT} -r ${ARROWS} \
--font ${SYMBOLS_FONT} -r ${SYMBOLS} \
--format lvgl -o lv_font.inc --force-fast-kern-format ${arg}
compress_font lv_font_${name}_${size}
}
function make_font_w_extra_sym() {
local name=$1
local ttf=$2
@@ -53,7 +76,8 @@ function make_font_w_extra_sym() {
lv_font_conv --no-prefilter --bpp 4 --size ${size} \
--font ${TTF_DIR}${ttf} -r ${ASCII},${DEGREE}${chars} \
--font EdgeTX/extra.ttf -r ${EXTRA_SYM} \
--format lvgl -o lv_font_${name}_${size}.c --force-fast-kern-format ${arg}
--format lvgl -o lv_font.inc --force-fast-kern-format ${arg}
compress_font lv_font_${name}_${size}
}
function make_font_no_sym() {
@@ -65,7 +89,8 @@ function make_font_no_sym() {
lv_font_conv --no-prefilter --bpp 4 --size ${size} \
--font ${TTF_DIR}${ttf} -r ${ASCII},${DEGREE}${chars} \
--format lvgl -o lv_font_${name}_${size}.c --force-fast-kern-format ${arg}
--format lvgl -o lv_font.inc --force-fast-kern-format ${arg}
compress_font lv_font_${name}_${size}
}
# LV_SYMBOL_CHARGE, LV_SYMBOL_NEW_LINE, LV_SYMBOL_SD_CARD, LV_SYMBOL_CLOSE
@@ -88,10 +113,10 @@ function make_font_set() {
local ttf_bold=$3
local chars=$4
make_font "${name}" "${ttf_normal}" 9 ${chars} --no-compress
make_font "${name}" "${ttf_normal}" 13 ${chars} --no-compress
make_font_lz4 "${name}" "${ttf_normal}" 9 ${chars} --no-compress
make_font_lz4 "${name}" "${ttf_normal}" 13 ${chars} --no-compress
make_font "${name}" "${ttf_normal}" 16 ${chars} --no-compress
make_font "${name}_bold" "${ttf_bold}" 16 ${chars}
make_font_lz4 "${name}_bold" "${ttf_bold}" 16 ${chars}
make_font_w_extra_sym "${name}" "${ttf_normal}" 24 ${chars}
make_font_no_sym "${name}_bold" "${ttf_bold}" 32 ${chars}
make_font_no_sym "${name}_bold" "${ttf_bold}" 64
@@ -109,3 +134,6 @@ make_font_set "noto_cn" "Noto/NotoSansCJKsc-Regular.otf" "Noto/NotoSansCJKsc-Bol
make_font_set "noto_jp" "Noto/NotoSansCJKsc-Regular.otf" "Noto/NotoSansCJKsc-Bold.otf" ",${JP_SYMBOLS}"
make_font_set "arimo_he" "Arimo/Arimo-Regular.ttf" "Arimo/Arimo-Bold.ttf" ",${HE_SYMBOLS}"
make_font_set "arimo_ru" "Arimo/Arimo-Regular.ttf" "Arimo/Arimo-Bold.ttf" ",${RU_SYMBOLS}"
rm lv_font.inc
rm lz4_font