16位DIB |
16位DIB |
32位DIB |
|
红色屏蔽 |
0x00007C00 |
0x0000F800 |
0x00FF0000 |
绿色屏蔽 |
0x000003E0 |
0x000007E0 |
0x0000FF00 |
蓝色屏蔽 |
0x0000001F |
0x0000001F |
0x000000FF |
速记为 |
5-5-5 |
5-6-5 |
8-8-8 |
SetDIBitsToDevice函数传回所显示的扫描行的数目。
因此,要呼叫SetDIBitsToDevice来显示整个DIB图像,您需要下列信息:
BITMAPFILEHEADER * DibLoadImage (PTSTR pstrFileName) { BOOL bSuccess ; DWORD dwFileSize, dwHighSize, dwBytesRead ; HANDLE hFile ; BITMAPFILEHEADER * pbmfh ; hFile = CreateFile (pstrFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL) ; if (hFile == INVALID_HANDLE_VALUE) return NULL ; dwFileSize = GetFileSize (hFile, &dwHighSize) ; if (dwHighSize) { CloseHandle (hFile) ; return NULL ; } pbmfh = malloc (dwFileSize) ; if (!pbmfh) { CloseHandle (hFile) ; return NULL ; } // 必须全部加载都内存中,不然显示不出来 bSuccess = ReadFile (hFile, pbmfh, dwFileSize, &dwBytesRead, NULL) ; // bSuccess = ReadFile(hFile, pbmfh, sizeof(BITMAPFILEHEADER),&dwBytesRead, NULL); CloseHandle (hFile) ; if (!bSuccess || (pbmfh->bfType != * (WORD *) "BM") || (pbmfh->bfSize != dwFileSize)) { free (pbmfh) ; return NULL ; } return pbmfh ; }
static BITMAPFILEHEADER * pbmfh ; static BITMAPINFO * pbmi ; static BYTE * pBits ; pbmi = (BITMAPINFO *) (pbmfh + 1) ; pBits = (BYTE *) pbmfh + pbmfh->bfOffBits ; // Get the DIB width and height //判断是不是旧格式 If 表示旧格式 if (pbmi->bmiHeader.biSize == sizeof (BITMAPCOREHEADER)) { cxDib = ((BITMAPCOREHEADER *) pbmi)->bcWidth ; cyDib = ((BITMAPCOREHEADER *) pbmi)->bcHeight ; } else { cxDib = pbmi->bmiHeader.biWidth ; cyDib = abs (pbmi->bmiHeader.biHeight) ; } if (pbmfh) SetDIBitsToDevice (hdc, 0, // xDst 0, // yDst cxDib, // cxSrc cyDib, // cySrc 0, // xSrc 源图坐标系左下角 X轴 0, // ySrc 0, // first scan line cyDib, // number of scan lines pBits, pbmi, DIB_RGB_COLORS) ;
hFile = CreateFile (szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL) ; if (hFile == INVALID_HANDLE_VALUE) { MessageBox (hwnd, TEXT ("Cannot open file."), szAppName, MB_ICONWARNING | MB_OK) ; return 0 ; } // Read in the BITMAPFILEHEADER bSuccess = ReadFile (hFile, &bmfh, sizeof (BITMAPFILEHEADER), &dwBytesRead, NULL) ; if (!bSuccess || dwBytesRead != sizeof (BITMAPFILEHEADER)) { MessageBox (hwnd, TEXT ("Cannot read file."), szAppName, MB_ICONWARNING | MB_OK) ; CloseHandle (hFile) ; return 0 ; } // Check that it's a bitmap if (bmfh.bfType != * (WORD *) "BM") { MessageBox (hwnd, TEXT ("File is not a bitmap."), szAppName, MB_ICONWARNING | MB_OK) ; CloseHandle (hFile) ; return 0 ; } // Allocate memory for header and bits iInfoSize = bmfh.bfOffBits - sizeof (BITMAPFILEHEADER) ; iBitsSize = bmfh.bfSize - bmfh.bfOffBits ; pbmi = malloc (iInfoSize) ; pBits = malloc (iBitsSize) ; if (pbmi == NULL || pBits == NULL) { MessageBox (hwnd, TEXT ("Cannot allocate memory."), szAppName, MB_ICONWARNING | MB_OK) ; if (pbmi) free (pbmi) ; if (pBits) free (pBits) ; CloseHandle (hFile) ; return 0 ; } // Read in the Information Header bSuccess = ReadFile (hFile, pbmi, iInfoSize, &dwBytesRead, NULL) ; if (!bSuccess || (int) dwBytesRead != iInfoSize) { MessageBox (hwnd, TEXT ("Cannot read file."), szAppName, MB_ICONWARNING | MB_OK) ; if (pbmi) free (pbmi) ; if (pBits) free (pBits) ; CloseHandle (hFile) ; return 0 ; } // Get the DIB width and height bTopDown = FALSE ; if (pbmi->bmiHeader.biSize == sizeof (BITMAPCOREHEADER)) { cxDib = ((BITMAPCOREHEADER *) pbmi)->bcWidth ; cyDib = ((BITMAPCOREHEADER *) pbmi)->bcHeight ; cBits = ((BITMAPCOREHEADER *) pbmi)->bcBitCount ; } else { if (pbmi->bmiHeader.biHeight < 0) bTopDown = TRUE ; cxDib = pbmi->bmiHeader.biWidth ; cyDib = abs (pbmi->bmiHeader.biHeight) ; cBits = pbmi->bmiHeader.biBitCount ; if (pbmi->bmiHeader.biCompression != BI_RGB && pbmi->bmiHeader.biCompression != BI_BITFIELDS) { MessageBox (hwnd, TEXT ("File is compressed."), szAppName, MB_ICONWARNING | MB_OK) ; if (pbmi) free (pbmi) ; if (pBits) free (pBits) ; CloseHandle (hFile) ; return 0 ; } } // Get the row length // 去除小于32的部分 0011 1111 = 31 取反与就去除了 >>3 表示除以8 iRowLength = ((cxDib * cBits + 31) & ~31) >> 3 ; iRowLength = 4 * ((cxDib * cBits + 31) / 32) ; // Read and display SetCursor (LoadCursor (NULL, IDC_WAIT)) ; ShowCursor (TRUE) ; hdc = GetDC (hwnd) ; for (y = 0 ; y < cyDib ; y++) { ReadFile (hFile, pBits + y * iRowLength, iRowLength, &dwBytesRead, NULL) ; SetDIBitsToDevice (hdc, 0, // xDst 0, // yDst cxDib, // cxSrc cyDib, // cySrc 0, // xSrc 0, // ySrc bTopDown ? cyDib - y - 1 : y, // first scan line 1, // number of scan lines 表示显示1行 pBits + y * iRowLength, pbmi, DIB_RGB_COLORS) ; } ReleaseDC (hwnd, hdc) ; CloseHandle (hFile) ; ShowCursor (FALSE) ; SetCursor (LoadCursor (NULL, IDC_ARROW)) ; return 0 ;
缩放到合适尺寸
SetDIBitsToDevice完成了将DIB的图素对点送入输出设备的显示程序。这对于打印DIB用处不大。打印机的分辨率越高,得到的图像就越小,您最终会得到如邮票大小的图像。
要通过缩小或放大DIB,在输出设备上以特定的大小显示它,可以使用StretchDIBits
iLines = StretchDIBits ( hdc, // device context handle xDst, // x destination coordinate yDst, // y destination coordinate cxDst, // destination rectangle width cyDst, // destination rectangle height xSrc, // x source coordinate ySrc, // y source coordinate cxSrc, // source rectangle width cySrc, // source rectangle height pBits, // pointer to DIB pixel bits pInfo, // pointer to DIB information fClrUse, // color use flag 一般使用 DIB_RGB_COLORS dwRop) ; // raster operation SRCCOPY
从DIB建立DDB
从DIB中建立GDI位图对象可能吗?基本上我们已经知道了方法:如果有DIB,您就能够使用CreateCompatibleBitmap来建立与DIB大小相同并与视讯显示器兼容的GDI位图对象。然后将该位图对象选入内存设备内容并呼叫SetDIBitsToDevice在那个内存DC上绘图。结果就是DDB具有与DIB相同的图像,但具有与视讯显示器兼容的颜色组织。
您也可以通过呼叫CreateDIBitmap用几个步骤完成上述工作。函数使用:DIB区块
我希望您已经对设备相关和设备无关位图的区别有了清晰的概念。DIB能拥有几种色彩组织中的一种,DDB必须是单色的或是与真实输出设备相同的格式。DIB是一个文件或内存块;DDB是GDI位图对象并由位图句柄表示。DIB能被显示或转换为DDB并转换回DIB,但是这里包含了设备无关位和设备相关位之间的转换程序。
现在您将遇到一个函数,它打破了这些规则。该函数在32位Windows版本中发表,称为CreateDIBSection,语法为:
hBitmap = CreateDIBSection ( hdc, // device context handle pInfo, // pointer to DIB information fClrUse, // color use flag ppBits, // pointer to pointer variable hSection, // file-mapping object handle dwOffset) ; // offset to bits in file-mapping object
HBITMAP CreateDibSectionFromDibFile (PTSTR szFileName) { BITMAPFILEHEADER bmfh ; BITMAPINFO * pbmi ; BYTE * pBits ; BOOL bSuccess ; DWORD dwInfoSize, dwBytesRead ; HANDLE hFile ; HBITMAP hBitmap ; // Open the file: read access, prohibit write access hFile = CreateFile (szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL) ; if (hFile == INVALID_HANDLE_VALUE) return NULL ; // Read in the BITMAPFILEHEADER bSuccess = ReadFile (hFile, &bmfh, sizeof (BITMAPFILEHEADER), &dwBytesRead, NULL) ; if (!bSuccess || (dwBytesRead != sizeof (BITMAPFILEHEADER)) || (bmfh.bfType != * (WORD *) "BM")) { CloseHandle (hFile) ; return NULL ; } // Allocate memory for the BITMAPINFO structure & read it in dwInfoSize = bmfh.bfOffBits - sizeof (BITMAPFILEHEADER) ; pbmi = malloc (dwInfoSize) ; bSuccess = ReadFile (hFile, pbmi, dwInfoSize, &dwBytesRead, NULL) ; if (!bSuccess || (dwBytesRead != dwInfoSize)) { free (pbmi) ; CloseHandle (hFile) ; return NULL ; } // Create the DIB Section hBitmap = CreateDIBSection (NULL, pbmi, DIB_RGB_COLORS, &pBits, NULL, 0) ; if (hBitmap == NULL) { free (pbmi) ; CloseHandle (hFile) ; return NULL ; } // Read in the bitmap bits ReadFile (hFile, pBits,pbmi->bmiHeader.biSizeImage /*bmfh.bfSize - bmfh.bfOffBits*/, &dwBytesRead, NULL) ; free (pbmi) ; CloseHandle (hFile) ; return hBitmap ; }
我之前曾说过,当在视讯显示器上显示DIB时,某些时候必须进行从设备无关图素到设备相关图素的转换,有时这些格式转换可能相当费时。来看一看三种用于显示DIB的方法: