ocGUI编写(6)--24位BMP图片解码

二维码是我创建的QQ群,欢迎新朋友加入。

先看实物效果

通过程序软解码BMP图片

ocDrawBmp(200,50,bmpPic);

首先要了解BMP图片的编码格式

一.简介

BMP(Bitmap-File)图形文件是Windows采用的图形文件格式,在Windows环境下运行的所有图象处理软件都支持BMP图象文件格式。Windows系统内部各图像绘制操作都是以BMP为基础的。Windows 3.0以前的BMP图文件格式与显示设备有关,因此把这种BMP图象文件格式称为设备相关位图DDB(device-dependent bitmap)文件格式。Windows 3.0以后的BMP图象文件与显示设备无关,因此把这种BMP图象文件格式称为设备无关位图DIB(device-independent bitmap)格式(注:Windows 3.0以后,在系统中仍然存在DDB位图,象BitBlt()这种函数就是基于DDB位图的,只不过如果你想将图像以BMP格式保存到磁盘文件中时,微软极力推荐你以DIB格式保存),目的是为了让Windows能够在任何类型的显示设备上显示所存储的图象。BMP位图文件默认的文件扩展名是BMP或者bmp(有时它也会以.DIB或.RLE作扩展名)。

二.BMP格式结构

BMP文件的数据按照从文件头开始的先后顺序分为四个部分:

◆ 位图文件头(bmp file header)  提供文件的格式、大小等信息

◆ 位图信息头(bitmap information)提供图像数据的尺寸、位平面数、压缩方式、颜色索引等信息

◆ 调色板(color palette)可选,如使用索引来表示图像,调色板就是索引与其对应的颜色的映射表

◆ 位图数据(bitmap data)图像数据区

BMP图片文件数据表如下:

数据段名称

大小(byte)

开始地址

结束地址

位图文件头(bitmap-file header)

14

0000h

000Dh

位图信息头(bitmap-information header)

40

000Eh

0035h

调色板(color table)

由biBitCount决定

0036h

未知

图片点阵数据(bitmap data)

由图片大小和颜色定

未知

未知

三.BMP文件头

BMP文件头结构体定义如下:

typedef struct tagBITMAPFILEHEADER

UINT16 bfType;        //2Bytes,必须为"BM",即0x424D 才是Windows位图文件

DWORD bfSize;         //4Bytes,整个BMP文件的大小

UINT16 bfReserved1;  //2Bytes,保留,为0

UINT16 bfReserved2;  //2Bytes,保留,为0

DWORD bfOffBits;     //4Bytes,文件起始位置到图像像素数据的字节偏移量

BITMAPFILEHEADER;

BMP文件头数据表如下:

变量名

地址偏移

大小

作用说明

bfType

0000h

2Bytes

文件标识符,必须为"BM",即0x424D 才是Windows位图文件

‘BM’:Windows 3.1x, 95, NT,…  ‘BA’:OS/2 Bitmap Array  ‘CI’:OS/2 Color Icon   

‘CP’:OS/2 Color Pointer   ‘IC’:OS/2 Icon   

‘PT’:OS/2 Pointer

因为OS/2系统并没有被普及开,所以在编程时,你只需判断第一个标识“BM”就行

bfSize

0002h

4Bytes

整个BMP文件的大小(以位B为单位)

bfReserved1

0006h

2Bytes

保留,必须设置为0

bfReserved2

0008h

2Bytes

保留,必须设置为0

bfOffBits

000Ah

4Bytes

说明从文件头0000h开始到图像像素数据的字节偏移量(以字节Bytes为单位),以为位图的调色板长度根据位图格式不同而变化,可以用这个偏移量快速从文件中读取图像数据

四.BMP信息头

BMP信息头结构体定义如下:

typedef struct _tagBMP_INFOHEADER

{

DWORD  biSize;    //4Bytes,INFOHEADER结构体大小,存在其他版本I NFOHEADER,用作区分

LONG   biWidth;    //4Bytes,图像宽度(以像素为单位)

LONG   biHeight;    //4Bytes,图像高度,+:图像存储顺序为Bottom2Top,-:Top2Bottom

WORD   biPlanes;    //2Bytes,图像数据平面,BMP存储RGB数据,因此总为1

WORD   biBitCount;         //2Bytes,图像像素位数

DWORD  biCompression;     //4Bytes,0:不压缩,1:RLE8,2:RLE4

DWORD  biSizeImage;       //4Bytes,4字节对齐的图像数据大小

LONG   biXPelsPerMeter;   //4 Bytes,用象素/米表示的水平分辨率

LONG   biYPelsPerMeter;   //4 Bytes,用象素/米表示的垂直分辨率

DWORD  biClrUsed;          //4 Bytes,实际使用的调色板索引数,0:使用所有的调色板索引

DWORD biClrImportant;     //4 Bytes,重要的调色板索引数,0:所有的调色板索引都重要

}BMP_INFOHEADER;

BMP信息头数据表如下:

变量名

地址偏移

大小

作用说明

biSize

000Eh

4Bytes

BNP信息头即BMP_INFOHEADER结构体所需要的字节数(以字节为单位)

biWidth

0012h

4Bytes

说明图像的宽度(以像素为单位)

biHeight

0016h

4Bytes

说明图像的高度(以像素为单位)。这个值还有一个用处,指明图像是正向的位图还是倒向的位图,该值是正数说明图像是倒向的即图像存储是由下到上;该值是负数说明图像是倒向的即图像存储是由上到下。大多数BMP位图是倒向的位图,所以此值是正值。

biPlanes

001Ah

2Bytes

为目标设备说明位面数,其值总设置为1

biBitCount

001Ch

2Bytes

说明一个像素点占几位(以比特位/像素位单位),其值可为1,4,8,16,24或32

biCompression

001Eh

4Bytes

说明图像数据的压缩类型,取值范围为:

0         BI_RGB 不压缩(最常用)

1         BI_RLE8 8比特游程编码(BLE),只用于8位位图

2         BI_RLE4 4比特游程编码(BLE),只用于4位位图

3         BI_BITFIELDS比特域(BLE),只用于16/32位位图

4          

biSizeImage

0022h

4Bytes

说明图像的大小,以字节为单位。当用BI_RGB格式时,总设置为0

biXPelsPerMeter

0026h

4Bytes

说明水平分辨率,用像素/米表示,有符号整数

biYPelsPerMeter

002Ah

4Bytes

说明垂直分辨率,用像素/米表示,有符号整数

biClrUsed

002Eh

4Bytes

说明位图实际使用的调色板索引数,0:使用所有的调色板索引

biClrImportant

0032h

4Bytes

说明对图像显示有重要影响的颜色索引的数目,如果是0,表示都重要。

五.BMP调色板

BMP调色板结构体定义如下:

typedef struct _tagRGBQUAD

{

BYTE  rgbBlue;       //指定蓝色强度

BYTE  rgbGreen;      //指定绿色强度

BYTE  rgbRed;        //指定红色强度

 BYTE  rgbReserved;  //保留,设置为0

RGBQUAD;

1,4,8位图像才会使用调色板数据,16,24,32位图像不需要调色板数据,即调色板最多只需要256项(索引0 - 255)。

颜色表的大小根据所使用的颜色模式而定:2色图像为8字节;16色图像位64字节;256色图像为1024字节。其中,每4字节表示一种颜色,并以B(蓝色)、G(绿色)、R(红色)、alpha(32位位图的透明度值,一般不需要)。即首先4字节表示颜色号1的颜色,接下来表示颜色号2的颜色,依此类推。

颜色表中RGBQUAD结构数据的个数有biBitCount来确定,当biBitCount=1,4,8时,分别有2,16,256个表项。

当biBitCount=1时,为2色图像,BMP位图中有2个数据结构RGBQUAD一个调色板占用4字节数据,所以2色图像的调色板长度为2*4为8字节。

当biBitCount=4时,为16色图像,BMP位图中有16个数据结构RGBQUAD一个调色板占用4字节数据,所以16像的调色板长度为16*4为64字节。

当biBitCount=8时,为256色图像,BMP位图中有256个数据结构RGBQUAD一个调色板占用4字节数据,所以256色图像的调色板长度为256*4为1024字节。

当biBitCount=16,24或32时,没有颜色表。

五.BMP图像数据区

位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占的字节数:

当biBitCount=1时,8个像素占1个字节;

当biBitCount=4时,2个像素占1个字节;

当biBitCount=8时,1个像素占1个字节;

当biBitCount=24时,1个像素占3个字节;

Windows规定一个扫描行所占的字节数必须是4的倍数(即以long为单位),不足的以0填充,

一个扫描行所占的字节数计算方法:

DataSizePerLine= (biWidth* biBitCount+31)/8;

// 一个扫描行所占的字节数

DataSizePerLine= DataSizePerLine/4*4; // 字节数必须是4的倍数

位图数据的大小(不压缩情况下):

DataSize= DataSizePerLine* biHeight;

颜色表接下来位为位图文件的图像数据区,在此部分记录着每点像素对应的颜色号,其记录方式也随颜色模式而定,既2色图像每点占1位(8位为1字节);16色图像每点占4位(半字节);256色图像每点占8位(1字节);真彩色图像每点占24位(3字节)。所以,整个数据区的大小也会随之变化。究其规律而言,可的出如下计算公式:图像数据信息大小=(图像宽度*图像高度*记录像素的位数)/8。

根据上面说明,开始软件码工作

首先定义两个结构体存放关键信息

//BMP文件头
typedef struct 
{ 
uint16_t bfType;        //2Bytes,必须为"BM",即0x424D 才是Windows位图文件
uint32_t bfSize;        //4Bytes,整个BMP文件的大小
uint16_t bfReserved1;   //2Bytes,保留,为0
uint16_t bfReserved2;   //2Bytes,保留,为0
uint32_t bfOffBits;     //4Bytes,文件起始位置到图像像素数据的字节偏移量
} ocBmpHeard_t;

//BMP信息头
typedef struct 
{
uint32_t  biSize;          //4Bytes,INFOHEADER结构体大小,存在其他版本I NFOHEADER,用作区分
uint32_t   biWidth;        //4Bytes,图像宽度(以像素为单位)
uint32_t   biHeight;       //4Bytes,图像高度,+:图像存储顺序为Bottom2Top,-:Top2Bottom
uint8_t   biPlanes;        //2Bytes,图像数据平面,BMP存储RGB数据,因此总为1
uint8_t   biBitCount;      //2Bytes,图像像素位数
uint32_t  biCompression;   //4Bytes,0:不压缩,1:RLE8,2:RLE4
uint32_t  biSizeImage;     //4Bytes,4字节对齐的图像数据大小
uint32_t   biXPelsPerMeter;//4Bytes,用象素/米表示的水平分辨率
uint32_t   biYPelsPerMeter;//4Bytes,用象素/米表示的垂直分辨率
uint32_t  biClrUsed;       //4Bytes,实际使用的调色板索引数,0:使用所有的调色板索引
uint32_t biClrImportant;   //4Bytes,重要的调色板索引数,0:所有的调色板索引都重要
}ocBmpInforHeard_t;
/**********************************************
 * @brief :显示BMP图片,以数组方式,文件形式需要读取二进制文件
 * @param : Xpos:      图片显示左上角X轴位置
 * @param : Ypos:      图片显示左上角Y轴位置
 * @param : pic:       图像数组
 * @note  :直接转换BMP原始数据
 * @retval: 绘制成功返回oc_OK,失败返回oc_ON
**********************************************/
uint8_t ocDrawBmp(uint16_t Xpos, uint16_t Ypos,const char *pic)
{
	ocBmpHeard_t ocBmpHeard;
	ocBmpInforHeard_t ocBmpInforHeard;
	
	uint32_t showLen,showW = 0,showH = 0;
	uint8_t dataBit,i;
	
	//获取BMP图像数据信息
	//BMP文件头
	ocBmpHeard.bfType = pic[0x00] << 8 | pic[0x01];//文件标识符,必须为"BM",即0x424D 才是Windows位图文件
	ocBmpHeard.bfSize = (pic[0x05] << 24 |
	                    pic[0x04] << 16 |
	                    pic[0x03] << 8 |
	                    pic[0x02] << 0)/1024;//整个BMP文件的大小(以位B为单位)
	ocBmpHeard.bfOffBits = pic[0x0a];//说明从文件头0000h开始到图像像素数据的字节偏移量(以字节Bytes为单位),以为位图的调色板长度根据位图格式不同而变化,可以用这个偏移量快速从文件中读取图像数据
	
	//BMP信息头
	ocBmpInforHeard.biSize = pic[0x0e];//BNP信息头即BMP_INFOHEADER结构体所需要的字节数(以字节为单位)
	ocBmpInforHeard.biWidth = pic[0x15] << 24 |
														pic[0x14] << 16 |
														pic[0x13] << 8 |
														pic[0x12] << 0;//说明图像的宽度(以像素为单位)
	ocBmpInforHeard.biHeight =  pic[0x19] << 24 |
															pic[0x18] << 16 |
															pic[0x17] << 8 |
															pic[0x16] << 0;//说明图像的高度(以像素为单位)。这个值还有一个用处,指明图像是正向的位图还是倒向的位图,该值是正数说明图像是倒向的即图像存储是由下到上;该值是负数说明图像是倒向的即图像存储是由上到下。大多数BMP位图是倒向的位图,所以此值是正值。
	ocBmpInforHeard.biPlanes = pic[0x1a] | pic[0x1b] << 8;//为目标设备说明位面数,其值总设置为1
	ocBmpInforHeard.biBitCount = pic[0x1c] | pic[0x1d] << 8;//说明一个像素点占几位(以比特位/像素位单位),其值可为1,4,8,16,24或32
	ocBmpInforHeard.biCompression = pic[0x21] << 24 |
																	pic[0x20] << 16 |
																	pic[0x1f] << 8  |
																	pic[0x1e] << 0; //说明图像数据的压缩类型,取值范围为:
																									//0         BI_RGB 不压缩(最常用)
																									//1         BI_RLE8 8比特游程编码(BLE),只用于8位位图
																									//2         BI_RLE4 4比特游程编码(BLE),只用于4位位图
																									//3         BI_BITFIELDS比特域(BLE),只用于16/32位位图
	ocBmpInforHeard.biSizeImage = pic[0x25] << 24 |
																pic[0x24] << 16 |
																pic[0x23] << 8 |
																pic[0x22] << 0;//说明图像的大小,以字节为单位。当用BI_RGB格式时,总设置为0
	ocBmpInforHeard.biXPelsPerMeter = pic[0x29] << 24 |
																pic[0x28] << 16 |
																pic[0x27] << 8 |
																pic[0x26] << 0;//说明水平分辨率,用像素/米表示,有符号整数
	ocBmpInforHeard.biYPelsPerMeter = pic[0x2d] << 24 |
																pic[0x2c] << 16 |
																pic[0x2b] << 8 |
																pic[0x2a] << 0;//说明垂直分辨率,用像素/米表示,有符号整数
	ocBmpInforHeard.biClrUsed = pic[0x31] << 24 |
																pic[0x30] << 16 |
																pic[0x2f] << 8 |
																pic[0x2e] << 0;//实际使用的调色板索引数,0:使用所有的调色板索引
	ocBmpInforHeard.biClrImportant = pic[0x35] << 24 |
																pic[0x34] << 16 |
																pic[0x33] << 8 |
																pic[0x32] << 0;//说明对图像显示有重要影响的颜色索引的数目,如果是0,表示都重要。
	
	//解析BMP图像信息
	if(ocBmpHeard.bfType == 0x424D)
	{//判断是不是BMP图像
		showLen = ocBmpHeard.bfOffBits;
		dataBit = ocBmpInforHeard.biBitCount / 8;
		while(showLen < ocBmpInforHeard.biSizeImage)
		{
			ocFontSet.textColor = 0;
			for(i=0;i<dataBit;i++)
			{
				ocFontSet.textColor = ocFontSet.textColor | 
				                      (pic[showLen+i]&0x000000ff) << (8*i);
			}
			
			ocPutDot(Xpos + showW,Ypos + ocBmpInforHeard.biHeight - showH);
			showW++;
			if(showW >= ocBmpInforHeard.biWidth)
			{
				showW = 0;
				showH++;
			}
			showLen += dataBit;
		}
	}
	
	return oc_OK;
}

猜你喜欢

转载自blog.csdn.net/Jun626/article/details/81416159
今日推荐