bmp格式图像的读取

本文介绍了BMP格式图像的读取,包括bmp文件头、位图信息头和颜色表三个部分的详细解析,并提供了相关数据结构的定义。通过理解这些内容,可以实现对BMP图像的读取操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一直想搞明白bmp格式今天弄了一下,附上代码一篇,只有读取,还没搞到存储部分,如果哪位哥们有欢迎交流。

bmp文件的格式:

分为四个部分:bmp文件头,位图信息头,颜色表和数据部分。

1、bmp文件头

BMP文件头数据结构含有BMP文件的类型、文件大小和位图起始位置等信息。

其结构定义如下:

typedef struct tagBITMAPFILEHEADER
{
       WORD bfType; // 位图文件的类型,必须为BM
       DWORD bfSize; // 位图文件的大小,以字节为单位
       WORD bfReserved1; // 位 图文件保留字,必须为0
       WORD bfReserved2; // 位 图文件保留字,必须为0
       DWORD bfOffBits; // 位图数据的起始位置,以相对于位图
       // 文件头的偏移量表示,以字节为单位
} BITMAPFILEHEADER;
2、位图信息头

BMP位图信息头数据用于说明位图的尺寸等信息。
typedef struct tagBITMAPINFOHEADER{
       DWORD biSize;    // 本结构所占用字节数
       LONG biWidth;     // 位图的宽度,以像素为单位
       LONG biHeight;    // 位图的高度,以像素为单位
       WORD biPlanes;   // 目标设备的级别,必须为1
       WORD biBitCount // 每个像素所需的位数,必须是1(双色),
                                   // 4(16色),8(256色)或24(真彩色)之一
       DWORD biCompression; // 位图压缩类型,必须是 0(不压缩),
                                   // 1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一
       DWORD biSizeImage; // 位图的大小,以字节为单位
       LONG biXPelsPerMeter;// 位图水平分辨率,每米像素数
       LONG biYPelsPerMeter;// 位图垂直分辨率,每米像素数
       DWORD biClrUsed;      // 位图实际使用的颜色表中的颜色数
       DWORD biClrImportant;// 位图显示过程中重要的颜色数
} BITMAPINFOHEADER;
3、颜色表

是单色、16色、256色图像文件所特有的,相对应的调色板大小是2、16、和256,调色板以4字节为单位,每4个字节存放一个颜色值。图像的数据是指向调色板的索引。

    颜色表用于说明位图中的颜色,它有若干个表项,每一个表项是一个RGBQUAD类型的结构,定义一种颜色。RGBQUAD结构的定义如下:


typedef struct tagRGBQUAD {
       BYTE rgbBlue;      // 蓝色的亮度(值范围为0-255)
       BYTE rgbGreen;   // 绿色的亮度(值范围为0-255)
       BYTE rgbRed;      // 红色的亮度(值范围为0-255)
       BYTE rgbReserved;// 保留,必须为0
} RGBQUAD;
颜色表中RGBQUAD结构数据的个数有biBitCount来确定:
当biBitCount=1,4,8时,分别有2,16,256个表项;
当biBitCount=24时,没有颜色表项。
位图信息头和颜色表组成位图信息,BITMAPINFO结构定义如下:
typedef struct tagBITMAPINFO {
       BITMAPINFOHEADER bmiHeader; // 位图信息头
       RGBQUAD bmiColors[1];                 // 颜色表
} BITMAPINFO;

4、数据部分

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

当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;






// r_w_p_bmp.cpp : 定义控制台应用程序的入口点。

//


#include "stdafx.h"
#include <string.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include "unistd.h"
#define WIDTHBYTES(bits) (((bits)+31)/32*4)


typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long DWORD;
typedef long LONG;


//位图文件头信息结构定义
//其中不包含文件类型信息(由于结构体的内存结构决定,要是加了的话将不能正确读取文件信息)
typedef struct tagBITMAPFILEHEADER {
DWORD bfSize; //文件大小
WORD bfReserved1; //保留字,不考虑
WORD bfReserved2; //保留字,同上
DWORD bfOffBits; //实际位图数据的偏移字节数,即前三个部分长度之和
} BITMAPFILEHEADER;


//信息头BITMAPINFOHEADER,也是一个结构,其定义如下:
typedef struct tagBITMAPINFOHEADER{
//public:
DWORD biSize; //指定此结构体的长度,为40
LONG biWidth; //位图宽
LONG biHeight; //位图高
WORD biPlanes; //平面数,为1
WORD biBitCount; //采用颜色位数,可以是1,2,4,8,16,24,新的可以是32
DWORD biCompression; //压缩方式,可以是0,1,2,其中0表示不压缩
DWORD biSizeImage; //实际位图数据占用的字节数
LONG biXPelsPerMeter; //X方向分辨率
LONG biYPelsPerMeter; //Y方向分辨率
DWORD biClrUsed; //使用的颜色数,如果为0,则表示默认值(2^颜色位数)
DWORD biClrImportant; //重要颜色数,如果为0,则表示所有颜色都是重要的
} BITMAPINFOHEADER;


//调色板Palette,当然,这里是对那些需要调色板的位图文件而言的。24位和32位是不需要调色板的。
//(似乎是调色板结构体个数等于使用的颜色数。)


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




void showBmpHead(BITMAPFILEHEADER* pBmpHead)
{
printf("位图文件头:\n");
printf("文件大小:%d\n",pBmpHead->bfSize);
printf("保留字:%d\n",pBmpHead->bfReserved1);
printf("保留字:%d\n",pBmpHead->bfReserved2);
printf("实际位图数据的偏移字节数:%d\n",pBmpHead->bfOffBits);


}


void showBmpInforHead(tagBITMAPINFOHEADER* pBmpInforHead)
{
printf("位图信息头:\n");
printf("结构体的长度:%d\n",pBmpInforHead->biSize);
printf("位图宽:%d\n",pBmpInforHead->biWidth);
printf("位图高:%d\n",pBmpInforHead->biHeight);
printf("biPlanes平面数:%d\n",pBmpInforHead->biPlanes);
printf("biBitCount采用颜色位数:%d\n",pBmpInforHead->biBitCount);
printf("压缩方式:%d\n",pBmpInforHead->biCompression);
printf("biSizeImage实际位图数据占用的字节数:%d\n",pBmpInforHead->biSizeImage);
printf("X方向分辨率:%d\n",pBmpInforHead->biXPelsPerMeter);
printf("Y方向分辨率:%d\n",pBmpInforHead->biYPelsPerMeter);
printf("使用的颜色数:%d\n",pBmpInforHead->biClrUsed);
printf("重要颜色数:%d\n",pBmpInforHead->biClrImportant);
}


void showRgbQuan(tagRGBQUAD* pRGB)
{
printf("(%-3d,%-3d,%-3d) ",pRGB->rgbRed,pRGB->rgbGreen,pRGB->rgbBlue);


}






int _tmain(int argc, char * argv[])
{


//argv[1] = "E:\\charging\\r_w_p_bmp1\r_w_p_bmp\\cs_1.bmp";
//char output_file[256];
//FILE *file;
//memset(output_file,0,sizeof(output_file));
//strcpy(output_file,argv[1]);
//file=fopen(output_file,"w+"); //打开一个文件进行读写操作。
//printf("file %d",file);


FILE *stream;
stream = fopen("cs2.bmp", "w+");






BITMAPFILEHEADER bitHead;
BITMAPINFOHEADER bitInfoHead;
FILE* pfile,* pfile1;


char strFile[50];
printf("输入bpm文件:\n");
scanf("%s",strFile);


pfile = fopen(strFile,"rb");//打开文件
pfile1 = fopen(strFile,"rb");//打开文件


if(pfile!=NULL)
{
printf("成功.\n");
//读取位图文件头信息
WORD fileType;
fread(&fileType,1,sizeof(WORD),pfile);
if(fileType != 0x4d42)
{
printf("file is not .bmp file!");
return -1;
}
fread(&bitHead,1,sizeof(tagBITMAPFILEHEADER),pfile);


showBmpHead(&bitHead);
printf("\n\n");


//读取位图信息头信息
fread(&bitInfoHead,1,sizeof(BITMAPINFOHEADER),pfile);
showBmpInforHead(&bitInfoHead);
printf("\n");
}
else
{
printf("打开失败!\n");
return -1;
}


tagRGBQUAD *pRgb ;


if(bitInfoHead.biBitCount < 24)//有调色板
{
//读取调色盘结信息
long nPlantNum = long(pow(2,double(bitInfoHead.biBitCount))); // Mix color Plant Number;
pRgb=(tagRGBQUAD *)malloc(nPlantNum*sizeof(tagRGBQUAD));
memset(pRgb,0,nPlantNum*sizeof(tagRGBQUAD));
int num = fread(pRgb,4,nPlantNum,pfile);


printf("Color Plate Number: %d\n",nPlantNum);


printf("颜色板信息:\n");
for (int i =0; i<nPlantNum;i++)
{
if (i%5==0)
{
printf("\n");
}
showRgbQuan(&pRgb[i]);


}
printf("\n");


}


int width = bitInfoHead.biWidth;
int height = bitInfoHead.biHeight;
//分配内存空间把源图存入内存
int l_width = WIDTHBYTES(width* bitInfoHead.biBitCount);//计算位图的实际宽度并确保它为32的倍数
BYTE *pColorData=(BYTE *)malloc(height*l_width);
memset(pColorData,0,height*l_width);
long nData = height*l_width;


//把位图数据信息读到数组里
fread(pColorData,1,nData,pfile);


//将位图数据转化为RGB数据
tagRGBQUAD* dataOfBmp;
dataOfBmp = (tagRGBQUAD *)malloc(width*height*sizeof(tagRGBQUAD));//用于保存各像素对应的RGB数据
memset(dataOfBmp,0,width*height*sizeof(tagRGBQUAD));


if(bitInfoHead.biBitCount<24)//有调色板,即位图为非真彩色
{
int k;
int index = 0;
if (bitInfoHead.biBitCount == 1)
{
for(int i=0;i<height;i++)
for(int j=0;j<width;j++)
{
BYTE mixIndex= 0;
k = i*l_width + j/8;//k:取得该像素颜色数据在实际数据数组中的序号
//j:提取当前像素的颜色的具体值
mixIndex = pColorData[k];
switch(j%8)
{
case 0:
mixIndex = mixIndex<<7;
mixIndex = mixIndex>>7;
break;
case 1:
mixIndex = mixIndex<<6;
mixIndex = mixIndex>>7;
break;
case 2:
mixIndex = mixIndex<<5;
mixIndex = mixIndex>>7;
break;


case 3:
mixIndex = mixIndex<<4;
mixIndex = mixIndex>>7;
break;
case 4:
mixIndex = mixIndex<<3;
mixIndex = mixIndex>>7;
break;


case 5:
mixIndex = mixIndex<<2;
mixIndex = mixIndex>>7;
break;
case 6:
mixIndex = mixIndex<<1;
mixIndex = mixIndex>>7;
break;


case 7:
mixIndex = mixIndex>>7;
break;
}


//将像素数据保存到数组中对应的位置
dataOfBmp[index].rgbRed = pRgb[mixIndex].rgbRed;
dataOfBmp[index].rgbGreen = pRgb[mixIndex].rgbGreen;
dataOfBmp[index].rgbBlue = pRgb[mixIndex].rgbBlue;
dataOfBmp[index].rgbReserved = pRgb[mixIndex].rgbReserved;
index++;


}
}


if(bitInfoHead.biBitCount==2)
{
for(int i=0;i<height;i++)
for(int j=0;j<width;j++)
{
BYTE mixIndex= 0;
k = i*l_width + j/4;//k:取得该像素颜色数据在实际数据数组中的序号
//j:提取当前像素的颜色的具体值
mixIndex = pColorData[k];
switch(j%4)
{
case 0:
mixIndex = mixIndex<<6;
mixIndex = mixIndex>>6;
break;
case 1:
mixIndex = mixIndex<<4;
mixIndex = mixIndex>>6;
break;
case 2:
mixIndex = mixIndex<<2;
mixIndex = mixIndex>>6;
break;
case 3:
mixIndex = mixIndex>>6;
break;
}


//将像素数据保存到数组中对应的位置
dataOfBmp[index].rgbRed = pRgb[mixIndex].rgbRed;
dataOfBmp[index].rgbGreen = pRgb[mixIndex].rgbGreen;
dataOfBmp[index].rgbBlue = pRgb[mixIndex].rgbBlue;
dataOfBmp[index].rgbReserved = pRgb[mixIndex].rgbReserved;
index++;




}
}
if(bitInfoHead.biBitCount == 4)
{
for(int i=0;i<height;i++)
for(int j=0;j<width;j++)
{
BYTE mixIndex= 0;
k = i*l_width + j/2;
mixIndex = pColorData[k];
if(j%2==0)
{//低
mixIndex = mixIndex<<4;
mixIndex = mixIndex>>4;
}
else
{//高
mixIndex = mixIndex>>4;
}


dataOfBmp[index].rgbRed = pRgb[mixIndex].rgbRed;
dataOfBmp[index].rgbGreen = pRgb[mixIndex].rgbGreen;
dataOfBmp[index].rgbBlue = pRgb[mixIndex].rgbBlue;
dataOfBmp[index].rgbReserved = pRgb[mixIndex].rgbReserved;
index++;


}


}
if(bitInfoHead.biBitCount == 8)
{
for(int i=0;i<height;i++)
for(int j=0;j<width;j++)
{
BYTE mixIndex= 0;


k = i*l_width + j;


mixIndex = pColorData[k];


dataOfBmp[index].rgbRed = pRgb[mixIndex].rgbRed;
dataOfBmp[index].rgbGreen = pRgb[mixIndex].rgbGreen;
dataOfBmp[index].rgbBlue = pRgb[mixIndex].rgbBlue;
dataOfBmp[index].rgbReserved = pRgb[mixIndex].rgbReserved;
index++;






}
}
if(bitInfoHead.biBitCount == 16)
{
for(int i=0;i<height;i++)
for(int j=0;j<width;j++)
{
WORD mixIndex= 0;


k = i*l_width + j*2;
WORD shortTemp;
shortTemp = pColorData[k+1];
shortTemp = shortTemp<<8;


mixIndex = pColorData[k] + shortTemp;


dataOfBmp[index].rgbRed = pRgb[mixIndex].rgbRed;
dataOfBmp[index].rgbGreen = pRgb[mixIndex].rgbGreen;
dataOfBmp[index].rgbBlue = pRgb[mixIndex].rgbBlue;
dataOfBmp[index].rgbReserved = pRgb[mixIndex].rgbReserved;
index++;
}
}
}
else//位图为24位真彩色
{
int k;
int index = 0;
for(int i=0;i<height;i++)
for(int j=0;j<width;j++)
{
k = i*l_width + j*3;
dataOfBmp[index].rgbRed = pColorData[k+2];
dataOfBmp[index].rgbGreen = pColorData[k+1];
dataOfBmp[index].rgbBlue = pColorData[k];
index++;
}
}




////printf("像素数据信息:\n");
////for (int i=0; i<width*height; i++)
////{
//// if (i%5==0)
//// {
//// printf("\n");
//// }
//// showRgbQuan(&dataOfBmp[i]);
////}




// /////////////////////
// //写文件  fread(&fileType,1,sizeof(WORD),pfile);
// fseek(stream,0L,0); //图像文件类型
// fwrite(&pfile1,sizeof(WORD),1,stream);
// fseek(stream,2L,0); //图像文件大小
// fwrite(&(bitHead.bfSize),sizeof(DWORD),1,stream);
// printf("bitHead.bfSize:%d\n",bitHead.bfSize);


//flush(file);//函数同步
//fclose(stream);


 //   //////////////////


fclose(pfile);
if (bitInfoHead.biBitCount<24)
{
free(pRgb);
}
free(dataOfBmp);
free(pColorData);
printf("\n");
return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值