windows 程序设计 DIB(设备无关的位图)

DIB 图
 

16位DIB

16位DIB

32位DIB

红色屏蔽

0x00007C00

0x0000F800

0x00FF0000

绿色屏蔽

0x000003E0

0x000007E0

0x0000FF00

蓝色屏蔽

0x0000001F

0x0000001F

0x000000FF

速记为

5-5-5

5-6-5

8-8-8




File size = 65078 bytes


BITMAPFILEHEADER
.bfType = 0x4D42
.bfSize = 65078
.bfReserved1 = 0
.bfReserved2 = 0
.bfOffBits = 1078


BITMAPINFOHEADER
.biSize = 40  结构大小
.biWidth = 200    位图宽度,单位为像素(有符号整数)
.biHeight = 320    位图高度,单位为像素(有符号整数)
.biPlanes = 1 颜色平面,目前只有1
.biBitCount = 8 颜色位数(2,4,8,16,24,32)
.biCompression = BI_RGB  压缩算法
.biSizeImage = 64000 指定实际的位图数据占用的字节数
.biXPelsPerMeter = 0   图像的横向分辨率,单位为像素每米(有符号整数
.biYPelsPerMeter = 0    图像的纵向分辨率,单位为像素每米(有符号整数)
.biClrUsed = 256  调色板颜色数
.biClrImportant = 0   0表示颜色都重要


显示位图的两个函数
SetDIBitsToDevice
StretchDIBits


SetDIBitsToDevice函数传回所显示的扫描行的数目。

因此,要呼叫SetDIBitsToDevice来显示整个DIB图像,您需要下列信息:

  • hdc目的表面的设备内容句柄
     
  • xDst和yDst图像左上角的目的坐标
     
  • cxDib和cyDibDIB的图素宽度和高度,在这里,cyDib是BITMAPINFOHEADER结构内biHeight字段的绝对值。
     
  • pInfo和pBits指向位图信息部分和图素位的指针
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) ;

windows 程序设计 DIB(设备无关的位图)_第1张图片


 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用几个步骤完成上述工作。函数使用:


BITMAPFILEHEADER * pbmfh

     hBitmap = CreateDIBitmap (hdc,              
                               (BITMAPINFOHEADER *) (pbmfh + 1),
                               CBM_INIT,
                               (BYTE *) pbmfh + pbmfh->bfOffBits,
                               (BITMAPINFO *) (pbmfh + 1),
                               DIB_RGB_COLORS) ;
if (hBitmap)
          {
               GetObject (hBitmap, sizeof (BITMAP), &bitmap) ;


               hdcMem = CreateCompatibleDC (hdc) ;
               SelectObject (hdcMem, hBitmap) ;

使用BitBlt画

               BitBlt (hdc,    0, 0, bitmap.bmWidth, bitmap.bmHeight, 
                       hdcMem, 0, 0, SRCCOPY) ;


               DeleteDC (hdcMem) ;
          }

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的方法:

  • 当使用SetDIBitsToDevice或StretchDIBits来把DIB直接显示在屏幕上,格式转换在SetDIBitsToDevice或StretchDIBits呼叫期间发生。
     
  • 当使用CreateDIBitmap和(可能是)SetDIBits把DIB转换为DDB,然后使用BitBlt或StretchBlt来显示它时,如果设定了CBM_INIT旗标,格式转换在CreateDIBitmap或SetDIBits期间发生。
     
  • 当使用CreateDIBSection建立DIB区块,然后使用BitBlt或StretchBlt显示它时,格式转换在BitBlt对StretchBlt的呼叫期间发生

你可能感兴趣的:(windows,位图)