里飞网

 找回密码
 立即注册
查看: 42|回复: 1
打印 上一主题 下一主题

使用LVGL v9.5+LvglFontTool V0.5测试版本支持中文

[复制链接]

1

主题

2

帖子

21

积分

新手上路

Rank: 1

积分
21
跳转到指定楼层
楼主
发表于 7 天前 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
以下是使用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;
}

回复

使用道具 举报

1

主题

2

帖子

21

积分

新手上路

Rank: 1

积分
21
沙发
 楼主| 发表于 7 天前 | 只看该作者
/************************************************字数限制补充**********************************************************/
#if LVGL_VERSION_MAJOR >= 8
static const lv_font_fmt_txt_dsc_t font_dsc = {
#else
static lv_font_fmt_txt_dsc_t font_dsc = {
#endif
    .glyph_bitmap = NULL,
    .glyph_dsc = NULL,
    .cmaps = NULL,
    .kern_dsc = NULL,
    .kern_scale = 16,
    .cmap_num = 2,
    .bpp = 4,
    .kern_classes = 1,
    .bitmap_format = LV_FONT_FMT_TXT_PLAIN,
#if LVGL_VERSION_MAJOR == 8
    .cache = &cache
#endif
};

//新宋体,常规,16
//字模高度:0
//XBF字体,外部bin文件
const lv_font_t songti_16 = {
    .get_glyph_bitmap = UserFontGetBitmap,
    .get_glyph_dsc = UserFontGetGlyphDsc,
    .line_height = 20,
    .base_line = -2,
#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0)
    .subpx = LV_FONT_SUBPX_NONE,
#endif
#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8
    .underline_position = -2,
    .underline_thickness = 1,
#endif
    .dsc = &font_dsc,          /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */
#if LV_VERSION_CHECK(8, 2, 0) || LVGL_VERSION_MAJOR >= 9
    .fallback = NULL,
#endif
    .user_data = NULL,
};
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|里飞网  

GMT+8, 2026-5-14 02:44 , Processed in 0.072490 second(s), 5 queries , File On.

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc. Template By 【未来科技】【 www.wekei.cn 】

快速回复 返回顶部 返回列表