Skip to content

Commit

Permalink
feat(color): Compress font data with LZ4 (#4366)
Browse files Browse the repository at this point in the history
  • Loading branch information
philmoz authored Dec 9, 2023
1 parent b4f5ed5 commit ecd50cf
Show file tree
Hide file tree
Showing 45 changed files with 98,768 additions and 273,257 deletions.
2,665 changes: 588 additions & 2,077 deletions radio/src/fonts/lvgl/lv_font_arimo_he_13.c

Large diffs are not rendered by default.

2,679 changes: 696 additions & 1,983 deletions radio/src/fonts/lvgl/lv_font_arimo_he_24.c

Large diffs are not rendered by default.

1,909 changes: 388 additions & 1,521 deletions radio/src/fonts/lvgl/lv_font_arimo_he_9.c

Large diffs are not rendered by default.

3,000 changes: 752 additions & 2,248 deletions radio/src/fonts/lvgl/lv_font_arimo_he_bold_16.c

Large diffs are not rendered by default.

3,222 changes: 848 additions & 2,374 deletions radio/src/fonts/lvgl/lv_font_arimo_he_bold_32.c

Large diffs are not rendered by default.

5,661 changes: 1,455 additions & 4,206 deletions radio/src/fonts/lvgl/lv_font_arimo_he_bold_64.c

Large diffs are not rendered by default.

3,555 changes: 700 additions & 2,855 deletions radio/src/fonts/lvgl/lv_font_arimo_ru_13.c

Large diffs are not rendered by default.

3,969 changes: 899 additions & 3,070 deletions radio/src/fonts/lvgl/lv_font_arimo_ru_24.c

Large diffs are not rendered by default.

2,691 changes: 484 additions & 2,207 deletions radio/src/fonts/lvgl/lv_font_arimo_ru_9.c

Large diffs are not rendered by default.

4,023 changes: 904 additions & 3,119 deletions radio/src/fonts/lvgl/lv_font_arimo_ru_bold_16.c

Large diffs are not rendered by default.

4,826 changes: 1,094 additions & 3,732 deletions radio/src/fonts/lvgl/lv_font_arimo_ru_bold_32.c

Large diffs are not rendered by default.

5,661 changes: 1,455 additions & 4,206 deletions radio/src/fonts/lvgl/lv_font_arimo_ru_bold_64.c

Large diffs are not rendered by default.

12,893 changes: 3,134 additions & 9,759 deletions radio/src/fonts/lvgl/lv_font_noto_cn_13.c

Large diffs are not rendered by default.

23,274 changes: 6,782 additions & 16,492 deletions radio/src/fonts/lvgl/lv_font_noto_cn_24.c

Large diffs are not rendered by default.

8,741 changes: 1,983 additions & 6,758 deletions radio/src/fonts/lvgl/lv_font_noto_cn_9.c

Large diffs are not rendered by default.

15,800 changes: 4,426 additions & 11,374 deletions radio/src/fonts/lvgl/lv_font_noto_cn_bold_16.c

Large diffs are not rendered by default.

34,902 changes: 10,015 additions & 24,887 deletions radio/src/fonts/lvgl/lv_font_noto_cn_bold_32.c

Large diffs are not rendered by default.

6,212 changes: 1,583 additions & 4,629 deletions radio/src/fonts/lvgl/lv_font_noto_cn_bold_64.c

Large diffs are not rendered by default.

11,262 changes: 2,321 additions & 8,941 deletions radio/src/fonts/lvgl/lv_font_noto_jp_13.c

Large diffs are not rendered by default.

17,629 changes: 4,660 additions & 12,969 deletions radio/src/fonts/lvgl/lv_font_noto_jp_24.c

Large diffs are not rendered by default.

8,268 changes: 1,502 additions & 6,766 deletions radio/src/fonts/lvgl/lv_font_noto_jp_9.c

Large diffs are not rendered by default.

13,106 changes: 3,190 additions & 9,916 deletions radio/src/fonts/lvgl/lv_font_noto_jp_bold_16.c

Large diffs are not rendered by default.

25,126 changes: 6,741 additions & 18,385 deletions radio/src/fonts/lvgl/lv_font_noto_jp_bold_32.c

Large diffs are not rendered by default.

6,212 changes: 1,583 additions & 4,629 deletions radio/src/fonts/lvgl/lv_font_noto_jp_bold_64.c

Large diffs are not rendered by default.

13,508 changes: 3,350 additions & 10,158 deletions radio/src/fonts/lvgl/lv_font_noto_tw_13.c

Large diffs are not rendered by default.

25,094 changes: 7,393 additions & 17,701 deletions radio/src/fonts/lvgl/lv_font_noto_tw_24.c

Large diffs are not rendered by default.

9,091 changes: 2,084 additions & 7,007 deletions radio/src/fonts/lvgl/lv_font_noto_tw_9.c

Large diffs are not rendered by default.

16,689 changes: 4,703 additions & 11,986 deletions radio/src/fonts/lvgl/lv_font_noto_tw_bold_16.c

Large diffs are not rendered by default.

37,753 changes: 10,956 additions & 26,797 deletions radio/src/fonts/lvgl/lv_font_noto_tw_bold_32.c

Large diffs are not rendered by default.

6,212 changes: 1,583 additions & 4,629 deletions radio/src/fonts/lvgl/lv_font_noto_tw_bold_64.c

Large diffs are not rendered by default.

4,503 changes: 834 additions & 3,669 deletions radio/src/fonts/lvgl/lv_font_roboto_13.c

Large diffs are not rendered by default.

6,041 changes: 1,379 additions & 4,662 deletions radio/src/fonts/lvgl/lv_font_roboto_24.c

Large diffs are not rendered by default.

3,339 changes: 581 additions & 2,758 deletions radio/src/fonts/lvgl/lv_font_roboto_9.c

Large diffs are not rendered by default.

5,359 changes: 1,213 additions & 4,146 deletions radio/src/fonts/lvgl/lv_font_roboto_bold_16.c

Large diffs are not rendered by default.

7,855 changes: 1,786 additions & 6,069 deletions radio/src/fonts/lvgl/lv_font_roboto_bold_32.c

Large diffs are not rendered by default.

5,624 changes: 1,437 additions & 4,187 deletions radio/src/fonts/lvgl/lv_font_roboto_bold_64.c

Large diffs are not rendered by default.

251 changes: 251 additions & 0 deletions radio/src/fonts/lvgl/lz4_font.cpp
Original file line number Diff line number Diff line change
@@ -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);
}
38 changes: 33 additions & 5 deletions radio/src/fonts/lvgl/make_fonts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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() {
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Loading

0 comments on commit ecd50cf

Please sign in to comment.