home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / atl / atlbutton / dibapi.cpp < prev    next >
C/C++ Source or Header  |  1998-03-26  |  16KB  |  569 lines

  1. //  dibapi.cpp
  2. //
  3. //  Source file for Device-Independent Bitmap (DIB) API.  Provides
  4. //  the following functions:
  5. //
  6. //  PaintDIB()          - Painting routine for a DIB
  7. //  CreateDIBPalette()  - Creates a palette from a DIB
  8. //  FindDIBBits()       - Returns a pointer to the DIB bits
  9. //  DIBWidth()          - Gets the width of the DIB
  10. //  DIBHeight()         - Gets the height of the DIB
  11. //  PaletteSize()       - Gets the size required to store the DIB's palette
  12. //  DIBNumColors()      - Calculates the number of colors
  13. //                        in the DIB's color table
  14. //  CopyHandle()        - Makes a copy of the given global memory block
  15. //
  16. // This is a part of the Microsoft Foundation Classes C++ library.
  17. // Copyright (C) 1992-1998 Microsoft Corporation
  18. // All rights reserved.
  19. //
  20. // This source code is only intended as a supplement to the
  21. // Microsoft Foundation Classes Reference and related
  22. // electronic documentation provided with the library.
  23. // See these sources for detailed information regarding the
  24. // Microsoft Foundation Classes product.
  25.  
  26. #include "stdafx.h"
  27. #include "dibapi.h"
  28. #include <io.h>
  29. #include <errno.h>
  30. #include <math.h>
  31. #include <direct.h>
  32.  
  33. /*
  34.  * Dib Header Marker - used in writing DIBs to files
  35.  */
  36. #define DIB_HEADER_MARKER   ((WORD) ('M' << 8) | 'B')
  37.  
  38. /*************************************************************************
  39.  
  40.   Function:  ReadDIBFile (CFile&)
  41.  
  42.    Purpose:  Reads in the specified DIB file into a global chunk of
  43.              memory.
  44.  
  45.    Returns:  A handle to a dib (hDIB) if successful.
  46.              NULL if an error occurs.
  47.  
  48.   Comments:  BITMAPFILEHEADER is stripped off of the DIB.  Everything
  49.              from the end of the BITMAPFILEHEADER structure on is
  50.              returned in the global memory handle.
  51.  
  52. *************************************************************************/
  53.  
  54.  
  55. HDIB WINAPI ReadDIBFile(LPCTSTR pszFileName )
  56. {
  57.     BITMAPFILEHEADER bmfHeader;
  58.     DWORD dwBitsSize;
  59.     HDIB hDIB;
  60.     LPSTR pDIB;
  61.     HANDLE hFile;
  62.     DWORD nBytesRead;
  63.  
  64.     /*
  65.      * get length of DIB in bytes for use when reading
  66.      */
  67.     hFile =  CreateFile(
  68.     pszFileName,    // pointer to name of the file
  69.     GENERIC_READ,   // access (read-write) mode
  70.     FILE_SHARE_READ,    // share mode
  71.     NULL,   // pointer to security descriptor
  72.     OPEN_EXISTING,  // how to create
  73.     FILE_ATTRIBUTE_NORMAL,  // file attributes
  74.     NULL    // handle to file with attributes to copy
  75.    );
  76.  
  77.  
  78.     dwBitsSize = GetFileSize(hFile,NULL);
  79.  
  80.     /*
  81.      * Go read the DIB file header and check if it's valid.
  82.      */
  83.     // attempt an asynchronous read operation
  84.     if(! ReadFile(hFile, (LPSTR)&bmfHeader, sizeof(bmfHeader), &nBytesRead,
  85.          NULL))
  86.         return NULL;
  87.  
  88.     if (bmfHeader.bfType != DIB_HEADER_MARKER)
  89.         return NULL;
  90.  
  91.     /*
  92.      * Allocate memory for DIB
  93.      */
  94.     hDIB = (HDIB) ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwBitsSize);
  95.     if (hDIB == 0)
  96.     {
  97.         return NULL;
  98.     }
  99.     pDIB = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);
  100.  
  101.     /*
  102.      * Go read the bits.
  103.      */
  104.     if(!ReadFile(hFile, (LPSTR)pDIB, dwBitsSize - sizeof(BITMAPFILEHEADER), &nBytesRead, NULL))
  105.     {
  106.         ::GlobalUnlock((HGLOBAL) hDIB);
  107.         ::GlobalFree((HGLOBAL) hDIB);
  108.         return NULL;
  109.     }
  110.     ::GlobalUnlock((HGLOBAL) hDIB);
  111.     CloseHandle(hFile);
  112.     return hDIB;
  113. }
  114.  
  115. /*************************************************************************
  116.  *
  117.  * PaintDIB()
  118.  *
  119.  * Parameters:
  120.  *
  121.  * HDC hDC          - DC to do output to
  122.  *
  123.  * LPRECT lpDCRect  - rectangle on DC to do output to
  124.  *
  125.  * HDIB hDIB        - handle to global memory with a DIB spec
  126.  *                    in it followed by the DIB bits
  127.  *
  128.  * LPRECT lpDIBRect - rectangle of DIB to output into lpDCRect
  129.  *
  130.  * CPalette* pPal   - pointer to CPalette containing DIB's palette
  131.  *
  132.  * Return Value:
  133.  *
  134.  * BOOL             - TRUE if DIB was drawn, FALSE otherwise
  135.  *
  136.  * Description:
  137.  *   Painting routine for a DIB.  Calls StretchDIBits() or
  138.  *   SetDIBitsToDevice() to paint the DIB.  The DIB is
  139.  *   output to the specified DC, at the coordinates given
  140.  *   in lpDCRect.  The area of the DIB to be output is
  141.  *   given by lpDIBRect.
  142.  *
  143.  ************************************************************************/
  144.  
  145. BOOL WINAPI PaintDIB(HDC     hDC,
  146.                     LPRECT  lpDCRect,
  147.                     HDIB    hDIB,
  148.                     LPRECT  lpDIBRect,
  149.                     HPALETTE hPal)
  150. {
  151.     LPSTR    lpDIBHdr;            // Pointer to BITMAPINFOHEADER
  152.     LPSTR    lpDIBBits;           // Pointer to DIB bits
  153.     BOOL     bSuccess=FALSE;      // Success/fail flag
  154.     HPALETTE hOldPal=NULL;        // Previous palette
  155.  
  156.     /* Check for valid DIB handle */
  157.     if (hDIB == NULL)
  158.         return FALSE;
  159.  
  160.     /* Lock down the DIB, and get a pointer to the beginning of the bit
  161.      *  buffer
  162.      */
  163.     lpDIBHdr  = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);
  164.     lpDIBBits = ::FindDIBBits(lpDIBHdr);
  165.  
  166.     // Get the DIB's palette, then select it into DC
  167.     // Select as background since we have
  168.     // already realized in forground if needed
  169.     hOldPal = ::SelectPalette(hDC, hPal, TRUE);
  170.  
  171.     /* Make sure to use the stretching mode best for color pictures */
  172.     ::SetStretchBltMode(hDC, COLORONCOLOR);
  173.  
  174.     /* Determine whether to call StretchDIBits() or SetDIBitsToDevice() */
  175.     if ((RECTWIDTH(lpDCRect)  == RECTWIDTH(lpDIBRect)) && (RECTHEIGHT(lpDCRect) == RECTHEIGHT(lpDIBRect)))
  176.     {
  177.         bSuccess = ::SetDIBitsToDevice(hDC,                    // hDC
  178.             lpDCRect->left,             // DestX
  179.             lpDCRect->top,              // DestY
  180.             RECTWIDTH(lpDCRect),        // nDestWidth
  181.             RECTHEIGHT(lpDCRect),       // nDestHeight
  182. //          RECTWIDTH(lpDIBRect),           // wSrcWidth
  183. //          RECTHEIGHT(lpDIBRect),          // wSrcHeight
  184.             lpDIBRect->left,            // SrcX
  185.             (int)DIBHeight(lpDIBHdr) -
  186.             lpDIBRect->top -
  187.             RECTHEIGHT(lpDIBRect),   // SrcY
  188.             0,                          // nStartScan
  189.             (WORD)DIBHeight(lpDIBHdr),  // nNumScans
  190.             lpDIBBits,                  // lpBits
  191.             (LPBITMAPINFO)lpDIBHdr,     // lpBitsInfo
  192.             DIB_RGB_COLORS);            // wUsage
  193.     }
  194.     else
  195.     {
  196.         bSuccess = ::StretchDIBits(hDC,                          // hDC
  197.             lpDCRect->left,                 // DestX
  198.             lpDCRect->top,                  // DestY
  199.             RECTWIDTH(lpDCRect),            // nDestWidth
  200.             RECTHEIGHT(lpDCRect),           // nDestHeight
  201. //          RECTWIDTH(lpDIBRect),           // wSrcWidth
  202. //          RECTHEIGHT(lpDIBRect),          // wSrcHeight
  203.             lpDIBRect->left,                // SrcX
  204.             lpDIBRect->top,                 // SrcY
  205.             RECTWIDTH(lpDIBRect),           // wSrcWidth
  206.             RECTHEIGHT(lpDIBRect),          // wSrcHeight
  207.             lpDIBBits,                      // lpBits
  208.             (LPBITMAPINFO)lpDIBHdr,         // lpBitsInfo
  209.             DIB_RGB_COLORS,                 // wUsage
  210.             SRCCOPY);                       // dwROP
  211.     }
  212.  
  213.    ::GlobalUnlock((HGLOBAL) hDIB);
  214.  
  215.     /* Reselect old palette */
  216.     if (hOldPal != NULL)
  217.     {
  218.         ::SelectPalette(hDC, hOldPal, TRUE);
  219.     }
  220.  
  221.    return bSuccess;
  222. }
  223.  
  224. /*************************************************************************
  225.  *
  226.  * CreateDIBPalette()
  227.  *
  228.  * Parameter:
  229.  *
  230.  * HDIB hDIB        - specifies the DIB
  231.  *
  232.  * Return Value:
  233.  *
  234.  * HPALETTE         - specifies the palette
  235.  *
  236.  * Description:
  237.  *
  238.  * This function creates a palette from a DIB by allocating memory for the
  239.  * logical palette, reading and storing the colors from the DIB's color table
  240.  * into the logical palette, creating a palette from this logical palette,
  241.  * and then returning the palette's handle. This allows the DIB to be
  242.  * displayed using the best possible colors (important for DIBs with 256 or
  243.  * more colors).
  244.  *
  245.  ************************************************************************/
  246.  
  247.  
  248. BOOL WINAPI CreateDIBPalette(HDIB hDIB, HPALETTE* pPal)
  249. {
  250.     LPLOGPALETTE lpPal;      // pointer to a logical palette
  251.     HANDLE hLogPal;          // handle to a logical palette
  252.     HPALETTE hPal = NULL;    // handle to a palette
  253.     int i;                   // loop index
  254.     WORD wNumColors;         // number of colors in color table
  255.     LPSTR lpbi;              // pointer to packed-DIB
  256.     LPBITMAPINFO lpbmi;      // pointer to BITMAPINFO structure (Win3.0)
  257.     LPBITMAPCOREINFO lpbmc;  // pointer to BITMAPCOREINFO structure (old)
  258.     BOOL bWinStyleDIB;       // flag which signifies whether this is a Win3.0 DIB
  259.     BOOL bResult = FALSE;
  260.  
  261.     /* if handle to DIB is invalid, return FALSE */
  262.  
  263.     if (hDIB == NULL)
  264.       return FALSE;
  265.  
  266.    lpbi = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);
  267.  
  268.    /* get pointer to BITMAPINFO (Win 3.0) */
  269.    lpbmi = (LPBITMAPINFO)lpbi;
  270.  
  271.    /* get pointer to BITMAPCOREINFO (old 1.x) */
  272.    lpbmc = (LPBITMAPCOREINFO)lpbi;
  273.  
  274.    /* get the number of colors in the DIB */
  275.    wNumColors = ::DIBNumColors(lpbi);
  276.  
  277.    if (wNumColors != 0)
  278.    {
  279.         /* allocate memory block for logical palette */
  280.         hLogPal = ::GlobalAlloc(GHND, sizeof(LOGPALETTE)
  281.                                     + sizeof(PALETTEENTRY)
  282.                                     * wNumColors);
  283.  
  284.         /* if not enough memory, clean up and return NULL */
  285.         if (hLogPal == 0)
  286.         {
  287.             ::GlobalUnlock((HGLOBAL) hDIB);
  288.             return FALSE;
  289.         }
  290.  
  291.         lpPal = (LPLOGPALETTE) ::GlobalLock((HGLOBAL) hLogPal);
  292.  
  293.         /* set version and number of palette entries */
  294.         lpPal->palVersion = PALVERSION;
  295.         lpPal->palNumEntries = (WORD)wNumColors;
  296.  
  297.         /* is this a Win 3.0 DIB? */
  298.         bWinStyleDIB = IS_WIN30_DIB(lpbi);
  299.         for (i = 0; i < (int)wNumColors; i++)
  300.         {
  301.             if (bWinStyleDIB)
  302.             {
  303.                 lpPal->palPalEntry[i].peRed = lpbmi->bmiColors[i].rgbRed;
  304.                 lpPal->palPalEntry[i].peGreen = lpbmi->bmiColors[i].rgbGreen;
  305.                 lpPal->palPalEntry[i].peBlue = lpbmi->bmiColors[i].rgbBlue;
  306.                 lpPal->palPalEntry[i].peFlags = 0;
  307.             }
  308.             else
  309.             {
  310.                 lpPal->palPalEntry[i].peRed = lpbmc->bmciColors[i].rgbtRed;
  311.                 lpPal->palPalEntry[i].peGreen = lpbmc->bmciColors[i].rgbtGreen;
  312.                 lpPal->palPalEntry[i].peBlue = lpbmc->bmciColors[i].rgbtBlue;
  313.                 lpPal->palPalEntry[i].peFlags = 0;
  314.             }
  315.         }
  316.  
  317.         /* create the palette and get handle to it */
  318.         hPal = (HPALETTE)::CreatePalette((LPLOGPALETTE)lpPal);
  319.         ::GlobalUnlock((HGLOBAL) hLogPal);
  320.         ::GlobalFree((HGLOBAL) hLogPal);
  321.         *pPal = hPal;
  322.     }
  323.  
  324.     ::GlobalUnlock((HGLOBAL) hDIB);
  325.  
  326.     return (NULL != pPal);
  327. }
  328.  
  329. /*************************************************************************
  330.  *
  331.  * FindDIBBits()
  332.  *
  333.  * Parameter:
  334.  *
  335.  * LPSTR lpbi       - pointer to packed-DIB memory block
  336.  *
  337.  * Return Value:
  338.  *
  339.  * LPSTR            - pointer to the DIB bits
  340.  *
  341.  * Description:
  342.  *
  343.  * This function calculates the address of the DIB's bits and returns a
  344.  * pointer to the DIB bits.
  345.  *
  346.  ************************************************************************/
  347.  
  348.  
  349. LPSTR WINAPI FindDIBBits(LPSTR lpbi)
  350. {
  351.     return (lpbi + *(LPDWORD)lpbi + ::PaletteSize(lpbi));
  352. }
  353.  
  354.  
  355. /*************************************************************************
  356.  *
  357.  * DIBWidth()
  358.  *
  359.  * Parameter:
  360.  *
  361.  * LPSTR lpbi       - pointer to packed-DIB memory block
  362.  *
  363.  * Return Value:
  364.  *
  365.  * DWORD            - width of the DIB
  366.  *
  367.  * Description:
  368.  *
  369.  * This function gets the width of the DIB from the BITMAPINFOHEADER
  370.  * width field if it is a Windows 3.0-style DIB or from the BITMAPCOREHEADER
  371.  * width field if it is an other-style DIB.
  372.  *
  373.  ************************************************************************/
  374.  
  375.  
  376. DWORD WINAPI DIBWidth(LPSTR lpDIB)
  377. {
  378.     LPBITMAPINFOHEADER lpbmi;  // pointer to a Win 3.0-style DIB
  379.     LPBITMAPCOREHEADER lpbmc;  // pointer to an other-style DIB
  380.  
  381.     /* point to the header (whether Win 3.0 and old) */
  382.  
  383.     lpbmi = (LPBITMAPINFOHEADER)lpDIB;
  384.     lpbmc = (LPBITMAPCOREHEADER)lpDIB;
  385.  
  386.     /* return the DIB width if it is a Win 3.0 DIB */
  387.     if (IS_WIN30_DIB(lpDIB))
  388.         return lpbmi->biWidth;
  389.     else  /* it is an other-style DIB, so return its width */
  390.         return (DWORD)lpbmc->bcWidth;
  391. }
  392.  
  393.  
  394. /*************************************************************************
  395.  *
  396.  * DIBHeight()
  397.  *
  398.  * Parameter:
  399.  *
  400.  * LPSTR lpbi       - pointer to packed-DIB memory block
  401.  *
  402.  * Return Value:
  403.  *
  404.  * DWORD            - height of the DIB
  405.  *
  406.  * Description:
  407.  *
  408.  * This function gets the height of the DIB from the BITMAPINFOHEADER
  409.  * height field if it is a Windows 3.0-style DIB or from the BITMAPCOREHEADER
  410.  * height field if it is an other-style DIB.
  411.  *
  412.  ************************************************************************/
  413.  
  414.  
  415. DWORD WINAPI DIBHeight(LPSTR lpDIB)
  416. {
  417.     LPBITMAPINFOHEADER lpbmi;  // pointer to a Win 3.0-style DIB
  418.     LPBITMAPCOREHEADER lpbmc;  // pointer to an other-style DIB
  419.  
  420.     /* point to the header (whether old or Win 3.0 */
  421.  
  422.     lpbmi = (LPBITMAPINFOHEADER)lpDIB;
  423.     lpbmc = (LPBITMAPCOREHEADER)lpDIB;
  424.  
  425.     /* return the DIB height if it is a Win 3.0 DIB */
  426.     if (IS_WIN30_DIB(lpDIB))
  427.         return lpbmi->biHeight;
  428.     else  /* it is an other-style DIB, so return its height */
  429.         return (DWORD)lpbmc->bcHeight;
  430. }
  431.  
  432.  
  433. /*************************************************************************
  434.  *
  435.  * PaletteSize()
  436.  *
  437.  * Parameter:
  438.  *
  439.  * LPSTR lpbi       - pointer to packed-DIB memory block
  440.  *
  441.  * Return Value:
  442.  *
  443.  * WORD             - size of the color palette of the DIB
  444.  *
  445.  * Description:
  446.  *
  447.  * This function gets the size required to store the DIB's palette by
  448.  * multiplying the number of colors by the size of an RGBQUAD (for a
  449.  * Windows 3.0-style DIB) or by the size of an RGBTRIPLE (for an other-
  450.  * style DIB).
  451.  *
  452.  ************************************************************************/
  453.  
  454.  
  455. WORD WINAPI PaletteSize(LPSTR lpbi)
  456. {
  457.    /* calculate the size required by the palette */
  458.    if (IS_WIN30_DIB (lpbi))
  459.       return (WORD)(::DIBNumColors(lpbi) * sizeof(RGBQUAD));
  460.    else
  461.       return (WORD)(::DIBNumColors(lpbi) * sizeof(RGBTRIPLE));
  462. }
  463.  
  464.  
  465. /*************************************************************************
  466.  *
  467.  * DIBNumColors()
  468.  *
  469.  * Parameter:
  470.  *
  471.  * LPSTR lpbi       - pointer to packed-DIB memory block
  472.  *
  473.  * Return Value:
  474.  *
  475.  * WORD             - number of colors in the color table
  476.  *
  477.  * Description:
  478.  *
  479.  * This function calculates the number of colors in the DIB's color table
  480.  * by finding the bits per pixel for the DIB (whether Win3.0 or other-style
  481.  * DIB). If bits per pixel is 1: colors=2, if 4: colors=16, if 8: colors=256,
  482.  * if 24, no colors in color table.
  483.  *
  484.  ************************************************************************/
  485.  
  486.  
  487. WORD WINAPI DIBNumColors(LPSTR lpbi)
  488. {
  489.     WORD wBitCount;  // DIB bit count
  490.  
  491.     /*  If this is a Windows-style DIB, the number of colors in the
  492.      *  color table can be less than the number of bits per pixel
  493.      *  allows for (i.e. lpbi->biClrUsed can be set to some value).
  494.      *  If this is the case, return the appropriate value.
  495.      */
  496.  
  497.     if (IS_WIN30_DIB(lpbi))
  498.     {
  499.         DWORD dwClrUsed;
  500.  
  501.         dwClrUsed = ((LPBITMAPINFOHEADER)lpbi)->biClrUsed;
  502.         if (dwClrUsed != 0)
  503.             return (WORD)dwClrUsed;
  504.     }
  505.  
  506.     /*  Calculate the number of colors in the color table based on
  507.      *  the number of bits per pixel for the DIB.
  508.      */
  509.     if (IS_WIN30_DIB(lpbi))
  510.         wBitCount = ((LPBITMAPINFOHEADER)lpbi)->biBitCount;
  511.     else
  512.         wBitCount = ((LPBITMAPCOREHEADER)lpbi)->bcBitCount;
  513.  
  514.     /* return number of colors based on bits per pixel */
  515.     switch (wBitCount)
  516.     {
  517.         case 1:
  518.             return 2;
  519.  
  520.         case 4:
  521.             return 16;
  522.  
  523.         case 8:
  524.             return 256;
  525.  
  526.         default:
  527.             return 0;
  528.     }
  529. }
  530.  
  531.  
  532. //////////////////////////////////////////////////////////////////////////
  533. //// Clipboard support
  534.  
  535. //---------------------------------------------------------------------
  536. //
  537. // Function:   CopyHandle (from SDK DibView sample clipbrd.c)
  538. //
  539. // Purpose:    Makes a copy of the given global memory block.  Returns
  540. //             a handle to the new memory block (NULL on error).
  541. //
  542. //             Routine stolen verbatim out of ShowDIB.
  543. //
  544. // Parms:      h == Handle to global memory to duplicate.
  545. //
  546. // Returns:    Handle to new global memory block.
  547. //
  548. //---------------------------------------------------------------------
  549.  
  550. HGLOBAL WINAPI CopyHandle (HGLOBAL h)
  551. {
  552.     if (h == NULL)
  553.         return NULL;
  554.  
  555.     DWORD dwLen = ::GlobalSize((HGLOBAL) h);
  556.     HGLOBAL hCopy = ::GlobalAlloc(GHND, dwLen);
  557.  
  558.     if (hCopy != NULL)
  559.     {
  560.         void* lpCopy = ::GlobalLock((HGLOBAL) hCopy);
  561.         void* lp     = ::GlobalLock((HGLOBAL) h);
  562.         memcpy(lpCopy, lp, dwLen);
  563.         ::GlobalUnlock(hCopy);
  564.         ::GlobalUnlock(h);
  565.     }
  566.  
  567.     return hCopy;
  568. }
  569.