c语言实现bmp文件读入到内存中(二维数组)

bmp文件的格式:

包括4部分。第一部分是文件头,占用14字节;第二部分是信息头,占用40字节;第三部分是调色板,这是可选的部分;第四部分是像素信息。

各部分的字段的详细信息可见下表:

 

bmp文件的结构体的定义:

​
#pragma once
#include <stdio.h>
#include <stdlib.h>

typedef unsigned int UINT; //4 bytes
typedef unsigned short USHORT; //2 bytes
typedef signed int INT; //4 bytes
typedef unsigned char BYTE; //1 byte

//pragma用来取消默认对齐,如果没有,所占大小为16字节 
#pragma pack(push)
#pragma pack(1)
//文件头 
typedef struct BITMAPFILEHEADER{
	USHORT bFileType;//文件类型,有固定值 
	UINT bFileSize;//文件的字节大小 
	USHORT bReserved1;//保留1 
	USHORT bReserved2;//保留2 
	UINT bPixelDataOffset;//文件头起始到位图数据之间的偏移量 
}BITMAPFILEHEADER;
#pragma pack(pop)

//信息头 
typedef struct BITMAPINFOHEADER{
	UINT bHeaderSize;//信息头的字节大小,有固定值 
	INT bImageWidth;//图像的宽度(单位:像素) 
	INT bImageHeight;//图像的高度(单位:像素) 
	USHORT bPlanes;//色层 
	USHORT bBitsPerPixel;//像素位数 
	UINT bCompression;//图像压缩,有固定值 
	UINT bImageSize;//图像大小,有固定值 
	INT bXpixelsPerMeter;//x轴的每米像素数 
	INT bYpixelsPerMeter;//y轴的每米像素数 
	INT bTotalColors;//调色板里颜色数 
	UINT bImportantColors;//重要颜色数,ignored 
}BITMAPINFOHEADER;

//RGB 
typedef struct RGBDATA{
	BYTE blue;
	BYTE green;
	BYTE red;
}RGBDATA;

//调色板 
typedef struct RGBQUAD {
    BYTE    rgbBlue;
    BYTE    rgbGreen;
    BYTE    rgbRed;
    BYTE    rgbReserved;
}RGBQUAD;

​

接下来是方法:

#include "bmpModel.h"
#include <string.h>

//图像的宽度(像素) 
int width = 0;
//图像的高度(像素) 
int height = 0;


//打开bmp文件 
FILE* openImage(char* filename, char* mode){
	FILE* fp;
	//准备文件的打开模式,给打开模式一个合适的值 
	if(strcmp(mode,"r") == 0){
		mode="rb";
	}else if(strcmp(mode,"w") == 0){
		mode="ab";
	}else{
		fprintf(stderr,"文件打开模式%s使用错误",mode);
		
		return 0;
	}
	//bmp文件打开 
	if((fp = fopen(filename,mode)) == 0){
		fprintf(stderr,"文件打开%s失败",filename);
		return 0;
	}
	return fp;
}


//关闭bmp文件 
void closeImage(FILE* fp){
	fclose(fp);//关闭文件 
	free(fp);//释放指针 
}


//读取bmp文件的文件头 
BITMAPFILEHEADER* readFileHeader(FILE* fp){
	BITMAPFILEHEADER* fileHead = (BITMAPFILEHEADER*)malloc(sizeof(BITMAPFILEHEADER));
	//错误处理 
	if(fileHead == NULL){
		fprintf(stderr,"文件头内存分配失败");
	}
	if(fread(fileHead,sizeof(BITMAPFILEHEADER),1,fp) != 1){
		fprintf(stderr,"文件头读取失败");
	} 
	
	return fileHead;
}


//读取bmp文件的信息头 
BITMAPINFOHEADER* readInfoHeader(FILE* fp){
	BITMAPINFOHEADER* infoHead = (BITMAPINFOHEADER*)malloc(sizeof(BITMAPINFOHEADER));
	//错误处理
	if(infoHead == NULL) {
		fprintf(stderr,"信息头内存分配失败");
	}
	
	if(fread(infoHead,sizeof(BITMAPINFOHEADER),1,fp) != 1){
		fprintf(stderr,"信息头读取失败");
	}
	
	return infoHead;
} 


// 读取bmp文件的像素信息,创建二维数组,并存入二维数组 
RGBDATA** readBmpData(FILE *fp){
	int i = 0;
	int j = 0;
	
	RGBDATA** data;//存储图像像素信息的二维数组 
	BYTE* temp;//一个字节,用于放图像对齐的填充数据 
	
	//读取文件头 
	BITMAPFILEHEADER* fileHead = readFileHeader(fp);
	//读取信息头 
	BITMAPINFOHEADER* infoHead = readInfoHeader(fp);
	
	printf("fileHeader size=%d\n",sizeof(BITMAPFILEHEADER)); 
	printf("infoHeader size=%d\n",sizeof(BITMAPINFOHEADER)); 
	//printf("RGBDATA size=%d",sizeof(RGBDATA)); 
	
	//获取图像的宽高 
	width = infoHead->bImageWidth;
	height = infoHead->bImageHeight;
	
	
	//给二维数组分配内存 
	data = (RGBDATA**)malloc(sizeof(RGBDATA*)*height);
	temp = (BYTE*)malloc(sizeof(BYTE));
	
	if(data ==NULL){
		fprintf(stderr,"像素内存分配失败");
		return 0;
	}
	
	int k = 0;
	for(; k < height; k++){
		data[k] = (RGBDATA*)malloc(sizeof(RGBDATA)*width);
		
		if(data[k] == NULL){
			fprintf(stderr,"像素内存分配失败");
			return 0;
		}
	}
	//如果有调色板,读取它 
	if(fileHead->bPixelDataOffset > 54){
		RGBQUAD* quad = (RGBQUAD*)malloc(sizeof(RGBQUAD));
		
		if(quad == NULL){
		   	fprintf(stderr,"调色板内存分配失败");
		}
		if(fread(quad,sizeof(RGBQUAD),1,fp) != 1){
			fprintf(stderr,"调色板读取失败");
		}
	} 
	//把像素数据存储到二维数组中 
	for(;i < height; i++){
		for(j = 0; j < width; j++){
			fread(&data[i][j],sizeof(RGBDATA),1,fp);
		}
		//处理对齐问题。
		//bmp文件存储要求每行字节数必须是4的倍数 
		//这里把超过width的且不是4的倍数的数据取出 
		int num = j * 3; 
		while(num%4 != 0){
			fread(temp,sizeof(BYTE),1,fp);
			num++;
		}
	}
	
	return data;
}

int main(){
	FILE* fp;
	//bmp文件打开 
	fp = openImage("bmp1.bmp","r");
	//读取像素信息,存入二维数组arr 
	RGBDATA** arr = readBmpData(fp);
	int i = 0;
	int j = 0;
	printf("\n");
	printf("以下为从上到下的RGB顺序:\n");
	
	//打印,调整了展示顺序 
	for(i = height - 1; i >= 0 ; i--){
		for(j = 0; j < width; j++){
			printf("[%3d,%3d,%3d]\t",arr[i][j].red,arr[i][j].green,arr[i][j].blue);
		}
		printf("\n");
	}
	//关闭文件 
	closeImage(fp);
	return 0;
}

注意点:

1.需要用#pragma取消结构体的默认对齐,否则结构体不是规定的14字节。

2.判断是否有调色板,使用BITMAPFILEHEADER.bPixelDataOffset参数,这个参数表示从文件信息开头到pixel data区的位移,如果没有调色板,则该值为固定的14+40=54字节。

3.bmp文件存储格式要求每行的字节数必须是4的倍数。这被称为dword对齐(dword是一种数据类型,长度为4个字节)。如果图像的一行字节数不能被4整除,就需要在每行的末尾补齐0以达到规定。因此需要处理掉可能补0的地方:在存入二维数组时,对于超过图像宽度的部分,如果不能整除4,指针就再移动一个字节,直到可以整除4为止。

4.输出需要注意:

    文件的颜色格式为b,g,r的顺序,不是常说的RGB顺序。

    图像的像素信息是从左至右,从下到上存储的,二维数组中最后一行对应图像的第一行……

  • 5
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
将一个bitmap转换成C语言数组可以按照以下步骤进行: 1. 使用图片处理软件打开需要转换的bitmap文件,并将其转化为灰度图像。 2. 将灰度图像转换为黑白图像,即将所有非黑色像素点设置为白色。 3. 使用C语言编写一个程序,读取经过处理后的黑白图像文件,并将像素值转换成C语言数组的元素。 4. 将每个像素点的值存储在C语言数组。 下面是一个示例代码: ```c #include <stdio.h> #include <stdlib.h> int main() { FILE *fp; unsigned char *bitmap; unsigned char *bmp_array; int width, height; int i, j, k; fp = fopen("image.bmp", "rb"); if(fp == NULL) { printf("Cannot open file.\n"); return 1; } fseek(fp, 18, SEEK_SET); fread(&width, sizeof(int), 1, fp); fread(&height, sizeof(int), 1, fp); fseek(fp, 54, SEEK_SET); bitmap = (unsigned char*) malloc(sizeof(unsigned char) * width * height); bmp_array = (unsigned char*) malloc(sizeof(unsigned char) * width * height); fread(bitmap, sizeof(unsigned char), width * height, fp); fclose(fp); for(i = 0; i < height; i++) { for(j = 0; j < width; j++) { k = i * width + j; bmp_array[k] = bitmap[k * 3]; } } free(bitmap); free(bmp_array); return 0; } ``` 上述代码,我们首先打开了一个名为“image.bmp”的bitmap文件,并读取了该文件的宽度和高度。 然后,我们使用malloc函数动态分配了两个数组——bitmap和bmp_array,分别用于存储bitmap文件的像素值和C语言数组的元素。 接着,我们从文件读取了像素值,并将每个像素点的红色、绿色、蓝色值的平均值存储在了bmp_array数组。 最后,我们释放了动态分配的内存空间,结束了程序运行。 需要注意的是,这里的代码仅适用于24位真彩色的bitmap文件。如果需要转换其他类型的bitmap文件,需要根据文件格式进行相应修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值