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 >
Wrap
C/C++ Source or Header
|
1997-09-07
|
60KB
|
1,715 lines
//THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
//ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
//THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright 1994-1997 Microsoft Corporation. All Rights Reserved.
//
// FILE:
// DIBS.C
//
// PURPOSE:
// DIB routines for the ICMVIEW application.
//
// PLATFORMS:
// Windows 95, Windows NT
//
// SPECIAL INSTRUCTIONS: N/A
//
// Windows Header Files:
#pragma warning(disable:4001) // Single-line comment warnings
#pragma warning(disable:4115) // Named type definition in parentheses
#pragma warning(disable:4201) // Nameless struct/union warning
#pragma warning(disable:4214) // Bit field types other than int warnings
#pragma warning(disable:4514) // Unreferenced inline function has been removed
// Windows Header Files:
#include <Windows.h>
#include <WindowsX.h>
//#include <CommCtrl.h>
#include <icm.h>
// Restore the warnings--leave the single-line comment warning OFF
#pragma warning(default:4115) // Named type definition in parentheses
#pragma warning(default:4201) // Nameless struct/union warning
#pragma warning(default:4214) // Bit field types other than int warnings
#pragma warning(default:4514) // Unreferenced inline function has been removed
// C RunTime Header Files
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <TCHAR.H>
// Local Header Files
#include "icmview.h" // specific to this program
#include "child.h"
#include "dibinfo.h"
#include "dibs.h" // specific to this file
#include "dialogs.h"
#include "debug.h"
#include "print.h"
#include "regutil.h"
#include "resource.h"
// local definitions
DWORD NumColorsInDIB(LPBITMAPINFOHEADER lpbi);
LONG DIBHeight (LPBYTE lpDIB);
LONG DIBWidth (LPBYTE lpDIB);
LPLOGCOLORSPACE GetColorSpaceFromBitmap(LPBITMAPINFOHEADER lpBitmapInfo, DWORD dwIntent, LPBOOL pbDeleteProfile);
HPROFILE OpenColorProfileFromFile(LPTSTR lpszProfileName);
BOOL TranslateColorTable(HTRANSFORM hColorTransform, PCOLOR paInputColors, DWORD nColors, COLORTYPE ctInput, PCOLOR paOutputColors, COLORTYPE ctOutput, int biBitCount);
// default settings
// external functions
// external data
// public data
// private data
// public functions
// private functions
///////////////////////////////////////////////////////////////////////
//
// Function: DIBPaint
//
// Purpose: Painting routine for a DIB. Calls StretchDIBits() or
// SetDIBitsToDevice() to paint the DIB. The DIB is
// output to the specified DC, at the coordinates given
// in lpDCRect. The area of the DIB to be output is
// given by lpDIBRect. The specified palette is used.
//
// Parms: hDC == DC to do output to.
// lpDCRect == Rectangle on DC to do output to.
// hDIB == Handle to global memory with a DIB spec
// in it (either a BITMAPINFO or BITMAPCOREINFO
// followed by the DIB bits).
// lpDIBRect == Rect of DIB to output into lpDCRect.
// hPal == Palette to be used.
//
///////////////////////////////////////////////////////////////////////
void DIBPaint (HDC hDC, LPRECT lpDCRect, HGLOBAL hDIB,LPRECT lpDIBRect,
LPDIBINFO lpDIBInfo)
{
int iScanLines;
HDC hDCPrinter;
BOOL bRC;
LPBYTE lpbDIBBits;
HPALETTE hOldPal;
LPBITMAPINFOHEADER lpDIBHdr;
LPBITMAPINFOHEADER lpbi;
// Initialize variables
if (!hDIB)
{
return;
}
ASSERT(hDC != NULL);
hDCPrinter = NULL;
SetLastError(0);
hOldPal = NULL;
lpbi = NULL;
// Lock down DIB, get a pointer to the beginning of the bit buffer.
lpDIBHdr = GlobalLock(hDIB);
if (NULL == lpDIBHdr )
{
goto Release;
}
lpbDIBBits = FindDIBBits(lpDIBHdr);
if (NULL == lpbDIBBits)
{
goto Release;
}
// If size > BITMAPINFOHEADER header then
// need to convert to BITMAPINFOHEADER.
lpbi = lpDIBHdr;
#ifdef OSR2
if (sizeof(BITMAPINFOHEADER) < lpDIBHdr->biSize)
{
DWORD dwColorTableSize;
DWORD dwHeaderDataSize;
// Allocate Bitmapinfo memory.
dwHeaderDataSize = sizeof(BITMAPINFOHEADER) + (lpDIBHdr->biCompression == BI_BITFIELDS ? 12 : 0);
dwColorTableSize = NumColorsInDIB(lpDIBHdr) * sizeof(RGBQUAD);
lpbi = (LPBITMAPINFOHEADER) GlobalAlloc(GPTR, dwHeaderDataSize + dwColorTableSize);
if (NULL == lpbi)
{
goto Release;
}
// Convert header data into bitmapinfo header.
memcpy(lpbi, lpDIBHdr, dwHeaderDataSize);
lpbi->biSize = sizeof(BITMAPINFOHEADER);
// Copy color table if any.
if (0 != dwColorTableSize)
memcpy((LPBYTE)lpbi + dwHeaderDataSize, (LPBYTE)lpDIBHdr + lpDIBHdr->biSize, dwColorTableSize);
}
#endif
SetupDC(hDC, lpDIBInfo, &hOldPal, &hDCPrinter);
// Determine whether to call StretchDIBits() or SetDIBitsToDevice().
if (!(lpDIBInfo->bStretch))
{
iScanLines = SetDIBitsToDevice (hDC, // hDC
lpDCRect->left, // dest upper-left x
lpDCRect->top, // dest upper-left y
RECTWIDTH (lpDCRect), // src width
RECTHEIGHT (lpDCRect), // src height
lpDIBRect->left, // src lower-left x
(int) DIBHeight((LPBYTE)lpDIBHdr) -
lpDIBRect->top -
RECTHEIGHT (lpDIBRect), // src lower-left y
0, // nStartScan
(UINT) DIBHeight((LPBYTE)lpDIBHdr), // nNumScans
lpbDIBBits, // lpBits
(LPBITMAPINFO) lpbi, // lpBitsInfo
DIB_RGB_COLORS); // wUsage
}
else
{
// Use the specified stretch mode
SetStretchBltMode (hDC, (int)lpDIBInfo->dwStretchBltMode);
iScanLines = StretchDIBits (hDC, // hDC
lpDCRect->left, // dest upper-left x
lpDCRect->top, // dest upper-left y
RECTWIDTH (lpDCRect), // src width
RECTHEIGHT (lpDCRect), // src height
lpDIBRect->left, // src lower-left x
lpDIBRect->top, // src lower-left y
RECTWIDTH (lpDIBRect), // nStartScan
RECTHEIGHT (lpDIBRect), // nNumScans
lpbDIBBits, // lpBits
(LPBITMAPINFO)lpbi, // lpBitsInfo
DIB_RGB_COLORS, // wUsage
SRCCOPY); // dwROP
}
if (DIBHeight((LPBYTE)lpDIBHdr) != iScanLines)
{
DebugMsg(__TEXT("DIBS.C : DIBPaint: iScanLines expected %ld, returned %ld\r\n"), DIBHeight((LPBYTE)lpDIBHdr), iScanLines);
}
// Fix up the palette.
if (NULL == SelectPalette (hDC, hOldPal, TRUE))
{
DISPLAY_LASTERROR(LASTERROR_NOALLOC, GetLastError());
}
Release:
if (lpbi != lpDIBHdr)
GlobalFree((HANDLE)lpbi);
if (NULL != lpDIBHdr)
{
GlobalUnlock(hDIB);
}
if (hDCPrinter)
{
bRC = ColorMatchToTarget(hDC, hDCPrinter, CS_DISABLE);
if (0 == bRC)
{
DebugMsg(__TEXT("DIBS.C : DIBPaint : ColorMatchToTarget failed to DISABLE transform.\r\n"));
DISPLAY_LASTERROR(LASTERROR_NOALLOC,GetLastError());
}
bRC = ColorMatchToTarget(hDC, hDCPrinter, CS_DELETE_TRANSFORM);
if (0 == bRC)
{
DebugMsg( __TEXT( "DIBS.C : DIBPaint : ColorMatchToTarget failed to DELETE transform.\r\n"));
DISPLAY_LASTERROR(LASTERROR_NOALLOC,GetLastError());
}
bRC = DeleteDC(hDCPrinter);
if (0 == bRC)
{
DebugMsg(__TEXT("DIBS.C : DIBPaint : Failed to delete printer DC\r\n"));
DISPLAY_LASTERROR(LASTERROR_NOALLOC,GetLastError());
}
}
}
///////////////////////////////////////////////////////////////////////
//
// Function: CreateDIBPalette
//
// Purpose: Given a handle to a DIB, constructs a logical palette,
// and returns a handle to this palette.
//
// Stolen almost verbatim from ShowDIB.
//
// Parms: hDIB == HANDLE to global memory with a DIB header
// (either BITMAPINFOHEADER or BITMAPCOREHEADER)
//
///////////////////////////////////////////////////////////////////////
HPALETTE CreateDIBPalette(HANDLE hDIB)
{
LPLOGPALETTE lpPal;
HGLOBAL hLogPal;
HPALETTE hPal = NULL;
UINT i;
DWORD dwNumColors;
LPBITMAPINFOHEADER lpBmpInfoHdr;
LPBITMAPINFO lpbmi;
LPBITMAPCOREINFO lpbmc;
BOOL bWinStyleDIB;
if (!hDIB)
{
return NULL;
}
lpBmpInfoHdr = GlobalLock (hDIB);
lpbmi = (LPBITMAPINFO)lpBmpInfoHdr;
lpbmc = (LPBITMAPCOREINFO)lpBmpInfoHdr;
dwNumColors = NumColorsInDIB(lpBmpInfoHdr);
bWinStyleDIB = IS_WIN30_DIB(lpBmpInfoHdr);
if (0 != dwNumColors)
{
hLogPal = GlobalAlloc (GHND, sizeof (LOGPALETTE) + sizeof (PALETTEENTRY) * dwNumColors);
if (!hLogPal)
{
GlobalUnlock(hDIB);
return NULL;
}
lpPal = (LPLOGPALETTE) GlobalLock (hLogPal);
lpPal->palVersion = PALVERSION;
lpPal->palNumEntries = (WORD)dwNumColors;
for (i = 0; i < dwNumColors; i++)
{
if (bWinStyleDIB)
{
lpPal->palPalEntry[i].peRed = lpbmi->bmiColors[i].rgbRed;
lpPal->palPalEntry[i].peGreen = lpbmi->bmiColors[i].rgbGreen;
lpPal->palPalEntry[i].peBlue = lpbmi->bmiColors[i].rgbBlue;
lpPal->palPalEntry[i].peFlags = 0;
}
else
{
lpPal->palPalEntry[i].peRed = lpbmc->bmciColors[i].rgbtRed;
lpPal->palPalEntry[i].peGreen = lpbmc->bmciColors[i].rgbtGreen;
lpPal->palPalEntry[i].peBlue = lpbmc->bmciColors[i].rgbtBlue;
lpPal->palPalEntry[i].peFlags = 0;
}
}
hPal = CreatePalette (lpPal);
GlobalUnlock(hLogPal);
GlobalFree(hLogPal);
}
GlobalUnlock(hDIB);
return(hPal);
}
//////////////////////////////////////////////////////////////////////////
// Function: GetDefaultICMProfile
//
// Description:
// Uses GetICMProfile to retrieve the filename of the default ICM
// profile for the DC.
//
// Parameters:
// @@@
//
// Returns:
// LPTSTR
//
// Comments:
//
//
//////////////////////////////////////////////////////////////////////////
LPTSTR GetDefaultICMProfile(HDC hDC)
{
// Local variables
LPTSTR lpszProfileName;
BOOL bProfile;
DWORD dwProfileLen;
TCHAR stProfileName[MAX_PATH+1];
HGLOBAL hFree;
// Initialize variables
lpszProfileName = NULL;
dwProfileLen = 0;
stProfileName[0] = __TEXT('\0');
// Query for size of profile name string
bProfile = GetICMProfile(hDC, &dwProfileLen, NULL);
if (bProfile)
{
DebugMsg(__TEXT("GetDefaultICMProfile: GetICMProfile returned TRUE on query, dwProfileLen = %ld\r\n"), dwProfileLen);
return(FALSE);
}
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
{
DebugMsg(__TEXT("GetDefaultICMProfile: GetICMProfile set unexpected LastError %ld on query, dwProfileLen = %ld\r\n"),
GetLastError(), dwProfileLen);
DISPLAY_LASTERROR(LASTERROR_NOALLOC, GetLastError());
dwProfileLen = MAX_PATH;
}
else
{
if (0 == dwProfileLen)
{
DebugMsg(__TEXT("GetDefaultICMProfile: GetICMProfile returned FALSE on query, DID NOT SET dwProfileLen\r\n"));
return(FALSE);
}
}
// Fill in lpszProfileName with actual profile filename
lpszProfileName = GlobalAlloc(GPTR, (dwProfileLen+1) * sizeof(TCHAR));
if (lpszProfileName != NULL)
{
bProfile = GetICMProfile(hDC, &dwProfileLen, lpszProfileName);
if (!bProfile)
{
DebugMsg(__TEXT("GetDefaultICMProfile: GetICMProfile FAILED\r\n"));
DISPLAY_LASTERROR(LASTERROR_NOALLOC, GetLastError());
hFree = GlobalFree(lpszProfileName);
return(NULL);
}
else // Successfully id'd default profile
{
TCHAR szName[MAX_PATH], szExt[MAX_PATH];
DebugMsg(__TEXT("Full profile name: <%s>\r\n"), lpszProfileName);
_tsplitpath(lpszProfileName, NULL, NULL, szName, szExt);
wsprintf(lpszProfileName, __TEXT("%s%s"), szName, szExt);
}
}
else
{
DebugMsg(__TEXT("GetDefaultICMProfile: Unable to allocate lpszProfileName.\r\n"));
}
return(lpszProfileName);
} // End of function GetDefaultICMProfile
//////////////////////////////////////////////////////////////////////////
// Function: TransformDIBOutsideDC
//
// Description:
// Transforms the provided hDIB using the provided profile names.
//
// Parameters:
// HANDLE Handle to DIB to process
// LPTSTR Destination profile
// LPTSTR Target profile
//
// Returns:
// HANDLE to transformed bits; NULL upon failure.
//
// Comments:
// Uses ICM functions
// CreateColorTransform
// TranslateBitmapBits
// TranslateColors
//
//////////////////////////////////////////////////////////////////////////
HANDLE TransformDIBOutsideDC(HANDLE hDIB, BMFORMAT bmInput, LPTSTR lpszDestProfile,
LPTSTR lpszTargetProfile, DWORD dwIntent, PBMCALLBACKFN pBMCallback,
ULONG ulCallbackData)
{
// Local variables
HANDLE hDIBTransformed; // Handle to transformed DIB
HPROFILE hDestProfile, hTargetProfile;
HTRANSFORM hTransform;
LPLOGCOLORSPACE lpLogColorSpace;
PVOID pSrcBits, pDestBits;
LPBITMAPINFOHEADER lpbSrcDIBHdr, lpbDestDIBHdr;
BOOL bTranslated, bProfileClosed, bDeleted, bDeleteProfile;
DWORD dwCopySize;
// Initialize variables
ASSERT(NULL != hDIB);
ASSERT(NULL != lpszDestProfile);
hDIBTransformed = NULL;
SetLastError(0);
hTransform = NULL;
bTranslated = FALSE;
hDestProfile = OpenColorProfileFromFile(lpszDestProfile );
hTargetProfile = OpenColorProfileFromFile(lpszTargetProfile);
if (NULL == hDestProfile)
{
DebugMsg(__TEXT("TransformDIBOutsideDC : NULL dest file\r\n"));
return(NULL);
}
// Get bits from original DIB
lpbSrcDIBHdr = GlobalLock(hDIB);
pSrcBits = (PVOID)FindDIBBits(lpbSrcDIBHdr);
// Get LPLOGCOLORSPACE for transform
lpLogColorSpace = GetColorSpaceFromBitmap(lpbSrcDIBHdr, dwIntent, &bDeleteProfile);
if (NULL != lpLogColorSpace)
{
//Create the transform to use
SetLastError(0);
hTransform = CreateColorTransform(lpLogColorSpace, hDestProfile, hTargetProfile, ENABLE_GAMUT_CHECKING | NORMAL_MODE | 0x80000000);
if (NULL != hTransform)
{
// Allocate for new DIB
hDIBTransformed = GlobalAlloc(GHND, GlobalSize(hDIB));
lpbDestDIBHdr = GlobalLock(hDIBTransformed);
switch (BITCOUNT(lpbSrcDIBHdr))
{
DWORD dwSrcOffBytes, dwDestOffBytes;
case 1: // BM_1GRAY:
case 4:
case 8:
ASSERT((((LPBITMAPV5HEADER)lpbSrcDIBHdr)->bV5ClrUsed) <= (DWORD)( 1 << ((LPBITMAPV5HEADER)lpbSrcDIBHdr)->bV5BitCount));
// Copy entire DIB. Color table will be replaced by TranslateColors
dwCopySize = GlobalSize(hDIB);
memset(lpbDestDIBHdr, 0x17, dwCopySize);
memcpy(lpbDestDIBHdr, lpbSrcDIBHdr, dwCopySize);
dwSrcOffBytes = *(LPDWORD)lpbSrcDIBHdr;
dwDestOffBytes = *(LPDWORD)lpbDestDIBHdr;
pSrcBits = (PBYTE)lpbSrcDIBHdr + dwSrcOffBytes;
pDestBits = (PBYTE)lpbDestDIBHdr + dwDestOffBytes;
// Needed to use different translation if BITMAPCORE bitmap.
if (dwSrcOffBytes >= sizeof(BITMAPINFOHEADER))
{
bTranslated = TranslateColorTable(hTransform,
(PCOLOR)pSrcBits, // paInputColors,
((LPBITMAPV5HEADER)lpbSrcDIBHdr)->bV5ClrUsed, // nColors,
COLOR_RGB, // ctInput,
(PCOLOR)pDestBits, // paOutputColors,
COLOR_RGB, // ctOutput)
lpbSrcDIBHdr->biBitCount);
}
else
{
bTranslated = TranslateBitmapBits(hTransform,
pSrcBits,
BM_RGBTRIPLETS,
NumColorsInDIB(lpbSrcDIBHdr),
1,
0,
pDestBits,
BM_RGBTRIPLETS,
0,
NULL,
0);
}
if (0 == bTranslated)
{
DebugMsg(__TEXT("TransformDIBOutsideDC : TranslateColors failed, :"));
DISPLAY_LASTERROR(LASTERROR_NOALLOC, GetLastError());
}
break;
case 16: // BM_RGBTRIPLETS:
case 24: // BM_xRGBQUADS:
case 32: // BM_x555RGB:
// Copy header from original DIB to new DIB
memcpy(lpbDestDIBHdr, lpbSrcDIBHdr, sizeof(BITMAPV5HEADER));
pDestBits = (PVOID)FindDIBBits(lpbDestDIBHdr);
bTranslated = TranslateBitmapBits(hTransform,
pSrcBits,
bmInput,
BITMAPWIDTH(lpbSrcDIBHdr),
abs(BITMAPHEIGHT(lpbSrcDIBHdr)),
0,
pDestBits,
bmInput,
0,
pBMCallback,
ulCallbackData);
if (0 == bTranslated)
{
DebugMsg(__TEXT("TransformDIBOutsideDC : TranslateBitmapBits failed:\r\n"));
DISPLAY_LASTERROR(LASTERROR_NOALLOC, GetLastError());
}
break;
default: // 8bpp
DebugMsg(__TEXT("TransformDIBOutsideDC : Unrecognized format\r\n"));
bTranslated = FALSE;
break;
}
bDeleted = DeleteColorTransform(hTransform);
if (0 == bDeleted)
{
DebugMsg(__TEXT("TransformDIBOutsideDC : DeleteColorTransform failed, : "));
DISPLAY_LASTERROR(LASTERROR_NOALLOC, GetLastError());
}
}
else
{
ErrMsg(NULL, __TEXT("TransformDIBOutsideDC : CreateColorTransform failed"));
DISPLAY_LASTERROR(LASTERROR_NOALLOC, GetLastError());
}
if (bDeleteProfile)
{
DeleteFile(lpLogColorSpace->lcsFilename);
}
GlobalFree((HANDLE)lpLogColorSpace);
}
else // Failed to get LOGCOLORSPACE
{
ErrMsg(NULL, __TEXT("TransformDIBOutsideDC : Failed to get LOGCOLORSPACE"));
}
if (NULL != hDestProfile)
{
bProfileClosed = CloseColorProfile(hDestProfile);
if (0 == bProfileClosed)
{
DebugMsg(__TEXT("TransformDIBOutsideDC : Failed to close hDestProfile, "));
DISPLAY_LASTERROR(LASTERROR_NOALLOC, GetLastError());
}
}
if (NULL != hTargetProfile)
{
bProfileClosed = CloseColorProfile(hTargetProfile);
if (0 == bProfileClosed)
{
DebugMsg(__TEXT("TransformDIBOutsideDC : Failed to close hTargetProfile, "));
DISPLAY_LASTERROR(LASTERROR_NOALLOC, GetLastError());
}
}
if (NULL != hDIBTransformed)
{
GlobalUnlock(hDIBTransformed);
}
if ((NULL == hTransform) || (0 == bTranslated))
{
if (NULL != hDIBTransformed)
{
GlobalFree(hDIBTransformed);
hDIBTransformed = NULL;
}
lpbDestDIBHdr = NULL;
pDestBits = NULL;
}
return(hDIBTransformed);
} // End of function TransformDIBOutsideDC
//////////////////////////////////////////////////////////////////////////
// Function: OpenColorProfileFromFile
//
// Description:
// Creates a color profile based upon the parameters passed.
//
// Parameters:
// LPTSTR Profile name
//
// Returns:
// HPROFILE Handle to PROFILE structure, NULL if failure.
//
// Comments:
//
//
//////////////////////////////////////////////////////////////////////////
HPROFILE OpenColorProfileFromFile(LPTSTR lpszProfileName)
{
// Local variables
PPROFILE pProfile;
HPROFILE hProfile;
DWORD cbDataSize;
DWORD dwProfileSize;
TCHAR stFullProfile[MAX_PATH];
BOOL bValid;
// Initialize variables
if (NULL == lpszProfileName)
{
return(NULL);
}
// Add COLOR dir path if profile name does not contain a path.
if ( (NULL == _tcschr(lpszProfileName, __TEXT(':')))
&&
(NULL == _tcschr(lpszProfileName, __TEXT('\\')))
)
{
wsprintf(stFullProfile, __TEXT("%s\\%s"), gstProfilesDir, lpszProfileName);
}
else
{
lstrcpy(stFullProfile, lpszProfileName);
}
dwProfileSize = sizeof(PROFILE);
cbDataSize = (lstrlen(stFullProfile) * sizeof(TCHAR)) + sizeof(TCHAR); // String plus NULL
pProfile = GlobalAlloc(GPTR, (dwProfileSize + cbDataSize));
#ifdef _DEBUG
memset(pProfile, UNINIT_BYTE, (cbDataSize+dwProfileSize));
#endif
pProfile->dwType = PROFILE_FILENAME;
pProfile->cbDataSize = cbDataSize;
pProfile->pProfileData = (PVOID)((LPBYTE)pProfile + dwProfileSize);
_tcscpy(pProfile->pProfileData, stFullProfile);
hProfile = OpenColorProfile(pProfile, PROFILE_READ, FILE_SHARE_READ, OPEN_EXISTING);
if (NULL == hProfile)
{
ErrMsg(NULL,__TEXT("Unable to open color profile <%s>"), stFullProfile);
DISPLAY_LASTERROR(LASTERROR_NOALLOC, GetLastError());
}
else
{
// Validate the profile
bValid = IsColorProfileValid(hProfile, &bValid);
if (0 == bValid)
{
ErrMsg(NULL,__TEXT("Color profile %s is not valid"), stFullProfile);
DISPLAY_LASTERROR(LASTERROR_NOALLOC, GetLastError());
CloseColorProfile(hProfile);
hProfile = NULL;
}
}
// Cleanup
GlobalFree(GlobalHandle(pProfile));
return(hProfile);
} // End of function OpenColorProfileFromDisk
///////////////////////////////////////////////////////////////////////
//
// Function: GetColorSpaceFromBitmap
//
// Purpose: Creates a LOGCOLORSPACE based on information in bitmap.
//
//
// Parms: lpBitmapHeader Pointer to bitmap header and info.
// dwIntent Color Space Intent.
// pbDeleteProfile Flag, on return, will indicate if the profile needs
// to be deleted before LOGCOLORSPACE is freed.
//
//
///////////////////////////////////////////////////////////////////////
LPLOGCOLORSPACE GetColorSpaceFromBitmap(LPBITMAPINFOHEADER lpBitmapInfo, DWORD dwIntent,
LPBOOL pbDeleteProfile)
{
LPLOGCOLORSPACE lpColorSpace = NULL;
PBITMAPV5HEADER lpBitmapV5 = (PBITMAPV5HEADER) lpBitmapInfo;
// Validate parameters.
ASSERT(NULL != lpBitmapInfo);
if ( (NULL == lpBitmapInfo)
||
(NULL == pbDeleteProfile)
||
( (sizeof(BITMAPCOREHEADER) != lpBitmapInfo->biSize)
&&
(sizeof(BITMAPINFOHEADER) != lpBitmapInfo->biSize)
&&
(sizeof(BITMAPV4HEADER) != lpBitmapInfo->biSize)
&&
(sizeof(BITMAPV5HEADER) != lpBitmapInfo->biSize)
)
)
{
return NULL;
}
// Initalize delete flag.
*pbDeleteProfile = FALSE;
// Allocate LOGCOLORSPACE.
lpColorSpace = (LPLOGCOLORSPACE) GlobalAlloc(GPTR, sizeof(LOGCOLORSPACE));
if (NULL == lpColorSpace)
{
return NULL;
}
// Initialize color space.
lpColorSpace->lcsSignature = 'PSOC'; // The signature should always be 'PSOC'.
lpColorSpace->lcsVersion = 0x400;
lpColorSpace->lcsSize = sizeof(LOGCOLORSPACE);
// If BITMAPCOREHEADER or BITMAPINFOHEADER, bitmap has no information
// about color space; use sRGB.
if (sizeof(BITMAPINFOHEADER) >= lpBitmapInfo->biSize)
{
// Set color space to default values.
lpColorSpace->lcsCSType = LCS_sRGB;
// Set endpoints to sRGB values.
lpColorSpace->lcsEndpoints.ciexyzRed.ciexyzX = __FXPT2DOT30(.64);
lpColorSpace->lcsEndpoints.ciexyzRed.ciexyzY = __FXPT2DOT30(.33);
lpColorSpace->lcsEndpoints.ciexyzRed.ciexyzZ = __FXPT2DOT30(.03);
lpColorSpace->lcsEndpoints.ciexyzGreen.ciexyzX = __FXPT2DOT30(.3);
lpColorSpace->lcsEndpoints.ciexyzGreen.ciexyzY = __FXPT2DOT30(.6);
lpColorSpace->lcsEndpoints.ciexyzGreen.ciexyzZ = __FXPT2DOT30(.1);
lpColorSpace->lcsEndpoints.ciexyzBlue.ciexyzX = __FXPT2DOT30( .15);
lpColorSpace->lcsEndpoints.ciexyzBlue.ciexyzY = __FXPT2DOT30(.06);
lpColorSpace->lcsEndpoints.ciexyzBlue.ciexyzZ = __FXPT2DOT30(.79);
// Just so that if monitor has 2.2 gamma, the over all gamma is 1.0.
lpColorSpace->lcsGammaRed = __FXPT16DOT16(0.45);
lpColorSpace->lcsGammaGreen = __FXPT16DOT16(0.45);
lpColorSpace->lcsGammaBlue = __FXPT16DOT16(0.45);
}
else
{
// Copy information from portion that is similar between BITMAPV4HEADERs and
// BITMAPV5HEADERs.
memcpy(&lpColorSpace->lcsEndpoints, &lpBitmapV5->bV5Endpoints, sizeof(CIEXYZTRIPLE));
lpColorSpace->lcsGammaRed = lpBitmapV5->bV5GammaRed;
lpColorSpace->lcsGammaGreen = lpBitmapV5->bV5GammaGreen;
lpColorSpace->lcsGammaBlue = lpBitmapV5->bV5GammaBlue;
// BITMAPV4HEADERs do not have complete color space information,
// we need to assume some things.
if (sizeof(BITMAPV4HEADER) == lpBitmapInfo->biSize)
{
// Fill in default values for fields that do not
// have equivalents in BITMAPV4HEADER.
lpColorSpace->lcsCSType = lpBitmapV5->bV5CSType;
lpColorSpace->lcsIntent = LCS_GM_IMAGES;
}
else
{
// BITMAPV5HEADERs have complete color space information.
// No assumptions to make.
lpColorSpace->lcsIntent = lpBitmapV5->bV5Intent;
// Look to see if no, linked, or embedded profile.
switch (lpBitmapV5->bV5CSType)
{
case 'MBED':
// Need to create profile file and reference
// profile in the color space.
lpColorSpace->lcsCSType = LCS_CALIBRATED_RGB;
// Make sure that profile data offset is valid and not zero length.
if ( (lpBitmapV5->bV5Size > lpBitmapV5->bV5ProfileData)
||
(0L == lpBitmapV5->bV5ProfileSize)
)
{
GlobalFree((HANDLE)lpColorSpace);
return NULL;
}
// Create unique temp name.
{
DWORD dwWritten;
TCHAR szTempPath[MAX_PATH];
HANDLE hFile;
GetTempPath(MAX_PATH, szTempPath);
if (!GetTempFileName(szTempPath, __TEXT("ICM"), 0, lpColorSpace->lcsFilename))
{
GlobalFree((HANDLE)lpColorSpace);
return NULL;
}
// Create temp profile that contains the embedded profile.
hFile = CreateFile(lpColorSpace->lcsFilename, GENERIC_READ | GENERIC_WRITE,
0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE == hFile)
{
GlobalFree((HANDLE)lpColorSpace);
return NULL;
}
// Write embedded profile to disk.
WriteFile(hFile, GETPROFILEDATA(lpBitmapV5), lpBitmapV5->bV5ProfileSize,
&dwWritten, NULL);
// No longer need file open.
CloseHandle(hFile);
// Need to indicate to caller that this file needs to be deleted
// before LOGCOLORSPACE is freed.
*pbDeleteProfile = TRUE;
}
break;
case 'LINK':
// Need to reference profile.
lpColorSpace->lcsCSType = LCS_CALIBRATED_RGB;
lstrcpyn(lpColorSpace->lcsFilename, (LPTSTR) GETPROFILEDATA(lpBitmapV5), MAX_PATH);
break;
default:
// Just use color space type in the bitmap.
lpColorSpace->lcsCSType = lpBitmapV5->bV5CSType;
break;
}
}
}
// Set intent to default or to users selection.
if (0xffffffffL == dwIntent)
{
lpColorSpace->lcsIntent = LCS_GM_IMAGES;
}
else
{
lpColorSpace->lcsIntent = dwIntent;
}
return(lpColorSpace);
}
//
// Functions for extracting information from DIBs
//
//////////////////////////////////////////////////////////////////////////
// Function: NumColorsInDIB
//
// Description:
// Determines the number of colors in the DIB by looking at the
// BitCount field in the info block.
//
// Parameters:
// LPBINTMAPV5HEADER Pointer to BITMAPINFO structure
//
// Returns:
// DWORD Number of colors in the DIB
//
// Comments:
//
//
//////////////////////////////////////////////////////////////////////////
DWORD NumColorsInDIB(LPBITMAPINFOHEADER lpbi)
{
WORD wBitCount;
DWORD dwColors = 0;
// If this is a Windows style DIB, the number of colors in the
// color table can be less than the number of bits per pixel
// allows for (i.e. lpbi->biClrUsed can be set to some value).
// If this is the case, return the appropriate value.
if ( (sizeof(BITMAPINFOHEADER) <= lpbi->biSize)
&&
(0 != lpbi->biClrUsed)
)
{
dwColors = lpbi->biClrUsed;
}
else
{
// Calculate the number of colors in the color table based on
// the number of bits per pixel for the DIB.
wBitCount = BITCOUNT(lpbi);
if (MAX_BPP_COLOR_TABLE >= wBitCount)
{
dwColors = 1 << wBitCount; // Colors = 2^BitCount
}
}
return dwColors;
} // End of function NumColorsInDIB
//////////////////////////////////////////////////////////////////////////
// Function: PaletteSize
//
// Description:
// Calculates the palette size in bytes.
//
// Parameters:
// @@@
//
// Returns:
// DWORD Palette size in bytes.
//
// Comments:
//
//
//////////////////////////////////////////////////////////////////////////
DWORD PaletteSize(LPBITMAPINFOHEADER lpbi)
{
DWORD dwSize = 0L;
if (sizeof(BITMAPINFOHEADER) <= lpbi->biSize)
{
dwSize = NumColorsInDIB(lpbi) * sizeof(RGBQUAD);
if ( (lpbi->biCompression == BI_BITFIELDS)
&&
(sizeof(BITMAPV4HEADER) > lpbi->biSize)
)
{
dwSize = 3 * sizeof(DWORD);
}
}
else
{
dwSize = NumColorsInDIB(lpbi) * sizeof (RGBTRIPLE);
}
return dwSize;
} // End of function PaletteSize
///////////////////////////////////////////////////////////////////////
//
// Function: FindDIBBits
//
// Purpose: Given a pointer to a DIB, returns a pointer to the
// DIB's bitmap bits.
//
// Parms: lpbi == pointer to DIB header (either BITMAPINFOHEADER
// or BITMAPCOREHEADER)
//
///////////////////////////////////////////////////////////////////////
LPBYTE FindDIBBits(LPBITMAPINFOHEADER lpbi)
{
ASSERT(NULL != lpbi);
return ((LPBYTE)lpbi + *(LPDWORD)lpbi + PaletteSize(lpbi) + PROFILESIZE(lpbi));
}
///////////////////////////////////////////////////////////////////////
//
// Function: FindDIBBits
//
// Purpose: Given a pointer to a DIB, returns a pointer to the
// DIB's bitmap bits.
//
// Parms: lpbi == pointer to DIB header (either BITMAPINFOHEADER
// or BITMAPCOREHEADER)
//
///////////////////////////////////////////////////////////////////////
LPBYTE FindColorTable(LPBITMAPINFOHEADER lpbi)
{
ASSERT(NULL != lpbi);
return ((LPBYTE)lpbi + *(LPDWORD)lpbi + PaletteSize(lpbi) + PROFILESIZE(lpbi));
}
///////////////////////////////////////////////////////////////////////
//
// Function: DIBHeight
//
// Purpose: Given a pointer to a DIB, returns the ABSOLUTE VALUE of
// its height. Note that it returns a DWORD (since a Win30
// DIB can have a DWORD in its height field), but under
// Win30, the high order word isn't used!
//
// Parms: lpDIB == pointer to DIB header (either BITMAPINFOHEADER
// or BITMAPCOREHEADER)
//
///////////////////////////////////////////////////////////////////////
LONG DIBHeight (LPBYTE lpDIB)
{
LPBITMAPINFOHEADER lpbmi;
LPBITMAPCOREHEADER lpbmc;
lpbmi = (LPBITMAPINFOHEADER) lpDIB;
lpbmc = (LPBITMAPCOREHEADER) lpDIB;
if (lpbmi->biSize >= sizeof (BITMAPINFOHEADER))
{
return labs(lpbmi->biHeight); // biHeight can now be negative! 8/9/93
}
else
{
return (LONG) lpbmc->bcHeight;
}
}
///////////////////////////////////////////////////////////////////////
//
// Function: DIBWidth
//
// Purpose: Given a pointer to a DIB, returns its width. Note
// that it returns a DWORD (since a Win30 DIB can have
// a DWORD in its width field), but under Win30, the
// high order word isn't used!
//
// Parms: lpDIB == pointer to DIB header (either BITMAPINFOHEADER
// or BITMAPCOREHEADER)
//
///////////////////////////////////////////////////////////////////////
LONG DIBWidth (LPBYTE lpDIB)
{
LPBITMAPINFOHEADER lpbmi;
LPBITMAPCOREHEADER lpbmc;
lpbmi = (LPBITMAPINFOHEADER) lpDIB;
lpbmc = (LPBITMAPCOREHEADER) lpDIB;
if (lpbmi->biSize >= sizeof (BITMAPINFOHEADER))
{
return lpbmi->biWidth;
}
else
{
return (LONG) lpbmc->bcWidth;
}
}
//
// Functions for reading DIBs
//
//////////////////////////////////////////////////////////////////////////
// Function: ReadDIBFile
//
// Description:
// Open a DIB file and create
// -a memory DIB
// -a memory handle containing BITMAPINFO, palette, and the bits
//
//
// Parameters:
// @@@
//
// Returns:
// HGLOBAL Handle to DIB memory; NULL upon failure.
//
// Comments:
//
//////////////////////////////////////////////////////////////////////////
HGLOBAL ReadDIBFile(LPTSTR lpszFileName)
{
// Local variables
HGLOBAL hDIBInfo;
LPDIBINFO lpDIBInfo;
BOOL bGotDIBInfo;
// Initialize variables
hDIBInfo = CreateDIBInfo();
if (hDIBInfo == NULL)
{
return(NULL);
}
lpDIBInfo = GlobalLock(hDIBInfo);
if (lpDIBInfo == (LPDIBINFO)NULL)
{
GlobalFree(hDIBInfo);
return(NULL);
}
bGotDIBInfo = fReadDIBInfo(lpszFileName, lpDIBInfo);
GlobalUnlock(hDIBInfo);
if (0 == bGotDIBInfo) // failed to open file
{
fFreeDIBInfo(hDIBInfo, TRUE);
hDIBInfo = NULL;
}
return(hDIBInfo);
} // End of function ReadDIBFile
//////////////////////////////////////////////////////////////////////////
// Function: ReadDIBFromFile
//
// Description:
// Reads in the bitmap information.
//
// Parameters:
// hFile Handle to bitmap file.
//
// Returns: Handle to DIB Bitmap. NULL on error.
//
// Comments:
//
//////////////////////////////////////////////////////////////////////////
HANDLE ReadDIBFromFile(HANDLE hFile)
{
UINT nNumColors;
DWORD offBits;
DWORD dwRead;
DWORD dwImageBytes;
DWORD dwSizeImage;
HANDLE hDIB;
BITMAPFILEHEADER BmpFileHeader;
LPBITMAPINFOHEADER lpbi;
// Make sure non-null file handle.
if (NULL == hFile)
{
return NULL;
}
// Read in Bitmap file header.
if (0L != SetFilePointer(hFile, 0, NULL, FILE_BEGIN))
{
return NULL;
}
ReadFile(hFile, &BmpFileHeader, sizeof(BITMAPFILEHEADER), &dwRead, NULL);
if (sizeof(BITMAPFILEHEADER) != dwRead)
{
return NULL;
}
// Make sure that the file is a bitmap file.
if (BFT_BITMAP != BmpFileHeader.bfType)
{
return NULL;
}
// Detemine size of bitmap header.
ReadFile(hFile, &dwImageBytes, sizeof(DWORD), &dwRead, NULL);
if (sizeof(DWORD) != dwRead)
{
return NULL;
}
// Allocate memory for header & color table.
// We'll enlarge this memory as needed.
hDIB = GlobalAlloc(GHND, dwImageBytes + (256L * sizeof(RGBQUAD)));
if (!hDIB)
{
return NULL;
}
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
if (!lpbi)
{
GlobalFree(hDIB);
return NULL;
}
// Back up to begining of bitmap header and read bitmap header.
SetFilePointer(hFile, sizeof(BITMAPFILEHEADER), NULL, FILE_BEGIN);
ReadFile(hFile, lpbi, dwImageBytes, &dwRead, NULL);
if (dwRead != dwImageBytes)
{
GlobalUnlock(hDIB);
GlobalFree(hDIB);
return NULL;
}
// Dump debug info about type of bitmap opened.
#ifdef MAXDEBUG
DumpBmpHeader((LPVOID)lpbi);
#endif
// Check to see that it's a Windows DIB or an OS/2 DIB.
// It assumed that anything that is not a OS/2 DIB is a Windows DIB.
// This at least allows the opening of newer bitmap types, although GDI
// may not handle them so we may not be able to display them.
// More critical checking could be done by checking against
// BITMAPV4HEADER and BITMAPV5HEADER sizes.
if (lpbi->biSize >= sizeof(BITMAPINFOHEADER))
{
DWORD dwProfileData = 0;
DWORD dwColorTableSize;
HANDLE hTemp;
// Now determine the size of the color table and read it. Since the
// bitmap bits are offset in the file by bfOffBits, we need to do some
// special processing here to make sure the bits directly follow
// the color table (because that's the format we are susposed to pass
// back)
// no color table for 24-bit, default size otherwise
nNumColors = (UINT)lpbi->biClrUsed;
if (0 == nNumColors)
{
if (lpbi->biBitCount <= MAX_BPP_COLOR_TABLE)
{
nNumColors = 1 << lpbi->biBitCount; // standard size table
}
}
// Fill in some default values if they are zero
if (0 == lpbi->biClrUsed)
{
lpbi->biClrUsed = nNumColors;
}
if (0 == lpbi->biSizeImage)
{
// Calculate size using DWORD alignment
dwSizeImage = (((lpbi->biWidth * lpbi->biBitCount + 31) & ~31)
>> 3) * abs(lpbi->biHeight);
}
else
{
dwSizeImage = lpbi->biSizeImage;
}
// get a proper-sized buffer for header, color table and bits
// Figure out the size of the bitmap AND it's color table.
dwColorTableSize = PaletteSize(lpbi);
// Calculate profile data size;
// zero if not BITMAPV5HEADER, else in use bV5ProfileSize.
dwProfileData = PROFILESIZE(lpbi);
// Resize DIB buffer.
dwImageBytes = lpbi->biSize + dwSizeImage + dwColorTableSize + dwProfileData;
GlobalUnlock(hDIB);
hTemp = GlobalReAlloc(hDIB, dwImageBytes, GHND);
DebugMsg(__TEXT("ReadDIBFromFile: Allocating %lu bytes for header, color table, and image\r\n"), dwImageBytes);
if (NULL == hTemp) // can't resize buffer for loading
{
GlobalFree(hDIB);
return NULL;
}
hDIB = hTemp;
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
// read the color table, if any, into buffer starting past Bitmap header.
if (0 != dwColorTableSize)
{
ReadFile(hFile, (LPBYTE)lpbi + lpbi->biSize, dwColorTableSize, &dwRead, NULL);
if (dwColorTableSize != dwRead)
{
GlobalUnlock(hDIB);
GlobalFree(hDIB);
return NULL;
}
}
// Load profile data, if any.
if (0 != dwProfileData)
{
// Move to profile data.
SetFilePointer(hFile, sizeof(BITMAPFILEHEADER)
+ ((LPBITMAPV5HEADER)lpbi)->bV5ProfileData, NULL, FILE_BEGIN);
// Read the profile data in after the header and color table.
ReadFile(hFile, (LPBYTE)lpbi + lpbi->biSize + dwColorTableSize, dwProfileData, &dwRead, NULL);
if (dwProfileData != dwRead)
{
GlobalUnlock(hDIB);
GlobalFree(hDIB);
return NULL;
}
// Need to change the offset in the header.
((LPBITMAPV5HEADER)lpbi)->bV5ProfileData = lpbi->biSize + dwColorTableSize;
}
// offset to the bits from start of DIB header
offBits = lpbi->biSize + dwColorTableSize + dwProfileData;
DumpBmpHeader((LPVOID)lpbi);
}
else
{
// It's an OS/2 DIB, the color table is an array of RGBTRIPLEs.
HANDLE hTemp;
LPBITMAPCOREHEADER lpbc = (LPBITMAPCOREHEADER) lpbi;
// Gotta back up to beginning of color table.
SetFilePointer(hFile, sizeof (BITMAPFILEHEADER) + sizeof (BITMAPCOREHEADER), NULL, FILE_BEGIN);
// Now determine the size of the color table and read it. Since the
// bitmap bits are offset in the file by bfOffBits, we need to do some
// special processing here to make sure the bits directly follow
// the color table (because that's the format we are susposed to pass
// back)
if (lpbc->bcBitCount <= MAX_BPP_COLOR_TABLE)
{
nNumColors = 1 << lpbc->bcBitCount; // standard size table
}
else
{
nNumColors = 0;
}
// Determine the size of the image
dwSizeImage = (((lpbc->bcWidth * lpbc->bcBitCount + 31) & ~31) >> 3)
* lpbc->bcHeight;
// get a proper-sized buffer for header, color table and bits
GlobalUnlock(hDIB);
hTemp = GlobalReAlloc(hDIB, lpbc->bcSize + (nNumColors * sizeof(RGBTRIPLE))
+ dwSizeImage, GHND);
if (!hTemp) // can't resize buffer for loading
{
GlobalFree(hDIB);
return NULL;
}
hDIB = hTemp;
lpbc = (LPBITMAPCOREHEADER) GlobalLock(hDIB);
lpbi = (LPBITMAPINFOHEADER) lpbc;
// read the color table
ReadFile(hFile, (LPBYTE)lpbc + lpbc->bcSize, nNumColors * sizeof(RGBTRIPLE), &dwRead, NULL);
if (nNumColors * sizeof(RGBTRIPLE) != dwRead)
{
GlobalUnlock(hDIB);
GlobalFree(hDIB);
return NULL;
}
// offset to the bits from start of DIB header
offBits = lpbc->bcSize + nNumColors * sizeof(RGBTRIPLE);
}
// If the bfOffBits field is non-zero, then the bits might *not* be
// directly following the color table in the file. Use the value in
// bfOffBits to seek the bits.
if (BmpFileHeader.bfOffBits != 0L)
{
SetFilePointer(hFile, BmpFileHeader.bfOffBits, NULL, FILE_BEGIN);
}
// Read the actual bits
ReadFile(hFile, (LPBYTE)lpbi + offBits, dwSizeImage, &dwRead, NULL);
if (dwRead != dwSizeImage)
{
GlobalUnlock(hDIB);
GlobalFree(hDIB);
return NULL;
}
GlobalUnlock(hDIB);
return hDIB;
} // End of function ReadDIBFromFile
//////////////////////////////////////////////////////////////////////////
// Function: TranslateColorTable
//
// Description:
//
//
// Parameters:
// @@@
//
// Returns:
// BOOL
//
// Comments:
//
//
//////////////////////////////////////////////////////////////////////////
BOOL TranslateColorTable(HTRANSFORM hColorTransform,
PCOLOR paInputColors,
DWORD nColors,
COLORTYPE ctInput,
PCOLOR paOutputColors,
COLORTYPE ctOutput,
int biBitCount
)
{
// Initialize variables
if (ctInput == COLOR_RGB)
{
return(TranslateBitmapBits(hColorTransform,
(PVOID)paInputColors,
BM_xRGBQUADS,
1<<biBitCount,
1,
0,
(PVOID)paOutputColors,
BM_xRGBQUADS,
0,
NULL,
0));
}
else
{
return(TranslateColors(hColorTransform, paInputColors, nColors, ctInput, paOutputColors, ctOutput));
}
} // End of function TranslateColorTable
//////////////////////////////////////////////////////////////////////////
// Function: SaveDIBToFile
//
// Description:
//
//
// Parameters:
// @@@
//
// Returns:
// BOOL
//
// Comments:
//
//
//////////////////////////////////////////////////////////////////////////
BOOL SaveDIBToFile(HWND hWnd, LPCTSTR lpszFileName, LPDIBINFO lpDIBInfo, DWORD dwType)
{
BOOL bResult = FALSE;
HANDLE hFile;
HANDLE hDIBTransformed = NULL;
PBITMAPINFOHEADER pBitmapInfo;
// Validate Parameters.
if ( (NULL == lpszFileName)
||
(NULL == lpDIBInfo)
||
(NULL == lpDIBInfo->hDIB)
||
( (LCS_sRGB != dwType)
&&
(LCS_CALIBRATED_RGB != dwType)
&&
(PROFILE_LINKED != dwType)
&&
(PROFILE_EMBEDDED != dwType)
)
)
{
return FALSE;
}
pBitmapInfo = (PBITMAPINFOHEADER) GlobalLock(lpDIBInfo->hDIB);
// Open file handle.
hFile = CreateFile(lpszFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE != hFile)
{
DWORD dwBytes;
DWORD dwProfileSize;
PBYTE pProfileData;
LPSTR lpszProfileName;
BITMAPV5HEADER BitmapHeader;
BITMAPFILEHEADER FileHeader;
// Initialize variables.
dwProfileSize = PROFILESIZE(pBitmapInfo);
pProfileData = GETPROFILEDATA(pBitmapInfo);
lpszProfileName = NULL;
memset(&BitmapHeader, 0, sizeof(BITMAPV5HEADER));
memset(&FileHeader, 0, sizeof(BITMAPFILEHEADER));
// Convert to proper type.
if (dwType != BITMAPCSTYPE(pBitmapInfo))
{
if (PROFILE_LINKED == dwType)
{
ASSERT(PROFILE_EMBEDDED == BITMAPCSTYPE(pBitmapInfo));
// Going from Embedded profile to linked.
// Save embedded profile data to file.
// Create file name from manufacture and model name of profile header.
lpszProfileName = (LPSTR) GlobalAlloc(GPTR, 1024);
// Get save name and save profile data.
if (GetProfileSaveName(hWnd, &lpszProfileName, 1024))
{
HANDLE hProfile;
hProfile = CreateFileA(lpszProfileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE != hProfile)
{
WriteFile(hProfile, pProfileData, dwProfileSize, &dwBytes, NULL);
CloseHandle(hProfile);
}
// Change profile variables to point to linked name.
pProfileData = (PBYTE) lpszProfileName;
dwProfileSize = strlen(lpszProfileName);
}
}
else if (PROFILE_EMBEDDED == dwType)
{
DWORD dwSize = 0;
PROFILE Profile;
HPROFILE hProfile;
ASSERT(PROFILE_EMBEDDED == BITMAPCSTYPE(pBitmapInfo));
// Going from linked profile to Embedded.
// Embed Linked profile data.
// Open profile.
Profile.dwType = PROFILE_FILENAME;
Profile.pProfileData = pProfileData;
Profile.cbDataSize = dwProfileSize;
hProfile = OpenColorProfile(&Profile, PROFILE_READ, FILE_SHARE_READ, OPEN_EXISTING);
// Get profile data form handle.
if (NULL != hProfile)
{
GetColorProfileFromHandle(hProfile, NULL, &dwSize);
lpszProfileName = (LPSTR) GlobalAlloc(GPTR, dwSize);
GetColorProfileFromHandle(hProfile, (PBYTE) lpszProfileName, &dwSize);
CloseColorProfile(hProfile);
}
// Change profile variables to point at data to embed.
pProfileData = (PBYTE) lpszProfileName;
dwProfileSize = dwSize;
}
else if (LCS_sRGB == dwType)
{
DWORD dwSize;
LPTSTR pszSRGB;
// Need to translate from current type to sRGB.
// Open sRGB profile.
GetStandardColorSpaceProfile(NULL, LCS_sRGB, NULL, &dwSize);
pszSRGB = (LPTSTR) GlobalAlloc(GPTR, dwSize);
GetStandardColorSpaceProfile(NULL, LCS_sRGB, pszSRGB, &dwSize);
if (NULL != pszSRGB)
{
// Translate DIB.
hDIBTransformed = TransformDIBOutsideDC(lpDIBInfo->hDIB,
lpDIBInfo->bmFormat,
pszSRGB,
NULL,
USE_BITMAP_INTENT,
NULL,
0);
// Clean up.
GlobalFree((HANDLE)pszSRGB);
// Change bitmap info variable to point at tranlated DIB.
pBitmapInfo = (PBITMAPINFOHEADER) GlobalLock(hDIBTransformed);
}
}
}
if (NULL != pBitmapInfo)
{
// Create file header and write it to the file.
FileHeader.bfType = BFT_BITMAP;
FileHeader.bfSize = sizeof(BITMAPFILEHEADER);
FileHeader.bfSize += sizeof(BITMAPV5HEADER);
FileHeader.bfSize += NumColorsInDIB(pBitmapInfo) * sizeof(RGBQUAD);
FileHeader.bfSize += BITMAPSIZE(pBitmapInfo);
FileHeader.bfSize += dwProfileSize;
FileHeader.bfOffBits = sizeof(BITMAPFILEHEADER);
FileHeader.bfOffBits += sizeof(BITMAPV5HEADER);
FileHeader.bfOffBits += NumColorsInDIB(pBitmapInfo) * sizeof(RGBQUAD);
WriteFile(hFile, &FileHeader, sizeof(BITMAPFILEHEADER), &dwBytes, NULL);
// Create bitmap header and write it to file.
BitmapHeader.bV5Size = sizeof(BITMAPV5HEADER);
BitmapHeader.bV5Width = BITMAPWIDTH(pBitmapInfo);
BitmapHeader.bV5Height = BITMAPHEIGHT(pBitmapInfo);
BitmapHeader.bV5Planes = 1;
BitmapHeader.bV5BitCount = (WORD) BITCOUNT(pBitmapInfo);
BitmapHeader.bV5Compression = BITMAPCOMPRESSION(pBitmapInfo);
BitmapHeader.bV5SizeImage = BITMAPIMAGESIZE(pBitmapInfo);
BitmapHeader.bV5ClrUsed = BITMAPCLRUSED(pBitmapInfo);
BitmapHeader.bV5ClrImportant = BITMAPCLRIMPORTANT(pBitmapInfo);
BitmapHeader.bV5RedMask = BITMAPREDMASK(pBitmapInfo);
BitmapHeader.bV5GreenMask = BITMAPGREENMASK(pBitmapInfo);
BitmapHeader.bV5BlueMask = BITMAPBLUEMASK(pBitmapInfo);
BitmapHeader.bV5CSType = dwType;
if (sizeof(BITMAPV4HEADER) <= *(LPDWORD)pBitmapInfo)
{
memcpy(&BitmapHeader.bV5Endpoints, &((PBITMAPV4HEADER)pBitmapInfo)->bV4Endpoints,
sizeof(CIEXYZTRIPLE) + sizeof(DWORD) * 3);
}
BitmapHeader.bV5Intent = BITMAPINTENT(pBitmapInfo);
BitmapHeader.bV5ProfileData = sizeof(BITMAPV5HEADER);
BitmapHeader.bV5ProfileData += NumColorsInDIB(pBitmapInfo) * sizeof(RGBQUAD);
BitmapHeader.bV5ProfileData += BITMAPSIZE(pBitmapInfo);
BitmapHeader.bV5ProfileSize = dwProfileSize;
WriteFile(hFile, &BitmapHeader, sizeof(BITMAPV5HEADER), &dwBytes, NULL);
// Write color table.
if (!IS_BITMAPCOREHEADER(pBitmapInfo))
{
PBYTE pColorTable;
DWORD dwColorTableSize;
dwColorTableSize = NumColorsInDIB(pBitmapInfo) * sizeof(RGBQUAD);
pColorTable = (PBYTE)pBitmapInfo + *(LPDWORD)pBitmapInfo;
if ( IS_BITMAPINFOHEADER(pBitmapInfo)
&&
(BI_BITFIELDS == BITMAPCOMPRESSION(pBitmapInfo))
)
{
dwColorTableSize += sizeof(DWORD) * 3;
}
WriteFile(hFile, pColorTable, dwColorTableSize, &dwBytes, NULL);
}
else
{
PBYTE pColorTable;
DWORD dwCount;
RGBQUAD ColorTable[256];
pColorTable = (PBYTE)pBitmapInfo + *(LPDWORD)pBitmapInfo;
memset(ColorTable, 0, sizeof(ColorTable));
for (dwCount = 0; dwCount < NumColorsInDIB(pBitmapInfo); dwCount++)
memcpy(ColorTable + dwCount, pColorTable + dwCount, sizeof(RGBTRIPLE));
WriteFile(hFile, ColorTable, NumColorsInDIB(pBitmapInfo) * sizeof(RGBQUAD), &dwBytes, NULL);
}
// Save bitmap data.
WriteFile(hFile, FindDIBBits(pBitmapInfo), BITMAPSIZE(pBitmapInfo), &dwBytes, NULL);
// Save profile data.
if (0 != dwProfileSize)
{
WriteFile(hFile, pProfileData, dwProfileSize, &dwBytes, NULL);
}
bResult = TRUE;
}
// Clean up.
CloseHandle(hFile);
if (NULL != lpszProfileName)
GlobalFree((HANDLE)lpszProfileName);
if (NULL != hDIBTransformed)
{
GlobalUnlock(hDIBTransformed);
GlobalFree(hDIBTransformed);
}
// If failed, delete file.
if (!bResult)
DeleteFile(lpszFileName);
}
//Clean up.
GlobalUnlock(lpDIBInfo->hDIB);
return bResult;
}