前面讲了为了提高DIB的显示性能和效率,我们将DIB转换成DDB,但是这又遇到一个问题,如果我想操作DIB的数据的话,显然是不能使用DDB:一是因为DIB转DDB时发生了颜色转换,再就是DDB无法直接提取指定像素点的数据。那么我们怎么办呢,Windows使用一种折中的方式来达到这一目标(既提高了显示效率和性能,又可以直接操作像素点)。

1.DIB Section存储和显示

Windows使用DIB块(DIB Section)来存储DIB数据,其内存结构示意图如下

其实,和我们自己读入DIB数据到自己分配的各个数据区感觉是一样的,只是现在这些DIB的各个数据区是由Windows自己分配维护的,值得注意的是这些Windows自己维护的DIB数据区是通过HBITMAP句柄来组织的,这个HBITMAP句柄和BITMAP的HBITMAP句柄是不一样的,至于为什么同一种句柄可表示不同的对象可以查看笔者的博文“深入了解Windows句柄到底是什么”。

继续说现在的问题,这里存储的是DIB的数据,只有在使用BitBlt和StretchBlt显示的时候,才会发生DIB->DDB的转换,显然这里BitBlt和StretchBlt会对句柄属性做一个判断来确认指向BITMAP的HBITMAP及指向DIB Section的HBITMAP的不同操作。当然,这里的DIB Section各个区不一定是连续的,这是一定要注意的。

这里Windows自己维护DIB各个数据区,做了一定优化,所以比我们自己分配和存储DIB各个数据区的显示效率和性能要高。

2.DIB Section的相关函数使用

明白了Windows对于DIB Section的存储原理和转换规则以后,我们说一下DIB Section的相关函数使用。

1.CreateDIBSection

HBITMAP CreateDIBSection(HDC hdc,                // 设备描述表句柄CONST BITMAPINFO *pbmi,   // 包含Info Header、Mask、Color Table数据的BITMAPINFO指针UINT iUsage,            // DIB_PAL_COLORS或DIB_RGB_COLORSVOID *ppvBits,          // 指向存储位图数据的地址的指针HANDLE hSection,  DWORD dwOffset
);

使用如下:

1.一般不考虑后两个参数

2.传入包含DIB位图信息头(Info Header)、压缩掩码(Mask)及调色板信息(Color Table,主要针对位图深度<=8)的BITMAPINFO* pbmi指针,这三者必须是连续存储的,一般指明DIB_RGB_COLORS参数,这样Windows会自动按照pbmi提供的信息分配对应的DIB Section,包括Info Header、Mask、Color Table及Bits四个区,其中分配的Bits区的地址被写到ppvBits指向的指针中。

即常用调用步骤如下:

a.读入DIB的位图信息头(Info Header)、压缩掩码(Mask)及调色板信息(Color Table)到pbmi指向内存中

b.hBitmap = CreateDIBSection(NULL, pbmi, DIB_RGB_COLORS, &pBits, NULL, 0);

c.读入DIB的Bits数据到pBits指向的内存中

d.BitBlt或StretchBlt显示hBitmap

3.只有使用DIB_PAL_COLORS参数时才需要hdc参数。只有DIB的调色板使用索引存储方式才需要使用这两个参数。实际上,这里的hdc和DIB_PAL_COLORS实际上最终被SetDIBitsToDevice和StretchDIBits函数调用,可以查看他们两个的参数。

4.pBits指向的内存由Windows操作系统托管,但是用户可以操作pBits数据,删除hBitmap时pBits内存区同时也会释放掉。

2.GetDIBColorTable和SetDIBColorTable

两个函数定义如下:
UINT GetDIBColorTable(HDC hdc,          // 设备描述表句柄UINT uStartIndex, // 调色板起始索引UINT cEntries,    // 要获取的调色板项个数RGBQUAD *pColors  // 存储调色板项的地址
);UINT SetDIBColorTable(HDC hdc,          // 设备描述表句柄UINT uStartIndex, // 调色板起始索引UINT cEntries,    // 要设置的调色板项个数RGBQUAD *pColors  // 存储调色板项的地址
);
分别用来获取和设置指定的调色板项,一般如下使用。

hdcMem = CreateCompatibleDC(NULL);
SelectObject(hdcMem, hBitmap);
GetDIBColorTable(hdcMem, uFirstIndex, uNumEntries, &prgb);
DeleteDC(hdcMem);
hdcMem = CreateCompatibleDC(NULL);
SelectObject(hdcMem, hBitmap);
SetDIBColorTable(hdcMem, uFirstIndex, uNumEntries, &prgb);
DeleteDC(hdcMem);

通过DIB Section来获取和设置调色板,可以屏蔽OS/2兼容位图带来的差异(BITMAPCOREINFO调色板项采用RGBTRIPLE结构体而不是BITMAPINFOHEADER采用的RGBQUAD)。


3.获取DIBSECTION

DIBSECTION定义如下:
typedef struct tagDIBSECTION { BITMAP              dsBm; BITMAPINFOHEADER    dsBmih; DWORD               dsBitfields[3]; HANDLE              dshSection; DWORD               dsOffset;
} DIBSECTION;

使用

GetObject(hBitmap, sizeof(DIBSECTION), &dibsection);

不同于BITMAP,DIB Section使用GetObject获取的是DIB Section,可以看到DIBSECTION将BITMAP设为第一个属性,这是为了保证和BITMAP的兼容,万一你不知道hBitmap的属性是指向DIB Section的,那么GetObject(hBitmap, sizeof(BITMAP), &bitmap)也不至于发生错误。

通过DIB Section来获取位图信息,可以不考虑不同DIB位图格式带来的差异,位图信息头均使用BITMAPINFOHEADER,压缩掩码使用DWORD来单独指定,不用考虑BITMAPCOREHEADER、BITMAPV4HEADER、BITMAPV5HWEADER带来的差异。

3.代码演示

在演示程序中,我们读入一幅图片(8bit、16bit、24bit)创建成DIB Section形式显示、查看调色板及压缩掩码
//读入DIB文件并转换成DIB Section
HBITMAP CreateDibSectionFromDibFile(PTSTR szFileName)
{BITMAPFILEHEADER   bmfh;BITMAPINFO         *pbmi;BYTE              *pBits;BOOL             bSuccess;DWORD              dwInfoSize, dwBytesRead;HANDLE              hFile;HBITMAP               hBitmap;//打开文件hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);if (INVALID_HANDLE_VALUE == hFile){return NULL;}//读入DIB文件头bSuccess = ReadFile(hFile, &bmfh, sizeof(BITMAPFILEHEADER), &dwBytesRead, NULL);if (!bSuccess || (dwBytesRead != sizeof(BITMAPFILEHEADER)) || (bmfh.bfType != *(WORD *)"BM")){CloseHandle(hFile);return NULL;}//为DIB BITMAPINFO分配内存,并读入DIB数据dwInfoSize = bmfh.bfOffBits - sizeof(BITMAPFILEHEADER);pbmi = malloc(dwInfoSize);if (NULL == pbmi){CloseHandle(hFile);return NULL;}bSuccess = ReadFile(hFile, pbmi, dwInfoSize, &dwBytesRead, NULL);if (!bSuccess || (dwBytesRead != dwInfoSize)){free(pbmi);CloseHandle(hFile);return NULL;}//创建DIB SectionhBitmap = CreateDIBSection(NULL, pbmi, DIB_RGB_COLORS, &pBits, NULL, 0);free(pbmi);if (NULL == hBitmap){CloseHandle(hFile);return NULL;}//读入位图数据到分配的DIB Section的Bits区(pBits指向)bSuccess = ReadFile(hFile, pBits, bmfh.bfSize-bmfh.bfOffBits, &dwBytesRead, NULL);CloseHandle(hFile);if (!bSuccess || (dwBytesRead != (bmfh.bfSize-bmfh.bfOffBits))){return NULL;}return hBitmap;
}//如果有调色板则获得第一个调色板项
BOOL GetFirstColorTableItem(HBITMAP hBitmap, RGBQUAD *prgb)
{HDC hdcMem;int iNum;hdcMem = CreateCompatibleDC(NULL);SelectObject(hdcMem, hBitmap);iNum = GetDIBColorTable(hdcMem, 0, 1, prgb);DeleteDC(hdcMem);return 0==iNum ?  FALSE : TRUE;
}//获得第一个调色板项
DWORD GetFirstMaskItem(HBITMAP hBitmap)
{DIBSECTION ds;GetObject(hBitmap, sizeof(DIBSECTION), &ds);return ds.dsBitfields[0];
}

在后续我会讲解使用DIB Section来完成图像指定像素点的读写,实际上,一旦能够操作pBits,那么完成指定像素点的读写也不是什么难事。


完整演示代码下载链接
原创,转载请注明来自http://blog.csdn.net/wenzhou1219

Windows DIB文件操作详解-4.使用DIB Section相关推荐

  1. Windows DIB文件操作详解-1.DIB的读入、保存和显示

    DIB(设备无关位图)是存储在磁盘上的位图文件,可以从磁盘读到内存中或从内存保存到磁盘上,它的磁盘文件结构是标准化的,在Linux.Unix及Windows上都可以以同样效果显示.位图是最接近硬件的图 ...

  2. Windows DIB文件操作详解-3.DDB转DIB

    上一节讲到DIB转换成DDB以提高位图显示性能,那么这里自然想到DDB转DIB.DDB转DIB有什么用呢?最常见的应用场合就是你得到了一个屏幕截图的DDB,现在想把它保存到磁盘上,这时候就要用到DDB ...

  3. Windows DIB文件操作详解-2.DIB转DDB

    上一节讲到显示DIB的显示时需要将文件内容读到内存中(如下图),当使用SetDIBitsToDevice和StretchDIBits函数显示时中间涉及到一系列的转换,这样大大增加了性能消耗,特别是在重 ...

  4. C 和 C++ 文件操作详解

    来源:http://www.cnblogs.com/likebeta/archive/2012/06/16/2551662.html 来源:http://www.cnblogs.com/likebet ...

  5. Qt QFile文件操作详解

    Qt QFile文件操作详解 很多应用程序都需要具备操作文件的能力,包括对文件内容进行读/写.创建和删除文件等,甚至某些应用程序的诞生纯粹是为了操作文件,比如 WPS Office.PDFedit 等 ...

  6. Python文件操作详解(一)

    今天继续给大家介绍Python相关知识,本文主要内容是Python文件操作详解. 一.Python文件处理简介 使用Python可以编写程序处理文件,Python可以处理的文件值得是任何存储在辅助存储 ...

  7. C++文件操作详解(ifstream、ofstream、fstream)【笔记本】

    C++文件操作详解(ifstream.ofstream.fstream) C++ 通过以下几个类支持文件的输入输出: ofstream: 写操作(输出)的文件类 (由ostream引申而来) ifst ...

  8. 简述python文件操作的流程_Python文件操作详解

    这篇文章主要介绍了Python 文件操作的详解及实例的相关资料,希望通过本文大家能够理解掌握Python 文件操作的知识,需要的朋友可以参考下 Python 文件操作的详解及实例 一.文件操作 1.对 ...

  9. 【Kubernetes 018】cfssl创建证书并结合RBAC的RoleBinding配置新用户config文件操作详解

    安全性是企业生产环境中的头等大事,对于访问同一集群的不同用户或者用户组来说,将权限分级是很有必要的.和很多云厂商一样,k8s也是采用按照角色和用户绑定的方式来分配权限的,这一节我们就来实际操作下,新建 ...

最新文章

  1. ArcSDE、ArcGis Engine、ArcGis Desktop的授权配置
  2. android截取字符串工具类,StringsUtil字符串工具类---灵活截取
  3. Android开发基本概念
  4. linux命令在线查
  5. htcvr设备计算机配置,准备买HTC VIVE了?来测试一下你的电脑配置够不够
  6. 第六十期:华为:希望把VR/AR打造成下个智能手机产业
  7. 排烟管道过长怎么处理_厨房装修失误导致烟道过长该怎么办?
  8. 陈天石吴翰清顾嘉唯光速对话(汤晓鸥今天没有晒娃)
  9. matlab 简单的图像填充例子
  10. VRay高级材质素材分享,精选,热门
  11. 利用JavaScript实现京东自动叠蛋糕+淘宝自动领喵币,叠列车+618全民购物
  12. 计算机设计大赛南京邮电大学,喜讯:我校信息学子在中国大学生计算机设计大赛中再创佳绩...
  13. 串级控制系统matlab仿真,锅炉串级三冲量给水控制系统的MATLAB 仿真
  14. MatLab 计算开根号
  15. 用R进行文本分析初探——包含导入词库和和导入李白语句
  16. 计算机里不显示u盘盘符,U盘不显示盘符怎么办 U盘没了盘符解决方法【详解】...
  17. 【计算机组成与结构】中央处理器
  18. TApplicaiton.ProcessMessages不能在非主线程使用
  19. U281819 糟心的语文课
  20. 你来讲讲AQS是什么吧?都是怎么用的?

热门文章

  1. 产品数据管理(PDM)技术与应用
  2. Spring——16 自动注入
  3. everything文件快速搜索工具
  4. centos上安装TeamViewer
  5. 【15】processing-三角函数(中文)
  6. 【学习笔记】vim 编辑器
  7. Selenium笔记(一)selenium简介、安装
  8. 儒家经典三礼,你知道指的是哪三礼吗?它们有什么区别?
  9. UE4学习笔记 物体跟着spline移动
  10. 哪款蓝牙耳机性价比高?南卡和华为蓝牙耳机对比测评