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

1.DIB Section存储和显示

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

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2VuemhvdTEyMTk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

事实上,和我们自己读入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_COLORS
VOID *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 Section
hBitmap = 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文件操作具体解释-5.DIB和调色板

    Windows调色板是256色显卡时期的产物,如今显卡最少也是16bit的了.所以调色板基本上是用不到了的. 可是以下几种情况还是须要去使用和了解调色板: 1.在新显卡上保证256色兼容模式的正常执行 ...

  2. Unix/Linux环境C编程新手教程(41) C语言库函数的文件操作具体解释

     上一篇博客我们解说了怎样使用Linux提供的文件操作函数,本文主要解说使用C语言提供的文件操作的库函数. 1.函数介绍 fopen(打开文件) 相关函数 open,fclose 表头文件 #in ...

  3. sed命令针对文件操作具体解释

    Linux的简单shell脚本中改动文件操作 1.Sed简单介绍 sed 是一种在线编辑器,它一次处理一行内容.处理时.把当前处理的行存储在暂时缓冲区中,称为"模式空间"(patt ...

  4. C# Xml文件操作,解释见注释

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  5. 记录Windows下文件操作记录

    https://blog.csdn.net/huashuolin001/article/details/73863324

  6. Java路径操作具体解释

    1.基本概念的理解 绝对路径:绝对路径就是你的主页上的文件或文件夹在硬盘上真正的路径.(URL和物理路径)比如: C:\xyz\test.txt 代表了test.txt文件的绝对路径.http://w ...

  7. Windows与Linux下文件操作监控的实现

    一.需求分析: 随着渲染业务的不断进行,数据传输渐渐成为影响业务时间最大的因素.究其原因就是因为数据传输耗费较长的时间.于是,依托于渲染业务的网盘开发逐渐成为迫切需要解决的需求.该网盘的实现和当前市场 ...

  8. Windows phone 8 学习笔记(2) 数据文件操作(转)

    Windows phone 8 应用用于数据文件存储访问的位置仅仅限于安装文件夹.本地文件夹(独立存储空间).媒体库和SD卡四个地方.本节主要讲解它们的用法以及相关限制性.另外包括本地数据库的使用方式 ...

  9. Windows文件操作的API函数[转载]

    在VC中,大多数情况对文件的操作都使用系统提供的 API 函数,但有的函数我们不是很熟悉,以下提供一些文件操作 API 函数介绍: 一般文件操作 API CreateFile 打开文件 要对文件进行读 ...

随机推荐

  1. docker 定时清理none镜像

    =============================================== 2019/3/31_第1次修改                       ccb_warlock == ...

  2. python for dl

    算是python的简明教程吧,总结的不错: https://zhuanlan.zhihu.com/p/24162430 python for opencv: https://zhuanlan.zhih ...

  3. ssh-keygen -t rsa -b 4096 -C "邮箱"

    ssh-keygen -t rsa -b 4096 -C "邮箱":这条命令的目的是为了让本地机器ssh登录远程机器上的GitHub账户无需输入密码.将这条命令分解: 1.ssh- ...

  4. ubuntu 查看进程信息

    查看进程信息 ps ps -aux 查看所有进程,每行一个程序 top 显示当前运行程序 kill 98 (98为PID号,) kill -9 98 (强制杀死98) ps -e Linux如何查看端 ...

  5. Java 清理和垃圾回收

    java.lang.ref.cleaner包 finalize()//该方法已过时,有风险,慎用 1.对象不可能被垃圾回收 2.垃圾回收并不等于"析构" 只有当垃圾回收发生时fin ...

  6. php数据类型之自动转换和强制转换

    PHP在PHP 5.x阶段都是完全的弱类型的编程语言.所谓弱类型,就是在声明变量的时候,不需要指定变量的类型.我要声明一个整型的变量,我不用在前面非得写上类型,再写变量.而PHP 7 的性能有很大的提 ...

  7. gcd,lcm

    定理:gcd(a,b)*lcm(a,b)=a*b; 更相损减术:gcd(a,b)=gcd(b,a-b)=gcd(a,a-b) 欧几里得算法:gcd(a,b)=gcd(b,a mod b) 复杂度O(l ...

  8. 设计模式【转自JackFrost的博客】

    首先,感谢作者对知识的分享 使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性.设计模式使代码编制真正工程化,是软件工程的基石脉络,如同大厦的结构一样. 文章结构:1.单一职责原则( ...

  9. #3 Codeforces-865C Gotta Go Fast(期望dp)

    题意:一个游戏一共有n个关卡,对于第i关,用a[i]时间通过的概率为p[i],用b[i]通过的时间为1-p[i],每通过一关后可以选择继续下一关或者时间清0并从第一关开始,先要求通过所有关卡的时间和不 ...

  10. A. 【UR #4】元旦三侠的游戏

    题解: 挺水的吧 会发现当b不等于1的时候,状态只有sigma i x^(1/i) 显然这东西很小.. 然后我们会发现每个点向两个点动 定义必胜点和必败点 当一个点有一条边连向必败点 那么它就是必胜点 ...