使用 C 语言读取位图
2010-09-16 16:04:43| 分类: C 语言 | 标签:c 语言处理位图 |字号 订阅
一、位图文件结构
位图文件由三部分组成:文件头 + 位图信息 + 位图像素数据
1、位图文件头。位图文件头主要用于识别位图文件。以下是位图文件头结构的定义:
typedef struct tagBITMAPFILEHEADER { // bmfh
WORD
bfType;
DWORD
bfSize;
WORD
WORD
bfReserved1;
bfReserved2;
DWORD
bfOffBits;
} BITMAPFILEHEADER;
其中的 bfType 值应该是“BM”(0x4d42),标志该文件是位图文件。bfSize 的值是位图文件
的大小。
2、位图信息中所记录的值用于分配内存,设置调色板信息,读取像素值等。
以下是位图信息结构的定义:
typedef struct tagBITMAPINFO {
BITMAPINFOHEADER
bmiHeader;
RGBQUAD
bmiColors[1];
} BITMAPINFO;
可见位图信息也是由两部分组成的:位图信息头 + 颜色表
2.1 位图信息头。位图信息头包含了单个像素所用字节数以及描述颜色的格式,此外还包括
位图的宽度、高度、目标设备的位平面数、图像的压缩格式。以下是位图信息头结构的定义:
typedef struct tagBITMAPINFOHEADER{ // bmih
DWORD
biSize;
LONG
LONG
WORD
WORD
biWidth;
biHeight;
biPlanes;
biBitCount
DWORD
biCompression;
DWORD
biSizeImage;
LONG
LONG
biXPelsPerMeter;
biYPelsPerMeter;
DWORD
biClrUsed;
DWORD
biClrImportant;
} BITMAPINFOHEADER;
下表是对结构体当中各个成员的说明:
结构成员
biSize
biWidth
biHeight
biplanes
结构 BITMAPINFOHEADER 的字节数,即 sizeof(BITMAPINFOHEADER)*
说 明
以像素为单位的图像宽度*
以像素为单位的图像长度*
目标设备的位平面数
biBitCount
每个像素的位数*(1)
biCompression
图像的压缩格式(这个值几乎总是为 0)
biSizeImage
以字节为单位的图像数据的大小(对 BI_RGB 压缩方式而言)
biXPelsPermeter 水平方向上的每米的像素个数
biYpelsPerMeter 垂直方向上的每米的像素个数
biClrused
调色板中实际使用的颜色数(2)
biClrImportant 现实位图时必须的颜色数(3)
说明:*是需要加以注意的部分,因为它们是我们在进行位图操作时经常参考的变量
(1)对于每个像素的字节数,分别有一下意义:
0,用在 JPEG 格式中
1,单色图,调色板中含有两种颜色,也就是我们通常说的黑白图片
4,16 色图
8,256 色图,通常说的灰度图
16,64K 图,一般没有调色板,图像数据中每两个字节表示一个像素,5 个或 6 个位表示一
个 RGB 分量
24,16M 真彩色图,一般没有调色板,图像数据中每 3 个字节表示一个像素,每个字节表
示一个 RGB 分量
32,4G 真彩色,一般没有调色板,每 4 个字节表示一个像素,相对 24 位真彩图而言,加
入了一个透明度,即 RGBA 模式
(2)这个值通常为 0,表示使用 biBitCount 确定的全部颜色,例外是使用的颜色树木小于
制定的颜色深度的颜色数目的最大值。
(3)这个值通常为 0,表示所有的颜色都是必需的
2.2 颜色表。颜色表一般是针对 16 位一下的图像而设置的,对于 16 位和 16 位以上的图像,
由于其位图像素数据中直接对对应像素的 RGB(A)颜色进行描述,因而省却了调色板。而对
于 16 位一下的图像,由于其位图像素数据中记录的只是调色板索引值,因而需要根据这个
索引到调色板去取得相应的 RGB(A)颜色。颜色表的作用就是创建调色板。
颜色表是由颜色表项组成的,颜色表项结构的定义如下:
typedef struct tagRGBQUAD { // rgbq
BYTE
BYTE
BYTE
BYTE
rgbBlue;
rgbGreen;
rgbRed;
rgbReserved;
} RGBQUAD;
其中需要注意的问题是,RGBQUAD 结构中的颜色顺序是 BGR,而不是平常的 RGB。
3、位图数据。最后,在位图文件头、位图信息头、位图颜色表之后,便是位图的主体部分:
位图数据。根据不同的位图,位图数据所占据的字节数也是不同的,比如,对于 8 位位图,
每个字节代表了一个像素,对于 16 位位图,每两个字节代表了一个像素,对于 24 位位图,
每三个字节代表了一个像素,对于 32 位位图,每四个字节代表了一个像素。
下面附上代码:
// Bmp.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
int ReadFileHeader(char *filepath,BITMAPFILEHEADER *bmfh);
int ReadInfoHeader(char *filepaht,BITMAPINFOHEADER *bmih);
int ReadPixelData(char *filepath);
DWORD GetLineBytes(int width,int bitCount);
//BYTE *imgData;
//int i=ReadPixelData("E:\\1\\1.bmp");
int i=ReadPixelData("D:\\2.bmp");
scanf("%d");
return 0;
}
//读入文件头
int ReadFileHeader(char *filepath,BITMAPFILEHEADER *bmfh)
{
FILE *fp;
//打开文件
fp=fopen(filepath,"rb");
if(!fp)
{ //如果打开失败
printf("Can not open the file:%s\n",filepath);
return -1;
}
//读入 bfType
if(fread(&bmfh->bfType,sizeof(WORD),1,fp)!=1)
{
printf("Can not read bfType in the file header.\n");
fclose(fp);
return -1;
}
//读入 bfSize
if(fread(&bmfh->bfSize,sizeof(DWORD),1,fp)!=1)
{
printf("Can not read bfSize in the file header.\n");
fclose(fp);
return -1;
}
//读入 bfReserved1
if(fread(&bmfh->bfReserved1,sizeof(WORD),1,fp)!=1)
{
printf("Can not read bfReserved1 in the file header.\n");
fclose(fp);
return -1;
}
//读入 bfReserved2
if(fread(&bmfh->bfReserved2,sizeof(WORD),1,fp)!=1)
{
printf("Can not read bfReserved2 in the file header.\n");
fclose(fp);
return -1;
}
//读入 bfOffBits
if(fread(&bmfh->bfOffBits,sizeof(DWORD),1,fp)!=1)
{
printf("Can not read bfOffBits in the file header.\n");
fclose(fp);
return -1;
}
//关闭文件指针
fclose(fp);
return 0;
}
//读入信息头
int ReadInfoHeader(char *filepath,BITMAPINFOHEADER *bmih)
{
FILE *fp;
//打开文件
fp=fopen(filepath,"rb");
if(!fp)
{
printf("Can not open the file:%s\n",filepath);
return -1;
}
//使文件指针跳过文件头(14 字节)
fseek(fp,14,SEEK_SET);
//读入 biSize
if(fread(&bmih->biSize,sizeof(DWORD),1,fp)!=1)
{
printf("Can not read biSize in the info header.\n");
fclose(fp);
return -1;
}
//读入 biWidth
if(fread(&bmih->biWidth,sizeof(LONG),1,fp)!=1)
{
printf("Can not read biWidth in the info header.\n");
fclose(fp);
return -1;
}
//读入 biHeight
if(fread(&bmih->biHeight,sizeof(LONG),1,fp)!=1)
{
printf("Can not read biHeight in the info header.\n");
fclose(fp);
return -1;
}
//读入 biPlanes
if(fread(&bmih->biPlanes,sizeof(WORD),1,fp)!=1)
{
printf("Can not read biPlanes in the info header.\n");
fclose(fp);
return -1;
}
//读入 biBitCount
if(fread(&bmih->biBitCount,sizeof(WORD),1,fp)!=1)
{
printf("Can not read biBitCount in the info header.\n");
fclose(fp);
return -1;
}
//读入 biCompression
if(fread(&bmih->biCompression,sizeof(DWORD),1,fp)!=1)
{
printf("Can not read biCompression in the info header.\n");
fclose(fp);
return -1;
}
//读入 biSizeImage
if(fread(&bmih->biSizeImage,sizeof(DWORD),1,fp)!=1)
{
printf("Can not read biSizeImage in the info header.\n");
fclose(fp);
return -1;
}
//读入 biXPelsPerMeter
if(fread(&bmih->biXPelsPerMeter,sizeof(LONG),1,fp)!=1)
{
printf("Can not read biXPelsPerMeter in the info header.\n");
fclose(fp);
return -1;
}
//读入 biYPelsPerMeter
if(fread(&bmih->biYPelsPerMeter,sizeof(LONG),1,fp)!=1)
{
printf("Can not read biYPelsPerMeter in the info header.\n");
fclose(fp);
return -1;
}
//读入 biClrUsed
if(fread(&bmih->biClrUsed,sizeof(DWORD),1,fp)!=1)
{
printf("Can not read biClrUsed in the info header.\n");
fclose(fp);
return -1;
}
//读入 biClrImportant
if(fread(&bmih->biClrImportant,sizeof(DWORD),1,fp)!=1)
{
printf("Can not read biClrImportant in the info header.\n");
fclose(fp);
return -1;
}
//关闭文件
fclose(fp);
return 0;
}
//读取像素数据
int ReadPixelData(char *filepath)
{
BITMAPINFOHEADER bmih;
BITMAPFILEHEADER bmfh;
BYTE *imgdata;
FILE *fp;
int n;
int width;
int height;
int bitCount;
long biSizeImage;
int i;
int j;
long a[256]={0};
int p;
DWORD dwLineBytes;
//读入文件头
n=ReadFileHeader(filepath,&bmfh);
if(n==-1)
{
printf("Can not read the file header of BMP file.\n");
return -1;
}
//读入信息头
n=ReadInfoHeader(filepath,&bmih);
if(n==-1)
{
printf("Can not read the info header of BMP file.\n");
return -1;
}
//获取信息头有用信息
width=bmih.biWidth;
height=bmih.biHeight;
bitCount=bmih.biBitCount;
biSizeImage=bmih.biSizeImage;
dwLineBytes=GetLineBytes(width,bitCount);
//printf("%ld\n",dwLineBytes);
printf("位图宽:%ld\n",width);
printf("位图高:%ld\n",height);
printf("位图位数:%d\n",bitCount);
printf("位图所占字节数:%ld\n",biSizeImage);
fp = fopen(filepath,"rb");
if(!fp)
{
printf("Can not open the file:%s\n",filepath);
return -1;