bmp格式解析(转)

  位图文件(Bitmap-File,BMP)格式是Windows采用的图像文件存储格式,在Windows环境下运行的所有图像处理软件都支持这种格式。Windows 3.0以前的BMP位图文件格式与显示设备有关,因此把它称为设备相关位图(device-dependent bitmap,DDB)文件格式。Windows 3.0以后的BMP位图文件格式与显示设备无关,因此把这种BMP位图文件格式称为设备无关位图(device-independent bitmap,DIB)格式,目的是为了让Windows能够在任何类型的显示设备上显示BMP位图文件。

      位图文件可看成由4个部分组成:位图文件头(bitmap-file header)、位图信息头(bitmap-information header)、彩色表(color table)和定义位图的字节阵列。可以文本打开方式打开BMP文件。

(1)文件头信息块

0000-0001:文件标识,为字母ASCII码“BM”,42 4D。亦或者与19778相比较。
0002-0005:整个文件大小,单位字节。
0006-0009:保留,每字节以“00”填写。
000A-000D:记录图像数据区的起始位置。从文件开始到位图数据(bitmap data)之间的偏移量。
(2)图像描述信息块

000E-0011:图像描述信息块的大小,常为28H。
0012-0015:图像宽度。以像素为单位。
0016-0019:图像高度。以像素为单位。
001A-001B:图像的plane总数(恒为1)。
001C-001D:记录像素的位数,很重要的数值,图像的颜色数由该值决定。1 - Monochrome bitmap,4 - 16 color bitmap,8 - 256 color bitmap,F - 16位位图,18 - 24bit (true color) bitmap,20 - 32位位图。

001E-0021:数据压缩方式(数值位0:不压缩;1:8位压缩;2:4位压缩;3:Bitfields压缩)。
0022-0025:图像区数据的大小。单位字节,该数必须是4的倍数。
0026-0029:水平每米有多少像素,在设备无关位图(.DIB)中,每字节以00H填写。
002A-002D:垂直每米有多少像素,在设备无关位图(.DIB)中,每字节以00H填写。
002E-0031:此图像所用的颜色数。

0032-0035:指定重要的颜色数。当该域的值等于颜色数时(或者等于0时),表示所有颜色都一样重要。

     如上,整个位图的信息头共54字节,每个位置有特定含义。

(3)颜色表(调色板)

      颜色表的大小根据所使用的颜色模式而定,其中每4字节表示一种颜色,并以B(蓝色)、G(绿色)、R(红色)、alpha(32位位图的透明度值,一般不需要)。对于24-位真彩色图象就不使用彩色表(同样也包括16位、和32位位图),因为位图中的RGB值就代表了每个象素的颜色;而对于使用索引颜色的,则需要较大的调色板。

(4)图像数据区

       颜色表接下来为位图文件的图像数据区,在此部分记录着每点像素对应的颜色索引号,其记录方式也随颜色模式而定,既2色图像每点占1位(8位为1字节);16色图像每点占4位(半字节);256色图像每点占8位(1字节);真彩色图像每点占24位(3字节)。所以,整个数据区的大小也会随之变化。究其规律而言,可的出如下计算公式:图像数据信息大小=(图像宽度*图像高度*记录像素的位数)/8。扫描行是由底向上存储的,这就是说,阵列中的第一个字节表示位图左下角的像素,而最后一个字节表示位图右上角的像素。

       然而,未压缩的图像信息区的大小。除了真彩色模式外,其余的均大于或等于数据信息的大小。这是为什么呢?原因有两个:
BMP文件记录一行图像是以字节为单位的。因此,就不存在一个字节中的数据位信息表示的点在不同的两行中。也就是说,设显示模式位16色,在每个字节分配两个点信息时,如果图像的宽度为奇数,那么最后一个像素点的信息将独占一个字节,这个字节的后4位将没有意义。接下来的一个字节将开始记录下一行的信息。

(5)实例分析

     如下的4x4像素的位图

,经过UE打开成16进制文件后,显示如下:

我们可以通过查找对应的数据位来验证上面所分析的各部分信息。这样就比较清楚了。

(6)位图操作常使用的结构体

      位图头文件结构:

typedef struct tagBITMAPFILEHEADER{
     short bfType;
     int bfSize;
     short bfReserved1;
     short bfReserved2;
     int bfOffBits;
}BITMAPFILEHEADER, *PBITMAPFILEHEADER;

      位图信息结构:

typedef struct tagBITMAPINFOHEADER{
      int biSize;
      int biWidth;
      int biHeight;
      short biPlanes;
      short biBitCount;
      int biCompression;
      int biSizeImage;
      int biXPelsPerMeter;
      int biYPelsPerMeter;
      int biClrUsed;
      int biClrImportant;
}BITMAPINFOHEADER,*PBITMAPINFOHEADER;

参考原文:http://blog.csdn.net/jsjjms/archive/2007/04/18/1568615.aspx

参考原文:http://blog.csdn.net/dl_hum/archive/2006/04/24/675301.aspx

BMP之二:转成RAW文件及应用

 

  RAW文件是位图的图像数据,根据不同的BMP格式它的内容和使用场合都有不同。比如在嵌入式系统中,显示LOGO要使用BMP图,只需要往映射地址放入像素的RGB数据即可实现。以下举一个DOS程序实例,把16位BMP转成十六进制RAW数据。

(1)主函数。因为main可以利用argv带参数,可处理同一路径下的具体文件。

[cpp] view plaincopy

  1. int main(int argc, char *argv[]) 
  2. FILE *fp_s=NULL; 
  3.     BITMAPFILEHEADER biFileHeader; 
  4.     BITMAPINFOHEADER biInfoHeader; 
  5.     PBITMAPFILEHEADER pbiFileHeader= &biFileHeader; 
  6.     PBITMAPINFOHEADER pbiInfoHeader= &biInfoHeader; 
  7. if(!(fp_s=fopen(argv[1],"r+b")))    //以二进制可读方式打开流文件
  8.     { 
  9.         printf("打开文件不成功!"); 
  10. return 1; 
  11.     } 
  12. //读取文件头
  13. if(!(GetBitmapHeader(fp_s, pbiFileHeader, pbiInfoHeader))) 
  14.     { 
  15.         printf("读取文件头不成功!"); 
  16. return 1; 
  17.     } 
  18. //用读取的数据头生成文件
  19. if(!(GenerateIFile(pbiFileHeader,pbiInfoHeader,fp_s, argv))) 
  20.     { 
  21.         printf("生成i文件失败!"); 
  22. return 1; 
  23.     } 
  24. if(fclose(fp_s)==EOF) 
  25.         printf("关闭失败!"); 
  26. return 0; 

(2)获取头文件信息函数

[cpp] view plaincopy

  1. int GetBitmapHeader(FILE *fp, BITMAPFILEHEADER *bfhp, BITMAPINFOHEADER *bihp) 
  2. //设置文件读写位置为开头
  3. if((fseek(fp,0,SEEK_SET)==-1)) 
  4.     { 
  5.         puts("GetBitmapHeader定位失败!"); 
  6. return 0; 
  7.     } 
  8. //读取fileheader
  9. if(!(fread(bfhp,sizeof(BITMAPFILEHEADER),1,fp))) 
  10.     { 
  11.         puts("GetBitmapHeader读取fileheader失败!"); 
  12. return 0; 
  13.     } 
  14. //读取fileheader后的位置
  15. long i;  
  16. if((i=ftell(fp))==-1L) 
  17.     { 
  18.         puts("GetBitmapHeader读取文件指针位置失败!"); 
  19. return 0; 
  20.     } 
  21. else
  22.         printf("当前位置为:%d\n",i); 
  23. //
  24. if(!(fread(bihp, sizeof(BITMAPINFOHEADER), 1, fp))) 
  25.     { 
  26.         puts("读取infoheader失败!"); 
  27. return 0; 
  28.     } 
  29. if((i=ftell(fp))==-1L) 
  30.     { 
  31.         puts("读取文件指针位置失败!"); 
  32. return 0; 
  33.     } 
  34. else
  35.         printf("当前位置为:%d\n",i); 
  36. return 1; 

(3)生成raw文本文件

[cpp] view plaincopy

  1. int GenerateIFile(PBITMAPFILEHEADER bfhp, PBITMAPINFOHEADER bihp, FILE *fp_s, char **stringp) 
  2. //检查是倒序文件还是正序文件
  3. if( bihp->biHeight > 0 ) 
  4.         puts("GenerateIFile该文件为倒序文件!"); 
  5. else
  6.     { 
  7.         puts("GenerateIFile该文件为正序文件!"); 
  8. return 0; 
  9.     } 
  10. //检查是否压缩,只处理BI_BITFIELDS的情况
  11. if( bihp->biCompression == BI_BITFIELDS )        //#define BI_BITFIELDS 3
  12.         puts("GenerateIFile该文件为BI_BITFIELDS压缩格式!"); 
  13. else
  14.     { 
  15.         printf("BI_BITFIELDS=%d\n", bihp->biCompression); 
  16.         puts("GenerateIFile该文件不为BI_BITFIELDS压缩格式!"); 
  17. return 0; 
  18.     } 
  19. //检查文件类型
  20. if(bfhp->bfType==19778)      //'M'  'B'
  21.         puts("该文件为bmp格式!"); 
  22. else
  23.     { 
  24.         puts("该文件不为bmp格式!"); 
  25. return 0; 
  26.     } 
  27. //检查像素位数
  28. if(bihp->biBitCount==16) 
  29.         puts("该bmp文件为16位!"); 
  30. else
  31.     { 
  32.         puts("该bmp文件不为16位!"); 
  33. return 0; 
  34.     } 
  35.     printf("the start of the image area is %d\n",bfhp->bfOffBits); 
  36.     printf("the size of the image area is %d\n",bihp->biSizeImage); 
  37.     printf("the height of the image is %d\n", bihp->biHeight); 
  38.     printf("the width of the image is %d\n", bihp->biWidth); 
  39. //开辟一个数据缓冲区,存储image区的数据
  40. short *pimage=NULL; 
  41.     pimage=(short *)malloc((bihp->biHeight * bihp->biWidth)*2); 
  42. if(pimage== NULL) 
  43.     { 
  44.         printf("分配缓冲区失败!"); 
  45. return 0; 
  46.     } 
  47.     fseek(fp_s, bfhp->bfOffBits, SEEK_SET);  //定位文件指针到数据区
  48.     printf("   %d\n",ftell(fp_s)); 
  49. if(!(fread(pimage, 1, bihp->biHeight * bihp->biWidth*2, fp_s)))  //填充缓冲区
  50.     { 
  51.         printf("填充数据缓存失败!"); 
  52. return 0; 
  53.     } 
  54. //重列顺序并且生成文件
  55. if(!(RerangeData(bfhp, bihp, pimage, stringp))) 
  56.     { 
  57.         printf("RerangeData函数失败!"); 
  58. return 0; 
  59.     } 
  60. //释放缓冲区
  61.     free(pimage); 
  62. return 1; 

BMP之三:转成RAW文件及应用

 

(4)生成I文件

[cpp] view plaincopy

  1. int RerangeData(PBITMAPFILEHEADER pbfh, PBITMAPINFOHEADER pbih, short *buffer, 
  2. char **strp) 
  3. FILE *fp_d=NULL; 
  4. int width=pbih->biWidth; 
  5. int height=pbih->biHeight; 
  6. int i; 
  7. int j; 
  8. int k; 
  9. //BMP存储是倒序的,交换数据使buffer内的数据正序
  10. short swap; 
  11. for(i=0,k=height-1; i<=height/2 && k>=height/2 ; i++, k--) 
  12.     { 
  13. for(j=0; j<width; j++)  
  14.         { 
  15.             swap=*(buffer+i*width+j); 
  16.             *(buffer+i*width+j)=*(buffer+k*width+j); 
  17.             *(buffer+k*width+j)=swap; 
  18.         } 
  19.     } 
  20. //生成i文件
  21. char *pbmp=NULL;                //重新生成的i文件名
  22. printf("ttt%d,%s,%s \r\n",strp,*strp,*(strp+1));    //main所带的参数:命令行本身,命令行参数
  23. char *p_ifilename= *(strp+1);       //指向BMP源文件名的指针
  24. printf("in RerangeData,%s   \r\n",p_ifilename);  
  25.     pbmp= strstr(p_ifilename, ".bmp");      //得到除BMP后缀之外的文件名字
  26. if(pbmp==NULL) 
  27.     { 
  28.         printf("该文件后缀不是.bmp,请确认该文件是bmp文件且后缀为.bmp"); 
  29. return 0; 
  30.     } 
  31.     * (pbmp+1)='i'; 
  32.     * (pbmp+2)='\0';        //新的文件名
  33.     fp_d=fopen(p_ifilename, "w+");  //新建待保存数据的文件
  34. if(fp_d==NULL) 
  35.     { 
  36.         puts("保存文件失败!"); 
  37. return 0; 
  38.     } 
  39. for(i=0; i<height; i++)   //将buffer内的像素按RGB565存于16位数据中
  40.     { 
  41.         fprintf(fp_d,"/*line%d*/ ", i); //格式化输出到一个流文件中
  42. for(j=0; j<width; j++) 
  43.         { 
  44.             fprintf(fp_d, "0x"); 
  45.             Data2Str(*(buffer+i*width+j),fp_d);  //转化pixel为RGB565
  46.         } 
  47.         fprintf(fp_d,"\n"); 
  48.     } 
  49. if(fclose(fp_d)==EOF) 
  50.     { 
  51.         puts("关闭文件失败!"); 
  52. return 0; 
  53.     } 
  54. return 1; 

(5)数字转字符串输出到文本

[cpp] view plaincopy

  1. void Data2Str(short pixel,FILE *fp) 
  2.     unsigned short const mask[4] = {0xf, 0xf0, 0xf00, 0xf000}; 
  3.     unsigned short masked; 
  4. for(int i=3; i>=0; i--)  //16位一个像素
  5.     { 
  6.         masked=pixel&mask[i]; 
  7.         masked=masked>>4*i; 
  8. if(masked>15) 
  9.             puts("wrong!\n"); 
  10. //printf("%d\n",masked);
  11. switch(masked) 
  12.         { 
  13. case 0: 
  14.                 fprintf(fp,"0"); 
  15. break; 
  16. case 1: 
  17.                 fprintf(fp,"1"); 
  18. break; 
  19. case 2: 
  20.                 fprintf(fp,"2"); 
  21. break; 
  22. case 3: 
  23.                 fprintf(fp,"3"); 
  24. break; 
  25. case 4: 
  26.                 fprintf(fp,"4"); 
  27. break; 
  28. case 5: 
  29.                 fprintf(fp,"5"); 
  30. break; 
  31. case 6: 
  32.                 fprintf(fp,"6"); 
  33. break; 
  34. case 7: 
  35.                 fprintf(fp,"7"); 
  36. break; 
  37. case 8: 
  38.                 fprintf(fp,"8"); 
  39. break; 
  40. case 9: 
  41.                 fprintf(fp,"9"); 
  42. break; 
  43. case 10: 
  44.                 fprintf(fp,"A"); 
  45. break; 
  46. case 11: 
  47.                 fprintf(fp,"B"); 
  48. break; 
  49. case 12: 
  50.                 fprintf(fp,"C"); 
  51. break; 
  52. case 13: 
  53.                 fprintf(fp,"D"); 
  54. break; 
  55. case 14: 
  56.                 fprintf(fp,"E"); 
  57. break; 
  58. case 15: 
  59.                 fprintf(fp,"F"); 
  60. break; 
  61. default: fprintf(fp,"x"); 
  62.         } 
  63.     } 
  64.     fprintf(fp,",");    //每个像素后一个分隔符

最终该软件会把特定的BMP位图数据转成相应的数据,行列与BMP像素完全对应。实例如下:

执行结果如下:

转成的文本如下:

/*line0*/ 0x001F,0x001F,0x001F,0x001F,0x001F,0x001F,
/*line1*/ 0x001F,0x001F,0x001F,0x001F,0x001F,0x001F,
/*line2*/ 0x001F,0x001F,0x001F,0x001F,0x001F,0x001F,
/*line3*/ 0x001F,0x001F,0x001F,0x001F,0x001F,0x001F,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值