读取位图(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 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))来实现相同的效果。

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

时间: 2024-10-25 17:31:28

读取位图(bitmap)实现及其要点的相关文章

(算法)位图BitMap

题目: 给定一数组,大小为M,数组中的数字范围为1-N,如果某带宽有限,无法传输该大小的数组,该怎么办? 思路: 通过位图BitMap来压缩数组,将数组中每个数字在bit位上标志,这样就可以将数组大小压缩很多倍,每个32位int只需要1bit来表示. 代码: #include<iostream> #include<string.h> using namespace std; char* compression(int *A,int imax,int n){ int m=(imax-

【数据结构】位图BitMap、布隆过滤器的算法实现

我们先给出之前我看过的腾讯公司的一道笔试题,引出位图BitMap. 给40亿个不重复的无符号整数,没排过序.给一个无符号整数,如何快速判断一个数是否在这40亿个数中. 这个问题怎么解决呢? 1)将40亿数据保存起来(保存在数组.链表.树中),再和该数判断是否相等. 那我们思考一下需要多少内存: 2)借助位图BitMap解决. 位图(BitMap) 是用一个数组中的每个数据的每个二进制位表示一个数是否存在.1表示存在,0表示不存在. 相当于把数组分成很多块的空间,每一块是32个比特位. 原来32个

c++ 读取位图信息显示位图 BITMAPINFOHEADER

在C++中要将一张位图信息BITMAPINFOHEADER读取并显示在一个控件上,具体步骤如下: 1.先读取位图信息 int ReadPictureBmp(unsigned char *pBmpBuffer) { // static int i=0; // if (i>5) // { // return TRUE; // } FILE *fp = NULL; char szFileName[MAX_PATH] = {0}; sprintf(szFileName, "E:\\工作目录\\20

海量数据处理第二谈-----位图BitMap

位图的概念: 在C++中,位图是以位来表示整数的结构,普通的整数一个数需要用4个字节来表示,我们可以换种思想,在整个整数的集合范围内,某个整数存在与否,只有两种情况,在或者不在,那么,我们可以考虑只用一个bit位,来表示该整数存在的状态,从而达到节省内存的目的. 位图实例分析: 给一个实际的例子,给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在那40亿个数当中 我们可以简单计算一下,40亿个整数全部放到内存,需要160亿个字节,粗略计算,大致

位图BitMap

引子: 给40亿个不重复的无符号整数,没排过序,给一个无符号整数,如何判断这个数是否在这40亿个数中. 分析:1 字节=8位 1 KB  =1024字节=2^10字节 1 MB  =1024KB 1 GB  =1024MB 40亿个数,40亿可以约看为2^32,即需要将近4G的空间存储,,如果内存够的话,40亿个整数使用位图存储需要500M的空间 位图即每一个位存储,如果这个数存在,则先找到这个字节大小,再将字节的这个位置1 template<class T>  class BitMap {

位图 bitmap 理解

在数据库学习与试用当中会遇到一个概念"位图索引",这是位图在索引检索中的一个应用案例.现在对位图的基本原来进行下学习.原理其实很简单,主要搞清楚一些基本概念. 先说一下基本的概念:bit,byte,word. bit  位 byte  字节 word  字 字长是指字的长度 关系如下: 1字=2字节(1 word = 2 byte) 1字节=8位(1 byte = 8bit) 1 Byte = 8 Bits 1 KB = 1024 Bytes 1 MB = 1024 KB 1 GB =

【转】Android开发之Bitmap的内存优化详解

本文来源:转载自: http://mobile.51cto.com/abased-410796.htm 在Android应用里,最耗费内存的就是图片资源.而且在Android系统中,读取位图Bitmap时,分给虚拟机中的图片的堆栈大小只有8M,如果超出了,就会出现OutOfMemory异常.所以,对于图片的内存优化,是Android应用开发中比较重要的内容. 1.要及时回收Bitmap的内存 Bitmap类有一个方法recycle(),从方法名可以看出意思是回收.这里就有疑问了,Android系

优化—对Bitmap的内存优化

在Android应用里,最耗费内存的就是图片资源.而且在Android系统中,读取位图Bitmap时,分给虚拟机中的图片的堆栈大小只有8M,如果超出了,就会出现OutOfMemory异常.所以,对于图片的内存优化,是Android应用开发中比较重要的内容. 1) 要及时回收Bitmap的内存 Bitmap类有一个方法recycle(),从方法名可以看出意思是回收.这里就有疑问了,Android系统有自己的垃圾回收机制,可以不定期的回收掉不使用的内存空间,当然也包括Bitmap的空间.那为什么还需

Bitmap详解与Bitmap的内存优化

感觉这里的排版看着更舒服些 Bitmap详解与Bitmap的内存优化 一.Bitmap: Bitmap是Android系统中的图像处理的最重要类之一.用它可以获取图像文件信息,进行图像剪切.旋转.缩放等操作,并可以指定格式保存图像文件. 常用方法: + public void recycle() // 回收位图占用的内存空间,把位图标记为Dead + public final boolean isRecycled() //判断位图内存是否已释放 + public final int getWid