当前位置:网站首页>C语言读取BMP文件

C语言读取BMP文件

2022-07-06 09:14:00 imxlw00

BMP图像编码

BMP即bitmap,也就是位图,一般由4部分组成:文件头信息块、图像描述信息块、颜色表(在真彩色模式无颜色表)和图像数据区。

在图像数据之前,如图所示,共有54位数据
在这里插入图片描述
其中,0x424d在十进制为19778,对应的ASCII码为BM,表示这是个bitmap文件。

Windows的数据是倒着念的,这是PC电脑的特色。如果一段数据为42 4D,倒着念就是4D 42,即0x4D42。
因此,如果bfSize的数据为A2 1E 04 00,实际上就成了0x00041EA2,也就是0x41EA2。

文件信息头[14字节]

存储着文件类型,文件大小等信息

// 文件信息头结构体
typedef struct tagBITMAPFILEHEADER{
    
    unsigned short bfType;        //必为"BM"
    unsigned int   bfSize;        //文件字节数(2-5)
    unsigned int bfReserved;    //位图文件保留字,必为0(6-9)
    unsigned int   bfOffBits;   //像素数据偏移 (10-13)
} bmpHeader;

图像描述信息[40字节]

#define uint unsigned int
#define ushort unsigned short
//图像信息头结构体
typedef struct tagBITMAPINFOHEADER{
    
    uint    biSize;          // 结构体尺寸 (14-17)
    int     biWidth;         // 图像宽度 (18-21)
    int     biHeight;        // 图像高度 (22-25)
    ushort  biPlanes;        // 目标设备的级别,为1(26-27)
    ushort  biBitCount;      // 像素位数,为1、4、8或24(28-29)
    uint    biCompression;   // 位图压缩类型,0为不压缩、1为BI_RLE8、2为BI_RLE4(30-33)
    uint    biSizeImage;     // 单像素数据大小,等于bfSize-bfOffBits (34-37)
    int     biXPelsPerMeter; // 水平分辨率,一般为0 (38-41)
    int     biYPelsPerMeter; // 垂直分辨率,一般为0 (42-45)
    uint    biClrUsed;       // 位图颜色表中的颜色数,0表示使用所有调色板项(46-49)
    uint    biClrImportant;  // 重要颜色索引的数目,0表示都重要(50-53)
} infoHeader;

像素信息结构体

typedef struct _PixelInfo {
    
	unsigned char rgbBlue;   //蓝色分量 (0-255)
	unsigned char rgbGreen;  //绿色分量 (0-255)
	unsigned char rgbRed;    //红色分量 (0-255)
	//unsigned char rgbReserved;// 保留,必须为0
} PixelInfo;

vs 2019 设置结构体对齐规则

在这里插入图片描述

示例图片

请添加图片描述

读取图像

int main()
{
    
	BITMAPFILEHEADER fileHeader;
	BITMAPINFOHEADER infoHeader;
	PixelInfo pixel;

	FILE* fp;
	fp = fopen("images/123456.bmp", "rb");
	//fp = fopen("images/b44.bmp", "rb");

	fread(&fileHeader, sizeof(fileHeader), 1, fp);
	fread(&infoHeader, sizeof(infoHeader), 1, fp);
	if (fileHeader.bfType != 19778)
	{
    
		printf("%s", "err");

	}
	printf("%d\n", fileHeader.bfType);
	printf("%d\n", fileHeader.bfSize);
	unsigned char b;
	unsigned char g;
	unsigned char r;
	unsigned char gray;
	int x, y, count = 0;
	int w = infoHeader.biWidth;
	int	h = infoHeader.biHeight;
	char info[] = "* ";
	int len = w * h + h + 1;
	char* out = (char*)malloc(len * sizeof(char));
	for (y = 0; y < h; y++)
	{
    
		for (x = 0; x < w; x++)
		{
    
			
			fread(&pixel, sizeof(pixel), 1, fp);
			//printf("%d, %d , %d \n", pixel.rgbRed, pixel.rgbGreen, pixel.rgbBlue);
			b = pixel.rgbBlue;
			g = pixel.rgbGreen;
			r = pixel.rgbRed;
			gray = (int)(r * 0.299 + g * 0.587 + b * 0.114);
			out[count++] = info[gray * strlen(info) / 256];
		}
		out[count++] = '\n';
	}
	out[count] = '\0';

	printf("%s\n", out);

	printf("helloWorld\n");
	return 0;
}

在这里插入图片描述
由于坐标系不同,需要修改读取像素顺序

int main3()
{
    
	BITMAPFILEHEADER fileHeader;
	BITMAPINFOHEADER infoHeader;
	PixelInfo pixel;

	FILE* fp;
	fp = fopen("images/123456.bmp", "rb");
	//fp = fopen("images/b44.bmp", "rb");

	fread(&fileHeader, sizeof(fileHeader), 1, fp);
	fread(&infoHeader, sizeof(infoHeader), 1, fp);
	if (fileHeader.bfType != 19778)
	{
    
		printf("%s", "err");

	}
	printf("%d\n", fileHeader.bfType);
	printf("%d\n", fileHeader.bfSize);
	unsigned char b;
	unsigned char g;
	unsigned char r;
	unsigned char gray;
	int x, y,count=0;
	int w = infoHeader.biWidth;
	int	h = infoHeader.biHeight;

	char info[] = "* ";
	int len = w * h + h+1;
	char* out = (char*)malloc(len * sizeof(char));

	for (y = h - 1; y >= 0; y--)
	{
    
		count = (w + 1) * y;
		for (x = 0; x < w; x++)
		{
    

			fread(&pixel, sizeof(pixel), 1, fp);
			b = pixel.rgbBlue;
			g = pixel.rgbGreen;
			r = pixel.rgbRed;
			gray = (int)(r * 0.299 + g * 0.587 + b * 0.114);
			out[count++] = info[gray * strlen(info) / 256];
		}
		
		out[count++] = '\n';
	}
	out[len-1] = '\0';


	printf("%s\n", out);

	printf("helloWorld\n");
	return 0;
}

在这里插入图片描述

图像变形

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

一个扫描行所占的字节数计算方法:
DataSizePerLine= (biWidth* biBitCount+31)/8;
// 一个扫描行所占的字节数
DataSizePerLine= DataSizePerLine/44; // 字节数必须是4的倍数
位图数据的大小(不压缩情况下):
DataSize= DataSizePerLine
biHeight;


int main()
{
    
	BITMAPFILEHEADER fileHeader;
	BITMAPINFOHEADER infoHeader;
	PixelInfo pixel;

	FILE* fp;
	fp = fopen("images/123456.bmp", "rb");
	//fp = fopen("images/b44.bmp", "rb");

	fread(&fileHeader, sizeof(fileHeader), 1, fp);
	fread(&infoHeader, sizeof(infoHeader), 1, fp);
	if (fileHeader.bfType != 19778)
	{
    
		printf("%s", "err");

	}
	printf("%d\n", fileHeader.bfType);
	printf("%d\n", fileHeader.bfSize);
	unsigned char b;
	unsigned char g;
	unsigned char r;
	unsigned char gray;
	int x, y,count=0;
	int w = infoHeader.biWidth;
	int	h = infoHeader.biHeight;
	int DataSizePerLine = (w * infoHeader.biBitCount + 31) / 8 / 4 * 4;   // 字节数必须是4的倍数 
	char info[] = "* ";
	int len = w * h + h+1;
	char* out = (char*)malloc(len * sizeof(char));
	for (y = h - 1; y >= 0; y--)
	{
    
		count = (w + 1) * y;
		for (x = 0; x < w; x++)
		{
    

			fread(&pixel, sizeof(pixel), 1, fp);
			b = pixel.rgbBlue;
			g = pixel.rgbGreen;
			r = pixel.rgbRed;
			gray = (int)(r * 0.299 + g * 0.587 + b * 0.114);
			out[count++] = info[gray * strlen(info) / 256];
		}
		if (w % 4 != 0)
		{
    
			fseek(fp, DataSizePerLine - 3 * w,SEEK_CUR);
		}
		out[count++] = '\n';
	}
	out[len-1] = '\0';


	printf("%s\n", out);

	printf("helloWorld\n");
	return 0;
}

参考链接 https://blog.csdn.net/qq_39400113/article/details/104750460
参考大牛视频 https://www.bilibili.com/video/BV1n5411N7T4?spm_id_from=333.999.0.0

原网站

版权声明
本文为[imxlw00]所创,转载请带上原文链接,感谢
https://blog.csdn.net/imxlw00/article/details/124926918