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


    位图的格式如下:

      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 blue ;
            BYTE green ;
            BYTE red ;
        } 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))来实现相同的效果。

           但是,在xcode 5.0下用#pragma pack(1) 居然可以~!

          总结可知:在实现对数据格式有严格要求的功能时,要注意到编译器的优化带来的麻烦。而且要注意PIXEL的定义,一定不能写成red ,green ,blue 。

  • 相关阅读:
    使用清华源进行pip install
    BERT和ULMFIT embedding比较文本分类结果
    Ubuntu16.04更新python3.5到python3.7
    base64方式显示控件
    在使用redis做缓存后,mybatis的延迟加载失效
    springboot:redis反序列化发生类型转换错误
    eclipse :代码自动补全不生效解决办法
    微信扫码支付:问题集锦
    微信扫码支付(4):统一下单
    微信扫码支付(3):获取验签秘钥
  • 原文地址:https://www.cnblogs.com/BlackWalnut/p/4227469.html
Copyright © 2020-2023  润新知