home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / icm20 / icmview / dibs.c < prev    next >
C/C++ Source or Header  |  1997-09-07  |  60KB  |  1,715 lines

  1. //THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  2. //ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  3. //THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  4. // PARTICULAR PURPOSE.
  5. //
  6. // Copyright  1994-1997  Microsoft Corporation.  All Rights Reserved.
  7. //
  8. //  FILE:
  9. //    DIBS.C
  10. //
  11. //  PURPOSE:
  12. //    DIB routines for the ICMVIEW application.
  13. //
  14. //  PLATFORMS:
  15. //    Windows 95, Windows NT
  16. //
  17. //  SPECIAL INSTRUCTIONS: N/A
  18. //
  19.  
  20. // Windows Header Files:
  21. #pragma warning(disable:4001)   // Single-line comment warnings
  22. #pragma warning(disable:4115)   // Named type definition in parentheses
  23. #pragma warning(disable:4201)   // Nameless struct/union warning
  24. #pragma warning(disable:4214)   // Bit field types other than int warnings
  25. #pragma warning(disable:4514)   // Unreferenced inline function has been removed
  26.  
  27. // Windows Header Files:
  28. #include <Windows.h>
  29. #include <WindowsX.h>
  30. //#include <CommCtrl.h>
  31. #include <icm.h>
  32.  
  33. // Restore the warnings--leave the single-line comment warning OFF
  34. #pragma warning(default:4115)   // Named type definition in parentheses
  35. #pragma warning(default:4201)   // Nameless struct/union warning
  36. #pragma warning(default:4214)   // Bit field types other than int warnings
  37. #pragma warning(default:4514)   // Unreferenced inline function has been removed
  38.  
  39. // C RunTime Header Files
  40. #include <string.h>
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43. #include <TCHAR.H>
  44.  
  45. // Local Header Files
  46. #include "icmview.h"  // specific to this program
  47. #include "child.h"
  48. #include "dibinfo.h"
  49. #include "dibs.h"      // specific to this file
  50. #include "dialogs.h"
  51. #include "debug.h"
  52. #include "print.h"
  53. #include "regutil.h"
  54. #include "resource.h"
  55.  
  56. // local definitions
  57. DWORD NumColorsInDIB(LPBITMAPINFOHEADER lpbi);
  58. LONG      DIBHeight (LPBYTE lpDIB);
  59. LONG      DIBWidth (LPBYTE lpDIB);
  60. LPLOGCOLORSPACE GetColorSpaceFromBitmap(LPBITMAPINFOHEADER lpBitmapInfo, DWORD dwIntent, LPBOOL pbDeleteProfile);
  61. HPROFILE  OpenColorProfileFromFile(LPTSTR lpszProfileName);
  62. BOOL TranslateColorTable(HTRANSFORM hColorTransform, PCOLOR paInputColors, DWORD nColors, COLORTYPE ctInput, PCOLOR paOutputColors, COLORTYPE ctOutput, int biBitCount);
  63.  
  64. // default settings
  65.  
  66. // external functions
  67.  
  68. // external data
  69.  
  70. // public data
  71.  
  72. // private data
  73.  
  74. // public functions
  75.  
  76. // private functions
  77.  
  78.  
  79. ///////////////////////////////////////////////////////////////////////
  80. //
  81. // Function:   DIBPaint
  82. //
  83. // Purpose:    Painting routine for a DIB.  Calls StretchDIBits() or
  84. //             SetDIBitsToDevice() to paint the DIB.  The DIB is
  85. //             output to the specified DC, at the coordinates given
  86. //             in lpDCRect.  The area of the DIB to be output is
  87. //             given by lpDIBRect.  The specified palette is used.
  88. //
  89. // Parms:      hDC       == DC to do output to.
  90. //             lpDCRect  == Rectangle on DC to do output to.
  91. //             hDIB      == Handle to global memory with a DIB spec
  92. //                          in it (either a BITMAPINFO or BITMAPCOREINFO
  93. //                          followed by the DIB bits).
  94. //             lpDIBRect == Rect of DIB to output into lpDCRect.
  95. //             hPal      == Palette to be used.
  96. //
  97. ///////////////////////////////////////////////////////////////////////
  98.  
  99. void DIBPaint (HDC hDC, LPRECT lpDCRect, HGLOBAL hDIB,LPRECT lpDIBRect,
  100.                LPDIBINFO lpDIBInfo)
  101. {
  102.     int                 iScanLines;
  103.     HDC                 hDCPrinter;
  104.     BOOL                bRC;
  105.     LPBYTE              lpbDIBBits;
  106.     HPALETTE            hOldPal;
  107.     LPBITMAPINFOHEADER  lpDIBHdr;
  108.     LPBITMAPINFOHEADER  lpbi;
  109.  
  110.  
  111.     // Initialize variables
  112.     if (!hDIB)
  113.     {
  114.         return;
  115.     }
  116.     ASSERT(hDC != NULL);
  117.     hDCPrinter = NULL;
  118.     SetLastError(0);
  119.     hOldPal = NULL;
  120.     lpbi = NULL;
  121.  
  122.     // Lock down DIB, get a pointer to the beginning of the bit buffer.
  123.     lpDIBHdr  = GlobalLock(hDIB);
  124.     if (NULL == lpDIBHdr )
  125.     {
  126.         goto Release;
  127.     }
  128.     lpbDIBBits = FindDIBBits(lpDIBHdr);
  129.     if (NULL == lpbDIBBits)
  130.     {
  131.         goto Release;
  132.     }
  133.  
  134.     // If size > BITMAPINFOHEADER header then
  135.     // need to convert to BITMAPINFOHEADER.
  136.     lpbi = lpDIBHdr;
  137. #ifdef OSR2
  138.     if (sizeof(BITMAPINFOHEADER) < lpDIBHdr->biSize)
  139.     {
  140.         DWORD dwColorTableSize;
  141.         DWORD dwHeaderDataSize;
  142.  
  143.         // Allocate Bitmapinfo memory.
  144.         dwHeaderDataSize = sizeof(BITMAPINFOHEADER) + (lpDIBHdr->biCompression == BI_BITFIELDS ? 12 : 0);
  145.         dwColorTableSize = NumColorsInDIB(lpDIBHdr) * sizeof(RGBQUAD);
  146.         lpbi = (LPBITMAPINFOHEADER) GlobalAlloc(GPTR, dwHeaderDataSize + dwColorTableSize);
  147.         if (NULL == lpbi)
  148.         {
  149.             goto Release;
  150.         }
  151.  
  152.         // Convert header data into bitmapinfo header.
  153.         memcpy(lpbi, lpDIBHdr, dwHeaderDataSize);
  154.         lpbi->biSize = sizeof(BITMAPINFOHEADER);
  155.  
  156.         // Copy color table if any.
  157.         if (0 != dwColorTableSize)
  158.             memcpy((LPBYTE)lpbi + dwHeaderDataSize, (LPBYTE)lpDIBHdr + lpDIBHdr->biSize, dwColorTableSize);
  159.     }
  160. #endif
  161.  
  162.     SetupDC(hDC, lpDIBInfo, &hOldPal, &hDCPrinter);
  163.  
  164.     // Determine whether to call StretchDIBits() or SetDIBitsToDevice().
  165.     if (!(lpDIBInfo->bStretch))
  166.     {
  167.         iScanLines = SetDIBitsToDevice (hDC,          // hDC
  168.                                         lpDCRect->left,               // dest upper-left x
  169.                                         lpDCRect->top,                // dest upper-left y
  170.                                         RECTWIDTH (lpDCRect),         // src width
  171.                                         RECTHEIGHT (lpDCRect),        // src height
  172.                                         lpDIBRect->left,              // src lower-left x
  173.                                         (int) DIBHeight((LPBYTE)lpDIBHdr) -
  174.                                         lpDIBRect->top -
  175.                                         RECTHEIGHT (lpDIBRect),       // src lower-left y
  176.                                         0,                            // nStartScan
  177.                                         (UINT) DIBHeight((LPBYTE)lpDIBHdr),   // nNumScans
  178.                                         lpbDIBBits,                   // lpBits
  179.                                         (LPBITMAPINFO) lpbi,      // lpBitsInfo
  180.                                         DIB_RGB_COLORS);              // wUsage
  181.     }
  182.     else
  183.     {
  184.         // Use the specified stretch mode
  185.         SetStretchBltMode (hDC, (int)lpDIBInfo->dwStretchBltMode);
  186.         iScanLines = StretchDIBits (hDC,                          // hDC
  187.                                     lpDCRect->left,               // dest upper-left x
  188.                                     lpDCRect->top,                // dest upper-left y
  189.                                     RECTWIDTH (lpDCRect),         // src width
  190.                                     RECTHEIGHT (lpDCRect),        // src height
  191.                                     lpDIBRect->left,              // src lower-left x
  192.                                     lpDIBRect->top,               // src lower-left y
  193.                                     RECTWIDTH (lpDIBRect),        // nStartScan
  194.                                     RECTHEIGHT (lpDIBRect),       // nNumScans
  195.                                     lpbDIBBits,                   // lpBits
  196.                                     (LPBITMAPINFO)lpbi,                   // lpBitsInfo
  197.                                     DIB_RGB_COLORS,               // wUsage
  198.                                     SRCCOPY);                     // dwROP
  199.     }
  200.     if (DIBHeight((LPBYTE)lpDIBHdr) != iScanLines)
  201.     {
  202.         DebugMsg(__TEXT("DIBS.C : DIBPaint:  iScanLines expected %ld, returned %ld\r\n"), DIBHeight((LPBYTE)lpDIBHdr), iScanLines);
  203.     }
  204.  
  205.     // Fix up the palette.
  206.     if (NULL == SelectPalette (hDC, hOldPal, TRUE))
  207.     {
  208.         DISPLAY_LASTERROR(LASTERROR_NOALLOC, GetLastError());
  209.     }
  210.  
  211.  
  212.     Release:
  213.     if (lpbi != lpDIBHdr)
  214.         GlobalFree((HANDLE)lpbi);
  215.     if (NULL != lpDIBHdr)
  216.     {
  217.         GlobalUnlock(hDIB);
  218.     }
  219.     if (hDCPrinter)
  220.     {
  221.         bRC = ColorMatchToTarget(hDC, hDCPrinter, CS_DISABLE);
  222.         if (0 == bRC)
  223.         {
  224.             DebugMsg(__TEXT("DIBS.C : DIBPaint : ColorMatchToTarget failed to DISABLE transform.\r\n"));
  225.             DISPLAY_LASTERROR(LASTERROR_NOALLOC,GetLastError());
  226.         }
  227.         bRC = ColorMatchToTarget(hDC, hDCPrinter, CS_DELETE_TRANSFORM);
  228.         if (0 == bRC)
  229.         {
  230.             DebugMsg(  __TEXT(  "DIBS.C : DIBPaint : ColorMatchToTarget failed to DELETE transform.\r\n"));
  231.             DISPLAY_LASTERROR(LASTERROR_NOALLOC,GetLastError());
  232.         }
  233.         bRC = DeleteDC(hDCPrinter);
  234.         if (0 == bRC)
  235.         {
  236.             DebugMsg(__TEXT("DIBS.C : DIBPaint : Failed to delete printer DC\r\n"));
  237.             DISPLAY_LASTERROR(LASTERROR_NOALLOC,GetLastError());
  238.         }
  239.     }
  240. }
  241.  
  242. ///////////////////////////////////////////////////////////////////////
  243. //
  244. // Function:   CreateDIBPalette
  245. //
  246. // Purpose:    Given a handle to a DIB, constructs a logical palette,
  247. //             and returns a handle to this palette.
  248. //
  249. //             Stolen almost verbatim from ShowDIB.
  250. //
  251. // Parms:      hDIB == HANDLE to global memory with a DIB header
  252. //                     (either BITMAPINFOHEADER or BITMAPCOREHEADER)
  253. //
  254. ///////////////////////////////////////////////////////////////////////
  255. HPALETTE CreateDIBPalette(HANDLE hDIB)
  256. {
  257.     LPLOGPALETTE          lpPal;
  258.     HGLOBAL               hLogPal;
  259.     HPALETTE              hPal = NULL;
  260.     UINT                  i;
  261.     DWORD                 dwNumColors;
  262.     LPBITMAPINFOHEADER    lpBmpInfoHdr;
  263.     LPBITMAPINFO          lpbmi;
  264.     LPBITMAPCOREINFO      lpbmc;
  265.     BOOL                  bWinStyleDIB;
  266.  
  267.     if (!hDIB)
  268.     {
  269.         return NULL;
  270.     }
  271.  
  272.     lpBmpInfoHdr = GlobalLock (hDIB);
  273.     lpbmi        = (LPBITMAPINFO)lpBmpInfoHdr;
  274.     lpbmc        = (LPBITMAPCOREINFO)lpBmpInfoHdr;
  275.     dwNumColors  = NumColorsInDIB(lpBmpInfoHdr);
  276.     bWinStyleDIB = IS_WIN30_DIB(lpBmpInfoHdr);
  277.  
  278.     if (0 != dwNumColors)
  279.     {
  280.         hLogPal = GlobalAlloc (GHND, sizeof (LOGPALETTE) + sizeof (PALETTEENTRY) * dwNumColors);
  281.         if (!hLogPal)
  282.         {
  283.             GlobalUnlock(hDIB);
  284.             return NULL;
  285.         }
  286.  
  287.         lpPal = (LPLOGPALETTE) GlobalLock (hLogPal);
  288.         lpPal->palVersion    = PALVERSION;
  289.         lpPal->palNumEntries = (WORD)dwNumColors;
  290.  
  291.         for (i = 0;  i < dwNumColors;  i++)
  292.         {
  293.             if (bWinStyleDIB)
  294.             {
  295.                 lpPal->palPalEntry[i].peRed   = lpbmi->bmiColors[i].rgbRed;
  296.                 lpPal->palPalEntry[i].peGreen = lpbmi->bmiColors[i].rgbGreen;
  297.                 lpPal->palPalEntry[i].peBlue  = lpbmi->bmiColors[i].rgbBlue;
  298.                 lpPal->palPalEntry[i].peFlags = 0;
  299.             }
  300.             else
  301.             {
  302.                 lpPal->palPalEntry[i].peRed   = lpbmc->bmciColors[i].rgbtRed;
  303.                 lpPal->palPalEntry[i].peGreen = lpbmc->bmciColors[i].rgbtGreen;
  304.                 lpPal->palPalEntry[i].peBlue  = lpbmc->bmciColors[i].rgbtBlue;
  305.                 lpPal->palPalEntry[i].peFlags = 0;
  306.             }
  307.         }
  308.  
  309.         hPal = CreatePalette (lpPal);
  310.         GlobalUnlock(hLogPal);
  311.         GlobalFree(hLogPal);
  312.     }
  313.     GlobalUnlock(hDIB);
  314.     return(hPal);
  315. }
  316.  
  317.  
  318. //////////////////////////////////////////////////////////////////////////
  319. //  Function:  GetDefaultICMProfile
  320. //
  321. //  Description:
  322. //    Uses GetICMProfile to retrieve the filename of the default ICM
  323. //    profile for the DC.
  324. //
  325. //  Parameters:
  326. //    @@@
  327. //
  328. //  Returns:
  329. //    LPTSTR
  330. //
  331. //  Comments:
  332. //
  333. //
  334. //////////////////////////////////////////////////////////////////////////
  335. LPTSTR GetDefaultICMProfile(HDC hDC)
  336. {
  337.     // Local variables
  338.     LPTSTR    lpszProfileName;
  339.     BOOL      bProfile;
  340.     DWORD     dwProfileLen;
  341.     TCHAR     stProfileName[MAX_PATH+1];
  342.     HGLOBAL   hFree;
  343.  
  344.     //  Initialize variables
  345.     lpszProfileName = NULL;
  346.     dwProfileLen = 0;
  347.     stProfileName[0] = __TEXT('\0');
  348.  
  349.     // Query for size of profile name string
  350.     bProfile = GetICMProfile(hDC, &dwProfileLen, NULL);
  351.     if (bProfile)
  352.     {
  353.         DebugMsg(__TEXT("GetDefaultICMProfile:  GetICMProfile returned TRUE on query, dwProfileLen = %ld\r\n"), dwProfileLen);
  354.         return(FALSE);
  355.     }
  356.  
  357.     if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
  358.     {
  359.         DebugMsg(__TEXT("GetDefaultICMProfile:  GetICMProfile set unexpected LastError %ld on query, dwProfileLen = %ld\r\n"),
  360.                  GetLastError(), dwProfileLen);
  361.         DISPLAY_LASTERROR(LASTERROR_NOALLOC, GetLastError());
  362.         dwProfileLen = MAX_PATH;
  363.     }
  364.     else
  365.     {
  366.         if (0 == dwProfileLen)
  367.         {
  368.             DebugMsg(__TEXT("GetDefaultICMProfile:  GetICMProfile returned FALSE on query, DID NOT SET dwProfileLen\r\n"));
  369.             return(FALSE);
  370.         }
  371.     }
  372.  
  373.  
  374.     // Fill in lpszProfileName with actual profile filename
  375.     lpszProfileName = GlobalAlloc(GPTR, (dwProfileLen+1) * sizeof(TCHAR));
  376.     if (lpszProfileName != NULL)
  377.     {
  378.         bProfile = GetICMProfile(hDC, &dwProfileLen, lpszProfileName);
  379.         if (!bProfile)
  380.         {
  381.             DebugMsg(__TEXT("GetDefaultICMProfile:  GetICMProfile FAILED\r\n"));
  382.             DISPLAY_LASTERROR(LASTERROR_NOALLOC, GetLastError());
  383.             hFree = GlobalFree(lpszProfileName);
  384.             return(NULL);
  385.         }
  386.         else  // Successfully id'd default profile
  387.         {
  388.             TCHAR   szName[MAX_PATH], szExt[MAX_PATH];
  389.  
  390.             DebugMsg(__TEXT("Full profile name:  <%s>\r\n"), lpszProfileName);
  391.             _tsplitpath(lpszProfileName, NULL, NULL, szName, szExt);
  392.             wsprintf(lpszProfileName, __TEXT("%s%s"), szName, szExt);
  393.         }
  394.     }
  395.     else
  396.     {
  397.         DebugMsg(__TEXT("GetDefaultICMProfile:  Unable to allocate lpszProfileName.\r\n"));
  398.     }
  399.     return(lpszProfileName);
  400. } // End of function GetDefaultICMProfile
  401.  
  402.  
  403. //////////////////////////////////////////////////////////////////////////
  404. //  Function:  TransformDIBOutsideDC
  405. //
  406. //  Description:
  407. //    Transforms the provided hDIB using the provided profile names.
  408. //
  409. //  Parameters:
  410. //    HANDLE      Handle to DIB to process
  411. //    LPTSTR      Destination profile
  412. //    LPTSTR      Target profile
  413. //
  414. //  Returns:
  415. //    HANDLE to transformed bits; NULL upon failure.
  416. //
  417. //  Comments:
  418. //    Uses ICM functions
  419. //        CreateColorTransform
  420. //        TranslateBitmapBits
  421. //        TranslateColors
  422. //
  423. //////////////////////////////////////////////////////////////////////////
  424. HANDLE TransformDIBOutsideDC(HANDLE hDIB, BMFORMAT bmInput, LPTSTR lpszDestProfile,
  425.                              LPTSTR lpszTargetProfile, DWORD dwIntent, PBMCALLBACKFN pBMCallback,
  426.                              ULONG ulCallbackData)
  427. {
  428.     // Local variables
  429.     HANDLE          hDIBTransformed;    // Handle to transformed DIB
  430.     HPROFILE        hDestProfile, hTargetProfile;
  431.     HTRANSFORM      hTransform;
  432.     LPLOGCOLORSPACE lpLogColorSpace;
  433.     PVOID           pSrcBits, pDestBits;
  434.     LPBITMAPINFOHEADER  lpbSrcDIBHdr, lpbDestDIBHdr;
  435.     BOOL            bTranslated, bProfileClosed, bDeleted, bDeleteProfile;
  436.     DWORD           dwCopySize;
  437.  
  438.     //  Initialize variables
  439.     ASSERT(NULL != hDIB);
  440.     ASSERT(NULL != lpszDestProfile);
  441.     hDIBTransformed = NULL;
  442.     SetLastError(0);
  443.     hTransform = NULL;
  444.     bTranslated = FALSE;
  445.  
  446.     hDestProfile   = OpenColorProfileFromFile(lpszDestProfile );
  447.     hTargetProfile = OpenColorProfileFromFile(lpszTargetProfile);
  448.  
  449.     if (NULL == hDestProfile)
  450.     {
  451.         DebugMsg(__TEXT("TransformDIBOutsideDC : NULL dest file\r\n"));
  452.         return(NULL);
  453.     }
  454.  
  455.     // Get bits from original DIB
  456.     lpbSrcDIBHdr = GlobalLock(hDIB);
  457.  
  458.     pSrcBits = (PVOID)FindDIBBits(lpbSrcDIBHdr);
  459.  
  460.     // Get LPLOGCOLORSPACE for transform
  461.     lpLogColorSpace = GetColorSpaceFromBitmap(lpbSrcDIBHdr, dwIntent, &bDeleteProfile);
  462.  
  463.     if (NULL != lpLogColorSpace)
  464.     {
  465.         //Create the transform to use
  466.         SetLastError(0);
  467.         hTransform = CreateColorTransform(lpLogColorSpace, hDestProfile, hTargetProfile, ENABLE_GAMUT_CHECKING | NORMAL_MODE | 0x80000000);
  468.  
  469.         if (NULL != hTransform)
  470.         {
  471.             // Allocate for new DIB
  472.             hDIBTransformed = GlobalAlloc(GHND, GlobalSize(hDIB));
  473.             lpbDestDIBHdr = GlobalLock(hDIBTransformed);
  474.  
  475.             switch (BITCOUNT(lpbSrcDIBHdr))
  476.             {
  477.                 DWORD   dwSrcOffBytes, dwDestOffBytes;
  478.  
  479.                 case 1: // BM_1GRAY:
  480.                 case 4:
  481.                 case 8:
  482.                     ASSERT((((LPBITMAPV5HEADER)lpbSrcDIBHdr)->bV5ClrUsed) <= (DWORD)( 1 << ((LPBITMAPV5HEADER)lpbSrcDIBHdr)->bV5BitCount));
  483.                     // Copy entire DIB.  Color table will be replaced by TranslateColors
  484.                     dwCopySize = GlobalSize(hDIB);
  485.                     memset(lpbDestDIBHdr, 0x17, dwCopySize);
  486.                     memcpy(lpbDestDIBHdr, lpbSrcDIBHdr, dwCopySize);
  487.  
  488.                     dwSrcOffBytes = *(LPDWORD)lpbSrcDIBHdr;
  489.                     dwDestOffBytes   = *(LPDWORD)lpbDestDIBHdr;
  490.  
  491.                     pSrcBits  = (PBYTE)lpbSrcDIBHdr  + dwSrcOffBytes;
  492.                     pDestBits = (PBYTE)lpbDestDIBHdr + dwDestOffBytes;
  493.  
  494.                     // Needed to use different translation if BITMAPCORE bitmap.
  495.                     if (dwSrcOffBytes >= sizeof(BITMAPINFOHEADER))
  496.                     {
  497.                         bTranslated = TranslateColorTable(hTransform,
  498.                                                           (PCOLOR)pSrcBits, // paInputColors,
  499.                                                           ((LPBITMAPV5HEADER)lpbSrcDIBHdr)->bV5ClrUsed, // nColors,
  500.                                                           COLOR_RGB, // ctInput,
  501.                                                           (PCOLOR)pDestBits, // paOutputColors,
  502.                                                           COLOR_RGB,  // ctOutput)
  503.                                                           lpbSrcDIBHdr->biBitCount);
  504.                     }
  505.                     else
  506.                     {
  507.                         bTranslated = TranslateBitmapBits(hTransform,
  508.                                                           pSrcBits,
  509.                                                           BM_RGBTRIPLETS,
  510.                                                           NumColorsInDIB(lpbSrcDIBHdr),
  511.                                                           1,
  512.                                                           0,
  513.                                                           pDestBits,
  514.                                                           BM_RGBTRIPLETS,
  515.                                                           0,
  516.                                                           NULL,
  517.                                                           0);
  518.                     }
  519.  
  520.                     if (0 == bTranslated)
  521.                     {
  522.                         DebugMsg(__TEXT("TransformDIBOutsideDC : TranslateColors failed, :"));
  523.                         DISPLAY_LASTERROR(LASTERROR_NOALLOC, GetLastError());
  524.                     }
  525.                     break;
  526.  
  527.                 case 16: // BM_RGBTRIPLETS:
  528.                 case 24: // BM_xRGBQUADS:
  529.                 case 32: // BM_x555RGB:
  530.  
  531.                     // Copy header from original DIB to new DIB
  532.                     memcpy(lpbDestDIBHdr, lpbSrcDIBHdr, sizeof(BITMAPV5HEADER));
  533.                     pDestBits = (PVOID)FindDIBBits(lpbDestDIBHdr);
  534.  
  535.                     bTranslated = TranslateBitmapBits(hTransform,
  536.                                                       pSrcBits,
  537.                                                       bmInput,
  538.                                                       BITMAPWIDTH(lpbSrcDIBHdr),
  539.                                                       abs(BITMAPHEIGHT(lpbSrcDIBHdr)),
  540.                                                       0,
  541.                                                       pDestBits,
  542.                                                       bmInput,
  543.                                                       0,
  544.                                                       pBMCallback,
  545.                                                       ulCallbackData);
  546.  
  547.                     if (0 == bTranslated)
  548.                     {
  549.                         DebugMsg(__TEXT("TransformDIBOutsideDC : TranslateBitmapBits failed:\r\n"));
  550.                         DISPLAY_LASTERROR(LASTERROR_NOALLOC, GetLastError());
  551.                     }
  552.                     break;
  553.  
  554.                 default:  // 8bpp
  555.                     DebugMsg(__TEXT("TransformDIBOutsideDC : Unrecognized format\r\n"));
  556.                     bTranslated = FALSE;
  557.                     break;
  558.             }
  559.             bDeleted = DeleteColorTransform(hTransform);
  560.             if (0 == bDeleted)
  561.             {
  562.                 DebugMsg(__TEXT("TransformDIBOutsideDC : DeleteColorTransform failed, : "));
  563.                 DISPLAY_LASTERROR(LASTERROR_NOALLOC, GetLastError());
  564.             }
  565.         }
  566.         else
  567.         {
  568.             ErrMsg(NULL, __TEXT("TransformDIBOutsideDC : CreateColorTransform failed"));
  569.             DISPLAY_LASTERROR(LASTERROR_NOALLOC, GetLastError());
  570.         }
  571.  
  572.         if (bDeleteProfile)
  573.         {
  574.             DeleteFile(lpLogColorSpace->lcsFilename);
  575.         }
  576.  
  577.         GlobalFree((HANDLE)lpLogColorSpace);
  578.     }
  579.     else // Failed to get LOGCOLORSPACE
  580.     {
  581.         ErrMsg(NULL, __TEXT("TransformDIBOutsideDC : Failed to get LOGCOLORSPACE"));
  582.     }
  583.  
  584.     if (NULL != hDestProfile)
  585.     {
  586.         bProfileClosed = CloseColorProfile(hDestProfile);
  587.         if (0 == bProfileClosed)
  588.         {
  589.             DebugMsg(__TEXT("TransformDIBOutsideDC : Failed to close hDestProfile, "));
  590.             DISPLAY_LASTERROR(LASTERROR_NOALLOC, GetLastError());
  591.         }
  592.     }
  593.  
  594.     if (NULL != hTargetProfile)
  595.     {
  596.         bProfileClosed = CloseColorProfile(hTargetProfile);
  597.         if (0 == bProfileClosed)
  598.         {
  599.             DebugMsg(__TEXT("TransformDIBOutsideDC : Failed to close hTargetProfile, "));
  600.             DISPLAY_LASTERROR(LASTERROR_NOALLOC, GetLastError());
  601.         }
  602.     }
  603.     if (NULL != hDIBTransformed)
  604.     {
  605.         GlobalUnlock(hDIBTransformed);
  606.     }
  607.     if ((NULL == hTransform) || (0 == bTranslated))
  608.     {
  609.         if (NULL != hDIBTransformed)
  610.         {
  611.             GlobalFree(hDIBTransformed);
  612.             hDIBTransformed = NULL;
  613.         }
  614.         lpbDestDIBHdr = NULL;
  615.         pDestBits = NULL;
  616.     }
  617.     return(hDIBTransformed);
  618. }   // End of function TransformDIBOutsideDC
  619.  
  620. //////////////////////////////////////////////////////////////////////////
  621. //  Function:  OpenColorProfileFromFile
  622. //
  623. //  Description:
  624. //    Creates a color profile based upon the parameters passed.
  625. //
  626. //  Parameters:
  627. //    LPTSTR  Profile name
  628. //
  629. //  Returns:
  630. //    HPROFILE Handle to PROFILE structure, NULL if failure.
  631. //
  632. //  Comments:
  633. //
  634. //
  635. //////////////////////////////////////////////////////////////////////////
  636. HPROFILE OpenColorProfileFromFile(LPTSTR lpszProfileName)
  637. {
  638.     // Local variables
  639.     PPROFILE  pProfile;
  640.     HPROFILE  hProfile;
  641.     DWORD     cbDataSize;
  642.     DWORD     dwProfileSize;
  643.     TCHAR     stFullProfile[MAX_PATH];
  644.     BOOL      bValid;
  645.  
  646.     //  Initialize variables
  647.     if (NULL == lpszProfileName)
  648.     {
  649.         return(NULL);
  650.     }
  651.  
  652.     // Add COLOR dir path if profile name does not contain a path.
  653.     if ( (NULL == _tcschr(lpszProfileName, __TEXT(':')))
  654.          &&
  655.          (NULL == _tcschr(lpszProfileName, __TEXT('\\')))
  656.        )
  657.     {
  658.         wsprintf(stFullProfile, __TEXT("%s\\%s"), gstProfilesDir, lpszProfileName);
  659.     }
  660.     else
  661.     {
  662.         lstrcpy(stFullProfile, lpszProfileName);
  663.     }
  664.     dwProfileSize = sizeof(PROFILE);
  665.     cbDataSize = (lstrlen(stFullProfile) * sizeof(TCHAR)) + sizeof(TCHAR); // String plus NULL
  666.     pProfile = GlobalAlloc(GPTR, (dwProfileSize + cbDataSize));
  667. #ifdef _DEBUG
  668.     memset(pProfile, UNINIT_BYTE, (cbDataSize+dwProfileSize));
  669. #endif
  670.  
  671.     pProfile->dwType = PROFILE_FILENAME;
  672.     pProfile->cbDataSize = cbDataSize;
  673.     pProfile->pProfileData = (PVOID)((LPBYTE)pProfile + dwProfileSize);
  674.     _tcscpy(pProfile->pProfileData, stFullProfile);
  675.     hProfile = OpenColorProfile(pProfile, PROFILE_READ, FILE_SHARE_READ, OPEN_EXISTING);
  676.     if (NULL  == hProfile)
  677.     {
  678.         ErrMsg(NULL,__TEXT("Unable to open color profile <%s>"), stFullProfile);
  679.         DISPLAY_LASTERROR(LASTERROR_NOALLOC, GetLastError());
  680.     }
  681.     else
  682.     {
  683.         // Validate the profile
  684.         bValid = IsColorProfileValid(hProfile, &bValid);
  685.         if (0 == bValid)
  686.         {
  687.             ErrMsg(NULL,__TEXT("Color profile %s is not valid"), stFullProfile);
  688.             DISPLAY_LASTERROR(LASTERROR_NOALLOC, GetLastError());
  689.             CloseColorProfile(hProfile);
  690.             hProfile = NULL;
  691.         }
  692.     }
  693.     // Cleanup
  694.     GlobalFree(GlobalHandle(pProfile));
  695.     return(hProfile);
  696. }   // End of function OpenColorProfileFromDisk
  697.  
  698.  
  699. ///////////////////////////////////////////////////////////////////////
  700. //
  701. // Function:   GetColorSpaceFromBitmap
  702. //
  703. // Purpose:    Creates a LOGCOLORSPACE based on information in bitmap.
  704. //
  705. //
  706. // Parms:      lpBitmapHeader   Pointer to bitmap header and info.
  707. //             dwIntent         Color Space Intent.
  708. //             pbDeleteProfile  Flag, on return, will indicate if the profile needs
  709. //                              to be deleted before LOGCOLORSPACE is freed.
  710. //
  711. //
  712. ///////////////////////////////////////////////////////////////////////
  713.  
  714. LPLOGCOLORSPACE GetColorSpaceFromBitmap(LPBITMAPINFOHEADER lpBitmapInfo, DWORD dwIntent,
  715.                                         LPBOOL pbDeleteProfile)
  716. {
  717.     LPLOGCOLORSPACE lpColorSpace = NULL;
  718.     PBITMAPV5HEADER lpBitmapV5 = (PBITMAPV5HEADER) lpBitmapInfo;
  719.  
  720.     // Validate parameters.
  721.     ASSERT(NULL != lpBitmapInfo);
  722.     if ( (NULL == lpBitmapInfo)
  723.          ||
  724.          (NULL == pbDeleteProfile)
  725.          ||
  726.          ( (sizeof(BITMAPCOREHEADER) != lpBitmapInfo->biSize)
  727.            &&
  728.            (sizeof(BITMAPINFOHEADER) != lpBitmapInfo->biSize)
  729.            &&
  730.            (sizeof(BITMAPV4HEADER) != lpBitmapInfo->biSize)
  731.            &&
  732.            (sizeof(BITMAPV5HEADER) != lpBitmapInfo->biSize)
  733.          )
  734.        )
  735.     {
  736.         return NULL;
  737.     }
  738.  
  739.     // Initalize delete flag.
  740.     *pbDeleteProfile = FALSE;
  741.  
  742.     // Allocate LOGCOLORSPACE.
  743.     lpColorSpace = (LPLOGCOLORSPACE) GlobalAlloc(GPTR, sizeof(LOGCOLORSPACE));
  744.     if (NULL == lpColorSpace)
  745.     {
  746.         return NULL;
  747.     }
  748.  
  749.     // Initialize color space.
  750.     lpColorSpace->lcsSignature = 'PSOC';  // The signature should always be 'PSOC'.
  751.     lpColorSpace->lcsVersion = 0x400;
  752.     lpColorSpace->lcsSize = sizeof(LOGCOLORSPACE);
  753.  
  754.     // If BITMAPCOREHEADER or BITMAPINFOHEADER, bitmap has no information
  755.     // about color space; use sRGB.
  756.     if (sizeof(BITMAPINFOHEADER) >= lpBitmapInfo->biSize)
  757.     {
  758.         // Set color space to default values.
  759.  
  760.         lpColorSpace->lcsCSType = LCS_sRGB;
  761.  
  762.         // Set endpoints to sRGB values.
  763.  
  764.         lpColorSpace->lcsEndpoints.ciexyzRed.ciexyzX = __FXPT2DOT30(.64);
  765.         lpColorSpace->lcsEndpoints.ciexyzRed.ciexyzY = __FXPT2DOT30(.33);
  766.         lpColorSpace->lcsEndpoints.ciexyzRed.ciexyzZ = __FXPT2DOT30(.03);
  767.  
  768.         lpColorSpace->lcsEndpoints.ciexyzGreen.ciexyzX = __FXPT2DOT30(.3);
  769.         lpColorSpace->lcsEndpoints.ciexyzGreen.ciexyzY = __FXPT2DOT30(.6);
  770.         lpColorSpace->lcsEndpoints.ciexyzGreen.ciexyzZ = __FXPT2DOT30(.1);
  771.  
  772.         lpColorSpace->lcsEndpoints.ciexyzBlue.ciexyzX   =   __FXPT2DOT30(  .15);
  773.         lpColorSpace->lcsEndpoints.ciexyzBlue.ciexyzY = __FXPT2DOT30(.06);
  774.         lpColorSpace->lcsEndpoints.ciexyzBlue.ciexyzZ = __FXPT2DOT30(.79);
  775.  
  776.         // Just so that if monitor has 2.2 gamma, the over all gamma is 1.0.
  777.         lpColorSpace->lcsGammaRed = __FXPT16DOT16(0.45);
  778.         lpColorSpace->lcsGammaGreen = __FXPT16DOT16(0.45);
  779.         lpColorSpace->lcsGammaBlue = __FXPT16DOT16(0.45);
  780.     }
  781.     else
  782.     {
  783.         // Copy information from portion that is similar between BITMAPV4HEADERs and
  784.         // BITMAPV5HEADERs.
  785.         memcpy(&lpColorSpace->lcsEndpoints, &lpBitmapV5->bV5Endpoints, sizeof(CIEXYZTRIPLE));
  786.         lpColorSpace->lcsGammaRed = lpBitmapV5->bV5GammaRed;
  787.         lpColorSpace->lcsGammaGreen = lpBitmapV5->bV5GammaGreen;
  788.         lpColorSpace->lcsGammaBlue = lpBitmapV5->bV5GammaBlue;
  789.  
  790.         // BITMAPV4HEADERs do not have complete color space information,
  791.         // we need to assume some things.
  792.         if (sizeof(BITMAPV4HEADER) == lpBitmapInfo->biSize)
  793.         {
  794.             // Fill in default values for fields that do not
  795.             // have equivalents in BITMAPV4HEADER.
  796.             lpColorSpace->lcsCSType = lpBitmapV5->bV5CSType;
  797.             lpColorSpace->lcsIntent = LCS_GM_IMAGES;
  798.         }
  799.         else
  800.         {
  801.             // BITMAPV5HEADERs have complete color space information.
  802.             // No assumptions to make.
  803.             lpColorSpace->lcsIntent = lpBitmapV5->bV5Intent;
  804.  
  805.             // Look to see if no, linked, or embedded profile.
  806.             switch (lpBitmapV5->bV5CSType)
  807.             {
  808.                 case 'MBED':
  809.                     // Need to create profile file and reference
  810.                     // profile in the color space.
  811.                     lpColorSpace->lcsCSType = LCS_CALIBRATED_RGB;
  812.  
  813.                     // Make sure that profile data offset is valid and not zero length.
  814.                     if ( (lpBitmapV5->bV5Size > lpBitmapV5->bV5ProfileData)
  815.                          ||
  816.                          (0L == lpBitmapV5->bV5ProfileSize)
  817.                        )
  818.                     {
  819.                         GlobalFree((HANDLE)lpColorSpace);
  820.                         return NULL;
  821.                     }
  822.  
  823.                     // Create unique temp name.
  824.                     {
  825.                         DWORD   dwWritten;
  826.                         TCHAR   szTempPath[MAX_PATH];
  827.                         HANDLE  hFile;
  828.  
  829.                         GetTempPath(MAX_PATH, szTempPath);
  830.                         if (!GetTempFileName(szTempPath, __TEXT("ICM"), 0, lpColorSpace->lcsFilename))
  831.                         {
  832.                             GlobalFree((HANDLE)lpColorSpace);
  833.                             return NULL;
  834.                         }
  835.  
  836.                         // Create temp profile that contains the embedded profile.
  837.                         hFile = CreateFile(lpColorSpace->lcsFilename, GENERIC_READ | GENERIC_WRITE,
  838.                                            0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  839.                         if (INVALID_HANDLE_VALUE == hFile)
  840.                         {
  841.                             GlobalFree((HANDLE)lpColorSpace);
  842.                             return NULL;
  843.                         }
  844.  
  845.                         // Write embedded profile to disk.
  846.                         WriteFile(hFile, GETPROFILEDATA(lpBitmapV5), lpBitmapV5->bV5ProfileSize,
  847.                                   &dwWritten, NULL);
  848.  
  849.                         // No longer need file open.
  850.                         CloseHandle(hFile);
  851.  
  852.                         // Need to indicate to caller that this file needs to be deleted
  853.                         // before LOGCOLORSPACE is freed.
  854.                         *pbDeleteProfile = TRUE;
  855.                     }
  856.                     break;
  857.  
  858.                 case 'LINK':
  859.                     // Need to reference profile.
  860.                     lpColorSpace->lcsCSType = LCS_CALIBRATED_RGB;
  861.                     lstrcpyn(lpColorSpace->lcsFilename, (LPTSTR) GETPROFILEDATA(lpBitmapV5), MAX_PATH);
  862.                     break;
  863.  
  864.                 default:
  865.                     // Just use color space type in the bitmap.
  866.                     lpColorSpace->lcsCSType = lpBitmapV5->bV5CSType;
  867.                     break;
  868.             }
  869.         }
  870.     }
  871.     // Set intent to default or to users selection.
  872.     if (0xffffffffL == dwIntent)
  873.     {
  874.         lpColorSpace->lcsIntent = LCS_GM_IMAGES;
  875.     }
  876.     else
  877.     {
  878.         lpColorSpace->lcsIntent = dwIntent;
  879.     }
  880.  
  881.     return(lpColorSpace);
  882. }
  883.  
  884.  
  885. //
  886. // Functions for extracting information from DIBs
  887. //
  888.  
  889. //////////////////////////////////////////////////////////////////////////
  890. //  Function:  NumColorsInDIB
  891. //
  892. //  Description:
  893. //    Determines the number of colors in the DIB by looking at the
  894. //    BitCount field in the info block.
  895. //
  896. //  Parameters:
  897. //    LPBINTMAPV5HEADER Pointer to BITMAPINFO structure
  898. //
  899. //  Returns:
  900. //    DWORD   Number of colors in the DIB
  901. //
  902. //  Comments:
  903. //
  904. //
  905. //////////////////////////////////////////////////////////////////////////
  906. DWORD NumColorsInDIB(LPBITMAPINFOHEADER lpbi)
  907. {
  908.     WORD    wBitCount;
  909.     DWORD   dwColors = 0;
  910.  
  911.  
  912.     // If this is a Windows style DIB, the number of colors in the
  913.     //  color table can be less than the number of bits per pixel
  914.     //  allows for (i.e. lpbi->biClrUsed can be set to some value).
  915.     //  If this is the case, return the appropriate value.
  916.     if ( (sizeof(BITMAPINFOHEADER) <= lpbi->biSize)
  917.          &&
  918.          (0 != lpbi->biClrUsed)
  919.        )
  920.     {
  921.         dwColors = lpbi->biClrUsed;
  922.     }
  923.     else
  924.     {
  925.         // Calculate the number of colors in the color table based on
  926.         //  the number of bits per pixel for the DIB.
  927.         wBitCount = BITCOUNT(lpbi);
  928.         if (MAX_BPP_COLOR_TABLE >= wBitCount)
  929.         {
  930.             dwColors = 1 << wBitCount;  // Colors = 2^BitCount
  931.         }
  932.     }
  933.  
  934.     return dwColors;
  935. }   // End of function NumColorsInDIB
  936.  
  937.  
  938. //////////////////////////////////////////////////////////////////////////
  939. //  Function:  PaletteSize
  940. //
  941. //  Description:
  942. //    Calculates the palette size in bytes.
  943. //
  944. //  Parameters:
  945. //    @@@
  946. //
  947. //  Returns:
  948. //    DWORD   Palette size in bytes.
  949. //
  950. //  Comments:
  951. //
  952. //
  953. //////////////////////////////////////////////////////////////////////////
  954. DWORD PaletteSize(LPBITMAPINFOHEADER lpbi)
  955. {
  956.     DWORD   dwSize = 0L;
  957.  
  958.  
  959.     if (sizeof(BITMAPINFOHEADER) <= lpbi->biSize)
  960.     {
  961.         dwSize = NumColorsInDIB(lpbi) * sizeof(RGBQUAD);
  962.  
  963.         if ( (lpbi->biCompression == BI_BITFIELDS)
  964.              &&
  965.              (sizeof(BITMAPV4HEADER) > lpbi->biSize)
  966.            )
  967.         {
  968.             dwSize = 3 * sizeof(DWORD);
  969.         }
  970.     }
  971.     else
  972.     {
  973.         dwSize = NumColorsInDIB(lpbi) * sizeof (RGBTRIPLE);
  974.     }
  975.  
  976.     return dwSize;
  977. }   // End of function PaletteSize
  978.  
  979.  
  980. ///////////////////////////////////////////////////////////////////////
  981. //
  982. // Function:   FindDIBBits
  983. //
  984. // Purpose:    Given a pointer to a DIB, returns a pointer to the
  985. //             DIB's bitmap bits.
  986. //
  987. // Parms:      lpbi == pointer to DIB header (either BITMAPINFOHEADER
  988. //                       or BITMAPCOREHEADER)
  989. //
  990. ///////////////////////////////////////////////////////////////////////
  991.  
  992. LPBYTE FindDIBBits(LPBITMAPINFOHEADER lpbi)
  993. {
  994.     ASSERT(NULL != lpbi);
  995.     return ((LPBYTE)lpbi + *(LPDWORD)lpbi + PaletteSize(lpbi) + PROFILESIZE(lpbi));
  996. }
  997.  
  998. ///////////////////////////////////////////////////////////////////////
  999. //
  1000. // Function:   FindDIBBits
  1001. //
  1002. // Purpose:    Given a pointer to a DIB, returns a pointer to the
  1003. //             DIB's bitmap bits.
  1004. //
  1005. // Parms:      lpbi == pointer to DIB header (either BITMAPINFOHEADER
  1006. //                       or BITMAPCOREHEADER)
  1007. //
  1008. ///////////////////////////////////////////////////////////////////////
  1009.  
  1010. LPBYTE FindColorTable(LPBITMAPINFOHEADER lpbi)
  1011. {
  1012.     ASSERT(NULL != lpbi);
  1013.     return ((LPBYTE)lpbi + *(LPDWORD)lpbi + PaletteSize(lpbi) + PROFILESIZE(lpbi));
  1014. }
  1015.  
  1016. ///////////////////////////////////////////////////////////////////////
  1017. //
  1018. // Function:   DIBHeight
  1019. //
  1020. // Purpose:    Given a pointer to a DIB, returns the ABSOLUTE VALUE of
  1021. //             its height.  Note that it returns a DWORD (since a Win30
  1022. //             DIB can have a DWORD in its height field), but under
  1023. //             Win30, the high order word isn't used!
  1024. //
  1025. // Parms:      lpDIB == pointer to DIB header (either BITMAPINFOHEADER
  1026. //                       or BITMAPCOREHEADER)
  1027. //
  1028. ///////////////////////////////////////////////////////////////////////
  1029.  
  1030. LONG DIBHeight (LPBYTE lpDIB)
  1031. {
  1032.     LPBITMAPINFOHEADER lpbmi;
  1033.     LPBITMAPCOREHEADER lpbmc;
  1034.  
  1035.     lpbmi = (LPBITMAPINFOHEADER) lpDIB;
  1036.     lpbmc = (LPBITMAPCOREHEADER) lpDIB;
  1037.     if (lpbmi->biSize >= sizeof (BITMAPINFOHEADER))
  1038.     {
  1039.         return labs(lpbmi->biHeight); // biHeight can now be negative! 8/9/93
  1040.     }
  1041.     else
  1042.     {
  1043.         return (LONG) lpbmc->bcHeight;
  1044.     }
  1045. }
  1046.  
  1047.  
  1048.  
  1049. ///////////////////////////////////////////////////////////////////////
  1050. //
  1051. // Function:   DIBWidth
  1052. //
  1053. // Purpose:    Given a pointer to a DIB, returns its width.  Note
  1054. //             that it returns a DWORD (since a Win30 DIB can have
  1055. //             a DWORD in its width field), but under Win30, the
  1056. //             high order word isn't used!
  1057. //
  1058. // Parms:      lpDIB == pointer to DIB header (either BITMAPINFOHEADER
  1059. //                       or BITMAPCOREHEADER)
  1060. //
  1061. ///////////////////////////////////////////////////////////////////////
  1062.  
  1063. LONG DIBWidth (LPBYTE lpDIB)
  1064. {
  1065.     LPBITMAPINFOHEADER lpbmi;
  1066.     LPBITMAPCOREHEADER lpbmc;
  1067.  
  1068.     lpbmi = (LPBITMAPINFOHEADER) lpDIB;
  1069.     lpbmc = (LPBITMAPCOREHEADER) lpDIB;
  1070.  
  1071.     if (lpbmi->biSize >= sizeof (BITMAPINFOHEADER))
  1072.     {
  1073.         return lpbmi->biWidth;
  1074.     }
  1075.     else
  1076.     {
  1077.         return (LONG) lpbmc->bcWidth;
  1078.     }
  1079. }
  1080.  
  1081.  
  1082. //
  1083. //  Functions for reading DIBs
  1084. //
  1085.  
  1086. //////////////////////////////////////////////////////////////////////////
  1087. //  Function:  ReadDIBFile
  1088. //
  1089. //  Description:
  1090. //     Open a DIB file and create
  1091. //          -a memory DIB
  1092. //          -a memory handle containing BITMAPINFO, palette, and the bits
  1093. //
  1094. //
  1095. //  Parameters:
  1096. //    @@@
  1097. //
  1098. //  Returns:
  1099. //    HGLOBAL Handle to DIB memory; NULL upon failure.
  1100. //
  1101. //  Comments:
  1102. //
  1103. //////////////////////////////////////////////////////////////////////////
  1104. HGLOBAL ReadDIBFile(LPTSTR lpszFileName)
  1105. {
  1106.     // Local variables
  1107.     HGLOBAL             hDIBInfo;
  1108.     LPDIBINFO           lpDIBInfo;
  1109.     BOOL                bGotDIBInfo;
  1110.  
  1111.     //  Initialize variables
  1112.     hDIBInfo = CreateDIBInfo();
  1113.     if (hDIBInfo == NULL)
  1114.     {
  1115.         return(NULL);
  1116.     }
  1117.     lpDIBInfo = GlobalLock(hDIBInfo);
  1118.     if (lpDIBInfo == (LPDIBINFO)NULL)
  1119.     {
  1120.         GlobalFree(hDIBInfo);
  1121.         return(NULL);
  1122.     }
  1123.     bGotDIBInfo =  fReadDIBInfo(lpszFileName, lpDIBInfo);
  1124.     GlobalUnlock(hDIBInfo);
  1125.     if (0 == bGotDIBInfo)  // failed to open file
  1126.     {
  1127.         fFreeDIBInfo(hDIBInfo, TRUE);
  1128.         hDIBInfo = NULL;
  1129.     }
  1130.     return(hDIBInfo);
  1131. }   // End of function ReadDIBFile
  1132.  
  1133.  
  1134. //////////////////////////////////////////////////////////////////////////
  1135. //  Function:   ReadDIBFromFile
  1136. //
  1137. //  Description:
  1138. //      Reads in the bitmap information.
  1139. //
  1140. //  Parameters:
  1141. //      hFile   Handle to bitmap file.
  1142. //
  1143. //  Returns:  Handle to DIB Bitmap.  NULL on error.
  1144. //
  1145. //  Comments:
  1146. //
  1147. //////////////////////////////////////////////////////////////////////////
  1148. HANDLE ReadDIBFromFile(HANDLE hFile)
  1149. {
  1150.     UINT                    nNumColors;
  1151.     DWORD                   offBits;
  1152.     DWORD                   dwRead;
  1153.     DWORD                   dwImageBytes;
  1154.     DWORD                   dwSizeImage;
  1155.     HANDLE                  hDIB;
  1156.     BITMAPFILEHEADER        BmpFileHeader;
  1157.     LPBITMAPINFOHEADER      lpbi;
  1158.  
  1159.     // Make sure non-null file handle.
  1160.  
  1161.     if (NULL == hFile)
  1162.     {
  1163.         return NULL;
  1164.     }
  1165.  
  1166.     // Read in Bitmap file header.
  1167.     if (0L != SetFilePointer(hFile, 0, NULL, FILE_BEGIN))
  1168.     {
  1169.         return NULL;
  1170.     }
  1171.     ReadFile(hFile, &BmpFileHeader, sizeof(BITMAPFILEHEADER), &dwRead, NULL);
  1172.     if (sizeof(BITMAPFILEHEADER) != dwRead)
  1173.     {
  1174.         return NULL;
  1175.     }
  1176.  
  1177.     // Make sure that the file is a bitmap file.
  1178.     if (BFT_BITMAP != BmpFileHeader.bfType)
  1179.     {
  1180.         return NULL;
  1181.     }
  1182.  
  1183.     // Detemine size of bitmap header.
  1184.     ReadFile(hFile, &dwImageBytes, sizeof(DWORD), &dwRead, NULL);
  1185.     if (sizeof(DWORD) != dwRead)
  1186.     {
  1187.         return NULL;
  1188.     }
  1189.  
  1190.     // Allocate memory for header & color table.
  1191.     // We'll enlarge this memory as needed.
  1192.     hDIB = GlobalAlloc(GHND, dwImageBytes + (256L * sizeof(RGBQUAD)));
  1193.     if (!hDIB)
  1194.     {
  1195.         return NULL;
  1196.     }
  1197.     lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
  1198.     if (!lpbi)
  1199.     {
  1200.         GlobalFree(hDIB);
  1201.         return NULL;
  1202.     }
  1203.  
  1204.     // Back up to begining of bitmap header and read bitmap header.
  1205.     SetFilePointer(hFile, sizeof(BITMAPFILEHEADER), NULL, FILE_BEGIN);
  1206.     ReadFile(hFile, lpbi, dwImageBytes, &dwRead, NULL);
  1207.     if (dwRead != dwImageBytes)
  1208.     {
  1209.         GlobalUnlock(hDIB);
  1210.         GlobalFree(hDIB);
  1211.         return NULL;
  1212.     }
  1213.  
  1214.     // Dump debug info about type of bitmap opened.
  1215. #ifdef MAXDEBUG
  1216.     DumpBmpHeader((LPVOID)lpbi);
  1217. #endif
  1218.  
  1219.     // Check to see that it's a Windows DIB or an OS/2 DIB.
  1220.     // It assumed that anything that is not a OS/2 DIB is a Windows DIB.
  1221.     // This at least allows the opening of newer bitmap types, although GDI
  1222.     // may not handle them so we may not be able to display them.
  1223.     // More critical checking could be done by checking against
  1224.     // BITMAPV4HEADER and BITMAPV5HEADER sizes.
  1225.  
  1226.     if (lpbi->biSize >= sizeof(BITMAPINFOHEADER))
  1227.     {
  1228.         DWORD   dwProfileData = 0;
  1229.         DWORD   dwColorTableSize;
  1230.         HANDLE  hTemp;
  1231.  
  1232.         // Now determine the size of the color table and read it.  Since the
  1233.         // bitmap bits are offset in the file by bfOffBits, we need to do some
  1234.         // special processing here to make sure the bits directly follow
  1235.         // the color table (because that's the format we are susposed to pass
  1236.         // back)
  1237.  
  1238.         // no color table for 24-bit, default size otherwise
  1239.         nNumColors = (UINT)lpbi->biClrUsed;
  1240.         if (0 == nNumColors)
  1241.         {
  1242.             if (lpbi->biBitCount <= MAX_BPP_COLOR_TABLE)
  1243.             {
  1244.                 nNumColors = 1 << lpbi->biBitCount;             // standard size table
  1245.             }
  1246.         }
  1247.  
  1248.         // Fill in some default values if they are zero
  1249.         if (0 == lpbi->biClrUsed)
  1250.         {
  1251.             lpbi->biClrUsed = nNumColors;
  1252.         }
  1253.  
  1254.         if (0 == lpbi->biSizeImage)
  1255.         {
  1256.             // Calculate size using DWORD alignment
  1257.             dwSizeImage = (((lpbi->biWidth * lpbi->biBitCount + 31) & ~31)
  1258.                            >> 3) * abs(lpbi->biHeight);
  1259.         }
  1260.         else
  1261.         {
  1262.             dwSizeImage = lpbi->biSizeImage;
  1263.         }
  1264.  
  1265.         // get a proper-sized buffer for header, color table and bits
  1266.         // Figure out the size of the bitmap AND it's color table.
  1267.         dwColorTableSize = PaletteSize(lpbi);
  1268.  
  1269.         // Calculate profile data size;
  1270.         // zero if not BITMAPV5HEADER, else in use bV5ProfileSize.
  1271.         dwProfileData =  PROFILESIZE(lpbi);
  1272.  
  1273.         // Resize DIB buffer.
  1274.         dwImageBytes = lpbi->biSize + dwSizeImage + dwColorTableSize + dwProfileData;
  1275.         GlobalUnlock(hDIB);
  1276.         hTemp = GlobalReAlloc(hDIB, dwImageBytes, GHND);
  1277.         DebugMsg(__TEXT("ReadDIBFromFile:  Allocating %lu bytes for header, color table, and image\r\n"), dwImageBytes);
  1278.         if (NULL == hTemp) // can't resize buffer for loading
  1279.         {
  1280.             GlobalFree(hDIB);
  1281.             return NULL;
  1282.         }
  1283.  
  1284.         hDIB = hTemp;
  1285.         lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
  1286.  
  1287.         // read the color table, if any, into buffer starting past Bitmap header.
  1288.         if (0 != dwColorTableSize)
  1289.         {
  1290.             ReadFile(hFile, (LPBYTE)lpbi + lpbi->biSize, dwColorTableSize, &dwRead, NULL);
  1291.             if (dwColorTableSize != dwRead)
  1292.             {
  1293.                 GlobalUnlock(hDIB);
  1294.                 GlobalFree(hDIB);
  1295.                 return NULL;
  1296.             }
  1297.         }
  1298.  
  1299.         // Load profile data, if any.
  1300.         if (0 != dwProfileData)
  1301.         {
  1302.             // Move to profile data.
  1303.             SetFilePointer(hFile, sizeof(BITMAPFILEHEADER)
  1304.                            + ((LPBITMAPV5HEADER)lpbi)->bV5ProfileData, NULL, FILE_BEGIN);
  1305.  
  1306.             // Read the profile data in after the header and color table.
  1307.             ReadFile(hFile, (LPBYTE)lpbi + lpbi->biSize + dwColorTableSize, dwProfileData, &dwRead, NULL);
  1308.             if (dwProfileData != dwRead)
  1309.             {
  1310.                 GlobalUnlock(hDIB);
  1311.                 GlobalFree(hDIB);
  1312.                 return NULL;
  1313.             }
  1314.  
  1315.             // Need to change the offset in the header.
  1316.             ((LPBITMAPV5HEADER)lpbi)->bV5ProfileData = lpbi->biSize + dwColorTableSize;
  1317.         }
  1318.  
  1319.         // offset to the bits from start of DIB header
  1320.         offBits = lpbi->biSize + dwColorTableSize + dwProfileData;
  1321.         DumpBmpHeader((LPVOID)lpbi);
  1322.     }
  1323.     else
  1324.     {
  1325.         // It's an OS/2 DIB, the color table is an array of RGBTRIPLEs.
  1326.         HANDLE                          hTemp;
  1327.         LPBITMAPCOREHEADER      lpbc = (LPBITMAPCOREHEADER) lpbi;
  1328.  
  1329.         // Gotta back up to beginning of color table.
  1330.         SetFilePointer(hFile, sizeof (BITMAPFILEHEADER) + sizeof (BITMAPCOREHEADER), NULL, FILE_BEGIN);
  1331.  
  1332.         // Now determine the size of the color table and read it.  Since the
  1333.         // bitmap bits are offset in the file by bfOffBits, we need to do some
  1334.         // special processing here to make sure the bits directly follow
  1335.         // the color table (because that's the format we are susposed to pass
  1336.         // back)
  1337.  
  1338.         if (lpbc->bcBitCount <= MAX_BPP_COLOR_TABLE)
  1339.         {
  1340.             nNumColors = 1 << lpbc->bcBitCount;    // standard size table
  1341.         }
  1342.         else
  1343.         {
  1344.             nNumColors = 0;
  1345.         }
  1346.  
  1347.         // Determine the size of the image
  1348.         dwSizeImage = (((lpbc->bcWidth * lpbc->bcBitCount + 31) & ~31) >> 3)
  1349.                       * lpbc->bcHeight;
  1350.  
  1351.         // get a proper-sized buffer for header, color table and bits
  1352.         GlobalUnlock(hDIB);
  1353.         hTemp = GlobalReAlloc(hDIB, lpbc->bcSize + (nNumColors * sizeof(RGBTRIPLE))
  1354.                               + dwSizeImage, GHND);
  1355.         if (!hTemp) // can't resize buffer for loading
  1356.         {
  1357.             GlobalFree(hDIB);
  1358.             return NULL;
  1359.         }
  1360.  
  1361.         hDIB = hTemp;
  1362.         lpbc = (LPBITMAPCOREHEADER) GlobalLock(hDIB);
  1363.         lpbi = (LPBITMAPINFOHEADER) lpbc;
  1364.  
  1365.         // read the color table
  1366.         ReadFile(hFile, (LPBYTE)lpbc + lpbc->bcSize, nNumColors * sizeof(RGBTRIPLE), &dwRead, NULL);
  1367.         if (nNumColors * sizeof(RGBTRIPLE) != dwRead)
  1368.         {
  1369.             GlobalUnlock(hDIB);
  1370.             GlobalFree(hDIB);
  1371.             return NULL;
  1372.         }
  1373.  
  1374.         // offset to the bits from start of DIB header
  1375.         offBits = lpbc->bcSize + nNumColors * sizeof(RGBTRIPLE);
  1376.     }
  1377.  
  1378.     // If the bfOffBits field is non-zero, then the bits might *not* be
  1379.     // directly following the color table in the file.  Use the value in
  1380.     // bfOffBits to seek the bits.
  1381.  
  1382.     if (BmpFileHeader.bfOffBits != 0L)
  1383.     {
  1384.         SetFilePointer(hFile, BmpFileHeader.bfOffBits, NULL, FILE_BEGIN);
  1385.     }
  1386.  
  1387.     // Read the actual bits
  1388.     ReadFile(hFile, (LPBYTE)lpbi + offBits, dwSizeImage, &dwRead, NULL);
  1389.     if (dwRead != dwSizeImage)
  1390.     {
  1391.         GlobalUnlock(hDIB);
  1392.         GlobalFree(hDIB);
  1393.         return NULL;
  1394.     }
  1395.     GlobalUnlock(hDIB);
  1396.     return hDIB;
  1397. }  // End of function ReadDIBFromFile
  1398.  
  1399.  
  1400.  
  1401. //////////////////////////////////////////////////////////////////////////
  1402. //  Function:  TranslateColorTable
  1403. //
  1404. //  Description:
  1405. //
  1406. //
  1407. //  Parameters:
  1408. //    @@@
  1409. //
  1410. //  Returns:
  1411. //    BOOL
  1412. //
  1413. //  Comments:
  1414. //
  1415. //
  1416. //////////////////////////////////////////////////////////////////////////
  1417. BOOL TranslateColorTable(HTRANSFORM hColorTransform,
  1418.                          PCOLOR    paInputColors,
  1419.                          DWORD   nColors,
  1420.                          COLORTYPE     ctInput,
  1421.                          PCOLOR    paOutputColors,
  1422.                          COLORTYPE   ctOutput,
  1423.                          int         biBitCount
  1424.                         )
  1425. {
  1426.     //  Initialize variables
  1427.     if (ctInput == COLOR_RGB)
  1428.     {
  1429.         return(TranslateBitmapBits(hColorTransform,
  1430.                                    (PVOID)paInputColors,
  1431.                                    BM_xRGBQUADS,
  1432.                                    1<<biBitCount,
  1433.                                    1,
  1434.                                    0,
  1435.                                    (PVOID)paOutputColors,
  1436.                                    BM_xRGBQUADS,
  1437.                                    0,
  1438.                                    NULL,
  1439.                                    0));
  1440.     }
  1441.     else
  1442.     {
  1443.         return(TranslateColors(hColorTransform, paInputColors, nColors, ctInput, paOutputColors, ctOutput));
  1444.     }
  1445. }   // End of function TranslateColorTable
  1446.  
  1447.  
  1448. //////////////////////////////////////////////////////////////////////////
  1449. //  Function:  SaveDIBToFile
  1450. //
  1451. //  Description:
  1452. //
  1453. //
  1454. //  Parameters:
  1455. //    @@@
  1456. //
  1457. //  Returns:
  1458. //    BOOL
  1459. //
  1460. //  Comments:
  1461. //
  1462. //
  1463. //////////////////////////////////////////////////////////////////////////
  1464. BOOL SaveDIBToFile(HWND hWnd, LPCTSTR lpszFileName, LPDIBINFO lpDIBInfo, DWORD dwType)
  1465. {
  1466.     BOOL                bResult = FALSE;
  1467.     HANDLE              hFile;
  1468.     HANDLE              hDIBTransformed = NULL;
  1469.     PBITMAPINFOHEADER   pBitmapInfo;
  1470.  
  1471.  
  1472.     // Validate Parameters.
  1473.     if ( (NULL == lpszFileName)
  1474.          ||
  1475.          (NULL == lpDIBInfo)
  1476.          ||
  1477.          (NULL == lpDIBInfo->hDIB)
  1478.          ||
  1479.          ( (LCS_sRGB != dwType)
  1480.            &&
  1481.            (LCS_CALIBRATED_RGB != dwType)
  1482.            &&
  1483.            (PROFILE_LINKED != dwType)
  1484.            &&
  1485.            (PROFILE_EMBEDDED != dwType)
  1486.          )
  1487.        )
  1488.     {
  1489.         return FALSE;
  1490.     }
  1491.     pBitmapInfo = (PBITMAPINFOHEADER) GlobalLock(lpDIBInfo->hDIB);
  1492.  
  1493.     // Open file handle.
  1494.     hFile = CreateFile(lpszFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
  1495.                        FILE_ATTRIBUTE_NORMAL, NULL);
  1496.     if (INVALID_HANDLE_VALUE != hFile)
  1497.     {
  1498.         DWORD               dwBytes;
  1499.         DWORD               dwProfileSize;
  1500.         PBYTE               pProfileData;
  1501.         LPSTR               lpszProfileName;
  1502.         BITMAPV5HEADER      BitmapHeader;
  1503.         BITMAPFILEHEADER    FileHeader;
  1504.  
  1505.  
  1506.         // Initialize variables.
  1507.         dwProfileSize = PROFILESIZE(pBitmapInfo);
  1508.         pProfileData = GETPROFILEDATA(pBitmapInfo);
  1509.         lpszProfileName = NULL;
  1510.         memset(&BitmapHeader, 0, sizeof(BITMAPV5HEADER));
  1511.         memset(&FileHeader, 0, sizeof(BITMAPFILEHEADER));
  1512.  
  1513.         // Convert to proper type.
  1514.         if (dwType != BITMAPCSTYPE(pBitmapInfo))
  1515.         {
  1516.             if (PROFILE_LINKED == dwType)
  1517.             {
  1518.                 ASSERT(PROFILE_EMBEDDED == BITMAPCSTYPE(pBitmapInfo));
  1519.  
  1520.                 // Going from Embedded profile to linked.
  1521.                 // Save embedded profile data to file.
  1522.  
  1523.                 // Create file name from manufacture and model name of profile header.
  1524.                 lpszProfileName = (LPSTR) GlobalAlloc(GPTR, 1024);
  1525.  
  1526.                 // Get save name and save profile data.
  1527.                 if (GetProfileSaveName(hWnd, &lpszProfileName, 1024))
  1528.                 {
  1529.                     HANDLE  hProfile;
  1530.  
  1531.                     hProfile = CreateFileA(lpszProfileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
  1532.                                            FILE_ATTRIBUTE_NORMAL, NULL);
  1533.                     if (INVALID_HANDLE_VALUE != hProfile)
  1534.                     {
  1535.                         WriteFile(hProfile, pProfileData, dwProfileSize, &dwBytes, NULL);
  1536.                         CloseHandle(hProfile);
  1537.                     }
  1538.  
  1539.                     // Change profile variables to point to linked name.
  1540.                     pProfileData = (PBYTE) lpszProfileName;
  1541.                     dwProfileSize = strlen(lpszProfileName);
  1542.                 }
  1543.             }
  1544.             else if (PROFILE_EMBEDDED == dwType)
  1545.             {
  1546.                 DWORD       dwSize = 0;
  1547.                 PROFILE     Profile;
  1548.                 HPROFILE    hProfile;
  1549.  
  1550.  
  1551.                 ASSERT(PROFILE_EMBEDDED == BITMAPCSTYPE(pBitmapInfo));
  1552.  
  1553.                 // Going from linked profile to Embedded.
  1554.                 // Embed Linked profile data.
  1555.  
  1556.                 // Open profile.
  1557.                 Profile.dwType = PROFILE_FILENAME;
  1558.                 Profile.pProfileData = pProfileData;
  1559.                 Profile.cbDataSize = dwProfileSize;
  1560.                 hProfile = OpenColorProfile(&Profile, PROFILE_READ, FILE_SHARE_READ, OPEN_EXISTING);
  1561.  
  1562.                 // Get profile data form handle.
  1563.                 if (NULL != hProfile)
  1564.                 {
  1565.                     GetColorProfileFromHandle(hProfile, NULL, &dwSize);
  1566.                     lpszProfileName = (LPSTR) GlobalAlloc(GPTR, dwSize);
  1567.                     GetColorProfileFromHandle(hProfile, (PBYTE) lpszProfileName, &dwSize);
  1568.  
  1569.                     CloseColorProfile(hProfile);
  1570.                 }
  1571.  
  1572.                 // Change profile variables to point at data to embed.
  1573.                 pProfileData = (PBYTE) lpszProfileName;
  1574.                 dwProfileSize = dwSize;
  1575.             }
  1576.             else if (LCS_sRGB == dwType)
  1577.             {
  1578.                 DWORD       dwSize;
  1579.                 LPTSTR      pszSRGB;
  1580.  
  1581.  
  1582.                 // Need to translate from current type to sRGB.
  1583.  
  1584.                 // Open sRGB profile.
  1585.                 GetStandardColorSpaceProfile(NULL, LCS_sRGB, NULL, &dwSize);
  1586.                 pszSRGB = (LPTSTR) GlobalAlloc(GPTR, dwSize);
  1587.                 GetStandardColorSpaceProfile(NULL, LCS_sRGB, pszSRGB, &dwSize);
  1588.  
  1589.                 if (NULL != pszSRGB)
  1590.                 {
  1591.                     // Translate DIB.
  1592.                     hDIBTransformed = TransformDIBOutsideDC(lpDIBInfo->hDIB,
  1593.                                                             lpDIBInfo->bmFormat,
  1594.                                                             pszSRGB,
  1595.                                                             NULL,
  1596.                                                             USE_BITMAP_INTENT,
  1597.                                                             NULL,
  1598.                                                             0);
  1599.  
  1600.                     // Clean up.
  1601.                     GlobalFree((HANDLE)pszSRGB);
  1602.  
  1603.                     // Change bitmap info variable to point at tranlated DIB.
  1604.                     pBitmapInfo = (PBITMAPINFOHEADER) GlobalLock(hDIBTransformed);
  1605.                 }
  1606.             }
  1607.         }
  1608.  
  1609.         if (NULL != pBitmapInfo)
  1610.         {
  1611.             // Create file header and write it to the file.
  1612.             FileHeader.bfType = BFT_BITMAP;
  1613.             FileHeader.bfSize = sizeof(BITMAPFILEHEADER);
  1614.             FileHeader.bfSize += sizeof(BITMAPV5HEADER);
  1615.             FileHeader.bfSize += NumColorsInDIB(pBitmapInfo) * sizeof(RGBQUAD);
  1616.             FileHeader.bfSize += BITMAPSIZE(pBitmapInfo);
  1617.             FileHeader.bfSize += dwProfileSize;
  1618.             FileHeader.bfOffBits = sizeof(BITMAPFILEHEADER);
  1619.             FileHeader.bfOffBits += sizeof(BITMAPV5HEADER);
  1620.             FileHeader.bfOffBits += NumColorsInDIB(pBitmapInfo) * sizeof(RGBQUAD);
  1621.             WriteFile(hFile, &FileHeader, sizeof(BITMAPFILEHEADER), &dwBytes, NULL);
  1622.  
  1623.             // Create bitmap header and write it to file.
  1624.             BitmapHeader.bV5Size = sizeof(BITMAPV5HEADER);
  1625.             BitmapHeader.bV5Width = BITMAPWIDTH(pBitmapInfo);
  1626.             BitmapHeader.bV5Height = BITMAPHEIGHT(pBitmapInfo);
  1627.             BitmapHeader.bV5Planes = 1;
  1628.             BitmapHeader.bV5BitCount = (WORD) BITCOUNT(pBitmapInfo);
  1629.             BitmapHeader.bV5Compression = BITMAPCOMPRESSION(pBitmapInfo);
  1630.             BitmapHeader.bV5SizeImage = BITMAPIMAGESIZE(pBitmapInfo);
  1631.             BitmapHeader.bV5ClrUsed = BITMAPCLRUSED(pBitmapInfo);
  1632.             BitmapHeader.bV5ClrImportant = BITMAPCLRIMPORTANT(pBitmapInfo);
  1633.             BitmapHeader.bV5RedMask = BITMAPREDMASK(pBitmapInfo);
  1634.             BitmapHeader.bV5GreenMask = BITMAPGREENMASK(pBitmapInfo);
  1635.             BitmapHeader.bV5BlueMask = BITMAPBLUEMASK(pBitmapInfo);
  1636.             BitmapHeader.bV5CSType = dwType;
  1637.             if (sizeof(BITMAPV4HEADER) <= *(LPDWORD)pBitmapInfo)
  1638.             {
  1639.                 memcpy(&BitmapHeader.bV5Endpoints, &((PBITMAPV4HEADER)pBitmapInfo)->bV4Endpoints,
  1640.                        sizeof(CIEXYZTRIPLE) + sizeof(DWORD) * 3);
  1641.             }
  1642.             BitmapHeader.bV5Intent = BITMAPINTENT(pBitmapInfo);
  1643.             BitmapHeader.bV5ProfileData = sizeof(BITMAPV5HEADER);
  1644.             BitmapHeader.bV5ProfileData += NumColorsInDIB(pBitmapInfo) * sizeof(RGBQUAD);
  1645.             BitmapHeader.bV5ProfileData += BITMAPSIZE(pBitmapInfo);
  1646.             BitmapHeader.bV5ProfileSize = dwProfileSize;
  1647.             WriteFile(hFile, &BitmapHeader, sizeof(BITMAPV5HEADER), &dwBytes, NULL);
  1648.  
  1649.             // Write color table.
  1650.             if (!IS_BITMAPCOREHEADER(pBitmapInfo))
  1651.             {
  1652.                 PBYTE   pColorTable;
  1653.                 DWORD   dwColorTableSize;
  1654.  
  1655.                 dwColorTableSize = NumColorsInDIB(pBitmapInfo) * sizeof(RGBQUAD);
  1656.                 pColorTable = (PBYTE)pBitmapInfo + *(LPDWORD)pBitmapInfo;
  1657.                 if ( IS_BITMAPINFOHEADER(pBitmapInfo)
  1658.                      &&
  1659.                      (BI_BITFIELDS == BITMAPCOMPRESSION(pBitmapInfo))
  1660.                    )
  1661.                 {
  1662.                     dwColorTableSize += sizeof(DWORD) * 3;
  1663.                 }
  1664.  
  1665.                 WriteFile(hFile, pColorTable, dwColorTableSize, &dwBytes, NULL);
  1666.             }
  1667.             else
  1668.             {
  1669.                 PBYTE   pColorTable;
  1670.                 DWORD   dwCount;
  1671.                 RGBQUAD ColorTable[256];
  1672.  
  1673.  
  1674.                 pColorTable = (PBYTE)pBitmapInfo + *(LPDWORD)pBitmapInfo;
  1675.                 memset(ColorTable, 0, sizeof(ColorTable));
  1676.                 for (dwCount = 0; dwCount < NumColorsInDIB(pBitmapInfo); dwCount++)
  1677.                     memcpy(ColorTable + dwCount, pColorTable + dwCount, sizeof(RGBTRIPLE));
  1678.  
  1679.                 WriteFile(hFile, ColorTable, NumColorsInDIB(pBitmapInfo) * sizeof(RGBQUAD), &dwBytes, NULL);
  1680.             }
  1681.  
  1682.             // Save bitmap data.
  1683.             WriteFile(hFile, FindDIBBits(pBitmapInfo), BITMAPSIZE(pBitmapInfo), &dwBytes, NULL);
  1684.  
  1685.             // Save profile data.
  1686.             if (0 != dwProfileSize)
  1687.             {
  1688.                 WriteFile(hFile, pProfileData, dwProfileSize, &dwBytes, NULL);
  1689.             }
  1690.  
  1691.             bResult = TRUE;
  1692.         }
  1693.  
  1694.         // Clean up.
  1695.         CloseHandle(hFile);
  1696.         if (NULL != lpszProfileName)
  1697.             GlobalFree((HANDLE)lpszProfileName);
  1698.         if (NULL != hDIBTransformed)
  1699.         {
  1700.             GlobalUnlock(hDIBTransformed);
  1701.             GlobalFree(hDIBTransformed);
  1702.         }
  1703.  
  1704.         // If failed, delete file.
  1705.         if (!bResult)
  1706.             DeleteFile(lpszFileName);
  1707.     }
  1708.  
  1709.     //Clean up.
  1710.     GlobalUnlock(lpDIBInfo->hDIB);
  1711.  
  1712.     return bResult;
  1713. }
  1714.  
  1715.