|
|
以下是使用LvglFontTool V0.5测试版本 生成bin文件字库,并存储到外部存储中,用于对接LVGL层的接口demo
使用了缓冲优化显示速度
缓冲区数量 CACHE_MAX_NUM 和 CACHE_BMP_SIZE 位图缓冲区大小可根据平台资源更改
函数 GetFontCacheFromStore 从存储介质读取字体信息
其中 SYSTEM\\user_font_16.bin 为测试使用字库 可自行更改路径 或更改读取接口适配不同的存储介质
lv_font_fmt_txt_dsc_t 和 lv_font_t 变量内容根据自己取模设定修改
当字体偏高或偏低 可通过修改 base_line 来上下微调字体位置
不过修改过的可能会导致字体被剪裁之显示一部分字体
可尝试另一种方式
适当增大 line_height 也可实现上下微调的效果
参考:LVGL9.1使用lvglFontToolV0.5 bin文件字库_51CTO博客_lvgl字库格式
/***********************************************分割线*****************************************************/
#include "lvgl.h"
#include "ff.h"
#include <stdio.h>
#include <string.h>
#define CACHE_MAX_NUM 10
#define CACHE_BMP_SIZE 512
typedef struct{
uint16_t min;
uint16_t max;
uint8_t bpp;
uint8_t reserved[3];
}x_header_t;
typedef struct{
uint32_t pos;
}x_table_t;
typedef struct{
uint8_t adv_w;
uint8_t box_w;
uint8_t box_h;
int8_t ofs_x;
int8_t ofs_y;
uint8_t r;
}glyph_dsc_t;
static x_header_t __g_xbf_hd = {
.min = 0x0020,
.max = 0x9fa0,
.bpp = 4,
};
FIL f_songti;
typedef struct
{
uint32_t unicode; //unicode编码
uint32_t unicode_addr; //编码指向地址
uint32_t bmp_addr; //位图地址
glyph_dsc_t dsc; //位图描述
uint8_t bmp[CACHE_BMP_SIZE]; //位图数据
uint32_t bmp_size; //位图大小
uint32_t active; //cache活跃程度
}TypeFontCache;
static TypeFontCache FontCache[CACHE_MAX_NUM];
//找最废物的缓冲
TypeFontCache *FindFontLazyCache(void)
{
uint32_t LazyLevel = 0xFFFFFFFF;
uint8_t LazyID = 0;
for(uint8_t i=0;i<CACHE_MAX_NUM;i++){
if(FontCache.active<LazyLevel){
LazyID = i;
LazyLevel = FontCache.active;
}
}
return &FontCache[LazyID];
}
//在cache中找字体信息
TypeFontCache *FindFontInfoInCache(uint32_t unicode)
{
for(uint8_t i=0;i<CACHE_MAX_NUM;i++){
if(FontCache.unicode == unicode){
return &FontCache;
}
}
return NULL;
}
//从存储中获取字体信息
uint8_t GetFontCacheFromStore(TypeFontCache *Cache,uint32_t unicode)
{
UINT read_num = 0;
if(Cache==NULL)
{return 0xFF;}
if(f_songti.obj.fs==NULL)
{FRESULT Res = f_open(&f_songti,"SYSTEM\\user_font_16.bin",FA_READ);}
if(f_songti.obj.fs!=NULL){
Cache->unicode = unicode;
Cache->unicode_addr = sizeof(x_header_t) + (unicode - __g_xbf_hd.min) * 4;
f_lseek(&f_songti, Cache->unicode_addr); // 将文件指针定位到文件末尾
f_read(&f_songti, (uint8_t *)&Cache->bmp_addr,4,&read_num);
if(Cache->bmp_addr){
f_lseek(&f_songti, Cache->bmp_addr);
f_read(&f_songti,(uint8_t *)&Cache->dsc,sizeof(glyph_dsc_t),&read_num);
Cache->bmp_size = Cache->dsc.box_w*Cache->dsc.box_h*__g_xbf_hd.bpp / 8;
f_read(&f_songti,Cache->bmp,Cache->bmp_size,&read_num);
}
else{return 2;}
}
else
{return 1;}
return 0;
}
TypeFontCache *UserFontGetInfo(uint32_t unicode)
{
TypeFontCache *Cache = NULL;
Cache = FindFontInfoInCache(unicode);
if(Cache==NULL){//没找到
Cache = FindFontLazyCache();//找最不积极的废物
if(Cache!=NULL){
if(GetFontCacheFromStore(Cache,unicode)==0)
{Cache->active = 1;}
}
}
else{
if(Cache->active<0xFFFFFFFE)
{Cache->active++;}
}
return Cache;
}
static const uint8_t opa4_table[16] = { 0, 17, 34, 51,
68, 85, 102, 119,
136, 153, 170, 187,
204, 221, 238, 255
};
static const uint8_t opa2_table[4] = { 0, 85, 170, 255 };
static const void * UserFontGetBitmap(lv_font_glyph_dsc_t *dsc, lv_draw_buf_t *draw_buf)
{
uint32_t unicode_letter = dsc->gid.index;
uint8_t * bitmap_out = draw_buf->data;
const lv_font_t *font = dsc->resolved_font;
lv_font_fmt_txt_dsc_t * fdsc = (lv_font_fmt_txt_dsc_t *)font->dsc;
TypeFontCache *FontInfo = NULL;
if (unicode_letter > __g_xbf_hd.max || unicode_letter < __g_xbf_hd.min)
{return NULL;}
FontInfo = UserFontGetInfo(unicode_letter);
if(FontInfo==NULL){return NULL;}
if ( FontInfo->bmp_addr != 0 && FontInfo->unicode == unicode_letter ) {
glyph_dsc_t * gdsc = &FontInfo->dsc;
int32_t gsize = (int32_t)gdsc->box_w * gdsc->box_h;
if (gsize == 0) return NULL;
if (fdsc->bitmap_format == LV_FONT_FMT_TXT_PLAIN) {
const uint8_t * bitmap_in = FontInfo->bmp;
uint8_t * bitmap_out_tmp = bitmap_out;
int32_t i = 0;
int32_t x, y;
uint32_t stride = lv_draw_buf_width_to_stride(gdsc->box_w, LV_COLOR_FORMAT_A8);
if (fdsc->bpp == 1) {
for (y = 0; y < gdsc->box_h; y++) {
for (x = 0; x < gdsc->box_w; x++, i++) {
i = i & 0x7;
if (i == 0) bitmap_out_tmp[x] = (*bitmap_in) & 0x80 ? 0xff : 0x00;
else if (i == 1) bitmap_out_tmp[x] = (*bitmap_in) & 0x40 ? 0xff : 0x00;
else if (i == 2) bitmap_out_tmp[x] = (*bitmap_in) & 0x20 ? 0xff : 0x00;
else if (i == 3) bitmap_out_tmp[x] = (*bitmap_in) & 0x10 ? 0xff : 0x00;
else if (i == 4) bitmap_out_tmp[x] = (*bitmap_in) & 0x08 ? 0xff : 0x00;
else if (i == 5) bitmap_out_tmp[x] = (*bitmap_in) & 0x04 ? 0xff : 0x00;
else if (i == 6) bitmap_out_tmp[x] = (*bitmap_in) & 0x02 ? 0xff : 0x00;
else if (i == 7) {
bitmap_out_tmp[x] = (*bitmap_in) & 0x01 ? 0xff : 0x00;
bitmap_in++;
}
}
bitmap_out_tmp += stride;
}
}
else if (fdsc->bpp == 2) {
for (y = 0; y < gdsc->box_h; y++) {
for (x = 0; x < gdsc->box_w; x++, i++) {
i = i & 0x3;
if (i == 0) bitmap_out_tmp[x] = opa2_table[(*bitmap_in) >> 6];
else if (i == 1) bitmap_out_tmp[x] = opa2_table[((*bitmap_in) >> 4) & 0x3];
else if (i == 2) bitmap_out_tmp[x] = opa2_table[((*bitmap_in) >> 2) & 0x3];
else if (i == 3) {
bitmap_out_tmp[x] = opa2_table[((*bitmap_in) >> 0) & 0x3];
bitmap_in++;
}
}
bitmap_out_tmp += stride;
}
}
else if (fdsc->bpp == 4) {
for (y = 0; y < gdsc->box_h; y++) {
for (x = 0; x < gdsc->box_w; x++, i++) {
i = i & 0x1;
if (i == 0) {
bitmap_out_tmp[x] = opa4_table[(*bitmap_in) >> 4];
}
else if (i == 1) {
bitmap_out_tmp[x] = opa4_table[(*bitmap_in) & 0xF];
bitmap_in++;
}
}
bitmap_out_tmp += stride;
}
}
return draw_buf;
}
}
return NULL;
}
static bool UserFontGetGlyphDsc(const lv_font_t * font, lv_font_glyph_dsc_t * dsc_out, uint32_t unicode_letter, uint32_t unicode_letter_next) {
TypeFontCache *FontInfo = NULL;
if( unicode_letter>__g_xbf_hd.max || unicode_letter<__g_xbf_hd.min )
{return NULL;}
FontInfo = UserFontGetInfo(unicode_letter);
if(FontInfo==NULL){return NULL;}
if( FontInfo->bmp_addr != 0 && FontInfo->unicode == unicode_letter ) {
glyph_dsc_t * gdsc = &FontInfo->dsc;
dsc_out->adv_w = gdsc->adv_w;
dsc_out->box_h = gdsc->box_h;
dsc_out->box_w = gdsc->box_w;
dsc_out->ofs_x = gdsc->ofs_x;
dsc_out->ofs_y = gdsc->ofs_y;
dsc_out->format = (uint8_t)__g_xbf_hd.bpp;
dsc_out->gid.index = unicode_letter; //官方工具生成的字库赋的值就是uicode的id
dsc_out->is_placeholder = false;
return true;
}
return false;
}
|
|