C语言读取bmp图像并做简单显示)
bmp文件格式
bmp文件大体上分为四个部分:
bmp文件构成 |
---|
位图文件头BITMAPFILEHEADER |
位图信息头BITMAPINFOHEADER |
调色板Palette |
实际的位图数据ImageDate |
第一部分为位图文件头,位图文件头长度固定,为14个字节。
typdef struct {
WORD bfType; //指定文件类型,必须是0x424d,即”BM”
DWORD bfSize; //指定文件大小
WORD bfReserved1; //保留字
WORD bfReserved2; //保留字
DWORD bfOffBits; //为文件头到实际的位图数据的偏移字节数,即上图前三部分和
}bitmapFileHeader;
第二部分为位图信息头,这个结构的长度也是固定的,为40个字节。
typedef struct {
DWORD biSize; //指这个机构的长度,为40
LONG biWidth; //指定图像的宽度,单位是像素
LONG biHeight; //指定图像的高度,单位是像素
WORD biPlanes; //平面数,必须为1,不用考虑
WORD biBitCount; //指定表示颜色是要用到的位数,常用值为1(黑白二色图),
//4(16色图),8(256色),24(真彩色图)(新的.bmp格式支持32位色)
DWORD biCompression; //指定位图是否压缩,有效的值为BI_RGB,BI_RLE8,BI_RLE4,BI_BITFILELDS
DWORD biSizeImage; //指定实际的位图数据占用的字节数,其实也可以从以下的公式计算出来:
//biSizeImage=bitWidth’*biHeight,bitWidth‘为大于等于bitWidth的4的倍数
LONG biXPelsPerMeter; //指定设备的水平分辨率,单位是每米的图像个数
LONG biYPelsPerMeter; //同上,垂直分辨率
DWORD biClrUsed; //指定本图像实际用到的颜色数,如果该值为零,则用到的颜色数为2^biBitCount
DWORD biClrImportant;// 指定本图象中重要的颜色数,如果该值为零,则认为所有的颜色都是重要的
}bitmapInfoHeader;
第三部分为调色板(真彩图像不需要调色版,bitmapInfoHeader后直接是数据)调色板实际是一个数组,共有biClrUsed个元素(如果该值为0,则有2^biBitCount个元素),数组中每个元素的类型是一个RGBQUAD结构,占四个字节,其定义如下:
typedef struct {
BYTE rgbBlue; //该颜色的蓝色分量
BYTE rgbGreen; //该颜色的绿色分量
BYTE rgbRed; //该颜色的红色分量
BYTE rgbReserved; //保留值
} RGBQUAD;
第四部分为实际图像数据
对于用到调色版的位图,图像数据就是该像素颜在调色板中的索引值。对于真彩图,图像数据就是实际的R、G、B值。
需要注意两点:
(1)每一行的字节数必须是4的整倍数,如果不是,则需要补齐。
(2)一般来说,.bmp文件的数据是从下到上,从左到右的。也就是说,从文件中最先读到的是图象最下面一行的左边第一个像素,然后是左边第二个像素……接下来是倒数第二行左边第一个像素,左边第二个像素……依次类推 ,最后得到的是最上面一行的最右一个像素。
读取bmp文件信息并展示
以24位bmp图像为例
定义数据结构:
typedef struct {
unsigned char bfType[2];
unsigned long bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned long bfOffBits;
}bitmapFileHeader;
typedef struct {
unsigned long biSize;
long biWidth;
long biHeight;
unsigned short biPlanes;
unsigned short biBitCount;
unsigned long biCompression;
unsigned long biSizeImage;
long biXPixPerMeter;
long biYPixPerMeter;
unsigned long biClrused;
unsigned long biClrImportant;
}bitmapInfoHeader;
读入文件头:
//仅展示,不用于实验
int readFileHeader(FILE *fp,bitmapFileHeader*bfHeader){
fseek(fp,0,SEEK_SET);
fread(bfHeader,sizeof(bitmapFileHeader),1,fp);
/*
int i;
printf("读入文件头:");
char*p=(char*)bfHeader;
for(i=0;i<sizeof(bitmapFileHeader);i++,p++){
printf("%02x ",*p);
}
printf("\n");
printf("文件头信息如下:\n");
printf("文件类型:%c%c\n",bfHeader->bfType[0],bfHeader->bfType[1]);
printf("文件大小: %d 字节\n",bfHeader->bfSize);
printf("位图数据偏移:%d\n",bfHeader->bfOffBits);
*/
return 0;
}
读信息头:
//仅展示,不用于实验
int readInfoHeader(FILE*fp,bitmapInfoHeader*biHeader){
fseek(fp,14,SEEK_SET);
fread(biHeader,sizeof(bitmapInfoHeader),1,fp);
/*
int i;
printf("读入位图信息头:\n");
char*p=(char*)biHeader;
for(i=0;i<sizeof(bitmapInfoHeader);i++,p++){
printf("%02x ",*p);
if(i%20==0&&i!=0)
printf("\n");
}
printf("\n");
printf("位图信息头信息如下:\n");
printf("bmp图像宽度:%d\n",biHeader->biWidth);
printf("bmp图像高度:%d\n",biHeader->biHeight);
printf("bmp图像颜色位数: %d\n",biHeader->biBitCount);
printf("bmp图像实际数据占用字节:%d\n",biHeader->biSizeImage);
*/
return 0;
}
读入bmp图像数据,并展示:
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#pragma pack(1) //这个选项挺重要,不加的话程序就会报错,原因参考
//https://blog.csdn.net/qq_44310495/article/details/109181857
typedef struct {
unsigned char bfType[2];
unsigned long bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned long bfOffBits;
}bitmapFileHeader;
typedef struct {
unsigned long biSize;
long biWidth;
long biHeight;
unsigned short biPlanes;
unsigned short biBitCount;
unsigned long biCompression;
unsigned long biSizeImage;
long biXPixPerMeter;
long biYPixPerMeter;
unsigned long biClrused;
unsigned long biClrImportant;
}bitmapInfoHeader;
int main(){
FILE *fp,*fp_txt;
if((fp=fopen("d:\Temp\\skull.bmp","rb"))==NULL){
perror("can not open file!");
return -1;
}
bitmapFileHeader bfHeader;
fread(&bfHeader,14,1,fp);
bitmapInfoHeader biHeader;
fread(&biHeader,40,1,fp);
int imSize=biHeader.biSizeImage;
int width=biHeader.biWidth;
int height=biHeader.biHeight;
int bitCount=biHeader.biBitCount;
fseek(fp,bfHeader.bfOffBits,SEEK_SET);
unsigned char*imageData=(unsigned char*)malloc(imSize*sizeof(unsigned char));
fread(imageData,imSize*sizeof(unsigned char),1,fp);
//图像为24位图像
int lineBytes=(bitCount*width+31)/32*4;//得到图像数据的bitwidth'
int i,j;
int r,g,b;
for(i=0;i<height;i++){ //对于每一行
for(j=0;j<width*3;j++){ //对于每一列
r=*(imageData+lineBytes*(height-1-i)+j); //从最后一行往上读
j++;
g=*(imageData+lineBytes*(height-1-i)+j);
j++;
b=*(imageData+lineBytes*(height-1-i)+j);
if(r==255&&g==255&&b==255) //模拟二值图像展示
printf(" ");
else
printf(".$");
}
printf("\n");
}
free(imageData);
fclose(fp);
getchar();
return 0;
}
代码效果展示: