home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / winui / resource / iconpro / dib.c next >
Encoding:
C/C++ Source or Header  |  1997-10-05  |  20.6 KB  |  583 lines

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