大家好,又见面了,我是全栈君。
前面讲了为了提高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_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
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)也不至于错误发生。
3.代码演示
//读入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
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/115221.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...