C语言读写bmp位图文件

bitmap格式图片是未经压缩的,一般24bit位图(即一个像素点以24个二进制位表示)。

分别用8个二进制位表示R/G/B三种颜色,这样一共可以表示256*256*256=16777216种颜色。

8bit的位图则为黑白图像,32bit位图除16777216种颜色外还有8个bit表示光栅(有待具体研究)。


BMP图像文件被分成4个部分:位图文件头(Bitmap File Header)、位图信息头(Bitmap Info Header)、颜色表(Color Map)和位图数据(即图像数据,Data BitsData Body)。

1部分为位图文件头BITMAPFILEHEADER,是一个结构体类型,该结构的长度是固定的,为14个字节。其定义如下:

typedef struct FileHeader
{
	unsigned short	bfType;
	unsigned int	bfSize;
	unsigned short	bfReserved1;
	unsigned short	bfReserved2;
	unsigned int	bfOffBits;
}__attribute__((packed))FileHeader;

BITMAPFILEHEADER结构的各个域详细说明如下:

bfType:位图文件类型,必须是0x424D,即字符串“BM”,也就是说,所有的“*.bmp”文件的头两个字节都是“BM”

bfSize:位图文件大小,包括这14个字节。

bfReserved1, bfReserved2Windows保留字,暂不用。

bfOffBits:从文件头到实际的位图数据的偏移字节数,bitmap文件3个部分(文件头、信息头、颜色表)的长度之和。

2部分为位图信息头BITMAPINFOHEADER,也是一个结构体类型的数据结构,该结构的长度也是固定的,为40个字节。其定义如下:

typedef struct InfoHeader
{
	unsigned int	biSize;
	int				biWidth;
	int				biHeight;
	unsigned short	biPlanes;
	unsigned short	biBitCount;
	unsigned int	biCompression;
	unsigned int	biSizeImage;
	int				biXPelsPerMeter;
	int 			biYPelsPerMeter;
	unsigned int	biClrUsed;
	unsigned int	biClrImportant;
}__attribute__((packed))InfoHeader;
BITMAPINFOHEADER结构的各个域的详细说明如下:

biSize:本结构的长度,为40个字节。

biWidth:位图的宽度,以像素为单位。

biHeight:位图的高度,以像素为单位。

biPlanes:目标设备的级别,必须是1

biBitCount:每个像素所占的位数(bit),其值必须为1(黑白图像)、416色图)、8256色)、24(真彩色图),新的BMP格式支持32位色。

biCompresssion:位图压缩类型,有效的值为BI_RGB(未经压缩)、BI_RLE8BI_RLE4BI_BITFILEDS(均为Windows定义常量)。这里只讨论未经压缩的情况,即biCompression=BI_RGB

biSizeImage:实际的位图数据占用的字节数,该值的大小在第4部分位图数据中有具体解释。

biXPelsPerMeter:指定目标设备的水平分辨率,单位是像素/米。

biYPelsPerMeter:指定目标设备的垂直分辨率,单位是像素/米。

biClrUsed:位图实际用到的颜色数,如果该值为零,则用到的颜色数为2biBitCount次幂。

biClrImportant:位图显示过程中重要的颜色数,如果该值为零,则认为所有的颜色都是重要的。


3部分为颜色表。颜色表实际上是一个RGBQUAD结构的数组,数组的长度由biClrUsed指定(如果该值为零,则由biBitCount指定,即2biBitCount次幂个元素)。RGBQUAD结构是一个结构体类型,占4个字节,其定义如下:

typedef struct tagRGBQUAD
{
	unsigned char	rgbBlue;
	unsigned char	rgbGreen;
	unsigned char	rgbRed;
	unsigned char	rgbReserved;
}RGBQUAD;

RGBQUAD结构的各个域的详细说明如下:

rgbBlue:该颜色的蓝色分量;

rgbGreen:该颜色的绿色分量;

rgbRed:该颜色的红色分量;

rgbReserved:保留字节,暂不用。

有些位图需要颜色表;有些位图(如真彩色图)则不需要颜色表,颜色表的长度由BITMAPINFOHEADER结构中biBitCount分量决定。对于biBitCount值为1的二值图像,每像素占1bit,图像中只有两种(如黑白)颜色,颜色表也就有21=2个表项,整个颜色表的大小为 2*siezof(RGBQUAD)=2x4=8个字节;对于biBitCount值为8的灰度图像,每像素占8bit,图像中有2^8=256 颜色,颜色表也就有256个表项,且每个表项的RGB分量相等,整个颜色表的大小为 个字节;而对于biBitCount=24的真彩色图像,由于每像素3个字节中分别代表了RGB三分量的值,此时不需要颜色表,因此真彩色图的BITMAPINFOHEADER结构后面直接就是位图数据。


4部分是位图数据,即图像数据,其紧跟在位图文件头、位图信息头和颜色表(如果有颜色表的话)之后,记录了图像的每一个像素值。对于有颜色表的位图,位图数据就是该像素颜色在调色板中的索引值;对于真彩色图,位图数据就是实际的RGB值(三个分量的存储顺序是BGR)。下面分别就2色、16色、256色和真彩色位图的位图数据进行说明:

对于2色位图,用1位就可以表示该像素的颜色,所以1个字节能存储8个像素的颜色值。
对于16色位图,用4位可以表示一个像素的颜色。所以一个字节可以存储2个像素的颜色值。
对于256色位图,1个字节刚好存储1个像素的颜色值。
 
对于真彩色位图,3个字节才能表示1个像素的颜色值。

需要注意两点:

第一,图像格式规定一个扫描行所占的字节数必须是4的倍数,不足4的倍数则要对其进行扩充。假设图像的宽为biWidth个像素、每像素biBitCount个比特,其一个扫描行所占的真实字节数的计算公式如下:

DataSizePerLine = (biWidth * biBitCount /8+ 3) / 4*4

那么,不压缩情况下位图数据的大小(BITMAPINFOHEADER结构中的biSizeImage成员)计算如下:

biSizeImage = DataSizePerLine * biHeight

第二,一般来说,BMP文件的数据是从图像的左下角开始逐行扫描图像的,即从下到上、从左到右,将图像的像素值一一记录下来,因此图像坐标零点在图像左下角。



以下代码是C语言读写bitmap格式图片的几个函数,main()函数作为测试用。

为了兼容Linux 和windows平台用fopen、fread、fseek、fclose替换掉了open、read、lseek、close系列函数。

#include 
#include 
#include 
#include 
#include 
#include 
//#include "window.h"

/*bmp file header*/
typedef struct FileHeader
{
	unsigned short	bfType;
	unsigned int	bfSize;
	unsigned short	bfReserved1;
	unsigned short	bfReserved2;
	unsigned int	bfOffBits;
}__attribute__((packed))FileHeader;

/*bmp info header*/
typedef struct InfoHeader
{
	unsigned int	biSize;
	int				biWidth;
	int				biHeight;
	unsigned short	biPlanes;
	unsigned short	biBitCount;
	unsigned int	biCompression;
	unsigned int	biSizeImage;
	int				biXPelsPerMeter;
	int 			biYPelsPerMeter;
	unsigned int	biClrUsed;
	unsigned int	biClrImportant;
}__attribute__((packed))InfoHeader;

//we won't use it while BitCount=24
typedef struct tagRGBQUAD
{
	unsigned char	rgbBlue;
	unsigned char	rgbGreen;
	unsigned char	rgbRed;
	unsigned char	rgbReserved;
}RGBQUAD;
	
typedef struct
{
	unsigned char b;
	unsigned char g;
	unsigned char r;
}RGB_data;

/*for test global variable*/
/*maybe can not use this in the project*/
unsigned char 	*pBmpBuf,*pBmpBufOne,*pBmpBufTwo,*pBmpBufThree;
RGBQUAD 		*pColorTable;
int		bmpWidth,bmpWidthback,bmpWidthsky;
int		bmpHeight,bmpHeightback,bmpHeightsky;
int		biBitCount,biBitCountback,biBitCountsky;

char * readBmp(char *bmpName)
{
	FILE *fp = fopen(bmpName, "rb");
	//int fp;		/*maybe fd should be more comfortably*/
	//fp = open(bmpName, O_RDONLY);
	if (NULL == fp)
	{
		printf("There is no fp!!!\n");
		return 0;
	}

	fseek(fp, sizeof(FileHeader), SEEK_SET);
	//lseek(fp, sizeof(FileHeader), SEEK_SET);
	InfoHeader head;
	fread(&head, sizeof(InfoHeader), 1, fp);
	//read(fp, &head, sizeof(InfoHeader));

	bmpWidth = head.biWidth;
	bmpHeight = head.biHeight;
	biBitCount = head.biBitCount;

	int lineByte = (bmpWidth * biBitCount / 8 + 3) / 4 * 4;
	if (biBitCount == 8)
	{
		//pColorTable=new RGBQUAD[256];
		pColorTable = (RGBQUAD *)malloc(sizeof(RGBQUAD) * 1024);
		fread(pColorTable, sizeof(RGBQUAD), 256, fp);
	}

	pBmpBuf = (unsigned char *)malloc(sizeof(unsigned char) * lineByte * bmpHeight);
	fread(pBmpBuf, 1, lineByte * bmpHeight, fp);
	fclose(fp);
	
	return pBmpBuf;
}


int saveBmp(char *bmpName, unsigned char *imgBuf, int width, int height, int biBitCount, RGBQUAD *pColorTable)
{
	if(imgBuf == NULL)
	{
		printf("imgBuf is NULL!!\n");
		return -1;
	}

	int colorTablesize = 0;
	if (biBitCount == 8)
	{
		colorTablesize=1024;
	}
	
	int lineByte = (width * biBitCount / 8 + 3) / 4 * 4;

	FILE *fp = fopen(bmpName, "wb");
	if (fp == NULL)
	{
		printf("fopen error...\n");
		return -1;
	}
	
	FileHeader fileHead;
	fileHead.bfType=0x4D42;

	fileHead.bfSize = sizeof(FileHeader) + sizeof(InfoHeader) + colorTablesize + lineByte * height;
	
	fileHead.bfReserved1 = 0;
	fileHead.bfReserved2 = 0;

	fileHead.bfOffBits = 54 + colorTablesize;

	fwrite(&fileHead, sizeof(FileHeader), 1, fp);

	InfoHeader infoHead;
	infoHead.biBitCount = biBitCount;
	infoHead.biClrImportant = 0;
	infoHead.biClrUsed = 0;
	infoHead.biCompression = 0;
	infoHead.biHeight = height;
	infoHead.biPlanes = 1;
	infoHead.biSize = 40;
	infoHead.biSizeImage = lineByte * height;
	infoHead.biWidth = width;
	infoHead.biXPelsPerMeter = 0;
	infoHead.biYPelsPerMeter = 0;

	fwrite(&infoHead, sizeof(InfoHeader), 1, fp);

	if (biBitCount == 8)
	{
		fwrite(pColorTable,sizeof(RGBQUAD),256,fp);
	}
	
	fwrite(imgBuf, height * lineByte, 1, fp);

	fclose(fp);
	
	return 0;
}


/* main function test program*/
#if 1
int main(int argc, char *argv[])
{
	char readPath[] = "logo256.bmp";
	readBmp(readPath);

	printf("width = %d, height = %d, biBitCount = %d \n", bmpWidth, bmpHeight, biBitCount);

	char writePath[] = "logo256copy.bmp";
	saveBmp(writePath, pBmpBuf, bmpWidth, bmpHeight, biBitCount, pColorTable);

	free(pBmpBuf);
	if (biBitCount == 8)
	{
		free(pColorTable);
	}
	
	return 0;
}
#endif

#if 0
extern int a1,b1,n;
extern int a[50],b[50];

//int reviseBitMap(void)
int main(int argc,char *argv[])
{
	int i,j;
	int x,y;
	int k;

	char readPathOne[] = "back.bmp";
	pBmpBufOne = readBmp(readPathOne);
	printf("width = %d, height = %d, biBitCount = %d \n", bmpWidth, bmpHeight, biBitCount);
	bmpWidthback = bmpWidth;
	bmpHeightback = bmpHeight;
	biBitCountback = biBitCount;
	int lineByteback = (bmpWidthback * biBitCountback / 8 + 3) / 4 * 4;

	char readPathThree[] = "sky.bmp";
	pBmpBufThree = readBmp(readPathThree);
	printf("width = %d, height = %d, biBitCount = %d \n", bmpWidth, bmpHeight, biBitCount);
	bmpWidthsky = bmpWidth;
	bmpHeightsky = bmpHeight;
	biBitCountsky = biBitCount;
	int lineBytesky = (bmpWidthsky * biBitCountsky / 8 + 3) / 4 * 4;

	char readPathTwo[] = "plane.bmp";
	pBmpBufTwo = readBmp(readPathTwo);
	printf("wdith = %d, height = %d, biBitCount = %d \n", bmpWidth, bmpHeight, biBitCount);
	int lineByteplane = (bmpWidth * biBitCount / 8 + 3) / 4 * 4;		

	if (biBitCount == 8)
	{
		for (i = 0; i < bmpHeight / 2; i++)
		{
			for (j = 0; j < bmpWidth / 2; j++)
			{
				*(pBmpBuf + i * lineByteplane + j) = 0;
			}
		}
	}
	else if (biBitCount == 24)
	{
		x = a[a1];
		y = b[b1];
		for (i = 0; i < bmpHeight; i++)
		{
			for(j=0;j
如有转载请注明出处。

作者:super_bert@csdn

你可能感兴趣的:(C)