LVGL7.0高级界面开发-3

该博客介绍了如何在LVGL图形库中优化PNG和GIF的显示性能。通过修改源码,实现了提前解码PNG图片并在内存中存储,避免了运行时的解码延迟。此外,还分享了如何添加LV_GIF支持,并提供了一个创建动态背景的示例。最后,博主分享了一个包含LVGL改进的VS2019工程的下载链接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

vs2019开发,还是有点不方便,图片还要编码,然后显示,着实不方便,下一步搞搞freetype也可以显示。

1、添加LV_PNG

官网上的lv_png拉取,但需要做些修改,静态画面显示没问题,但是让图标动起来,那就“出问题”,显示太慢了。分析源码,可以看出是直接读取文件在解码。

看源码lodepng.c line:418左右。

#ifdef LODEPNG_COMPILE_DISK//从硬盘读取文件并解码
/* returns negative value on error. This should be pure C compatible, so no fstat. */
static long lodepng_filesize(const char* filename)
{
#if LV_PNG_USE_LV_FILESYSTEM
    lv_fs_file_t f;
    lv_fs_res_t res = lv_fs_open(&f, filename, LV_FS_MODE_RD);
    if(res != LV_FS_RES_OK) return -1;
    uint32_t size = 0;
    lv_fs_size(&f, &size);
    lv_fs_close(&f);
    return size;
#else
    if (!strcmp(&filename[strlen(filename) - 3], "png")) 
    {
        long size;
        FILE* file;
        file = fopen(filename, "rb");
        if (!file) return -1;

        if (fseek(file, 0, SEEK_END) != 0)
        {
            fclose(file);
            return -1;
        }

        size = ftell(file);
        /* It may give LONG_MAX as directory size, this is invalid for us. */
        if (size == LONG_MAX) size = -1;

        fclose(file);
        return size;
    }
#endif
}

/* load file into buffer that already has the correct allocated size. Returns error code.*/
static unsigned lodepng_buffer_file(unsigned char* out, size_t size, const char* filename)
{
#if LV_PNG_USE_LV_FILESYSTEM
    lv_fs_file_t f;
    lv_fs_res_t res = lv_fs_open(&f, filename, LV_FS_MODE_RD);
    if(res != LV_FS_RES_OK) return 78;

    uint32_t br;
    res = lv_fs_read(&f, out, size, &br);
    if(res != LV_FS_RES_OK) return 78;
    if (br != size) return 78;
    lv_fs_close(&f);
    return 0;
#else
    if (!strcmp(&filename[strlen(filename) - 3], "png"))
    {
        FILE* file;
        size_t readsize;
        file = fopen(filename, "rb");
        if (!file) return 78;

        readsize = fread(out, 1, size, file);
        fclose(file);
        int tuyp = size;
        if (readsize != size) return 78;
        return 0;
    }
  return 0;
#endif
}

unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename)
{
  long size = lodepng_filesize(filename);
  if (size < 0) return 78;
  *outsize = (size_t)size;

  *out = (unsigned char*)lodepng_malloc((size_t)size);
  if(!(*out) && size > 0) return 83; /*the above malloc failed*/

  return lodepng_buffer_file(*out, (size_t)size, filename);
}

#endif /*LODEPNG_COMPILE_DISK*/

 

问:那有没有办法可以提前解码,后显示呢!

答:可以!

 

在lodepng.h中 line:71 添加  #define LODEPNG_NO_COMPILE_DISK ,我们不需要这段代码。

修改lv_png.c,需要大改,有需要的可以备份一个原版。

修改如下:

/**********************
 *      TYPEDEFS
 **********************/
PNG_Decode_Struct  PNG_DS[PNG_MAX_NUM];

static lv_res_t decoder_info(struct _lv_img_decoder * decoder, const void * src, lv_img_header_t * header)
{
    (void) decoder; /*Unused*/
     lv_img_src_t src_type = lv_img_src_get_type(src);          /*Get the source type*/

     /*If it's a PNG file...*/
     if(src_type == LV_IMG_SRC_FILE)
     {
         const char * fn = src;
         if (atoi(fn) < PNG_MAX_NUM)//20210324修改 by ly
         {
             header->always_zero = 0;
             header->cf = LV_IMG_CF_RAW_ALPHA;
             /*The width and height are stored in Big endian format so convert them to little endian*/
             header->w = PNG_DS[atoi(fn)].Width;//直接赋值,不需要运算
             header->h = PNG_DS[atoi(fn)].Height;
             return LV_RES_OK;
         }
         else
         {
             printf("Exceed the maximum: %d",PNG_MAX_NUM);
             return LV_RES_INV;
         }
     }
     return LV_RES_INV;         /*If didn't succeeded earlier then it's an error*/
}

static lv_res_t decoder_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
{
    (void) decoder; /*Unused*/

    /*If it's a PNG file...*/
    if(dsc->src_type == LV_IMG_SRC_FILE) {
        const char * fn = dsc->src;

        if (atoi(fn) < PNG_MAX_NUM) {    //20210324 修改 by ly
            dsc->img_data = PNG_DS[atoi(fn)].img_data;
            dsc->user_data = 0;
            return LV_RES_OK;     /*The image is fully decoded. Return with its pointer*/
        }
    }
    return LV_RES_INV;    /*If not returned earlier then it failed*/
}

static void decoder_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
{
    (void) decoder; /*Unused*/
//    if(dsc->img_data) free((uint8_t *)dsc->img_data);//不在这里释放图片
}

修改OK!

添加自定义解码程序

/**
 * 解析PNG文件
 */
void load_png_file(const char* filename, uint32_t index)
{
    FILE* file;
    uint32_t error;                 /*For the return values of PNG decoder functions*/
    uint8_t* buf_data = NULL;
    /*Decode the PNG image*/
    uint32_t png_width;             /*Will be the width of the decoded image*/
    uint32_t png_height;            /*Will be the width of the decoded image*/
    size_t png_size;                //图片大小
    uint32_t W_H[2];

    file = fopen(filename, "rb");//打开文件
    if (!file)
    {
        fclose(file);
        return -1;
    }
    if (fseek(file, 16, SEEK_SET) != 0)//文件开头偏移16字节
    {
        fclose(file);
        return -1;
    }
    size_t rn = fread(W_H, 1, 8, file);//获取高度、宽度
    if (rn != 8)
    {
        fclose(file);
        return -1;
    }

    PNG_DS[index].Width = (lv_coord_t)((W_H[0] & 0xff000000) >> 24) + ((W_H[0] & 0x00ff0000) >> 8);//获得宽度
    PNG_DS[index].Height = (lv_coord_t)((W_H[1] & 0xff000000) >> 24) + ((W_H[1] & 0x00ff0000) >> 8);//获得高度

    png_size = ftell(file);//获得文件大小

    if (fseek(file, 0, SEEK_END) != 0)//文件偏移至结尾
    {
        fclose(file);
        return -1;
    }
    png_size = ftell(file);//获得文件大小
    buf_data = malloc(png_size);//分配空间
    if (buf_data == NULL)
    {
        fclose(file);
        return -1;
    }
    if (fseek(file, 0, SEEK_SET) != 0)//文件偏移至开头
    {
        fclose(file);
        return -1;
    }

    size_t len = fread(buf_data, 1, png_size, file);//读取整个图片

    /* Decode the loaded image in ARGB8888 */
    error = lodepng_decode32(&PNG_DS[index].img_data, &png_width, &png_height, buf_data, png_size);
    free(buf_data);
    if (error) {
        printf("error %u: %s\n", error, lodepng_error_text(error));
        return LV_RES_INV;
    }
    convert_color_depth(PNG_DS[index].img_data, png_width * png_height);

    fclose(file);
}
lv_png.h

#define PNG_MAX_NUM		  50//PNG图片最大同时载入数量

//PNG解码格式
typedef struct {
	uint8_t* img_data;//图形数据
	uint32_t Width;//图片的宽度
	uint32_t Height;//图片的高度
}PNG_Decode_Struct;

extern PNG_Decode_Struct  PNG_DS[PNG_MAX_NUM];

使用方法: 

example.c

……
load_png_file("F:\\03-lv_png\\0.png",0);
load_png_file("F:\\03-lv_png\\1.png", 1);
lv_png_init();

lv_obj_t* imgbtn2 = lv_imgbtn_create(parent, NULL);//创建图片按键
lv_imgbtn_set_src(imgbtn2, LV_BTN_STATE_PRESSED, "0");//按下
lv_imgbtn_set_src(imgbtn2, LV_BTN_STATE_RELEASED, "0");//抬起
lv_obj_align(imgbtn2, NULL, LV_ALIGN_IN_TOP_LEFT, 150, 25);//左上角对齐

2、添加LV_GIF

直接拉取lvgl在github的代码,添加即可,有些地方要改,时间长了忘了,好像是文件函数。也可以直接用我提供的代码。

 

3、让背景动起来?

背景么,静态的、动态的,静态的资源多,动态的难找哦,一些动态壁纸还要会员,要么就是不能下载,但还是有方法的,只是怕侵权,学习的话还是可以的。有需要的话私聊。

现在直接用gif作为背景图,一个字,酷。

 

static void action_task_cb(lv_task_t* t)
{
    lv_obj_t* img = t->user_data;
    lv_gif_restart(img);
}

//菜单页
void Home_Page_Create(void)
{
    /*Create a Tab view object*/
    lv_obj_t* tabview;

    lv_obj_t* bg_img = lv_gif_create_from_file(lv_scr_act(), "F:\\03-lv_png\\back.gif");
    lv_task_create(action_task_cb, 9000, LV_TASK_PRIO_HIGH, bg_img);
    
    lv_style_init(&env_set.page_style);//初始化风格
    lv_style_set_bg_opa(&env_set.page_style, LV_STATE_DEFAULT, LV_OPA_TRANSP);//设置背景为透明

    tabview = lv_tabview_create(lv_scr_act(), NULL);//创建一个tabview
    lv_obj_set_size(tabview, LV_HOR_RES_MAX, LV_VER_RES_MAX);//设置大小
    lv_obj_align(tabview, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0);//对齐
    lv_tabview_set_btns_pos(tabview, LV_TABVIEW_TAB_POS_NONE);//不显示btns
    lv_obj_add_style(tabview, LV_PAGE_PART_BG, &env_set.page_style);//添加风格

    lv_obj_t* tab1 = lv_tabview_add_tab(tabview, "Tab 1");//创建第一页
    lv_obj_t* tab2 = lv_tabview_add_tab(tabview, "Tab 2");//创建第二页
    notice_board(tabview);//创建通知栏
    First_Page_Create(tab1);//第一页
    Second_Page_Create(tab2);//第二页
}

改好的VS2019工程,注意文件名不要有中文,有需要的自己下载:

链接:https://pan.baidu.com/s/12Kv1XdKe18FWf-F4DHYWlQ 
提取码:wdnm 
 

 

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值