位图文件(bitmap file)保存顺序如下:
位图头文件(BITMAPFILEHEADER) | 位图信息头文件(BITMAPINFOHEADER) | 调色板RGBQUAD(真彩色位图没有调色板) | 图像数据 |
##释义1##位图头文件(BITMAPFILEHEADER):
- typedef struct tagBITMAPFILEHEADER
- { /*14 bytes BMP文件头数据结构含有BMP文件的类型、
- 文件大小和位图起始位置等信息*/
- WORD bfType; /*2,位图文件的类型,必须为BM(0-1字节)*/
- DWORD bfSize; /*4,位图文件的大小,以字节为单位(2-5字节)*/
- WORD bfReserved1; /*2,位图文件保留字,必须为0(6-7字节)*/
- WORD bfReserved2; /*2,位图文件保留字,必须为0(6-7字节)*/
- DWORD bfOffBits; /*4,位图数据的起始位置,以相对于位图(10-13字节) */
- }BITMAPFILEHEADER,*PBITMAPFILEHEADER;
##释义2##位图信息头文件(BITMAPINFOHEADER):
- typedef struct tagBITMAPINFOHEADER
- { /*40 bytes BMP位图信息头数据用于说明位图的尺寸等信息。*/
- DWORD biSize; /*4,本结构所占用字节数(14-17字节) */
- LONG biWidth; /*4,位图的宽度,以像素为单位(18-21字节)*/
- LONG biHeight; /*4,位图的高度,以像素为单位(22-25字节) */
- WORD biPlanes; /*2,目标设备的级别,必须为1(26-27字节) */
- WORD biBitCount;/*2每个像素所需的位数,必须是1(双色),(28-29字节)
- 4(16色),8(256色)或24(真彩色)之一 */
- DWORD biCompression;/*4,位图压缩类型,必须是 0(不压缩),(30-33字节)
- 1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一 */
- DWORD biSizeImage; /*4,位图的大小,以字节为单位(34-37字节) */
- LONG biXPelsPerMeter;/*4,位图水平分辨率,每米像素数(38-41字节) */
- LONG biYPelsPerMeter; /*4,位图垂直分辨率,每米像素数(42-45字节) */
- DWORD biClrUsed;/*4, 位图实际使用的颜色表中的颜色数(46-49字节) */
- DWORD biClrImportant;/*4,位图显示过程中重要的颜色数(50-53字节) */
- } BITMAPINFOHEADER,*PBITMAPINFOHEADER;
##释义3##调色板RGBQUAD(真彩色位图没有调色板):
- typedef struct tagRGBQUAD
- { /*颜色表用于说明位图中的颜色,它有若干个表项
- ,每一个表项是一个RGBQUAD类型的结构,定义一种颜色。*/
- BYTE rgbBlue; /*蓝色的亮度(值范围为0-255)*/
- BYTE rgbGreen; /*绿色的亮度(值范围为0-255) */
- BYTE rgbRed;/*红色的亮度(值范围为0-255)*/
- BYTE rgbReserved; /*保留,必须为0 */
- }RGBQUAD;
##释义4##图像数据:
对于用到调色板的位图,图像数据就是该像素颜色在调色板中的索引值。对于真彩色图像,图像数据就是实际的R、G、B值,一个像素由3个字节24位组成,第一个字节表示B,第二个字节表示G,第三个字节表示R。
注意:BMP文件是从下到上、从左都右排列的。读文件时,最先读到的是图像的最下面一行的左边的第一个像素,最后读到的是最上面一行的最右一个像素。
rgbtogray.h文件:
*****************
- /* C语言读入图像 位图文件结构声明 */
- #ifndef BMP_H_INCLUDED
- #define BMP_H_INCLUDED
-
-
- typedef unsigned short WORD;//2*8=16
- typedef unsigned long DWORD;//4*8=32
- typedef long LONG;//4*8=32
- typedef unsigned char BYTE;//1*8=8
-
- #pragma pack(1)
- typedef struct tagBITMAPFILEHEADER
- { /*14 bytes BMP文件头数据结构含有BMP文件的类型、
- 文件大小和位图起始位置等信息*/
- WORD bfType; /*2,位图文件的类型,必须为BM(0-1字节)*/
- DWORD bfSize; /*4,位图文件的大小,以字节为单位(2-5字节)*/
- WORD bfReserved1; /*2,位图文件保留字,必须为0(6-7字节)*/
- WORD bfReserved2; /*2,位图文件保留字,必须为0(6-7字节)*/
- DWORD bfOffBits; /*4,位图数据的起始位置,以相对于位图(10-13字节) */
- }BITMAPFILEHEADER,*PBITMAPFILEHEADER;
- #pragma pack()
-
- #pragma pack(1)
- typedef struct tagBITMAPINFOHEADER
- { /*40 bytes BMP位图信息头数据用于说明位图的尺寸等信息。*/
- DWORD biSize; /*4,本结构所占用字节数(14-17字节) */
- LONG biWidth; /*4,位图的宽度,以像素为单位(18-21字节)*/
- LONG biHeight; /*4,位图的高度,以像素为单位(22-25字节) */
- WORD biPlanes; /*2,目标设备的级别,必须为1(26-27字节) */
- WORD biBitCount;/*2每个像素所需的位数,必须是1(双色),(28-29字节)
- 4(16色),8(256色)或24(真彩色)之一 */
- DWORD biCompression;/*4,位图压缩类型,必须是 0(不压缩),(30-33字节)
- 1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一 */
- DWORD biSizeImage; /*4,位图的大小,以字节为单位(34-37字节) */
- LONG biXPelsPerMeter;/*4,位图水平分辨率,每米像素数(38-41字节) */
- LONG biYPelsPerMeter; /*4,位图垂直分辨率,每米像素数(42-45字节) */
- DWORD biClrUsed;/*4, 位图实际使用的颜色表中的颜色数(46-49字节) */
- DWORD biClrImportant;/*4,位图显示过程中重要的颜色数(50-53字节) */
- } BITMAPINFOHEADER,*PBITMAPINFOHEADER;
- #pragma pack()
-
- #pragma pack(1)
- typedef struct tagRGBQUAD
- { /*颜色表用于说明位图中的颜色,它有若干个表项
- ,每一个表项是一个RGBQUAD类型的结构,定义一种颜色。*/
- 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时,没有颜色表项。*/
- #pragma pack()
-
- #pragma pack(1)
- typedef struct tagBITMAPIMAGE
- { /*位图信息头和颜色表组成位图信息*/
- BITMAPFILEHEADER bmiHeader; /*位图信息头*/
- RGBQUAD bmiColors[1]; /*颜色表*/
- }BITMAPIMAGE;
- #pragma pack()
-
- #endif
*********************************************************************************************
rgbtogray.h文件:
******************
- /*******************************************************************************/
- #include<stdio.h>
- #include<stdlib.h>
- #include<malloc.h>
- #include<string.h>
- /********************************************************************/
- //自定义的有关图像处理的头文件为rgbtogray.h
-
- //系统定义有关图像处理的头文件为windows.h
-
- //目前,引用系统的windows.h程序工作正常,但自己的头文件有问题,待改正!
-
- //最终实现引用自己的头文件rgbtogray.h
-
- //太棒了:头文件的问题终于解决了
-
- //#include<windows.h>
-
- #include "rgbtogray.h"
- /********************************************************************/
- /*****************************************************************************/
- //全局变量声明
-
- FILE * fpSrcBmpfile;//定义文件指针,用于读入和存储图像文件
-
- FILE * fpDestBmpfile;
-
- /******************************************************************************/
- //程序子函数声明
-
- void GetBmpHeader(PBITMAPFILEHEADER, PBITMAPINFOHEADER);//获得位图的文件头和信息头
-
- void ChangeBmpHeader(PBITMAPFILEHEADER, PBITMAPINFOHEADER, WORD);//改变位图的文件头和信息头
-
- void SetBmpHeader(const PBITMAPFILEHEADER, const PBITMAPINFOHEADER);//将修改后的文件头和信息头存入新位图文件
-
- void SetRGBQUAD();//建立颜色板并存入灰度图文件中
-
- int RgbToGray();//24位真色图转化为8位灰度图的主要函数
-
-
- /******************************************************************************/
- //主函数框架,菜单!(方便调用其他程序,以便拓展)
-
- void main()
- {
- int command=1;
- while(command)//菜单选项,可拓展
-
- {
- printf("\n*****************************Image Processing Menu***************************\n");
- printf("|--------1:RGB To GRAY transform!--------|\n");
- printf("|--------0:End!---------|\n");
- printf("*****************************************************************************\n");
- printf("Hint:Processor Number?\n");
- scanf("%d",&command);
- switch(command)
- {
- case 1:
- RgbToGray();
- break;
- case 0:
- printf("---Bye-bye---\n");
- break;
- default:
- printf("---Not defined number!\n");
- break;
- }
- }
- }
-
- /******************************************************************************/
- //函数体部分(副)
-
- void GetBmpHeader(PBITMAPFILEHEADER pbfheader, PBITMAPINFOHEADER pbiheader)
- {
- fread(pbfheader, sizeof(BITMAPFILEHEADER), 1,fpSrcBmpfile);
- fread(pbiheader, sizeof(BITMAPINFOHEADER), 1,fpSrcBmpfile);
- }
- void ChangeBmpHeader(PBITMAPFILEHEADER pbfheader, PBITMAPINFOHEADER pbiheader, WORD wType)
- {
- pbiheader->biBitCount = wType; // 24 或者 8
-
- pbiheader->biClrUsed = (wType == 24) ? 0 : 256;
- pbfheader->bfOffBits = 54 + pbiheader->biClrUsed * sizeof(RGBQUAD);
- pbiheader->biSizeImage = ((((pbiheader->biWidth * pbiheader->biBitCount) + 31) & ~31) / 8) * pbiheader->biHeight;
- pbfheader->bfSize = pbfheader->bfOffBits + pbiheader->biSizeImage;
- }
- void SetBmpHeader(const PBITMAPFILEHEADER pbfheader, const PBITMAPINFOHEADER pbiheader)
- {
- fwrite(pbfheader, sizeof(BITMAPFILEHEADER), 1, fpDestBmpfile);
- fwrite(pbiheader, sizeof(BITMAPINFOHEADER), 1, fpDestBmpfile);
- }
- void SetRGBQUAD()
- {
- int i;
- RGBQUAD rgbquad[256];
- for(i=0;i<256;i++) {
- rgbquad[i].rgbBlue = i;
- rgbquad[i].rgbGreen = i;
- rgbquad[i].rgbRed = i;
- rgbquad[i].rgbReserved = 0;
- }
- fwrite(rgbquad, 256 * sizeof(RGBQUAD), 1, fpDestBmpfile);
- }
- /******************************************************************************/
- //函数体部分(主)
-
- int RgbToGray()
- {
- LONG w,h;
- BYTE r,g,b;
- BYTE gray;
- BYTE count24,count8;
- BYTE Bmpnul=0;
-
- char SrcBmpfile[256];
- char DestBmpfile[256];
-
- BITMAPFILEHEADER bmfh; // bmp文件头
-
- BITMAPINFOHEADER bmih; // 位图信息头
-
- BYTE *data;
-
- memset(&bmfh, 0, sizeof(BITMAPFILEHEADER));//内存初始化
-
- memset(&bmih, 0, sizeof(BITMAPINFOHEADER));
- data=(BYTE *)malloc(3*sizeof(BYTE));
- if(!data)
- {
- printf("Error:Can not allocate memory .\n");
- free(data);
- return -1;
- }
-
- getchar();
- printf("Input the path of SrcBmpfile:\n");
- gets(SrcBmpfile);
-
- if((fpSrcBmpfile=fopen(SrcBmpfile,"rb"))==NULL)
- {
- printf("Error:Open the file of SrcBmpfile failed!\n");//输入源位图文件
-
- free(data);
- return -1;
- }
-
- rewind(fpSrcBmpfile);
- GetBmpHeader(&bmfh,&bmih);
- //ceshie_start
-
- printf("The contents in the file header of the BMP file:\n");
- printf("bfType:%ld\n",bmfh.bfType);
- printf("bfSize:%ld\n",bmfh.bfSize);
- printf("bfReserved1:%ld\n",bmfh.bfReserved1);
- printf("bfReserved2:%ld\n",bmfh.bfReserved2);
- printf("bfOffBits:%ld\n",bmfh.bfOffBits);
- printf("The contents in the info header:\n");
- printf("biSize:%ld\n",bmih.biSize);
- //ceshi_end
-
- if(bmfh.bfType!=0x4D42)
- {
- printf("Error:This file is not bitmap file!\n");
- free(data);
- return -1;
- }
- if(bmih.biBitCount!=24)
- {
- printf("Error:This bmpfile is not 24bit bitmap!\n");
- free(data);
- return -1;
- }
- if(bmih.biCompression!=0)
- {
- printf("Error:This 8bit bitmap file is not BI_RGB type!\n");
- free(data);
- return -1;
- }
-
- printf("Input the path of the DestBmpfile:\n");//输入目标位图文件
-
- gets(DestBmpfile);
-
- if((fpDestBmpfile=fopen(DestBmpfile,"wb"))==NULL)
- {
- printf("Error:Open the file of DestBmpfile failed!\n");
- free(data);
- return -1;
- }
-
- ChangeBmpHeader(&bmfh,&bmih,8);
- SetBmpHeader(&bmfh,&bmih);
- SetRGBQUAD();
-
- count24=(4-(bmih.biWidth*3)%4)%4;
- count8=(4-(bmih.biWidth)%4)%4;
-
- for(h=bmih.biHeight-1;h>=0;h--)
- {
- for(w=0;w<bmih.biWidth;w++)
- {
- fread(data,3,1,fpSrcBmpfile);
- if(feof(fpSrcBmpfile))
- {
- printf("Error:Read Pixel data failed!\n");
- free(data);
- return -1;
- }
- b=*data;
- g=*(data+1);
- r=*(data+2);
- gray=(299*r+587*g+114*b)/1000;
- //if(gray>120)gray=250;
-
- fwrite(&gray,sizeof(gray),1,fpDestBmpfile);
- }
- fseek(fpSrcBmpfile,count24,SEEK_CUR);
- fwrite(&Bmpnul,1,count8,fpDestBmpfile);
- }
- printf("Hint:Convert RGB To GRAY Successfully!\n");
- free(data);//释放内存空间
-
-
- fclose(fpDestBmpfile);//关闭文件指针
-
- fclose(fpSrcBmpfile);
- return 0;
- }
- /******************************************************************************/
*******************************************************************************************
#prama pack(n)
结构体定义;
#prama pack()
##释义##:关于struct的使用方法:
struct是一种复合数据类型,其构成元素既可以是基本数据类型(如int、long、float等)的变量,也可以是一些复合数据类型(如array、struct、union等)的数据单元。对于结构体,编译器会自动进行成员变量的对齐,以提高运算效率。缺省情况下,编译器为结构体的每个成员按其自然对界(natural alignment)条件分配空间。各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同。
自然对界是指按结构体的成员中size最大的成员对齐。
#pragma pack规定的对齐长度,实际使用的规则是:
结构,联合,或者类的数据成员,第一个放在偏移为0的地方,以后每个数据成员的对齐,按照#pragma pack指定的数值和结构体的自然对齐长度中比较小的那个进行。
也就是说,当#pragma pack的值等于或超过所有数据成员长度的时候,这个值的大小将不产生任何效果。
结构体的对齐,按照结构体中size最大的数据成员和#pragma pack指定值之间,较小的那个进行。
*******************************************************************************************
参考资料:
书目:《Visual C++实用图像处理》;
网站:
www.cprogramming.com(解决了结构体定义的相关问题 ,即
#prama pack)