Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1676023
  • 博文数量: 311
  • 博客积分: 7778
  • 博客等级: 少将
  • 技术积分: 4186
  • 用 户 组: 普通用户
  • 注册时间: 2009-11-09 19:59
个人简介

蓝点工坊(http://www.bluedrum.cn) 创始人,App和嵌入式产品开发。同时也做相应培训和外包工作。 详细介绍 http://pan.baidu.com/s/1y2g88

文章存档

2012年(3)

2011年(115)

2010年(170)

2009年(23)

分类: 嵌入式

2011-05-08 00:32:19

Andrew Huang 转载请注明作者及网址
 
 
  位图(bmp)是所有图像格式最接近RGB的格式,因此它的处理最为简单。所以一般用来做RGB编程样例,但是在BMP虽简单,但是也充满不少细节,因此刚开处理时碰到不少问题.
  BMP格式是由MS和IBM共同发起的格式,用于MS的操作系统和IBM OS/2上,但是用得较少.因此成BMP几乎成了MS的单独使用标准格式.在其的操作系统都使用这种格式,其他图像实际最后都要转换成BMP显示.
 
1.BMP文件格式分析
 
1.1 BMP文件分区
  如果图像是小于等于8bpp格式的(包括1bpp,2bpp,4bpp,8bpp几种).BMP文件分为四大块 
 
 
   如果是16bpp/18bpp/24bpp/32bpp的位图,本身格式只分为三大块
1.2.BMP文件头和信息头定义
  .BMP有如下定义.
 
 
这里注意几个细节.
   1.文件头的定义不是字节对齐的,因此用结构去读位图文件头时,必须取消字节对齐
   2.里面所有整数,int32(int )或int16 (short)都是采用小端字节序的,因此用结构读取整数时,必须考虑字节序转换.
 
   3.对于显示位图最重要几个数据是
        bfOffBits :真正RGB数据区相于文件头的的偏移量
        Width:     图像宽度
        Height:    图像高度
        biBitCont: BPP的值.
 
1.3 RGB数据区的排列
 
  BMP的RGB数据区是排列非常奇怪,在最开始编程时忽略这一点,导致的显示图像总不正常.
 
 1.首先每一个点的数据是占用三个字节,并且是按 B,G,R的顺序倒排.
 2.另外整个数据区也是按行倒排的,即文件数据区中第一行存的是最后一行的数据!,而文件最后一行的数据才是第一行数据. 这个数据区第一个点实际上是左下角的点.而最后一个点实际上
 
  1.4 调色板数据处理
     
2.Frame Buffer显示位图
 
 
  首先们处理最简单的情况,即当前FB的bpp和高度和宽度正好与当前位图图像一致.主要来看显示算法.
 
   2.1 文件头/信息头的读取.
      对于BMP信息的读取.有两种方法,一种是定两个结构把文件头和信息头读出来,这一种必须考虑字节序和字节对齐,但代码可读性强.
    另外一种是把四个最关键的信息直接用偏移量来读取,这种无需考虑字节序和字节对齐,但是代码可读性差.关键是看编程如何处理.
  
  2.1.1  按结构来读数据
 
这里定义了BmpFileHeader和BmpInfoHeader,其中用了#pragma pack(1) 表示取消字节对齐,在大部分编译器下,包括GCC都可以使用.
 
 

#pragma pack(1)
 struct _BmpFileHeader
{
    unsigned short    bfType;         //Specifies the file type. It must be BM

    unsigned long     bfSize;     //Specifies the size, in bytes, of the bitmap file

    unsigned long     bfReserved1;     //Reserved; must be zero

    unsigned long     bfRebfOffBits;     //数据区偏移量 Specifies the offset, in bytes, from the BITMAPFILEHEADER structure to the bitmap bits

};

typedef struct _BmpFileHeader BmpFileHeader; //BMP文件头


 struct _BmpInfoHeader
{
    unsigned long biSize;        //Info Header的大小,Specifies the number of bytes required by the structure.

    long biWidth;        //biWidth Specifies the width of the bitmap.单位是像素

    long biHeight;        //Specifies the height of the bitmap, in pixels.

    unsigned short biPlanes;        //Specifies the number of planes for the target device. This value must be set to 1.

    unsigned short biBitCount ;    //BPP值,Specifies the number of bits per pixel,such as 1,4,8,24 .

    unsigned long biCompression;//Specifies the type of compression for a compressed bottom-up bitmap

                        //(top-down DIBs cannot be compressed). This member can be one of the

                        //following values: BI_RGB,BI_RLE8,BI_RLE4,BI_BITFIELDS,BI_JPEG.

                        
    unsigned long biSizeImage;    //图像尺寸,Specifies the size, in bytes, of the image. This may be set to zero for BI_RGB bitmaps.

    
    long biXPelsPerMeter;//Specifies the horizontal resolution, in pixels per meter, of the target device for the

                        //bitmap. An application can use this value to select a bitmap from a resource

                        //group that best matches the characteristics of the current device.

                        
    long biYPelsPerMeter;//Specifies the vertical resolution, in pixels per meter, of the target device for the bitmap.

    
    unsigned long biClrUsed;        //颜色数,Specifies the number of color indexes in the color table that are actually used by the bitmap.

                        //If this value is zero, the bitmap uses the maximum number of colors corresponding

                        //to the value of the biBitCount member for the compression mode specified by biCompression.

                        
    unsigned long biClrImportant;    //Specifies the number of color indexes that are required for displaying the bitmap. If this value is zero,

                        //all colors are required.

};

typedef struct _BmpInfoHeader BmpInfoHeader; //BMP文件信息



  struct _RGBQuad
{
    unsigned char rgbBlue;        //Specifies the intensity of blue in the color.

    unsigned char rgbGreen;    //Specifies the intensity of green in the color.

     unsigned char rgbRed;        //Specifies the intensity of red in the color.

     unsigned char rgbReserved;    //Reserved; must be zero.

};

typedef struct _RGBQuad RGBQuad; //RGB调色板数据


#pragma pack()


如果是小端字节序(X86,ARM),用这个结构直接读取文件即可,而大端字节序的CPU必须在读取后,每个成员要做一下字节序转换,即四字节对调(1,4字节对调,2,3字节对调)
 
结构读取算法
 

BmpFileHeader header;
BmpInfoHeader info;
   
   //读文件头信息

  len = fread(&header,1,sizeof(header),file);
  if(len != sizeof(header))
      {
       printf("bmp file %s header failure\n",file_name);
     fclose(file);
     return -2;
      }
    if(header.bfType!=DIB_HEADER_MARKER)
        {
         printf("bmp file %s no BM \n",file_name);
         fclose(file);
     return -3;
        }
      //读文件信息

     len = fread(&info,1,sizeof(info),file);
    if(len != sizeof(info))
      {
       printf("bmp file %s info failure\n",file_name);
     fclose(file);
     return -4;
      }

 

2.1.2 按位移来读取数据

  因为显示只需要四个数据即可,因此直接定义这个变量偏移量,然后用lseek/fseek去移到指定位置读取即可.

   2.2 RGB数据读取.

因为是倒排的数据,如果需要把BMP的数据映射到显存上.则需要一些特殊处理.因为RGB的显存可以自由移动可以在倒显存显示即可.

首先读文件点数据时,先移到显存最后一行开始处理,然后不断在显存上向前移动指针。

#define RGB_24_888(r,g,b) ( ((r & 0xff)<<16) | ((g & 0xff ) << 8) | ((b & 0xff) << 0) )


//注意BMP的RGB数据区是倒排,即图像最后一行存在文件最开始,这样文件中的第一点实际上是左下角数据.

//最后一个点是右上角数据。


int bmp_show_le_24bpp(char * file_name,unsigned char * fb_buf,int buf_len,int width,int height)
{
   FILE * file = NULL;
   int len,i,j,cnt=0;
   unsigned char ary[3]; //BMP的24位是用3byte保存

   unsigned char * p;
   unsigned long value;
   BmpFileHeader header;
   BmpInfoHeader info;

   printf("show BMP file %s,width %d,height %d\n",file_name,width,height);
   
   file = fopen(file_name,"rb");

   
   
   if(file == NULL)
       {
        printf("open bmp file %s failure\n",file_name);
     return -1;
       }

  len = fread(&header,1,sizeof(header),file);
  if(len != sizeof(header))
      {
       printf("bmp file %s header failure\n",file_name);
     fclose(file);
     return -2;
      }

  
    if(header.bfType!=DIB_HEADER_MARKER)
        {
         printf("bmp file %s no BM \n",file_name);
         fclose(file);
     return -3;
        }

     len = fread(&info,1,sizeof(info),file);
    if(len != sizeof(info))
      {
       printf("bmp file %s info failure\n",file_name);
     fclose(file);
     return -4;
      }

   p = (fb_buf+width*(height-1)*4); //移到FrameBuffer最后一行


   printf("bmp %s: fb_buf %x,Height %d,Width %d,bpp %d,data offset %d\n",file_name,fb_buf,info.biHeight,info.biWidth,info.biBitCount,header.bfRebfOffBits);

  //移到数据区

   fseek(file,header.bfRebfOffBits,SEEK_SET);

   //这里假设图像尺寸与屏幕完全一致.

   for(i=0; i< height ; i++)
       {
        //printf("%s:fb buf %x,line[%d]=%x\n",__FUNCTION__,fb_buf,i,p);

        for(j=0;j< width ; j++)
            {
        if(fread(ary,1,sizeof(ary),file)<0)
            break;
         //注意BMP文件中,是按BGR的顺序保存数据

         value = RGB_24_888(ary[2],ary[1],ary[0]);//注意其倒排顺序
           *((unsigned long *)p) = value;
         p+=4;
        
        //if(i<10)

        // printf("point[%d],value %x, red %x,green %x,blue %x\n",i,value,ary[2],ary[1],ary[0]);
            }
     p-= width*4*2; //回退2行,因为内循环移动一行,还要上移一行      
       }
   

   fclose(file);
   
}


 
附录: frame Buffer编程系列
  1. 设备操作
  2. 对显存操作
  3. 位图显示
  4. png/jpg/gif 显示
  4.fbv 分析
  5.截图程序


阅读(2967) | 评论(0) | 转发(6) |
给主人留下些什么吧!~~