BMP文件是Windows系统标准图像文件格式,是一种将内存中的图像数据不经过压缩直接按位存盘的文件格式,所以被称为位图(bitmap),文件扩展名为BMP.
BMP文件被分为以下四个部分:位图文件头(Bitmap File Header),位图信息头(Bitmap Info Header),颜色表(Color Map)和位图数据。灰度图像和彩色图像是其中最主要的两种图片表现方式。灰度图像只表达图像的亮度信息而没有颜色信息,图像中每个像素点用一个量化的离散数值表示其灰度级,通常用1个字节存储,可描述出0~255的灰度等级(人眼可分辨的灰度等级也就几十)。8位的灰度图需要颜色板,256个选项的颜色表记录了灰度图的灰度值,灰度图中的位图数据值仅是颜色表的索引。彩色图像包含图像的亮度信息和颜色信息,每个像素使用3个字节,3个字节分别由(RGB)的三基色组成,该类型亦被称为24位真彩色(24位图像不需要颜色表)。
位图文件头(Bitmap File Header)的结构:
typedef struct tagBITMAPFILEHEADER
{
WORD bfType; //位图文件类型,必须是0x424D
DWORD bfSize; //位图文件大小
WORD bfReserved1; //Windows保留字
WORD bfReserved2; //Windows保留字
DWORD bfOffBits; //从文件头到位图数据的偏移字节数
}BITMAPFILEHEADER,FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;
位图信息头(Bitmap Info Header)的结构:
typedef struct tagBITMAPINFOHEADER
{
DWORD biSize; //该结构的长度,大小为40个字节
LONG biWidth; //位图的宽度,以像素为单位
LONG biHeight; //位图的高度,以像素为单位
WORD biPlanes; //目标设备的级别,必须是1
WORD biBitCount; //每个像素所占的位数
DWORD biCompression; //位图压缩类型
DWORD biSizeImage; //位图数据所占的字节数
LONG biXPelsPerMeter; //目标设备水平分辨率
LONG biYPelsPerMeter; // 目标设备垂直分辨率
DWORD biClrUsed; //位图实际所用的颜色数
DWORD biClrImportant; //位图显示过程中重要的颜色数
}BITMAPINFOHEADER,FAR *LPBITMAPINFOHEADER,*PBITMAPINFOHEADER;
颜色表(Color Map)的结构:
typedef struct tagRGBQUAD
{
BYTE rgbBlue; //颜色的蓝色分量
BYTE rgbGreen; //颜色的绿色分量
BYTE rgbRed; //颜色的红色分量
ByTE rgbReserved; //保留字节
}RGBQUAD;
位图数据:
Windows规定每行的字节数必须是4的倍数,不足4的倍数要补足;如果一幅图像宽为Width,每像素所占用bit个比特,那么该行的字节数=(Width*bit/8+3)/4*4。(+3和/4是为了应对不足4的倍数的情况)。如果该图的高为Height,那么该图的实际拥有的字节数=高X每行字节数=Height*(Width*bit/8+3)/4*4。
BMP文件的数据是从图像左下角开始逐行载入内存(从左到右,从下到上),像素中的RGB基元是按照BGR排列(如一个a[3]数组表示24位的像素,那么a[0]=blue分量的值,a[1]=green分量的值,a[2]=red分量的值)
本文系转载,以前为c++程序。以下的程序由自己拿c语言改过:
BMP文件的载入和保存:
#include "Windows.h"
#include <stdio.h>
BOOL LoadBmp(char *);
BOOL SaveBmp(char *BmpName);
unsigned char *pBmpBuffer; //bmp像素指针
int BmpWidth; //位图的宽度
int BmpHeight; //位图的高度
RGBQUAD *ColorTable; //颜色表的指针
int BmpBit; //每个像素占用位数
void main()
{
char Load[]="lena24.bmp";
int i,j,k;
int LineByte;
char Save[]="lena0.BMP";
LoadBmp(Load);
printf("the height of the picture:/n");
scanf("%d",&BmpWidth);
printf("the bit of the per pixcel:/n");
scanf("%d",&BmpBit);
LineByte=(BmpWidth*BmpBit/8+3)/4*4; //图像每行的字节数
//将图像的左下角1/4部分置成黑色
if(BmpBit==8) //如果是8位图
{
for(i=0;i<BmpHeight/2;i++)
for(j=0;j<BmpWidth/2;j++)
*(pBmpBuffer+i*LineByte+j)=0;
}
if(BmpBit==24) //如果是24位图
{
for(i=0;i<BmpHeight/2;i++)
for(j=0;j<BmpWidth/2;j++)
for(k=0;k<3;k++)
*(pBmpBuffer+i*LineByte+j*3+k)=0;
}
SaveBmp(Save);
free(pBmpBuffer); //释放pBmpBuffer所指向的内存
if(BmpBit==8) //如果有颜色表,释放指向颜色表的内存
free(ColorTable);
}
BOOL LoadBmp(char *BmpName) //从硬盘中读取BMP文件进内存
{
BITMAPINFOHEADER head;
FILE *fp=fopen(BmpName,"rb");
int LineByte=0;
if(fp==0)
{
return 0;
}
fseek(fp,sizeof(BITMAPFILEHEADER),0); //跳过图像文件头结构BITMAPFILEHEADER
fread(&head,sizeof(BITMAPINFOHEADER),1,fp); //读取文件信息头进入head结构体
BmpWidth=head.biWidth; //导入图像的宽
BmpHeight=head.biHeight; //导入图像的高
BmpBit=head.biBitCount; //每个像素所占位数
LineByte=(BmpWidth*BmpBit/8+3)/4*4; //一个扫描行所占真实字节数
if(BmpBit==8) //如果是8位图
{
ColorTable=malloc(sizeof(RGBQUAD)*256); //申请颜色表需要的空间,读颜色表进内存
fread(ColorTable,sizeof(RGBQUAD),256,fp);
}
pBmpBuffer= (unsigned char*)malloc(sizeof(unsigned char)*LineByte*BmpHeight); //申请图像像素所用空间
fread(pBmpBuffer,1,LineByte*BmpHeight,fp); //读像素数据进内存
fclose(fp);
return 1;
}
BOOL SaveBmp(char *BmpName) //保存bmp文件
{
FILE *fp;
BITMAPINFOHEADER head;
BITMAPFILEHEADER fileHead;
int colorTablesize=0;
int LineByte=0;
if(!pBmpBuffer) //如果指针为空,退出
{
return 0;
}
if(BmpBit==8)
{
colorTablesize=1024;
}
LineByte=(BmpWidth*BmpBit/8+3)/4*4; //计算图像每行的像素
fp=fopen(BmpName,"wb"); //打开待被写入的BMP文件
if(fp==0) return 0;
//保存文件头
fileHead.bfType=0x4D42;
fileHead.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+colorTablesize+LineByte*BmpHeight;
fileHead.bfReserved1=0;
fileHead.bfReserved2=0;
fileHead.bfOffBits=54+colorTablesize;
fwrite(&fileHead,sizeof(BITMAPFILEHEADER),1,fp);
//保存信息头
head.biBitCount=BmpBit;
head.biClrImportant=0;
head.biClrUsed=0;
head.biCompression=0;
head.biHeight=BmpHeight;
head.biPlanes=1;
head.biSize=40;
head.biSizeImage=LineByte*BmpHeight;
head.biWidth=BmpWidth;
head.biXPelsPerMeter=0;
head.biYPelsPerMeter=0;
fwrite(&head,sizeof(BITMAPINFOHEADER),1,fp);
if(BmpBit==8) //如果存在颜色表
fwrite(ColorTable,sizeof(RGBQUAD),256,fp);
fwrite(pBmpBuffer,BmpHeight*LineByte,1,fp); //保存像素
fclose(fp);
return 1;
}