BMP位图格式分析
BMP位图是微软公司(Microsoft)和国际商用机器公司(IBM)共同倡导的一种图像格式。它按点阵排列顺序, 将每个象素的色彩值以规定的方式把整个图像记录下来。BMP格式还可细分为两种类型, 即Microsoft Windows 型和IBMOS?2型, 两者的差别主要在于说明部分(文件头)。由于IBMOS2类型的BMP用得比较少, 所以在绝大多数情况下,BMP默认为Microsoft Windows 类型。根据色彩位深度不同,WindowsBMP文件象素描述部分差别较大, 如256色每个象素需要8位(即1个字节)来描述, 而16色的图像每个象素描述者只需4位(即半个字节)。对于绝大部分电子设计者来说, 黑白二色的点阵式液晶显示器价格适中、接口简单, 因而最为常用。因此, 这里仅分析Microsoft Windows 类型1位(Bit) 描述的二色BMP图像文件。
图像点阵的获取
从上述对二色BMP文件的分析, 我们发现BMP文件的象素描述段中点阵的存放格式跟液晶图像显示所需的格式很类似。因此, 我们不难想到液晶显示所需的图像点阵借助于计算机高级软件从BMP文件中读取。
目标图像的编辑与处理
目标图像通常并不是BMP格式, 原始尺寸跟液晶显示中所需的也相差很多。因此, 在从图像文件中读取点阵前必须对目标图像进行适当的编辑与处理。其步骤如下:
(1)通过图像处理软件编辑或调整目标图像尺寸,使得图像跟液晶显示的尺寸要求一致。常用的有Photoshop、CaptureProfessional 等软件。
(2)将图像转换为二色Windows格式的BMP文件。注意, 如果是彩色图像, 则在转换为黑白图像时需要调节黑白对比效果, 以适合黑白显示。本步骤笔者使用的是CaptureProfessional3. 0版本Operations菜单下的Convert to- >BlackandWhite, 转换时会弹出消息框, 调整其Threshold的值可以预览到其黑白对比效果。
(3)将图像上下翻转(以水平线为轴)。从上面的分析可知,BMP文件中图像象素的内容是由下而上、由左及右存储的。所以按照习惯的由上而下、由左及右的顺序往液晶的显示RAM写图像点阵, 必须将上述处理后的图像进行翻转, 并存储为最终的图像文件。本步骤用Photoshop和CaptureProfessional 都比较方便。
BMP文件中读取点阵的程序设计
在完成对目标图像编辑与处理后, 就可以从最终得到的黑白二色WindowsBMP文件中读出图像点阵了。
设图像水平方向及垂直方向尺寸(点阵数)分别为hor_size、ver_size,
(1) 所要扫描的总行数为ver_size。
(2) 判断每行是否结束的方法为: 当ho_size被8整除时, 则每行应读取的字节数Byte_num=hor_size/8;否则 Byte_num=取整(hor_size/8)+1。
(3) 一行扫描完后, 确定下一行指针位置的方法为: 如每行字节数能被4整除时, 则指针加1即可,否则指针应加上(4- 取余(Byte num?4)+1)。
图像在液晶中的显示
经过前面的处理, 点阵存放顺序跟我们习惯的方向已经一致。因此, 只要在初始化液晶后, 按顺序从点阵文件中读取点阵值, 再写往液晶相应的显示区, 就能完成整幅静态图像的显示。
参考程序:
- /**
- * 基于BMP的图像点阵获取原理及其应用
- * Lzy 2012-9-28
- */
- //14byte
- typedef struct
- {
- char cfType[2]; /* 文件类型, 必须为 "BM" (0x4D42)*/
- char cfSize[4]; /* 文件的大小(字节) */
- char cfReserved[4]; /* 保留, 必须为 0 */
- char cfoffBits[4]; /* 位图阵列相对于文件头的偏移量(字节)*/
- }__attribute__((packed)) BITMAPFILEHEADER; /* 文件头结构 */
- //40byte
- typedef struct
- {
- char ciSize[4]; /* size of BITMAPINFOHEADER */
- char ciWidth[4]; /* 位图宽度(像素) */
- char ciHeight[4]; /* 位图高度(像素) */
- char ciPlanes[2]; /* 目标设备的位平面数, 必须置为1 */
- char ciBitCount[2]; /* 每个像素的位数, 1,4,8或24 */
- char ciCompress[4]; /* 位图阵列的压缩方法,0=不压缩 */
- char ciSizeImage[4]; /* 图像大小(字节) */
- char ciXPelsPerMeter[4];/* 目标设备水平每米像素个数 */
- char ciYPelsPerMeter[4];/* 目标设备垂直每米像素个数 */
- char ciClrUsed[4]; /* 位图实际使用的颜色表的颜色数 */
- char ciClrImportant[4]; /* 重要颜色索引的个数 */
- }__attribute__((packed)) BITMAPINFOHEADER; /* 位图信息头结构 */
- BITMAPFILEHEADER FileHead;
- BITMAPINFOHEADER InfoHead;
- long chartolong(char * string, int length)
- {
- long number;
- if (length <= 4)
- {
- memset(&number, 0x00, sizeof(long));
- memcpy(&number, string, length);
- }
- return (number);
- }
- void DrawBMP(int iStartX, int iStartY, unsigned char ucType, uchar *pvBitmapSrc)
- {
- FILE *fp;
- int i, j, rc;
- int ciBitCount, ciWidth, ciHeight;
- char tmp[1024 * 100], *ptr;
- /* 打开位图文件 */
- fp = fopen(pvBitmapSrc, "rb");
- if (fp == NULL)
- {
- return;
- }
- /* 读取位图文件头 */
- rc = fread(&FileHead, sizeof(BITMAPFILEHEADER), 1, fp);
- if (rc != 1)
- {
- // printf("read header error!\n");
- fclose(fp);
- return;
- }
- /* 判断位图的类型 */
- if (memcmp(FileHead.cfType, "BM", 2) != 0)
- {
- // printf("it's not a BMP file\n");
- fclose(fp);
- return;
- }
- /* 读取位图信息头 */
- rc = fread((char *) &InfoHead, sizeof(BITMAPINFOHEADER), 1, fp);
- if (rc != 1)
- {
- // printf("read infoheader error!\n");
- fclose(fp);
- return;
- }
- ciWidth = (int) chartolong(InfoHead.ciWidth, 4); // 宽度
- ciHeight = (int) chartolong(InfoHead.ciHeight, 4); // 高度
- ciBitCount = (int) chartolong(InfoHead.ciBitCount, 4);
- fseek(fp, (int) chartolong(FileHead.cfoffBits, 4), SEEK_SET);
-
- if(ciWidth % 8 == 0)
- Byte_num = ciWidth / 8; // 每行应读取的字节数
- else
- Byte_num = ciWidth / 8 + 1;
- fread(tmp, Byte_num, ciHeight, fp); // 读出所有数据至数组中
-
- if(ciWidth % 4 == 0) //确定下一行指针偏移的方法
- dotlen = 1;
- else
- dotlen = 4 - Byte_num % 4 + 1;
-
- ptr = tmp;
- for(j=0; j<ciHeight; j++)
- {
- for(i=0; i<ciWidth/8; i++)
- {
- printf("0x%x ",*ptr );
- ptr++;
- }
- ptr += dotlen -1 ; // 在内循环中已经加了一个1
- }
- }
源码: bmp.zip