DIB(设备无关位图)是存储在磁盘上的位图文件,可以从磁盘读到内存中或从内存保存到磁盘上,它的磁盘文件结构是标准化的,在Linux、Unix及Windows上都可以以同样效果显示。位图是最接近硬件的图像格式,Windows显示的核心是位图,它的SDK API专门提供了一组用于操作DIB文件的函数。但是由于这样或那样的原因,高效合理的使用这些DIB API是需要了解不少历史和使用背景的,在这里我抽茧剥丝介绍和演示DIB的使用,相信对你更好的使用DIB文件有帮助,由于DIB函数比较多,这里分为三部分介绍,首先是DIB的读入、保存和显示。
关于DIB文件的组成很多地方有详细描述,这里不再详细赘述。主要分为如下几个部分:
其中
其中,信息表头和RGB调色板合称为位图信息。
我们要把DIB数据读入到内存中,那么就要分配相应的内存,把读入的数据写到对应的内存区中,这里SDK 提供的数据结构是各种结构体,结构体的各个字段对应磁盘文件中各个信息值。我们这里为了逻辑清楚,使用最常使用的DIB结构体。
如图,文件中的数据读到对应的内存结构中完成文件的读入,内存结构中的数据写到对应的文件中完成文件的保存。
其中
把BITMAPINFOHEADER和RGBQUAD[0]作为BITMAPINFO结构体成员,这样一方面是为了和磁盘文件对应,另一方面也是为了访问调色板数据方便。
这里的磁盘文件中各个段在磁盘上保存位置必须是连续的,但是对应的内存中文件信息头、位图信息和位图数据三大块不一定要是连续的。因此,在读入文件中你既可以一次性读入磁盘文件到连续的内存中,也可以分开读入到三个分别连续的内存中,后面会做相关演示。
int SetDIBitsToDevice( HDC hdc, // handle to DC int XDest, // x-coord of destination upper-left corner int YDest, // y-coord of destination upper-left corner DWORD dwWidth, // source rectangle width DWORD dwHeight, // source rectangle height int XSrc, // x-coord of source lower-left corner int YSrc, // y-coord of source lower-left corner UINT uStartScan, // first scan line in array UINT cScanLines, // number of scan lines CONST VOID *lpvBits, // array of DIB bits CONST BITMAPINFO *lpbmi, // bitmap information UINT fuColorUse // RGB or palette indexes );
int StretchDIBits( HDC hdc, // handle to DC int XDest, // x-coord of destination upper-left corner int YDest, // y-coord of destination upper-left corner int nDestWidth, // width of destination rectangle int nDestHeight, // height of destination rectangle int XSrc, // x-coord of source upper-left corner int YSrc, // y-coord of source upper-left corner int nSrcWidth, // width of source rectangle int nSrcHeight, // height of source rectangle CONST VOID *lpBits, // bitmap bits CONST BITMAPINFO *lpBitsInfo, // bitmap data UINT iUsage, // usage options DWORD dwRop // raster operation code );
BOOL DibTotalLoad(PTSTR szBmpFile, PBITMAPFILEHEADER *ppbmfh, PBITMAPINFO *ppbmi, PBYTE *ppBits, PLONG pBmpWidth, PLONG pBmpHeight) { HANDLE hFile; DWORD dwFileSize, dwBytesRead; BOOL bSuccess; //打开文件 hFile = CreateFile( szBmpFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (INVALID_HANDLE_VALUE == hFile) { return FALSE; } //判断BMP文件大小(所有部分) dwFileSize = GetFileSize(hFile, NULL); //分配对应大小内存用于保存磁盘BMP文件内容 *ppbmfh = malloc(dwFileSize); if (!(*ppbmfh)) { CloseHandle(hFile); return FALSE; } //读入文件内容 bSuccess = ReadFile(hFile, *ppbmfh, dwFileSize, &dwBytesRead, NULL); CloseHandle(hFile); //校验读入是否正确和文件是否为BMP文件 if (!bSuccess || (dwBytesRead != dwFileSize) || (*ppbmfh)->bfType != *(WORD *)"BM") { free(*ppbmfh); return FALSE; } //计算剩余的返回参数 *ppbmi = (PBITMAPINFO)(*ppbmfh+1); *ppBits = (PBYTE)(*ppbmfh) + (*ppbmfh)->bfOffBits; *pBmpWidth = (*ppbmi)->bmiHeader.biWidth; *pBmpHeight = (*ppbmi)->bmiHeader.biHeight; return TRUE; } BOOL DibTotalSave(PTSTR szBmpFile, PBITMAPFILEHEADER pbmfh) { BOOL bSuccess; DWORD dwBytesWrite; HANDLE hFile; //打开要写入的文件 hFile = CreateFile(szBmpFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hFile) { return FALSE; } //写入文件 bSuccess = WriteFile(hFile, pbmfh, pbmfh->bfSize, &dwBytesWrite, NULL); CloseHandle(hFile); if (!bSuccess || dwBytesWrite != pbmfh->bfSize) { DeleteFile(hFile); return FALSE; } return TRUE; } void ShowDib(HDC hdc, PBITMAPINFO pbmi, PBYTE pBits, long nBmpWidth, long nBmpHeight, long cxClient, long cyClient, BOOL bFull) { if (FALSE == bFull)//居中显示 { SetDIBitsToDevice( hdc, (cxClient-nBmpWidth)/2, (cyClient-nBmpHeight)/2, nBmpWidth, nBmpHeight, 0, 0, 0, nBmpHeight, pBits, pbmi, DIB_RGB_COLORS); } else//拉伸显示 { SetStretchBltMode(hdc, COLORONCOLOR); StretchDIBits(hdc, 0, 0, cxClient, cyClient, 0, 0, nBmpWidth, nBmpHeight, pBits, pbmi, DIB_RGB_COLORS, SRCCOPY); } }