DIB.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:21k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /****************************************************************************
  2. *            
  3. *     FILE:     DIB.C
  4. *
  5. *     PURPOSE:  DIB functions for IconPro Project
  6. *
  7. *     COMMENTS: Icons are stored in a format almost identical to DIBs. For
  8. *               this reason, it is easiest to deal with the individual
  9. *               icon images as DIBs (or DIBSections). This has the added
  10. *               advantage of retaining color depth even on low-end displays.
  11. *
  12. *     FUNCTIONS:
  13. *      EXPORTS: 
  14. *               FindDIBBits()      - Locate the image bits in a DIB
  15. *               DIBNumColors()     - Calculate number of color table entries
  16. *               PaletteSize()      - Calculate number of color table bytes
  17. *               BytesPerLine()     - Calculate number of bytes per scan line
  18. *               ConvertDIBFormat() - Converts DIBs between formats
  19. *               SetMonoDIBPixel()  - Sets/Clears a pixel in a 1bpp DIB
  20. *               ReadBMPFile()      - Reads a BMP file into CF_DIB memory
  21. *               WriteBMPFile()     - Write a BMP file from CF_DIB memory
  22. *      LOCALS:
  23. *               CopyColorTable()   - Copies color table from DIB to DIB
  24. *
  25. *     Copyright 1995 - 1997 Microsoft Corp.
  26. *
  27. *
  28. * History:
  29. *                July '95 - Created
  30. *
  31. ****************************************************************************/
  32. #include <Windows.h>
  33. #include "Dib.H"
  34. /****************************************************************************/
  35. /* Local Function Prototypes */
  36. BOOL CopyColorTable( LPBITMAPINFO lpTarget, LPBITMAPINFO lpSource );
  37. /****************************************************************************/
  38. /****************************************************************************
  39. *
  40. *     FUNCTION: FindDIBits
  41. *
  42. *     PURPOSE:  Locate the image bits in a CF_DIB format DIB.
  43. *
  44. *     PARAMS:   LPSTR lpbi - pointer to the CF_DIB memory block
  45. *
  46. *     RETURNS:  LPSTR - pointer to the image bits
  47. *
  48. * History:
  49. *                July '95 - Copied <g>
  50. *
  51. ****************************************************************************/
  52. LPSTR FindDIBBits( LPSTR lpbi )
  53. {
  54.    return ( lpbi + *(LPDWORD)lpbi + PaletteSize( lpbi ) );
  55. }
  56. /* End FindDIBits() *********************************************************/
  57. /****************************************************************************
  58. *
  59. *     FUNCTION: DIBNumColors
  60. *
  61. *     PURPOSE:  Calculates the number of entries in the color table.
  62. *
  63. *     PARAMS:   LPSTR lpbi - pointer to the CF_DIB memory block
  64. *
  65. *     RETURNS:  WORD - Number of entries in the color table.
  66. *
  67. * History:
  68. *                July '95 - Copied <g>
  69. *
  70. ****************************************************************************/
  71. WORD DIBNumColors( LPSTR lpbi )
  72. {
  73.     WORD wBitCount;
  74.     DWORD dwClrUsed;
  75.     dwClrUsed = ((LPBITMAPINFOHEADER) lpbi)->biClrUsed;
  76.     if (dwClrUsed)
  77.         return (WORD) dwClrUsed;
  78.     wBitCount = ((LPBITMAPINFOHEADER) lpbi)->biBitCount;
  79.     switch (wBitCount)
  80.     {
  81.         case 1: return 2;
  82.         case 4: return 16;
  83.         case 8: return 256;
  84.         default:return 0;
  85.     }
  86.     return 0;
  87. }
  88. /* End DIBNumColors() ******************************************************/
  89. /****************************************************************************
  90. *
  91. *     FUNCTION: PaletteSize
  92. *
  93. *     PURPOSE:  Calculates the number of bytes in the color table.
  94. *
  95. *     PARAMS:   LPSTR lpbi - pointer to the CF_DIB memory block
  96. *
  97. *     RETURNS:  WORD - number of bytes in the color table
  98. *
  99. *
  100. * History:
  101. *                July '95 - Copied <g>
  102. *
  103. ****************************************************************************/
  104. WORD PaletteSize( LPSTR lpbi )
  105. {
  106.     return ( DIBNumColors( lpbi ) * sizeof( RGBQUAD ) );
  107. }
  108. /* End PaletteSize() ********************************************************/
  109. /****************************************************************************
  110. *
  111. *     FUNCTION: BytesPerLine
  112. *
  113. *     PURPOSE:  Calculates the number of bytes in one scan line.
  114. *
  115. *     PARAMS:   LPBITMAPINFOHEADER lpBMIH - pointer to the BITMAPINFOHEADER
  116. *                                           that begins the CF_DIB block
  117. *
  118. *     RETURNS:  DWORD - number of bytes in one scan line (DWORD aligned)
  119. *
  120. * History:
  121. *                July '95 - Created
  122. *
  123. ****************************************************************************/
  124. DWORD BytesPerLine( LPBITMAPINFOHEADER lpBMIH )
  125. {
  126.     return WIDTHBYTES(lpBMIH->biWidth * lpBMIH->biPlanes * lpBMIH->biBitCount);
  127. }
  128. /* End BytesPerLine() ********************************************************/
  129. /****************************************************************************
  130. *
  131. *     FUNCTION: ConvertDIBFormat
  132. *
  133. *     PURPOSE:  Creates a new DIB of the requested format, copies the source
  134. *               image to the new DIB.
  135. *
  136. *     PARAMS:   LPBITMAPINFO lpSrcDIB - the source CF_DIB
  137. *               UINT         nWidth   - width for new DIB
  138. *               UINT         nHeight  - height for new DIB
  139. *               UINT         nbpp     - bpp for new DIB
  140. *               BOOL         bStretch - TRUE to stretch source to dest
  141. *                                       FALSE to take upper left of image
  142. *
  143. *     RETURNS:  LPBYTE - pointer to new CF_DIB memory block with new image
  144. *               NULL on failure
  145. *
  146. * History:
  147. *                July '95 - Created
  148. *
  149. ****************************************************************************/
  150. LPBYTE ConvertDIBFormat( LPBITMAPINFO lpSrcDIB, UINT nWidth, UINT nHeight, UINT nbpp, BOOL bStretch )
  151. {
  152.     LPBITMAPINFO    lpbmi = NULL;
  153.     LPBYTE         lpSourceBits, lpTargetBits, lpResult;
  154.     HDC             hDC = NULL, hSourceDC, hTargetDC;
  155.     HBITMAP         hSourceBitmap, hTargetBitmap, hOldTargetBitmap, hOldSourceBitmap;
  156.     DWORD         dwSourceBitsSize, dwTargetBitsSize, dwTargetHeaderSize;
  157.     // Allocate and fill out a BITMAPINFO struct for the new DIB
  158.     // Allow enough room for a 256-entry color table, just in case
  159.     dwTargetHeaderSize = sizeof( BITMAPINFO ) + ( 256 * sizeof( RGBQUAD ) );
  160.     lpbmi = malloc( dwTargetHeaderSize );
  161.     lpbmi->bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
  162.     lpbmi->bmiHeader.biWidth = nWidth;
  163.     lpbmi->bmiHeader.biHeight = nHeight;
  164.     lpbmi->bmiHeader.biPlanes = 1;
  165.     lpbmi->bmiHeader.biBitCount = nbpp;
  166.     lpbmi->bmiHeader.biCompression = BI_RGB;
  167.     lpbmi->bmiHeader.biSizeImage = 0;
  168.     lpbmi->bmiHeader.biXPelsPerMeter = 0;
  169.     lpbmi->bmiHeader.biYPelsPerMeter = 0;
  170.     lpbmi->bmiHeader.biClrUsed = 0;
  171.     lpbmi->bmiHeader.biClrImportant = 0;
  172.     // Fill in the color table
  173.     if( ! CopyColorTable( lpbmi, (LPBITMAPINFO)lpSrcDIB ) )
  174.     {
  175.         free( lpbmi );
  176.         return NULL;
  177.     }
  178.     // Gonna use DIBSections and BitBlt() to do the conversion, so make 'em
  179.     hDC = GetDC( NULL );
  180.     hTargetBitmap = CreateDIBSection( hDC, lpbmi, DIB_RGB_COLORS, &lpTargetBits, NULL, 0 );
  181.     hSourceBitmap = CreateDIBSection( hDC, lpSrcDIB, DIB_RGB_COLORS, &lpSourceBits, NULL, 0 );
  182.     hSourceDC = CreateCompatibleDC( hDC );
  183.     hTargetDC = CreateCompatibleDC( hDC );
  184.     // Flip the bits on the source DIBSection to match the source DIB
  185.     dwSourceBitsSize = lpSrcDIB->bmiHeader.biHeight * BytesPerLine(&(lpSrcDIB->bmiHeader));
  186.     dwTargetBitsSize = lpbmi->bmiHeader.biHeight * BytesPerLine(&(lpbmi->bmiHeader));
  187.     memcpy( lpSourceBits, FindDIBBits((LPSTR)lpSrcDIB), dwSourceBitsSize );
  188.     // Select DIBSections into DCs
  189.     hOldSourceBitmap = SelectObject( hSourceDC, hSourceBitmap );
  190.     hOldTargetBitmap = SelectObject( hTargetDC, hTargetBitmap );
  191.     // Set the color tables for the DIBSections
  192.     if( lpSrcDIB->bmiHeader.biBitCount <= 8 )
  193.         SetDIBColorTable( hSourceDC, 0, 1 << lpSrcDIB->bmiHeader.biBitCount, lpSrcDIB->bmiColors );
  194.     if( lpbmi->bmiHeader.biBitCount <= 8 )
  195.         SetDIBColorTable( hTargetDC, 0, 1 << lpbmi->bmiHeader.biBitCount, lpbmi->bmiColors );
  196.     // If we are asking for a straight copy, do it
  197.     if( (lpSrcDIB->bmiHeader.biWidth==lpbmi->bmiHeader.biWidth) && (lpSrcDIB->bmiHeader.biHeight==lpbmi->bmiHeader.biHeight) )
  198.     {
  199.         BitBlt( hTargetDC, 0, 0, lpbmi->bmiHeader.biWidth, lpbmi->bmiHeader.biHeight, hSourceDC, 0, 0, SRCCOPY );
  200.     }
  201.     else
  202.     {
  203.         // else, should we stretch it?
  204.         if( bStretch )
  205.         {
  206.             SetStretchBltMode( hTargetDC, COLORONCOLOR );
  207.             StretchBlt( hTargetDC, 0, 0, lpbmi->bmiHeader.biWidth, lpbmi->bmiHeader.biHeight, hSourceDC, 0, 0, lpSrcDIB->bmiHeader.biWidth, lpSrcDIB->bmiHeader.biHeight, SRCCOPY );
  208.         }
  209.         else
  210.         {
  211.             // or just take the upper left corner of the source
  212.             BitBlt( hTargetDC, 0, 0, lpbmi->bmiHeader.biWidth, lpbmi->bmiHeader.biHeight, hSourceDC, 0, 0, SRCCOPY );
  213.         }
  214.     }
  215.     // Clean up and delete the DCs
  216.     SelectObject( hSourceDC, hOldSourceBitmap );
  217.     SelectObject( hSourceDC, hOldTargetBitmap );
  218.     DeleteDC( hSourceDC );
  219.     DeleteDC( hTargetDC );
  220.     ReleaseDC( NULL, hDC );
  221.     // Flush the GDI batch, so we can play with the bits
  222.     GdiFlush();
  223.     // Allocate enough memory for the new CF_DIB, and copy bits
  224.     lpResult = malloc( dwTargetHeaderSize + dwTargetBitsSize );
  225.     memcpy( lpResult, lpbmi, dwTargetHeaderSize );
  226.     memcpy( FindDIBBits( lpResult ), lpTargetBits, dwTargetBitsSize );
  227.     // final cleanup
  228.     DeleteObject( hTargetBitmap );
  229.     DeleteObject( hSourceBitmap );
  230.     free( lpbmi );
  231.     return lpResult;
  232. }
  233. /* End ConvertDIBFormat() ***************************************************/
  234. /****************************************************************************
  235. *
  236. *     FUNCTION: CopyColorTable
  237. *
  238. *     PURPOSE:  Copies the color table from one CF_DIB to another.
  239. *
  240. *     PARAMS:   LPBITMAPINFO lpTarget - pointer to target DIB
  241. *               LPBITMAPINFO lpSource - pointer to source DIB
  242. *
  243. *     RETURNS:  BOOL - TRUE for success, FALSE for failure
  244. *
  245. * History:
  246. *                July '95 - Created
  247. *
  248. ****************************************************************************/
  249. BOOL CopyColorTable( LPBITMAPINFO lpTarget, LPBITMAPINFO lpSource )
  250. {
  251.     // What we do depends on the target's color depth
  252.     switch( lpTarget->bmiHeader.biBitCount )
  253.     {
  254.         // 8bpp - need 256 entry color table
  255.         case 8:
  256.             if( lpSource->bmiHeader.biBitCount == 8 )
  257.             { // Source is 8bpp too, copy color table
  258.                 memcpy( lpTarget->bmiColors, lpSource->bmiColors, 256*sizeof(RGBQUAD) );
  259.                 return TRUE;
  260.             }
  261.             else
  262.             { // Source is != 8bpp, use halftone palette                
  263.                 HPALETTE        hPal;
  264.                 HDC             hDC = GetDC( NULL );
  265.                 PALETTEENTRY    pe[256];
  266.                 UINT            i;
  267.                 hPal = CreateHalftonePalette( hDC );
  268.                 ReleaseDC( NULL, hDC );
  269.                 GetPaletteEntries( hPal, 0, 256, pe );
  270.                 DeleteObject( hPal );
  271.                 for(i=0;i<256;i++)
  272.                 {
  273.                     lpTarget->bmiColors[i].rgbRed = pe[i].peRed;
  274.                     lpTarget->bmiColors[i].rgbGreen = pe[i].peGreen;
  275.                     lpTarget->bmiColors[i].rgbBlue = pe[i].peBlue;
  276.                     lpTarget->bmiColors[i].rgbReserved = pe[i].peFlags;
  277.                 }
  278.                 return TRUE;
  279.             }
  280.         break; // end 8bpp
  281.         // 4bpp - need 16 entry color table
  282.         case 4:
  283.             if( lpSource->bmiHeader.biBitCount == 4 )
  284.             { // Source is 4bpp too, copy color table
  285.                 memcpy( lpTarget->bmiColors, lpSource->bmiColors, 16*sizeof(RGBQUAD) );
  286.                 return TRUE;
  287.             }
  288.             else
  289.             { // Source is != 4bpp, use system palette
  290.                 HPALETTE        hPal;
  291.                 PALETTEENTRY    pe[256];
  292.                 UINT            i;
  293.                 hPal = GetStockObject( DEFAULT_PALETTE );
  294.                 GetPaletteEntries( hPal, 0, 16, pe );
  295.                 for(i=0;i<16;i++)
  296.                 {
  297.                     lpTarget->bmiColors[i].rgbRed = pe[i].peRed;
  298.                     lpTarget->bmiColors[i].rgbGreen = pe[i].peGreen;
  299.                     lpTarget->bmiColors[i].rgbBlue = pe[i].peBlue;
  300.                     lpTarget->bmiColors[i].rgbReserved = pe[i].peFlags;
  301.                 }
  302.                 return TRUE;
  303.             }
  304.         break; // end 4bpp
  305.         // 1bpp - need 2 entry mono color table
  306.         case 1:
  307.             lpTarget->bmiColors[0].rgbRed = 0;
  308.             lpTarget->bmiColors[0].rgbGreen = 0;
  309.             lpTarget->bmiColors[0].rgbBlue = 0;
  310.             lpTarget->bmiColors[0].rgbReserved = 0;
  311.             lpTarget->bmiColors[1].rgbRed = 255;
  312.             lpTarget->bmiColors[1].rgbGreen = 255;
  313.             lpTarget->bmiColors[1].rgbBlue = 255;
  314.             lpTarget->bmiColors[1].rgbReserved = 0;
  315.         break; // end 1bpp
  316.         // no color table for the > 8bpp modes
  317.         case 32:
  318.         case 24:
  319.         case 16:
  320.         default:
  321.             return TRUE;
  322.         break;
  323.     }
  324.     return TRUE;
  325. }
  326. /* End CopyColorTable() *****************************************************/
  327. /****************************************************************************
  328. *
  329. *     FUNCTION: SetMonoDIBPixel
  330. *
  331. *     PURPOSE:  Sets/Clears a pixel in a 1bpp DIB by directly poking the bits.
  332. *
  333. *     PARAMS:   LPBYTE pANDBits - pointer to the 1bpp image bits
  334. *               DWORD  dwWidth - width of the DIB
  335. *               DWORD  dwHeight - height of the DIB
  336. *               DWORD  x        - x location of pixel to set/clear
  337. *               DWORD  y        - y location of pixel to set/clear
  338. *               BOOL   bWhite - TRUE to set pixel, FALSE to clear it
  339. *
  340. *     RETURNS:  void
  341. *
  342. * History:
  343. *                July '95 - Created
  344. *
  345. ****************************************************************************/
  346. void SetMonoDIBPixel( LPBYTE pANDBits, DWORD dwWidth, DWORD dwHeight, DWORD x, DWORD y, BOOL bWhite )
  347. {
  348.     DWORD ByteIndex;
  349.     BYTE    BitNumber;
  350.     // Find the byte on which this scanline begins
  351.     ByteIndex = (dwHeight - y - 1) * WIDTHBYTES(dwWidth);
  352.     // Find the byte containing this pixel
  353.     ByteIndex += (x >> 3);
  354.     // Which bit is it?
  355.     BitNumber = (BYTE)( 7 - (x % 8) );
  356.     if( bWhite )
  357.         // Turn it on
  358.         pANDBits[ByteIndex] |= (1<<BitNumber);
  359.     else
  360.         // Turn it off
  361.         pANDBits[ByteIndex] &= ~(1<<BitNumber);
  362. }
  363. /* End SetMonoDIBPixel() *****************************************************/
  364. /****************************************************************************
  365. *
  366. *     FUNCTION: ReadBMPFile
  367. *
  368. *     PURPOSE:  Reads a BMP file into CF_DIB format
  369. *
  370. *     PARAMS:   LPCTSTR szFileName - the name of the file to read
  371. *
  372. *     RETURNS:  LPBYTE - pointer to the CF_DIB, NULL for failure
  373. *
  374. * History:
  375. *                July '95 - Created
  376. *
  377. ****************************************************************************/
  378. LPBYTE ReadBMPFile( LPCTSTR szFileName )
  379. {
  380.     HANDLE             hFile;
  381.     BITMAPFILEHEADER    bfh;
  382.     DWORD             dwBytes;
  383.     LPBYTE             lpDIB = NULL, lpTemp = NULL;
  384.     WORD                wPaletteSize = 0;
  385.     DWORD             dwBitsSize = 0;
  386.     // Open the file
  387.     if( (hFile=CreateFile( szFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE )
  388.     {
  389.         MessageBox( NULL, "Error opening file", szFileName, MB_OK );
  390.         return NULL;
  391.     }
  392.     // Read the header
  393.     if( ( ! ReadFile( hFile, &bfh, sizeof(BITMAPFILEHEADER), &dwBytes, NULL ) ) || ( dwBytes != sizeof( BITMAPFILEHEADER ) ) )
  394.     {
  395.         CloseHandle( hFile );
  396.         MessageBox( NULL, "Error reading file", szFileName, MB_OK );
  397.         return NULL;
  398.     }
  399.     // Does it look like a BMP file?
  400.     if( ( bfh.bfType != 0x4d42 ) || (bfh.bfReserved1!=0) || (bfh.bfReserved2!=0) )
  401.     {
  402.         CloseHandle( hFile );
  403.         MessageBox( NULL, "Not a recognised BMP format file", szFileName, MB_OK );
  404.         return NULL;
  405.     }
  406.     // Allocate some memory
  407.     if( (lpDIB = malloc( sizeof( BITMAPINFO ) )) == NULL )
  408.     {
  409.         CloseHandle( hFile );
  410.         MessageBox( NULL, "Failed to allocate memory for DIB", szFileName, MB_OK );
  411.         return NULL;
  412.     }
  413.     // Read in the BITMAPINFOHEADER
  414.     if( (!ReadFile( hFile, lpDIB, sizeof(BITMAPINFOHEADER), &dwBytes, NULL )) || (dwBytes!=sizeof(BITMAPINFOHEADER)) )
  415.     {
  416.         CloseHandle( hFile );
  417.         free( lpDIB );
  418.         MessageBox( NULL, "Error reading file", szFileName, MB_OK );
  419.         return NULL;
  420.     }
  421.     if( ((LPBITMAPINFOHEADER)lpDIB)->biSize != sizeof( BITMAPINFOHEADER ) )
  422.     {
  423.         CloseHandle( hFile );
  424.         free( lpDIB );
  425.         MessageBox( NULL, "OS/2 style BMPs Not Supported", szFileName, MB_OK );
  426.         return NULL;
  427.     }
  428.     // How big are the elements?
  429.     wPaletteSize = PaletteSize((LPSTR)lpDIB);
  430.     dwBitsSize = ((LPBITMAPINFOHEADER)lpDIB)->biHeight * BytesPerLine((LPBITMAPINFOHEADER)lpDIB);
  431.     // realloc to account for the total size of the DIB
  432.     if( (lpTemp = realloc( lpDIB, sizeof( BITMAPINFOHEADER ) + wPaletteSize + dwBitsSize )) == NULL )
  433.     {
  434.         CloseHandle( hFile );
  435.         MessageBox( NULL, "Failed to allocate memory for DIB", szFileName, MB_OK );
  436.         free( lpDIB );
  437.         return NULL;
  438.     }
  439.     lpDIB = lpTemp;
  440.     // If there is a color table, read it
  441.     if( wPaletteSize != 0 )
  442.     {
  443.         if( (!ReadFile( hFile, ((LPBITMAPINFO)lpDIB)->bmiColors, wPaletteSize, &dwBytes, NULL )) || (dwBytes!=wPaletteSize) )
  444.         {
  445.             CloseHandle( hFile );
  446.             free( lpDIB );
  447.             MessageBox( NULL, "Error reading file", szFileName, MB_OK );
  448.             return NULL;
  449.         }
  450.     }
  451.     // Seek to the bits
  452.     // checking against 0 in case some bogus app didn't set this element
  453.     if( bfh.bfOffBits != 0 )
  454.     {
  455.         if( SetFilePointer( hFile, bfh.bfOffBits, NULL, FILE_BEGIN ) == 0xffffffff )
  456.         {
  457.             CloseHandle( hFile );
  458.             free( lpDIB );
  459.             MessageBox( NULL, "Error reading file", szFileName, MB_OK );
  460.             return NULL;
  461.         }
  462.     }
  463.     // Read the image bits
  464.     if( (!ReadFile( hFile, FindDIBBits(lpDIB), dwBitsSize, &dwBytes, NULL )) || (dwBytes!=dwBitsSize) )
  465.     {
  466.         CloseHandle( hFile );
  467.         free( lpDIB );
  468.         MessageBox( NULL, "Error reading file", szFileName, MB_OK );
  469.         return NULL;
  470.     }
  471.     // clean up
  472.     CloseHandle( hFile );
  473.     return lpDIB;
  474. }
  475. /* End ReadBMPFile() ********************************************************/
  476. /****************************************************************************
  477. *
  478. *     FUNCTION: WriteBMPFile
  479. *
  480. *     PURPOSE:  Writes a BMP file from CF_DIB format
  481. *
  482. *     PARAMS:   LPCTSTR szFileName - the name of the file to read
  483. *               LPBYTE - pointer to the CF_DIB, NULL for failure
  484. *
  485. *     RETURNS:  BOOL - TRUE for success, FALSE for Failure
  486. *
  487. * History:
  488. *                July '95 - Created
  489. *
  490. ****************************************************************************/
  491. BOOL WriteBMPFile( LPCTSTR szFileName, LPBYTE lpDIB )
  492. {
  493.     HANDLE             hFile;
  494.     BITMAPFILEHEADER    bfh;
  495.     DWORD             dwBytes, dwBytesToWrite;
  496.     LPBITMAPINFOHEADER lpbmih;
  497.     // Open the file
  498.     if( (hFile=CreateFile( szFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE )
  499.     {
  500.         MessageBox( NULL, "Error opening file", szFileName, MB_OK );
  501.         return FALSE;
  502.     }
  503.     bfh.bfType = 0x4d42;
  504.     bfh.bfReserved1 = 0;
  505.     bfh.bfReserved2 = 0;
  506.     bfh.bfOffBits = sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER ) + PaletteSize( lpDIB );
  507.     bfh.bfSize = (bfh.bfOffBits + ((LPBITMAPINFOHEADER)lpDIB)->biHeight * BytesPerLine((LPBITMAPINFOHEADER)lpDIB))/4;
  508.     // Write the header
  509.     if( ( ! WriteFile( hFile, &bfh, sizeof(BITMAPFILEHEADER), &dwBytes, NULL ) ) || ( dwBytes != sizeof( BITMAPFILEHEADER ) ) )
  510.     {
  511.         CloseHandle( hFile );
  512.         MessageBox( NULL, "Error Writing file", szFileName, MB_OK );
  513.         return FALSE;
  514.     }
  515.     lpbmih = (LPBITMAPINFOHEADER)lpDIB;
  516.     lpbmih->biHeight /= 2;
  517.     dwBytesToWrite = bfh.bfOffBits + (lpbmih->biHeight * BytesPerLine(lpbmih));
  518.     if( ( ! WriteFile( hFile, lpDIB, dwBytesToWrite, &dwBytes, NULL ) ) || ( dwBytes != dwBytesToWrite ) )
  519.     {
  520.         CloseHandle( hFile );
  521.         MessageBox( NULL, "Error Writing file", szFileName, MB_OK );
  522.         return FALSE;
  523.     }
  524.     lpbmih->biHeight *= 2;
  525.     CloseHandle( hFile );
  526.     return TRUE;
  527. }
  528. /* End WriteBMPFile() *******************************************************/