设备无关位图(Device Independent Bitmap)是可以保存在磁盘的位图文件,可以从磁盘读取到内存或者从内存保存到磁盘上。它的文件结构是标准化的,可以在Windows/Linux/Unix等平台上显示相同的效果。本文主要介绍了

  1. 如果将位图文件从磁盘读到内存中
  2. 在内存中对位图文件进行操作后,如何将位图保存到磁盘

1 读取位图到内存中

1.1 DIB文件结构

要将位图文件(.bmp)从磁盘读取到内存,首先要了解其文件结构。DIB的文件组成有以下4个部分:

  1. 文件表头,主要包含了文件的类型(必须是BM),文件的大小(所占用的字节数)和位图的像素矩阵的便宜量。
  2. 信息表头,包含了两部分内容:位图的相关信息(位图的大小、位深度、位面数、压缩和编码等)和指向RGB颜色表(调色盘)的指针。
  3. RGB色彩对照表,也就是调色板,不一定会有。16位及以上直接使用RGB通道表示颜色,一般不需要调色板。
  4. 位图的像素信息矩阵,表示具体的像素。1,4,8位颜色,保存的是调色板的索引,具体的颜色根据索引在调色板中查找;16位及其以上不使用调色板,直接使用RGB组成像素颜色。

1.2 在Windows下DIB的内存结构

要将DIB数据读取到内存,就需要在内存中分配相应的空间。Windows提供了几种结构体,结构体中的字段对应着DIB文件的各个信息值,具体如下

引用自 http://blog.csdn.net/wenzhou1219/article/details/26162869

将DIB读取到内存只需要将磁盘数据填充到相应到结构体即可。在磁盘上DIB需要连续的结构存储,在内存中则不需要连续的存储空间,可以分段将数据读取到相应的结构体中。
读取DIB到内存的具体步骤:

  1. 将文件头信息读取到BITMAPFILEHEADER结构体中。
  2. 将位图头信息读取到BITMAPINFOHEADER结构体中。
  3. 如果有调色板,则将其信息读取到RGBQUAD中。
  4. 读取位图像素信息到像素矩阵中。
fp.Read(&bmfileHeader, sizeof(BITMAPFILEHEADER)); // 读取BMP文件头
...
//读取文件信息头
ret = fp.Read(&bmHeader, sizeof(BITMAPINFOHEADER));
...
fp.Read(m_dibBits, GetBodySize());  //读取像素信息 

1.3 结构体各字段信息

BITMAPFILEHEADER

代表文件头信息的结构体BITMAPFILEHEADER的声明如下:

typedef struct tagBITMAPFILEHEADER {WORD    bfType;DWORD   bfSize;WORD    bfReserved1;WORD    bfReserved2;DWORD   bfOffBits;
} BITMAPFILEHEADER  

其中,

  • bfType是文件类型,该字段必须是BM,如果不是则说明该文件不是DIB。
  • bfSize是位图文件的大小(字节数)
  • bfReserved1和bfReserved2 是保留字段
  • bfOffBits 从BITMAPFILEHEADER的起始位置到位图像素的字节偏移量。

    BITMAPINFO

    在上面提到,位图信息和位图的调色板是存放在同一个结构体中的,该结构体就是BITMAPINFO,其声明如下

typedef struct tagBITMAPINFO {BITMAPINFOHEADER bmiHeader;RGBQUAD          bmiColors[1];
} BITMAPINFO, *PBITMAPINFO;

bmiHeader是位图头信息
bmiColors是调色板

BITMAPINFOHEADER

位图的头信息结构BITMAPINFOHEADER,该结构包含了DIB的尺寸和颜色格式等信息,声明如下

typedef struct tagBITMAPINFOHEADER{DWORD      biSize;LONG       biWidth;LONG       biHeight;WORD       biPlanes;WORD       biBitCount;DWORD      biCompression;DWORD      biSizeImage;LONG       biXPelsPerMeter;LONG       biYPelsPerMeter;DWORD      biClrUsed;DWORD      biClrImportant;
} BITMAPINFOHEADER  

其中,

  • biSize是该结构体所占用的字节说
  • biWidth DIB的宽(以像素为单位),如果biCompression是BI_JPEG或者BI_PNG,则biWidth是解压缩后JPEG或者PNG图像的宽度。
  • biHeight,DIB的高(以像素为单位)。
    • 如果biHeight是正的,则DIB的像素是按照从下往上(bottom-up,也就是像素数组的第一行保存的实际是DIB的最后一行像素值),图像源点在左下角。
    • 如果biHeight是负的,则DIB的像素是按照从上往下保存的(up-bottom),而且像素的数据是不能被压缩的其biCompression必须是BI_RGB或者BI_FIELDS
    • 如果biCompression是BI_JPEG或者BI_PNG,则biHeight是解压缩后JPEG或者PNG的高
  • biPlanes 目标设备的平面数,总是设为1.
  • biBitCount,每个像素所占用的位数。0,表示JPEG或者PNG指定每个像素所占用的位数。还可以是1,4,8,16,24,32。
  • biCompression,数据的压缩方法(up-down的DIB不能被压缩),可以是以下值:
    • BI_RGB / BI_FIELDS未被压缩
    • BI_RLE4 / BI_RLE8 使用游程长度编码 (RLE,run-length encode)
    • BI_JPEG / BI_PNG 指示该图像是JPEG或者PNG图像。
  • biSizeImage 图像的字节数,对于BI_RGB的DIB其值为0.
  • biXPelsPerMeter / biYPelsPerMeter 显示该DIB的目标设备所需的分辨率(单位是像素每米)
  • biClrUsed DIB实际使用调色板中的颜色个数,通常为0表示使用调色板中的全部颜色。
  • biClrImportant 显示DIB所必须的颜色个数,通常为0表示全部颜色都是必须的。

    详细的解释参见 https://msdn.microsoft.com/en-us/library/dd183376(v=vs.85).aspx

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

注意,其存储顺序是BGR。

1.3 DIB的结构实例


是一幅宽和高都是32的位图(放大后,可以看到表示像素的一个个方块),其有16种颜色。下面是该图像的16进制数据

  • 首先是文件的头信息 BITMAPFILEINFO 共有14个字节(0x00-0x0D),其起始的两个字节为0x4d42(大端存储,高位在前)表示文件类型为BM,最后4个字节 0x0076是位图的像素信息相对于文件头的偏移量,也就是从0x0076为图像的像素信息。
  • 下面是位图的头信息 BITMAPINFOHEADER共有40个字节(0x0E-0x35),起始的4个字节是0x0028就是该结构体的大小,紧接着的4个字节是图像的宽0x0020
  • 跟着是图像的调色板,0x36 - 0x75。调色板共有16种颜色,也就是说有调色板中有16个RGBQUAD,其大小为16 * 4.
  • 最后是位图的数据 0x76-0x275

1.4 读取

    CFile fp(dibName, CFile::modeRead | CFile::typeBinary);BITMAPFILEHEADER bmfileHeader;BITMAPINFOHEADER bmHeader;ULONGLONG headpos;int paletteSize = 0;int ret, cbHeaderSize;headpos = fp.GetPosition(); // 获取文件指针的位置ret = fp.Read(&bmfileHeader, sizeof(BITMAPFILEHEADER)); // 读取BMP文件头if (bmfileHeader.bfType != 0x4d42) //判断文件类型标头是不是x4d42,表示该文件为BMP类型文件{AfxMessageBox(_T("文件不是bmp!"));return;}//读取文件信息头ret = fp.Read(&bmHeader, sizeof(BITMAPINFOHEADER));// 计算RGBQUAD的大小switch (bmHeader.biBitCount){case 1:paletteSize = 2;break;case 4:paletteSize = 16;break;case 8:paletteSize = 256;break;}// 为BITMAPINFO分配存储空间cbHeaderSize = sizeof(BITMAPINFOHEADER)+paletteSize * sizeof(RGBQUAD);m_dibInfo = (BITMAPINFO*) new char[cbHeaderSize];m_dibInfo->bmiHeader = bmHeader;if (paletteSize) //是否有调色板{ret = fp.Read(&(m_dibInfo->bmiColors[0]), paletteSize * sizeof(RGBQUAD));if (ret != int(paletteSize * sizeof(RGBQUAD) ) ){delete[] m_dibInfo;m_dibInfo = NULL;return;}}//为像素数组分配存储空间,大小由GetBodySize决定m_dibBits = (void*) new char[GetBodySize()];fp.Seek(headpos + bmfileHeader.bfOffBits, CFile::begin); // 将文件指针移动到DIB像素数组ret = fp.Read(m_dibBits, GetBodySize());if (ret != int(GetBodySize())){delete[] m_dibInfo;delete[] m_dibBits;m_dibInfo = NULL;m_dibBits = NULL;}fp.Close();  

知道了DIB的文件结构后,读取其到内存还是挺简单的,需要注意的是DIB的像素数组的大小。由于DIB的宽度需要时4的倍数,不是的话需要填充0将其凑成4的倍数,所以其像素数组的大小不能简单的width * height * biBitCount / 8,其中biBitCount是每个像素占用的位数。其具体的计算方法如下

  1. 首先计算一行所占用的字节数 bytesPerLine
    bytesPerLine = ((m_dibInfo->bmiHeader.biWidth * m_dibInfo->bmiHeader.biBitCount + 31) / 32 ) * 4
  2. 将bytesPerLine乘以图像的高
    bytesPerLine * m_dibInfo->bmiHeader.biHeight

1.5 总结

本文主要对DIB的文件结构以及其对应的内存中的结构体做了一个总结,并对一个具体的DIB16进制数据结构进行分析,最后实现了如何将一个DIB数据读取到内存中。

一直对位图结构不是很了解,趁着在公司实习没有具体的工作安排,对DIB的结构作了个总结。至于如何将处理后的位图数据写回磁盘文件,在知道位图结构的情况下,只需要填充相应的结构字段就行了,需要注意的还是位图的宽需要是4的倍数,不是的话要用0补齐。本来想写个DEMO的但是太累,明天再说吧。

转载于:https://www.cnblogs.com/wangguchangqing/p/5417444.html

DIB位图(Bitmap)的读取和保存相关推荐

  1. Bitmap位图文件读取、保存、屏幕截图

    虽然现在网上已经有很多位图读取.保存的文章,很多写的都很详细,提供的源代码功能也很强大,但是我仍然要自己重写一个位图加载程序.主要是因为这些大牛们的文章写的太深奥了,代码功能太强大了,以至于像我这样的 ...

  2. 【转】DIB位图(Bitmap)的读取和保存

    转自:https://www.cnblogs.com/wangguchangqing/p/5417444.html 设备无关位图(Device Independent Bitmap)是可以保存在磁盘的 ...

  3. 位图BitMap图像的读取与存储

    做图像处理时的源文件一般要用无损的图像文件格式,位图(BitMap)是windows系统下可存储无压缩图像的文件格式.要实现位图文件的读取和存储,首先要明白位图文件的的存储数据结构.位图文件由四部分依 ...

  4. 计算机视觉__基本图像操作(显示、读取、保存)

    计算机视觉__基本图像操作(显示.读取.保存) 本文目录: ✨ 一.前言 ✨ 二.图像显示(使用OpenCV和Matplotlib显示图像) (1).使用OpenCV显示图像 (2).使用Matplo ...

  5. matlab emf 读取,20140219-Emf_Demo EMF 矢量图 可以读取和保存EMF 的封闭类 非常实用 matlab 238万源代码下载- www.pudn.com...

    文件名称: 20140219-Emf_Demo下载 收藏√  [ 5  4  3  2  1 ] 开发工具: Visual C++ 文件大小: 6312 KB 上传时间: 2014-07-10 下载次 ...

  6. OpenCv图像处理之图像视频摄像头读取和保存

    OpenCv图像处理之图像视频摄像头读取与保存 使用cv::imread()读取图片 使用cv::imwrite()存储图片 使用cv::VideoCapture::open()读取视频 使用cv:: ...

  7. 位图Bitmap(基于Java实现)

    所谓bitmap,就是用每一位来存放某种状态,适用于大规模数据,但数据状态又不是很多的情况.通常是用来判断某个数据存不存在的. 设计原则: 尽可能的最大化利用内存,极限挖掘.利用.发挥Java的性能. ...

  8. 十二、【数据结构】位图(bitmap)的详解与实现

    一.定义     --概念部分参考http://www.iteblog.com/archives/148 位图法就是bitmap的缩写.所谓bitmap,就是用每一位来存放某种状态,适用于大规模数据, ...

  9. Spark的RDD 文件读取与保存

    RDD 文件读取与保存 Spark 的数据读取及数据保存可以从两个维度来作区分:文件格式以及文件系统.其中: (1)文件格式分为:text 文件.csv 文件.sequence 文件以及Object ...

最新文章

  1. php和css一样吗,php和css一样吗
  2. maya表情blendshape_Maya的形状融合变形器Blend Shape | 学步园
  3. AI一分钟 | 娃哈哈要造智能汽车?世界顶级机器学习科学家黄恒加盟京东
  4. Spring BeanFactoryPostProcessor接口详细使用
  5. android timer后函数继续执行_一切从android的handler说起(三)
  6. 【数据结构与算法】之柱状图中最大矩形的求解思路和算法示例
  7. Oracle 多行合并一行 方法
  8. Ajax 编程基础(一)
  9. 数学建模第六章 微分方程建模
  10. 博德之门联机等待服务器响应,《博德之门》系列疑难解答
  11. dvi线支持多少分辨率_dvi接口有哪几种_dvi支持最大分辨率
  12. 【小白笔记】目标跟踪(Unveiling the Power of Deep Tracking)论文笔记
  13. 微信公众号 去除 “防欺诈盗号请勿支付或输入qq密码“ 提示
  14. pytorch 将数据集加载到内存后再训练
  15. 关于HTML中a标签的重大安全性漏洞!!!
  16. java中什么路径_Java中的路径问题
  17. 硬件知识:如何快速挑选一款好的固态硬盘?
  18. 金融科技大数据产品推荐:百融信贷决策审批系统
  19. 当ChatGPT续写《红楼梦》,能替代原著吗?
  20. 【原理】极大似然法(MLE)——概率论在统计学的应用

热门文章

  1. 分享:Android程序员,必备精品网站大汇总
  2. 移动开发工程师面试题集:Android iOS
  3. JAVA分析html算法(JAVA网页蜘蛛算法)
  4. Whose Hall?
  5. spring boot 菜鸟教程学习:spring是一个超级大工厂能够管理java对象(bean)和他们之间的关系(依赖注入)
  6. 助力深度学习!阿里开源可插拔 GPU 共享调度工具
  7. Java容器源码分析-HashSet vs TreeSet vs LinkedHashSet
  8. python+xlrd+xlwt操作excel
  9. atCoder Ants on a Circle(又是蚂蚁问题。。。)
  10. hdu3037 Lucas定理