C语言读取bmp图像并做简单显示

C语言读取bmp图像并做简单显示)

bmp文件格式

bmp文件大体上分为四个部分:

bmp文件构成
位图文件头BITMAPFILEHEADER
位图信息头BITMAPINFOHEADER
调色板Palette
实际的位图数据ImageDate

第一部分为位图文件头,位图文件头长度固定,为14个字节。

typdef struct {
WORD bfType;    //指定文件类型,必须是0x424d,即”BM”
DWORD bfSize;   //指定文件大小
WORD bfReserved1; //保留字
WORD bfReserved2; //保留字
DWORD bfOffBits; //为文件头到实际的位图数据的偏移字节数,即上图前三部分和
}bitmapFileHeader;

第二部分为位图信息头,这个结构的长度也是固定的,为40个字节。

typedef struct {
	DWORD biSize;  //指这个机构的长度,为40
	LONG biWidth;  //指定图像的宽度,单位是像素
	LONG biHeight;  //指定图像的高度,单位是像素
	WORD biPlanes;  //平面数,必须为1,不用考虑 
	WORD biBitCount; //指定表示颜色是要用到的位数,常用值为1(黑白二色图),
	//4(16色图),8(256色),24(真彩色图)(新的.bmp格式支持32位色)
	DWORD biCompression; //指定位图是否压缩,有效的值为BI_RGB,BI_RLE8,BI_RLE4,BI_BITFILELDS
	DWORD biSizeImage; //指定实际的位图数据占用的字节数,其实也可以从以下的公式计算出来:
	//biSizeImage=bitWidth’*biHeight,bitWidth‘为大于等于bitWidth的4的倍数
	LONG biXPelsPerMeter; //指定设备的水平分辨率,单位是每米的图像个数
	LONG biYPelsPerMeter; //同上,垂直分辨率
	DWORD biClrUsed; //指定本图像实际用到的颜色数,如果该值为零,则用到的颜色数为2^biBitCount
	DWORD biClrImportant;// 指定本图象中重要的颜色数,如果该值为零,则认为所有的颜色都是重要的
}bitmapInfoHeader;

第三部分为调色板(真彩图像不需要调色版,bitmapInfoHeader后直接是数据)调色板实际是一个数组,共有biClrUsed个元素(如果该值为0,则有2^biBitCount个元素),数组中每个元素的类型是一个RGBQUAD结构,占四个字节,其定义如下:

typedef struct {
	BYTE rgbBlue; //该颜色的蓝色分量
	BYTE rgbGreen; //该颜色的绿色分量
	BYTE rgbRed; //该颜色的红色分量
	BYTE rgbReserved; //保留值
} RGBQUAD;

第四部分为实际图像数据
对于用到调色版的位图,图像数据就是该像素颜在调色板中的索引值。对于真彩图,图像数据就是实际的R、G、B值。

需要注意两点:
(1)每一行的字节数必须是4的整倍数,如果不是,则需要补齐。
(2)一般来说,.bmp文件的数据是从下到上,从左到右的。也就是说,从文件中最先读到的是图象最下面一行的左边第一个像素,然后是左边第二个像素……接下来是倒数第二行左边第一个像素,左边第二个像素……依次类推 ,最后得到的是最上面一行的最右一个像素。

读取bmp文件信息并展示

以24位bmp图像为例
在这里插入图片描述

定义数据结构:

typedef struct {
	unsigned char bfType[2];
	unsigned long bfSize;
	unsigned short bfReserved1;
	unsigned short bfReserved2;
	unsigned long bfOffBits;
}bitmapFileHeader;

typedef struct {
	unsigned long biSize;
	long biWidth;
	long biHeight;
	unsigned short biPlanes;
	unsigned short biBitCount;
	unsigned long biCompression;
	unsigned long biSizeImage;
	long biXPixPerMeter;
	long biYPixPerMeter;
	unsigned long biClrused;
	unsigned long biClrImportant;
}bitmapInfoHeader;

读入文件头:

//仅展示,不用于实验
int readFileHeader(FILE *fp,bitmapFileHeader*bfHeader){
	fseek(fp,0,SEEK_SET);
	fread(bfHeader,sizeof(bitmapFileHeader),1,fp);
	/*
	int i;	
	printf("读入文件头:");
	char*p=(char*)bfHeader;
	for(i=0;i<sizeof(bitmapFileHeader);i++,p++){
		printf("%02x ",*p);
	}
	printf("\n");
	printf("文件头信息如下:\n");
	printf("文件类型:%c%c\n",bfHeader->bfType[0],bfHeader->bfType[1]);
	printf("文件大小: %d 字节\n",bfHeader->bfSize);
	printf("位图数据偏移:%d\n",bfHeader->bfOffBits);
	*/
	return 0;
}

读信息头:

//仅展示,不用于实验
int readInfoHeader(FILE*fp,bitmapInfoHeader*biHeader){
	fseek(fp,14,SEEK_SET);
	fread(biHeader,sizeof(bitmapInfoHeader),1,fp);

	/*
	int i;
	printf("读入位图信息头:\n");
	char*p=(char*)biHeader;
	for(i=0;i<sizeof(bitmapInfoHeader);i++,p++){
		printf("%02x ",*p);
		if(i%20==0&&i!=0)
			printf("\n");
	}
	printf("\n");
	printf("位图信息头信息如下:\n");
	printf("bmp图像宽度:%d\n",biHeader->biWidth);
	printf("bmp图像高度:%d\n",biHeader->biHeight);
	printf("bmp图像颜色位数: %d\n",biHeader->biBitCount);
	printf("bmp图像实际数据占用字节:%d\n",biHeader->biSizeImage);
	*/
	return 0;
}

读入bmp图像数据,并展示

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>

#pragma pack(1)  //这个选项挺重要,不加的话程序就会报错,原因参考
//https://blog.csdn.net/qq_44310495/article/details/109181857

typedef struct {
	unsigned char bfType[2];
	unsigned long bfSize;
	unsigned short bfReserved1;
	unsigned short bfReserved2;
	unsigned long bfOffBits;
}bitmapFileHeader;

typedef struct {
	unsigned long biSize;
	long biWidth;
	long biHeight;
	unsigned short biPlanes;
	unsigned short biBitCount;
	unsigned long biCompression;
	unsigned long biSizeImage;
	long biXPixPerMeter;
	long biYPixPerMeter;
	unsigned long biClrused;
	unsigned long biClrImportant;
}bitmapInfoHeader;

int main(){
	FILE *fp,*fp_txt;
	if((fp=fopen("d:\Temp\\skull.bmp","rb"))==NULL){
		perror("can not open file!");
		return -1;
	}
	
	bitmapFileHeader bfHeader;
	fread(&bfHeader,14,1,fp);
	bitmapInfoHeader biHeader;
	fread(&biHeader,40,1,fp);

	int imSize=biHeader.biSizeImage;
	int width=biHeader.biWidth;
	int height=biHeader.biHeight;
	int bitCount=biHeader.biBitCount;

	fseek(fp,bfHeader.bfOffBits,SEEK_SET);
	unsigned char*imageData=(unsigned char*)malloc(imSize*sizeof(unsigned char));
	fread(imageData,imSize*sizeof(unsigned char),1,fp);

	//图像为24位图像
	int lineBytes=(bitCount*width+31)/32*4;//得到图像数据的bitwidth'
	int i,j;
	int r,g,b;
	for(i=0;i<height;i++){ //对于每一行
		for(j=0;j<width*3;j++){ //对于每一列
			r=*(imageData+lineBytes*(height-1-i)+j); //从最后一行往上读
			j++;
			g=*(imageData+lineBytes*(height-1-i)+j);
			j++;
			b=*(imageData+lineBytes*(height-1-i)+j);
			if(r==255&&g==255&&b==255) //模拟二值图像展示
				printf("  ");
			else
				printf(".$");
		}
		printf("\n");
	}
	
	free(imageData);
	fclose(fp);
	getchar();
	return 0;
}

代码效果展示:
在这里插入图片描述

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值