Windows DIB文件操作详解-4.使用DIB Section
2020-12-13 02:55
标签:dib bitmap createdibsection getdibcolortable dibsection 前面讲了为了提高DIB的显示性能和效率,我们将DIB转换成DDB,但是这又遇到一个问题,如果我想操作DIB的数据的话,显然是不能使用DDB:一是因为DIB转DDB时发生了颜色转换,再就是DDB无法直接提取指定像素点的数据。那么我们怎么办呢,Windows使用一种折中的方式来达到这一目标(既提高了显示效率和性能,又可以直接操作像素点)。 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各个数据区的显示效率和性能要高。 明白了Windows对于DIB Section的存储原理和转换规则以后,我们说一下DIB Section的相关函数使用。 使用如下: 2.传入包含DIB位图信息头(Info Header)、压缩掩码(Mask)及调色板信息(Color Table,主要针对位图深度
即常用调用步骤如下: 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内存区同时也会释放掉。
在后续我会讲解使用DIB Section来完成图像指定像素点的读写,实际上,一旦能够操作pBits,那么完成指定像素点的读写也不是什么难事。
Windows DIB文件操作详解-4.使用DIB Section,搜素材,soscw.com Windows DIB文件操作详解-4.使用DIB Section 标签:dib bitmap createdibsection getdibcolortable dibsection 原文地址:http://blog.csdn.net/wenzhou1219/article/details/307857771.DIB Section存储和显示
2.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
);
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];
}
完整演示代码下载链接
文章标题:Windows DIB文件操作详解-4.使用DIB Section
文章链接:http://soscw.com/essay/26577.html