首页 > 其他 > 详细

读取位图(bitmap)实现及其要点

时间:2015-01-15 23:39:57      阅读:429      评论:0      收藏:0      [点我收藏+]

位图的格式如下:

  1.文件头信息块

  0000-0001 :文件标识,为字母ASCII码“BM”。

  0002-0005 :文件大小。

  0006-0009 :保留,每字节以“00”填写。

  000A-000D :记录图像数据区的起始位置。各字节的信息含义依次为:文件头信息块大小,图像描述信息块的大小,图像颜色表的大小,保留(为01)。

  2.图像描述信息块

  000E-0011:图像描述信息块的大小,常为28H。

  0012-0015:图像宽度。

  0016-0019:图像高度。

  001A-001B:图像的plane总数(恒为1)。

  001C-001D:记录像素的位数,很重要的数值,图像的颜色数由该值决定。

  001E-0021:数据压缩方式(数值位0:不压缩;1:8位压缩;2:4位压缩)。

0022-0025:图像区数据的大小。

0026-0029:水平每米有多少像素,在设备无关位图(.DIB)中,每字节以00H填写。

002A-002D:垂直每米有多少像素,在设备无关位图(.DIB)中,每字节以00H填写。

002E-0031:此图像所用的颜色数,如值为0,表示所有颜色一样重要。

  3.颜色表

  颜色表的大小根据所使用的颜色模式而定:2色图像为8字节;16色图像位64字节;256色图像为1024字节。其中,每4字节表示一种颜色,并以B(蓝色)、G(绿色)、R(红色)、alpha(32位位图的透明度值,一般不需要)。即首先4字节表示颜色号0的颜色,接下来表示颜色号1的颜色,依此类推。

  4.图像数据区   

  颜色表接下来位是位图文件的图像数据区,在此部分记录着每点像素对应的颜色号,其记录方式也随颜色模式而定,既2色图像每点占1位;16色图像每点占4位;256色图像每点占8位;真彩色图像每点占24位。所以,整个数据区的大小也会随之变化。究其规律而言,可的出如下计算公式:图像数据信息大小=(图像宽度*图像高度*记录像素的位数)/8。 然而,未压缩的图像信息区的大小。除了真彩色模式外,其余的均大于或等于数据信息的大小。这是为什么呢?原因有两个:  

    1.BMP文件记录一行图像是以字节为单位的。因此,就不存在一个字节中的数据位信息表示的点在不同的两行中。也就是说,设显示模式位16色,在每个字节分配两个点信息时,如果图像的宽度位奇数,那么最后一个像素点的信息将独占一个字节,这个字节的后4位将没有意义。接下来的一个字节将开始记录下一行的信息。 

    2.为了显示的方便,除了真彩色外,其他的每中颜色模式的行字节数要用数据“00”补齐为4的整数倍。如果显示模式为16色,当图像宽为19时,存储时每行则要补充4-(19/2+1)%4=2个字节(加1是因为里面有一个像素点要独占了一字节)。如果显示模式为256色,当图像宽为19时,每行也要补充4-19%4=1个字节。

  一下代码实现的是位图宽,高是4的整数倍,颜色位深是24位。

头文件定义:

#pragma pack(1)
    typedef unsigned char BYTE ;
    typedef unsigned short  WORD ;
    typedef unsigned int    DWORD ;
    typedef long  LONG ;

    typedef struct BW_BITMAPFILEHEADER
    {
        WORD  fileType ;
        DWORD fileSize ;
        WORD  fileReserved1 ;
        WORD  fileReserved2 ;
        DWORD offSet ;
    } BITMAPFILEHEADER ;
    typedef struct BW_BITMAPFINFOHEADER
    {
        DWORD headSize ;
        LONG  width ;
        LONG  height ;
        WORD  plant ;
        WORD  bitCount ;
        DWORD compression ;
        DWORD sizeImage ;
        LONG  XPelPerMeter ;
        LONG  YPelPerMeter ;
        DWORD clrUsed ;
        DWORD clrImportant ;
    }BITMAPINFOHEAD;

    typedef struct BW_RGBQUAD
    {
        BYTE rgbBlue ;
        BYTE rgbGreen ;
        BYTE rgbRed ;
        BYTE rgbReserved ;
    }RGBQUAD;

    typedef struct BW_PIXEL 
    {
        BYTE red ;
        BYTE green ;
        BYTE blue ;
    } PIXEL ;

    class BW_BITMAP
    { 
    public:
        bool ReadBMP(char*) ;
        BITMAPFILEHEADER bitMapFileHeader ;
        BITMAPINFOHEAD bitMapInfoHead ;
        RGBQUAD *rgbquad ;
        PIXEL* pixelData ;
    };

具体cpp文件:

bool BW_BITMAP::ReadBMP(char *fileName)
    {
        FILE *fileR ,fileW ;
        fileR = fopen(fileName , "rb") ;
        if (fileR != NULL)
        {
            //BW_BITMAP* bitMap = new BW_BITMAP ;
             
            fread(&bitMapFileHeader , 1 , sizeof(BITMAPFILEHEADER) , fileR) ;
            if (0x4d42 != bitMapFileHeader.fileType)
            {
                fclose(fileR) ;
                return NULL ;
            }
            fread(&bitMapInfoHead, 1, sizeof(BITMAPINFOHEAD) , fileR) ;

            rgbquad = new    RGBQUAD[bitMapInfoHead.clrUsed] ;
            for (int icount = 0 ; icount < bitMapInfoHead.clrUsed ; ++icount)
            {
                fread((char *)&(rgbquad[icount].rgbBlue),1,sizeof(BYTE),fileR);  
                fread((char *)&(rgbquad[icount].rgbGreen),1,sizeof(BYTE),fileR);  
                fread((char *)&(rgbquad[icount].rgbRed),1,sizeof(BYTE),fileR);  
                //fread((char *)&(bitMap->rgbquad[icount].rgbReserved),1,sizeof(BYTE),fileR);  
            }

            int width =  bitMapInfoHead.width ;

            int height = bitMapInfoHead.height ;  
            pixelData =   new PIXEL[width * height * sizeof(PIXEL)];  
            //初始化原始图片的像素数组  

            //fseek(fpi,54,SEEK_SET);  
            //读出图片的像素数据  
            fread(pixelData,sizeof(PIXEL) * width,height,fileR);    
            fclose(fileR);  
            return true ;
        }  
        else  
        {  
            //cout<<"file open error!"<<endl;  
            return false ;
        }  
    }
}

  在写该段代码时要注意在头文件的文件头使用#pragma pack(1),这是告诉编译器使用边界1对齐(也就是不对齐)。

  如果不是用#pragma pack(1),经过测试有如下结果:sizeof(BITMAPFILEHEADER)的值为16,而不是14。说明编译器对其使用了4为边界对齐。

      如果实在linux环境下,要使用__attribute__((packed))来实现相同的效果。

      总结可知:在实现对数据格式有严格要求的功能时,要注意到编译器的优化带来的麻烦。

读取位图(bitmap)实现及其要点

原文:http://www.cnblogs.com/BlackWalnut/p/4227469.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!