位图的格式如下:

  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 , , sizeof(BITMAPFILEHEADER) , fileR) ;
if (0x4d42 != bitMapFileHeader.fileType)
{
fclose(fileR) ;
return NULL ;
}
fread(&bitMapInfoHead, , sizeof(BITMAPINFOHEAD) , fileR) ; rgbquad = new RGBQUAD[bitMapInfoHead.clrUsed] ;
for (int icount = ; icount < bitMapInfoHead.clrUsed ; ++icount)
{
fread((char *)&(rgbquad[icount].rgbBlue),,sizeof(BYTE),fileR);
fread((char *)&(rgbquad[icount].rgbGreen),,sizeof(BYTE),fileR);
fread((char *)&(rgbquad[icount].rgbRed),,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 。

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

  1. (算法)位图BitMap

    题目: 给定一数组,大小为M,数组中的数字范围为1-N,如果某带宽有限,无法传输该大小的数组,该怎么办? 思路: 通过位图BitMap来压缩数组,将数组中每个数字在bit位上标志,这样就可以将数组大小 ...

  2. EmguCV从位图(Bitmap)加载Image<Gray,byte>速度慢的问题

    先说背景.最近在用C#+EmguCV(其实就是用P/Invoke封闭了OpecCV,与OpenCVDotNet差不多) 做一个视频的东西.视频是由摄像头采集回来的1f/s,2048X1000大小,其实 ...

  3. [置顶] 程序员必知(二):位图(bitmap)

    位图是什么? 位图就是数组,一般来说是bit型的数组,具有快速定位某个值的功能,这种思想有很广泛的应用,比如下边两题: 1 找出一个不在5TB个整数中存在的数 假设整数是32位的,总共有4GB个数,我 ...

  4. Android学习之位图BitMap

    BitMap代表一张位图,扩展名可以是.bmp或者.dib.位图是Windows标准格式图形文件,它将图像定义为由点(像素)组成,每个点可以由多种色彩表示,包括2.4.8.16.24和32位色彩.例如 ...

  5. [2011-3-9 12:59 ]As3.0中的位图(Bitmap/BitmapData)用法

    1.位图使用(模糊)滤镜 //创建一个矩形区域的BitmapData var bmd:BitmapData = new BitmapData(80, 30, false, 0xefefef); //画 ...

  6. 【索引】位图BitMap索引

    位图(BitMap)索引 前段时间听同事分享,偶尔讲起Oracle数据库的位图索引,顿时大感兴趣.说来惭愧,在这之前对位图索引一无所知,因此趁此机会写篇博文介绍下位图索引. 1. 案例 有张表名为ta ...

  7. android在listview中放入从sdcard读取的bitmap

    重写viewbinder public class viewbinder_bookmark implements SimpleAdapter.ViewBinder{ @Override public ...

  8. 位图bitmap应用

    所有比特的编号方法是,从低字节的低位比特位开始,第一个bit为0,最后一个bit为 n-1. 比如说,现在有个数组是这样子的,int a[4],那么a[0]的比特位为0--31a[1]的比特位为32- ...

  9. redis位图(bitmap)常用命令的解析

    描述   bitmap是redis封装的用于针对位(bit)的操作,其特点是计算效率高,占用空间少,常被用来统计用户签到.登录等场景 常用命令及解析 常用命令 setbit key offset va ...

随机推荐

  1. cocos2d js的一些tip

    cocos2d-js-v3.2-rc0 cc.director.end();//退出app cc.Application.getInstance().openURL("http://www. ...

  2. [转]VS2010中使用模块定义文件(.def)

    都知道在写DLL的时候,使用模块定义文件(.def)可以防止DLL里的命名变更. vc6.0中只要在当前目录下添加.def文件,然后编译就Ok了 但在vs2010里这样做是不可以的,必须在项目--属性 ...

  3. GOF23设计模式之状态模式(state)

    一.状态模式概述 用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题. 结构: (1)Context 环境类   环境类中维护一个 State 对象,它定义了当前的状态. (2)State ...

  4. bzoj4598: [Sdoi2016]模式字符串

    Description 给出n个结点的树结构T,其中每一个结点上有一个字符,这里我们所说的字符只考虑大写字母A到Z,再给出长度为m 的模式串s,其中每一位仍然是A到z的大写字母.Alice希望知道,有 ...

  5. java代码--实现随机输出10个随机数,并显示最大值,最小值

    总结;对于length()属性,还不是很熟悉.不会用它. package com.s.x; //随机产生10个随机数,并且显示出最大值,最小值 public class Love { public s ...

  6. Java 面向对象 初探

    public class test { public static void main(String[] args) { // 利用new关键字创建了一个Person对象 Person p = new ...

  7. python学习笔记(七):面向对象编程、类

    一.面向对象编程 面向对象--Object Oriented Programming,简称oop,是一种程序设计思想.在说面向对象之前,先说一下什么是编程范式,编程范式你按照什么方式来去编程,去实现一 ...

  8. spring boot + slf4j + log4j配置

    https://docs.spring.io/spring-boot/docs/1.5.6.RELEASE/reference/htmlsingle/#boot-features-logging ht ...

  9. django之全文检索

    全文检索 全文检索不同于特定字段的模糊查询,使用全文检索的效率更高,并且能够对于中文进行分词处理 haystack:django的一个包,可以方便地对model里面的内容进行索引.搜索,设计为支持wh ...

  10. makefile .phony targets

    Phony Targets PHONY 目标并非实际的文件名:只是在显式请求时执行命令的名字.有两种理由需要使用PHONY 目标:避免和同名文件冲突,改善性能. 如果编写一个规则,并不产生目标文件,则 ...