项目场景:
公司要开发一款小家电,由于要使用到显示屏且模式切换要使用到比较大的图片,考虑到设备芯片flash内存不算很大,只有128k,还要存储app信息和代码,想到一种简单的压缩图片处理方法 (此方法适用于单色图片,即只有 背景色 和 图案色 ), 步骤如下:
1、将图片通过 Img2Lcd.exe 转换成C语言数组格式,并使用简易压缩算法压缩成小的数组;
2、存到创建的 lcd.h ,在代码里面使用解压缩算法进行切片展开显示;
具体步骤
1、使用 Img2Lcd.exe 将图片转成C语言数组保存 (由于我使用的LCD显示屏支持的RGB565格式,使用jpg压缩显示边缘会有白边,这里先使用 windows 自带的画图软件打开图片并另存为16位色图):
- windows画图打开图片存为16位色图:
- 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);
}