feat(color): Compress font data with LZ4 (#4366)
This commit is contained in:
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
+3134
-9759
File diff suppressed because it is too large
Load Diff
+6782
-16492
File diff suppressed because it is too large
Load Diff
+1983
-6758
File diff suppressed because it is too large
Load Diff
+4426
-11374
File diff suppressed because it is too large
Load Diff
+10015
-24887
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+2321
-8941
File diff suppressed because it is too large
Load Diff
+4660
-12969
File diff suppressed because it is too large
Load Diff
+1502
-6766
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+6741
-18385
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+3350
-10158
File diff suppressed because it is too large
Load Diff
+7393
-17701
File diff suppressed because it is too large
Load Diff
+2084
-7007
File diff suppressed because it is too large
Load Diff
+4703
-11986
File diff suppressed because it is too large
Load Diff
+10956
-26797
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
+1379
-4662
File diff suppressed because it is too large
Load Diff
+581
-2758
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
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user