一种减少flash占用的图片压缩显示方法

项目场景:

公司要开发一款小家电,由于要使用到显示屏且模式切换要使用到比较大的图片,考虑到设备芯片flash内存不算很大,只有128k,还要存储app信息和代码,想到一种简单的压缩图片处理方法 (此方法适用于单色图片,即只有 背景色 和 图案色 ), 步骤如下:
1、将图片通过 Img2Lcd.exe 转换成C语言数组格式,并使用简易压缩算法压缩成小的数组;
2、存到创建的 lcd.h ,在代码里面使用解压缩算法进行切片展开显示;


具体步骤

1、使用 Img2Lcd.exe 将图片转成C语言数组保存 (由于我使用的LCD显示屏支持的RGB565格式,使用jpg压缩显示边缘会有白边,这里先使用 windows 自带的画图软件打开图片并另存为16位色图):

  1. windows画图打开图片存为16位色图:

画图工具在这里插入图片描述

  1. Img2Lcd.exe 软件打开图片进行保存,具体步骤可以看资源链接里的教程
    在这里插入图片描述

2、将保存的数组使用简易压缩算法进行压缩(此算法只能对数组为16的整数倍的图片进行正常处理,这里只是提供一种思路,朋友们可以自行优化):

这里我们要先知道像素的保存方式,RGB565格式存储的是16位,也就是2个字节,算法里面,我默认将图片背景当作黑色 0x0000,图案为白色 0xFFFF,将图案部分存为 bit 1,将背景颜色存为 bit 0,相当于将图片压缩成原来数组的 16分之1


void compress(unsigned char * src, unsigned char *dst, unsigned int len)
{
    unsigned int i = 0, j = 0;
    unsigned int num = 0;

    printf("const unsigned char pic[%d]= {\n",len/2/8);
    for(i = 0; i < len/2/8; i++)
    {
        for(j = 0; j < 8; j++)
        {
            num = src[0] <<8 + src[1];

            if(num > 0) //图案
                dst[i] |= (1<<j);

            src+=2;
        }
        printf("0x%02x, ", dst[i]);
        if ((i + 1) % 16 == 0) 
            printf("\n");
    }
    printf("},");
}
const unsigned char gImage_1[4800] = {图片数组内容}void main(void)
{
    unsigned char pic[300] = {0}; //压缩存储内容

    compress(gImage_1, pic, 4800);
}

3、将压缩的数组存放到工程代码的 lcd.h,并使用解压函数进行解压显示,以下为图片解压显示接口函数

/******************************************************************************
      函数说明:显示图片
      入口数据:x,y起点坐标
                length 图片长度
                width  图片宽度
                pic[]  图片数组    
      返回值:  无
******************************************************************************/
void LCD_ShowPicture(u16 x,u16 y,u16 length,u16 width,const u8 pic[])
{
    //LCD显示图片
}

//将每个像素点压缩成 1 bit 的压缩图片从新解压为 RGB 565 双色图
void LCD_Pic_UnCompress(const u8 *src, u8 *dst, u16 srclen, u16 baColor, u16 foColor)
{
    int i = 0, j = 0;

    for(i = 0; i < srclen; i++)
    {
        for(j = 0; j < 8; j++)
        {
            if(src[i]&(1<<j))
            {
                dst[0] = foColor >> 8;
                dst[1] = foColor & 0xff;
            }
            else
            {
                dst[0] = baColor >> 8;
                dst[1] = baColor & 0xff;
            }
            dst+=2;
        }
    }
}

//将压缩大图切割成小图显示
//图片最好为16的整数倍
void LCD_Pic_DivideShow(const u8 *src, u8 *dst, u16 x, u16 y, u16 len, u16 wide, u16 divide, u16 baColor, u16 foColor)
{
    unsigned int i = 0;
    unsigned int n = wide/divide;
    unsigned int offset = len*wide/8/divide; //压缩图的大小为 len*wide*2/16

    for(i = 0; i < divide; i++)
    {
        LCD_Pic_UnCompress(src+i*offset, dst, offset, baColor, foColor);
        LCD_ShowPicture(x, y+i*n, len, n, dst);
    }
}

4、接口使用例子,这里我使用已经测试过的代码进行举例说明,图片切片显示的时候,每一片解压转存大小不能超过用来缓存的buffer大小,这里是 SmallPic[5000] ,也就是需要展开的图数组不能超过5000字节


unsigned char SmallPic[5000] = {0}; //图片显示缓存区

//图大小为160*160, C51格式为160*160*2=51200字节,压缩为51200/16 = 3200
const unsigned char StartBigPic[3200] = {图片数组缓存}

//模式小图为40*30,C51格式为40*30*2=2400字节,压缩为2400/16 = 150
const unsigned char AutoPic[150]= {图片数组缓存}

//大图分割显示
void LCD_Write_Start(void)
{
    const unsigned char *ptr = StartBigPic;

    //图片大小为160*160,C51格式为51200字节,切割成16份3200字节
    //存储是按顺序存储,所以按照宽度换行,即160/16=10,一份10的宽
    //小图压缩是3200份,分成16份为200
    LCD_Pic_DivideShow(ptr, SmallPic, 40, 40, 160, 160, 16, BackGround_Color, ForeGround_Color);
}

//小图直接显示
void LCD_Write_Mode(const unsigned char mode)
{
    const unsigned char *ptr = AutoPic;
    
    //图片大小为40*30
    LCD_Pic_UnCompress(ptr, SmallPic, 150, BackGround_Color, ForeGround_Color);
    LCD_ShowPicture(180,190,40,30,SmallPic);
}

注意事项: 本方法目前只能针对转成C51数组之后能被16整除的单色图片,朋友们可以自行展开思路进行不同图片压缩处理(●’◡’●)

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值