/******************************Module*Header*******************************\ * Module Name: icm.c * * Created: 4-Jun-1996 * Author: Mark Enstrom [marke] * * Copyright (c) 1996-1999 Microsoft Corporation \**************************************************************************/ #include "precomp.h" #pragma hdrstop #include "winuserk.h" #if DBG_ICM ULONG DbgIcm = 0x0; #endif // // Instance of MSCMS.DLL // HINSTANCE ghICM; // // Color Profile Directory // WCHAR ColorDirectory[MAX_PATH]; DWORD ColorDirectorySize; // // Primary display DC color profile filename. // WCHAR PrimaryDisplayProfile[MAX_PATH]; // // List of ICMINFO // LIST_ENTRY ListIcmInfo; // // Semaphore to protect ICMINFO list // RTL_CRITICAL_SECTION semListIcmInfo; // // Per process color space and color transform cache list // LIST_ENTRY ListCachedColorSpace; LIST_ENTRY ListCachedColorTransform; ULONG cCachedColorSpace = 0; ULONG cCachedColorTransform = 0; // // Semaphore to protect Cache list // RTL_CRITICAL_SECTION semColorTransformCache; RTL_CRITICAL_SECTION semColorSpaceCache; BOOL gbICMEnabledOnceBefore = FALSE; // // ANSI version function in MSCMS.DLL will not called. // // FPOPENCOLORPROFILEA fpOpenColorProfileA; // FPCREATECOLORTRANSFORMA fpCreateColorTransformA; // FPREGISTERCMMA fpRegisterCMMA; // FPUNREGISTERCMMA fpUnregisterCMMA; // FPINSTALLCOLORPROFILEA fpInstallColorProfileA; // FPUNINSTALLCOLORPROFILEA fpUninstallColorProfileA; // FPGETSTANDARDCOLORSPACEPROFILEA fpGetStandardColorSpaceProfileA; // FPENUMCOLORPROFILESA fpEnumColorProfilesA; // FPGETCOLORDIRECTORYA fpGetColorDirectoryA; // // And Following function does not used from gdi32.dll // // FPISCOLORPROFILEVALID fpIsColorProfileValid; // FPCREATEDEVICELINKPROFILE fpCreateDeviceLinkProfile; // FPTRANSLATECOLORS fpTranslateColors; // FPCHECKCOLORS fpCheckColors; // FPGETCMMINFO fpGetCMMInfo; // FPSELECTCMM fpSelectCMM; // FPOPENCOLORPROFILEW fpOpenColorProfileW; FPCLOSECOLORPROFILE fpCloseColorProfile; FPCREATECOLORTRANSFORMW fpCreateColorTransformW; FPDELETECOLORTRANSFORM fpDeleteColorTransform; FPTRANSLATEBITMAPBITS fpTranslateBitmapBits; FPTRANSLATECOLORS fpTranslateColors; FPCHECKBITMAPBITS fpCheckBitmapBits; FPREGISTERCMMW fpRegisterCMMW; FPUNREGISTERCMMW fpUnregisterCMMW; FPINSTALLCOLORPROFILEW fpInstallColorProfileW; FPUNINSTALLCOLORPROFILEW fpUninstallColorProfileW; FPENUMCOLORPROFILESW fpEnumColorProfilesW; FPGETSTANDARDCOLORSPACEPROFILEW fpGetStandardColorSpaceProfileW; FPGETCOLORPROFILEHEADER fpGetColorProfileHeader; FPGETCOLORDIRECTORYW fpGetColorDirectoryW; FPCREATEPROFILEFROMLOGCOLORSPACEW fpCreateProfileFromLogColorSpaceW; FPCREATEMULTIPROFILETRANSFORM fpCreateMultiProfileTransform; FPINTERNALGETDEVICECONFIG fpInternalGetDeviceConfig; // // MS COLOR MATCH DLL name // #define MSCMS_DLL_NAME L"mscms.dll" // // Misc. macros // #define ALIGN_DWORD(nBytes) (((nBytes) + 3) & ~3) // // sRGB color profile name // #define sRGB_PROFILENAME L"sRGB Color Space Profile.icm" // // DWORD 0x12345678 ---> 0x78563412 // #define IcmSwapBytes(x) ((((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | \ (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24)) // // Macro to check color DC or not. // // LATER: We can improve performance by caching this in client, since // GetDeviceCaps() goes to kernel in most cases. // #define IsColorDeviceContext(hdcThis) \ (2 < (unsigned) GetDeviceCaps((hdcThis), NUMCOLORS)) // // Macro to check the color space is GDI object dependent. // #define IsColorSpaceOwnedByGDIObject(pColorSpace,hGDIObj) \ ((pColorSpace) ? \ (((pColorSpace)->hObj == (hGDIObj)) ? TRUE : FALSE) \ : FALSE) // // Macro to get current color tranform in DC. // #define GetColorTransformInDC(pdcattr) ((pdcattr)->hcmXform) // // if the color space has DEVICE_CALIBRATE_COLORSPACE flag, returns TRUE, otherwise FALSE. // #define bDeviceCalibrate(pColorSpace) \ ((pColorSpace) ? \ (((pColorSpace)->flInfo & DEVICE_CALIBRATE_COLORSPACE) ? TRUE : FALSE) \ : FALSE) // // Increment reference count of colorpsace/colortransform. // #define IcmReferenceColorSpace(pColorSpace) \ if ((pColorSpace)) \ { \ ENTERCRITICALSECTION(&semColorSpaceCache); \ (pColorSpace)->cRef++; \ LEAVECRITICALSECTION(&semColorSpaceCache); \ } #define IcmReferenceColorTransform(pCXfrom) \ if ((pCXform)) \ { \ ENTERCRITICALSECTION(&semColorTransformCache); \ (pCXform)->cRef++; \ LEAVECRITICALSECTION(&semColorTransformCache); \ } // // Invalid color space handle // #define INVALID_COLORSPACE ((HCOLORSPACE)-1) // // Maximum number of cached color transform in list. // #define MAX_COLORTRANSFORM_CACHE 10 // // Maximum size of "on memory profile" which be able to cache. // #define MAX_SIZE_OF_COLORPROFILE_TO_CACHE (1024*3) /******************************Public*Routine******************************\ * GDI initialization routine called from dll init * * Arguments: * * None * * Return Value: * * Status * * History: * * 3-Jul-1996 -by- Mark Enstrom [marke] * \**************************************************************************/ BOOL IcmInitialize() { BOOL bStatus = TRUE; ICMAPI(("gdi32: IcmInitialize\n")); ENTERCRITICALSECTION(&semLocal); // // load MCSCM.DLL and get function addresses // if (ghICM == NULL) { HANDLE hmscms = LoadLibraryW(MSCMS_DLL_NAME); if (hmscms != NULL) { fpOpenColorProfileW = (FPOPENCOLORPROFILEW)GetProcAddress(hmscms,"OpenColorProfileW"); fpCloseColorProfile = (FPCLOSECOLORPROFILE)GetProcAddress(hmscms,"CloseColorProfile"); fpCreateColorTransformW = (FPCREATECOLORTRANSFORMW)GetProcAddress(hmscms,"CreateColorTransformW"); fpDeleteColorTransform = (FPDELETECOLORTRANSFORM)GetProcAddress(hmscms,"DeleteColorTransform"); fpTranslateBitmapBits = (FPTRANSLATEBITMAPBITS)GetProcAddress(hmscms,"TranslateBitmapBits"); fpTranslateColors = (FPTRANSLATECOLORS)GetProcAddress(hmscms,"TranslateColors"); fpCheckBitmapBits = (FPCHECKBITMAPBITS)GetProcAddress(hmscms,"CheckBitmapBits"); fpRegisterCMMW = (FPREGISTERCMMW)GetProcAddress(hmscms,"RegisterCMMW"); fpUnregisterCMMW = (FPUNREGISTERCMMW)GetProcAddress(hmscms,"UnregisterCMMW"); fpInstallColorProfileW = (FPINSTALLCOLORPROFILEW)GetProcAddress(hmscms,"InstallColorProfileW"); fpUninstallColorProfileW = (FPUNINSTALLCOLORPROFILEW)GetProcAddress(hmscms,"UninstallColorProfileW"); fpEnumColorProfilesW = (FPENUMCOLORPROFILESW)GetProcAddress(hmscms,"EnumColorProfilesW"); fpGetStandardColorSpaceProfileW = (FPGETSTANDARDCOLORSPACEPROFILEW)GetProcAddress(hmscms,"GetStandardColorSpaceProfileW"); fpGetColorProfileHeader = (FPGETCOLORPROFILEHEADER)GetProcAddress(hmscms,"GetColorProfileHeader"); fpGetColorDirectoryW = (FPGETCOLORDIRECTORYW)GetProcAddress(hmscms,"GetColorDirectoryW"); fpCreateProfileFromLogColorSpaceW = (FPCREATEPROFILEFROMLOGCOLORSPACEW)GetProcAddress(hmscms,"CreateProfileFromLogColorSpaceW"); fpCreateMultiProfileTransform = (FPCREATEMULTIPROFILETRANSFORM)GetProcAddress(hmscms,"CreateMultiProfileTransform"); fpInternalGetDeviceConfig = (FPINTERNALGETDEVICECONFIG)GetProcAddress(hmscms,"InternalGetDeviceConfig"); if ((fpOpenColorProfileW == NULL) || (fpCloseColorProfile == NULL) || (fpCreateColorTransformW == NULL) || (fpDeleteColorTransform == NULL) || (fpTranslateBitmapBits == NULL) || (fpTranslateColors == NULL) || (fpCheckBitmapBits == NULL) || (fpRegisterCMMW == NULL) || (fpUnregisterCMMW == NULL) || (fpInstallColorProfileW == NULL) || (fpUninstallColorProfileW == NULL) || (fpEnumColorProfilesW == NULL) || (fpGetStandardColorSpaceProfileW == NULL) || (fpGetColorProfileHeader == NULL) || (fpGetColorDirectoryW == NULL) || (fpCreateProfileFromLogColorSpaceW == NULL) || (fpCreateMultiProfileTransform == NULL) || (fpInternalGetDeviceConfig == NULL) ) { WARNING("LoadLibrary of mscms.dll failed to associate all proc addresses\n"); FreeLibrary(hmscms); hmscms = NULL; } else { // // Initialize Color Directory // ColorDirectorySize = sizeof(ColorDirectory) / sizeof(WCHAR); bStatus = (*fpGetColorDirectoryW)(NULL,ColorDirectory,&ColorDirectorySize); if (bStatus) { ColorDirectorySize = wcslen(ColorDirectory); } if (bStatus && ColorDirectorySize) { ICMMSG(("IcmInitialize():ColorDirectory = %ws\n",ColorDirectory)); // // Counts null-terminated char. // ColorDirectorySize += 1; // // Initialize Primary display color profile. // PrimaryDisplayProfile[0] = UNICODE_NULL; } else { WARNING("LoadLibrary of mscms.dll failed to obtain color directory\n"); FreeLibrary(hmscms); hmscms = NULL; } } // // Keep the handle to global veriable. // ghICM = hmscms; } } LEAVECRITICALSECTION(&semLocal); if (ghICM == NULL) { GdiSetLastError(ERROR_NOT_ENOUGH_MEMORY); bStatus = FALSE; } return(bStatus); } /******************************Public*Routine******************************\ * * SetIcmMode - turn ICM on or off in a DC * * Arguments: * * hdc - device context * mode - ICM_ON,ICM_OFF,ICM_QUERY * * Return Value: * * status * * History: * * Rewrite it: * 20-Jan-1997 -by- Hideyuki Nagase [hideyukn] * Write it: * 4-Jun-1996 -by- Mark Enstrom [marke] * \**************************************************************************/ int META WINAPI SetICMMode( HDC hdc, int mode ) { int iRet = (int)FALSE; PDC_ATTR pdcattr; ICMAPI(("gdi32: SetICMMode\n")); FIXUP_HANDLE(hdc); PSHARED_GET_VALIDATE(pdcattr,hdc,DC_TYPE); // // metafile (only for ICM_ON and ICM_OFF) // if (IS_ALTDC_TYPE(hdc)) { PLDC pldc; // // No ICM with Windows MetaFile. // if (IS_METADC16_TYPE(hdc)) return(iRet); DC_PLDC(hdc,pldc,iRet) #if DBG_ICM ICMMSG(("SetICMMode():%s ICM for %s\n", \ ((mode == ICM_ON) ? "Enable" : \ ((mode == ICM_OFF) ? "Disable" : "Query")), \ ((pldc->iType == LO_METADC) ? "Enhanced Metafile" : \ (!IsColorDeviceContext(hdc) ? "Monochrome Printer" : "Color Printer")) \ )); #endif // // If this is Enhanced Metafile, OR non-color printer device, don't enable ICM "really". // if (pldc->iType == LO_METADC || (!IsColorDeviceContext(hdc))) { switch (mode) { case ICM_ON: case ICM_OFF: case ICM_DONE_OUTSIDEDC: // // Record ICM ON/OFF only to metafile. // if (pldc->iType == LO_METADC) { if (!MF_SetD(hdc,(DWORD)mode,EMR_SETICMMODE)) { return((int)FALSE); } } // // We don't "really" turn-on ICM for metafile, metafile // should be device-independent, thus, non-ICMed color/images // will be metafiled. But still need to keep its status for ICM_QUERY. // And "real" image correction happen at play-back time. // if(pdcattr) { if (mode == ICM_ON) { pdcattr->lIcmMode |= DC_ICM_METAFILING_ON; } else if (mode == ICM_DONE_OUTSIDEDC) { pdcattr->lIcmMode |= (DC_ICM_METAFILING_ON | CTX_ICM_METAFILING_OUTSIDEDC); } else // if ((mode == ICM_OFF) { pdcattr->lIcmMode &= ~(DC_ICM_METAFILING_ON | CTX_ICM_METAFILING_OUTSIDEDC); } iRet = (int)TRUE; } break; case ICM_QUERY: if (pdcattr) { if (IS_ICM_METAFILING_ON(pdcattr->lIcmMode)) { iRet = ((pdcattr->lIcmMode & CTX_ICM_METAFILING_OUTSIDEDC) ? \ ICM_DONE_OUTSIDEDC : ICM_ON); } else { iRet = ICM_OFF; } } break; default: iRet = (int)FALSE; break; } return (iRet); } } if (pdcattr) { ULONG iPrevMode; // // Before change ICM mode, we need to flush batched gdi functions. // CHECK_AND_FLUSH(hdc,pdcattr); // // Get current mode. // iPrevMode = pdcattr->lIcmMode; // // validate input parameter // switch (ICM_MODE(mode)) { case ICM_QUERY: // // return current mode // if (IS_ICM_INSIDEDC(iPrevMode)) { iRet = ICM_ON; } else if (IS_ICM_OUTSIDEDC(iPrevMode)) { iRet = ICM_DONE_OUTSIDEDC; } else { iRet = ICM_OFF; } break; case ICM_ON: if (!IS_ICM_INSIDEDC(iPrevMode)) { // // As default, ICM will be done on HOST. // ULONG lReqMode = REQ_ICM_HOST; PGDI_ICMINFO pIcmInfo = INIT_ICMINFO(hdc,pdcattr); // // Initialize ICMINFO // if (pIcmInfo == NULL) { WARNING("gdi32: SetICMMode: Can't init icm info\n"); return((int)FALSE); } // // Load external ICM dlls. // LOAD_ICMDLL((int)FALSE); // // ICM is not enabled,yet. Let's enable ICM. // ASSERTGDI(GetColorTransformInDC(pdcattr) == NULL,"SetIcmMode: hcmXform is not NULL\n"); if (IS_DEVICE_ICM_DEVMODE(iPrevMode)) { ICMMSG(("SetIcmMode: Device ICM is requested\n")); // // if ICM on Device was requested by CreateDC(), let force do // ICM on device, if possible. // lReqMode = REQ_ICM_DEVICE; } else { ICMMSG(("SetIcmMode: Host ICM is requested\n")); } // // Turn ICM on for this DC. // if (!NtGdiSetIcmMode(hdc,ICM_SET_MODE,lReqMode)) { // // something wrong... we are fail to enable ICM. // iRet = (int)FALSE; break; } // // If we have cached transform and it is not dirty, we can use that. // if ((pIcmInfo->pCXform == NULL) || (pdcattr->ulDirty_ & DIRTY_COLORTRANSFORM)) { if (IcmUpdateDCColorInfo(hdc,pdcattr)) { // // Mark this process has experience about ICM ON. // gbICMEnabledOnceBefore = TRUE; iRet = (int)TRUE; } else { WARNING("SetIcmMode():IcmUpdateDCInfo failed\n"); // // Fail to create new transform // NtGdiSetIcmMode(hdc,ICM_SET_MODE,REQ_ICM_OFF); iRet = (int)FALSE; } } else { ICMMSG(("SetIcmMode: Use cached Color Transform\n")); // // Use cached transform, because since last time when we disabled ICM, // NO profile(s) and logical color space has been changed. // if (IcmSelectColorTransform( hdc,pdcattr,pIcmInfo->pCXform, bDeviceCalibrate(pIcmInfo->pCXform->DestinationColorSpace))) { // // Translate all DC objects to ICM colors. Must // force brush/pens to be re-realized when used next // IcmTranslateColorObjects(hdc,pdcattr,TRUE); iRet = (int)TRUE; } else { // // Fail to select cached transform to the DC. // NtGdiSetIcmMode(hdc,ICM_SET_MODE,REQ_ICM_OFF); iRet = (int)FALSE; } } } else { ICMMSG(("SetIcmMode: ICM has been enabled already\n")); iRet = (int)TRUE; } break; case ICM_DONE_OUTSIDEDC: if (!IS_ICM_OUTSIDEDC(iPrevMode)) { // // if inside-DC ICM is enabled, turned off it. // if (IS_ICM_INSIDEDC(iPrevMode)) { // // Invalidate current color tansform (but the cache in ICMINFO is still valid). // IcmSelectColorTransform(hdc,pdcattr,NULL,FALSE); // // Restore color data for ICM disable. // IcmTranslateColorObjects(hdc,pdcattr,FALSE); } // // Tell the kernel to disable color adjustment during halftone. // NtGdiSetIcmMode(hdc,ICM_SET_MODE,REQ_ICM_OUTSIDEDC); } else { ICMMSG(("SetIcmMode: OutsideDC ICM has been enabled already\n")); } iRet = (int)TRUE; break; case ICM_OFF: // // Is there any kind of ICM is enabled ? // if (IS_ICM_ON(iPrevMode)) { if (IS_ICM_INSIDEDC(iPrevMode)) { // // Invalidate current color tansform (but the cache in ICMINFO is still valid). // IcmSelectColorTransform(hdc,pdcattr,NULL,TRUE); // // Restore color data for ICM disable. // IcmTranslateColorObjects(hdc,pdcattr,FALSE); } // // Tell the kernel to disable ICM. // NtGdiSetIcmMode(hdc,ICM_SET_MODE,REQ_ICM_OFF); } else { ICMMSG(("SetIcmMode: ICM has been disabled already\n")); } iRet = (int)TRUE; break; default: GdiSetLastError(ERROR_INVALID_PARAMETER); iRet = (int)FALSE; break; } } else { GdiSetLastError(ERROR_INVALID_PARAMETER); iRet = (int)FALSE; } return((int)iRet); } /******************************Public*Routine******************************\ * CreateColorSpaceA * * Arguments: * * lpLogColorSpace - apps log color space * * Return Value: * * handle of color space or NULL * * History: * * 4-Jun-1996 -by- Mark Enstrom [marke] * \**************************************************************************/ HCOLORSPACE WINAPI CreateColorSpaceA( LPLOGCOLORSPACEA lpLogColorSpace ) { HCOLORSPACE hRet; LOGCOLORSPACEW LogColorSpaceW; ICMAPI(("gdi32: CreateColorSpaceA\n")); if (lpLogColorSpace == NULL) { GdiSetLastError(ERROR_INVALID_PARAMETER); return(NULL); } // // convert ascii to long character version // if ((lpLogColorSpace->lcsSignature != LCS_SIGNATURE) || (lpLogColorSpace->lcsVersion != 0x400) || (lpLogColorSpace->lcsSize != sizeof(LOGCOLORSPACEA))) { ICMWRN(("CreateColorSpaceA: Incorrect signature,version or size \n")); GdiSetLastError(ERROR_INVALID_COLORSPACE); return(NULL); } RtlZeroMemory(&LogColorSpaceW,sizeof(LOGCOLORSPACEW)); LogColorSpaceW.lcsSignature = lpLogColorSpace->lcsSignature; LogColorSpaceW.lcsVersion = lpLogColorSpace->lcsVersion; LogColorSpaceW.lcsCSType = lpLogColorSpace->lcsCSType; LogColorSpaceW.lcsIntent = lpLogColorSpace->lcsIntent; LogColorSpaceW.lcsEndpoints = lpLogColorSpace->lcsEndpoints; LogColorSpaceW.lcsGammaRed = lpLogColorSpace->lcsGammaRed; LogColorSpaceW.lcsGammaGreen = lpLogColorSpace->lcsGammaGreen; LogColorSpaceW.lcsGammaBlue = lpLogColorSpace->lcsGammaBlue; LogColorSpaceW.lcsSize = sizeof(LOGCOLORSPACEW); vToUnicodeN( LogColorSpaceW.lcsFilename,MAX_PATH, lpLogColorSpace->lcsFilename,strlen(lpLogColorSpace->lcsFilename)+1 ); hRet = CreateColorSpaceInternalW(&LogColorSpaceW,LCSEX_ANSICREATED); return(hRet); } /******************************Public*Routine******************************\ * CreateColorSpaceW * * ColorSpace is a KERNEL mode object * * Arguments: * * lpLogColorSpace - apps log color space * * Return Value: * * Handle of color space or NULL * * History: * * 18-Apr-1997 -by- Hideyuki Nagase [hideyukn] * \**************************************************************************/ HCOLORSPACE WINAPI CreateColorSpaceW( LPLOGCOLORSPACEW lpLogColorSpace ) { return (CreateColorSpaceInternalW(lpLogColorSpace,0)); } HCOLORSPACE WINAPI CreateColorSpaceInternalW( LPLOGCOLORSPACEW lpLogColorSpace, DWORD dwCreateFlags ) { HCOLORSPACE hRet = NULL; LOGCOLORSPACEEXW LogColorSpaceExOnStack; ICMAPI(("gdi32: CreateColorSpaceW\n")); if (lpLogColorSpace == NULL) { GdiSetLastError(ERROR_INVALID_PARAMETER); return(NULL); } // // validate color space // if ((lpLogColorSpace->lcsSignature != LCS_SIGNATURE) || (lpLogColorSpace->lcsVersion != 0x400) || (lpLogColorSpace->lcsSize != sizeof(LOGCOLORSPACEW))) { goto InvalidColorSpaceW; } // // validate lcsIntent // if ((lpLogColorSpace->lcsIntent != LCS_GM_BUSINESS) && (lpLogColorSpace->lcsIntent != LCS_GM_GRAPHICS) && (lpLogColorSpace->lcsIntent != LCS_GM_IMAGES) && (lpLogColorSpace->lcsIntent != LCS_GM_ABS_COLORIMETRIC)) { goto InvalidColorSpaceW; } // // We can not modify apps LOGCOLORSPACEW, so that make a copy on stack. // LogColorSpaceExOnStack.lcsColorSpace = *lpLogColorSpace; LogColorSpaceExOnStack.dwFlags = dwCreateFlags; // // validate lcsCSTYPE // if ((lpLogColorSpace->lcsCSType == LCS_CALIBRATED_RGB) || (lpLogColorSpace->lcsCSType == PROFILE_LINKED)) { // // Replace CSType in case PROFILE_LINKED. // LogColorSpaceExOnStack.lcsColorSpace.lcsCSType = LCS_CALIBRATED_RGB; if (lpLogColorSpace->lcsFilename[0] != L'\0') { HANDLE hFile; // // Normalize profile filename. but we will not over-write app's // path with our normalized path. // BuildIcmProfilePath(lpLogColorSpace->lcsFilename, LogColorSpaceExOnStack.lcsColorSpace.lcsFilename, MAX_PATH); // // profile name given, verify it exists // hFile = CreateFileW( LogColorSpaceExOnStack.lcsColorSpace.lcsFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile != INVALID_HANDLE_VALUE) { // // Yes, file is really exits. // CloseHandle(hFile); } else { ICMWRN(("CreateColorSpaceW: Couldn't open file specified by lcsFilename\n")); GdiSetLastError(ERROR_PROFILE_NOT_FOUND); return(NULL); } } } else // any other CSType { ULONG ulSize = MAX_PATH; // // Load external ICM dlls. // LOAD_ICMDLL(NULL); // // if CSType is not LCS_CALIBRATED_RGB, we should go to MSCMS.DLL to get color profile // for corresponding LCSType, then any given profile name from application is IGNORED. // if (!(*fpGetStandardColorSpaceProfileW)( NULL, lpLogColorSpace->lcsCSType, LogColorSpaceExOnStack.lcsColorSpace.lcsFilename, &ulSize)) { ICMWRN(("CreateColorSpaceW:Error CSType = %x\n",lpLogColorSpace->lcsCSType)); goto InvalidColorSpaceW; } } // // Call kernel to create this colorspace. // hRet = NtGdiCreateColorSpace(&LogColorSpaceExOnStack); return(hRet); InvalidColorSpaceW: ICMWRN(("CreateColorSpaceW: Incorrect ColorSpace parameter\n")); GdiSetLastError(ERROR_INVALID_COLORSPACE); return(NULL); } /******************************Public*Routine******************************\ * DeleteColorSpace - delete user object * * Arguments: * * hColorSpace - color space handle * * Return Value: * * status * * History: * * 5-Jun-1996 -by- Mark Enstrom [marke] * \**************************************************************************/ BOOL WINAPI DeleteColorSpace( HCOLORSPACE hColorSpace ) { ICMAPI(("gdi32: DeleteColorSpace\n")); FIXUP_HANDLE(hColorSpace); // // validate handle, delete // return (NtGdiDeleteColorSpace(hColorSpace)); } /******************************Public*Routine******************************\ * SetColorSpace - set logical color space into DC, force new xform to be * created and all objects re-realized * * Arguments: * * hdc - dc handle * hColorSpace - logical color space handle * * Return Value: * * Status * * History: * * 5-Jun-1996 -by- Mark Enstrom [marke] * \**************************************************************************/ HCOLORSPACE META WINAPI SetColorSpace( HDC hdc, HCOLORSPACE hColorSpace ) { HANDLE hRet = NULL; ICMAPI(("gdi32: SetColorSpace\n")); FIXUP_HANDLE(hdc); FIXUP_HANDLE(hColorSpace); if (IS_ALTDC_TYPE(hdc)) { PLDC pldc; if (IS_METADC16_TYPE(hdc)) return(hRet); DC_PLDC(hdc,pldc,hRet); if (pldc->iType == LO_METADC) { if (!MF_SelectAnyObject(hdc,(HANDLE)hColorSpace,EMR_SETCOLORSPACE)) return(hRet); } } // // Update source color space // hRet = IcmSetSourceColorSpace(hdc,hColorSpace,NULL,0); return(hRet); } /******************************Public*Routine******************************\ * GetColorSpace - return color space from DC * * Arguments: * * hdc * * Return Value: * * hColorSpace or NULL * * History: * * 5-Jun-1996 -by- Mark Enstrom [marke] * \**************************************************************************/ HCOLORSPACE WINAPI GetColorSpace( HDC hdc ) { HANDLE hRet = NULL; PDC_ATTR pdcattr; ICMAPI(("gdi32: GetColorSpace\n")); FIXUP_HANDLE(hdc); // // validate and access hdc // PSHARED_GET_VALIDATE(pdcattr,hdc,DC_TYPE); if (pdcattr) { // // get hColorSpace // hRet = (HANDLE)pdcattr->hColorSpace; } else { GdiSetLastError(ERROR_INVALID_PARAMETER); } return(hRet); } /******************************Public*Routine******************************\ * GetLogColorSpaceA - get colorspace and convert to ASCII * * typedef struct tagLOGCOLORSPACEW { * DWORD lcsSignature; * DWORD lcsVersion; * DWORD lcsSize; * LCSCSTYPE lcsCSType; * LCSGAMUTMATCH lcsIntent; * CIEXYZTRIPLE lcsEndpoints; * DWORD lcsGammaRed; * DWORD lcsGammaGreen; * DWORD lcsGammaBlue; * WCHAR lcsFilename[MAX_PATH]; * } LOGCOLORSPACEW, *LPLOGCOLORSPACEW; * * Arguments: * * hColorSpace - handle to color space * lpBuffer - buffer to hold logcolorspace * nSize - buffer size * * Return Value: * * status * * History: * * 5-Jun-1996 -by- Mark Enstrom [marke] * \**************************************************************************/ BOOL WINAPI GetLogColorSpaceA( HCOLORSPACE hColorSpace, LPLOGCOLORSPACEA lpBuffer, DWORD nSize ) { BOOL bRet = FALSE; LOGCOLORSPACEW LogColorSpaceW; ICMAPI(("gdi32: GetLogColorSpaceA\n")); if ((lpBuffer != NULL) && (nSize >= sizeof(LOGCOLORSPACEA))) { // // get info using W version // bRet = GetLogColorSpaceW(hColorSpace,&LogColorSpaceW,sizeof(LOGCOLORSPACEW)); if (bRet) { // // copy to user buffer // lpBuffer->lcsSignature = LogColorSpaceW.lcsSignature; lpBuffer->lcsVersion = LogColorSpaceW.lcsVersion; lpBuffer->lcsSize = sizeof(LOGCOLORSPACEA); lpBuffer->lcsCSType = LogColorSpaceW.lcsCSType; lpBuffer->lcsIntent = LogColorSpaceW.lcsIntent; lpBuffer->lcsEndpoints = LogColorSpaceW.lcsEndpoints; lpBuffer->lcsGammaRed = LogColorSpaceW.lcsGammaRed; lpBuffer->lcsGammaGreen = LogColorSpaceW.lcsGammaGreen; lpBuffer->lcsGammaBlue = LogColorSpaceW.lcsGammaBlue; // // convert W to A // bRet = bToASCII_N(lpBuffer->lcsFilename, MAX_PATH, LogColorSpaceW.lcsFilename, wcslen(LogColorSpaceW.lcsFilename)+1); } else { GdiSetLastError(ERROR_INVALID_PARAMETER); } } else { GdiSetLastError(ERROR_INSUFFICIENT_BUFFER); } return(bRet); } /******************************Public*Routine******************************\ * GetLogColorSpaceW - return logical color space info. * * Arguments: * * hColorSpace - handle to color space * lpBuffer - buffer to hold logcolorspace * nSize - buffer size * * Return Value: * * status * * History: * * 5-Jun-1996 -by- Mark Enstrom [marke] * \**************************************************************************/ BOOL WINAPI GetLogColorSpaceW( HCOLORSPACE hColorSpace, LPLOGCOLORSPACEW lpBuffer, DWORD nSize ) { BOOL bRet = FALSE; ICMAPI(("gdi32: GetLogColorSpaceW\n")); if ((lpBuffer != NULL) && (nSize >= sizeof(LOGCOLORSPACEW))) { FIXUP_HANDLE(hColorSpace); // // Call kernel to get contents // if (NtGdiExtGetObjectW(hColorSpace,sizeof(LOGCOLORSPACEW),lpBuffer) == sizeof(LOGCOLORSPACEW)) { // // Only for stock color space object. // if ((hColorSpace == GetStockObject(PRIV_STOCK_COLORSPACE)) && (lpBuffer->lcsCSType != LCS_CALIBRATED_RGB)) { ULONG ulSize = MAX_PATH; // // Load ICM DLL. // LOAD_ICMDLL(FALSE); // // Get corresponding profile name from CSType. // if (!(*fpGetStandardColorSpaceProfileW)( NULL, lpBuffer->lcsCSType, lpBuffer->lcsFilename, &ulSize)) { ICMMSG(("GetLogColorSpaceW():Fail to SCS(%x), leave it as is\n", lpBuffer->lcsCSType)); } } bRet = TRUE; } else { GdiSetLastError(ERROR_INVALID_PARAMETER); } } else { GdiSetLastError(ERROR_INSUFFICIENT_BUFFER); } return(bRet); } /******************************Public*Routine******************************\ * CheckColorsInGamut * * Arguments: * * hdc - DC * lpRGBQuad - Buffer of colors to check * dlpBuffer - result buffer * nCount - number of colors * * Return Value: * * status * * History: * * Rewrite it: * 26-Jan-1997 -by- Hideyuki Nagase [hideyukn] * Write it: * 5-Jun-1996 -by- Mark Enstrom [marke] * \**************************************************************************/ BOOL WINAPI CheckColorsInGamut( HDC hdc, LPVOID lpRGBTriple, LPVOID dlpBuffer, DWORD nCount ) { BOOL bRet = FALSE; PDC_ATTR pdcattr; ICMAPI(("gdi32: CheckColorsInGamut\n")); FIXUP_HANDLE(hdc); // // Check parameter // if ((lpRGBTriple == NULL) || (dlpBuffer == NULL) || (nCount == 0)) { GdiSetLastError(ERROR_INVALID_PARAMETER); return (FALSE); } // // validate and access hdc // PSHARED_GET_VALIDATE(pdcattr,hdc,DC_TYPE); if (pdcattr) { if (IS_ICM_HOST(pdcattr->lIcmMode) || IS_ICM_DEVICE(pdcattr->lIcmMode)) { ASSERTGDI(ghICM,"CheckColorsInGamut(): mscms.dll is not loaded\n"); if (GetColorTransformInDC(pdcattr)) { // // The input buffer may not be DWORD-aligned, And it buffer size // might be exactly nCount * sizeof(RGBTRIPLE). // So that, allocate DWORD-aligned buffer here. // PVOID pvBuf = LOCALALLOC(ALIGN_DWORD(nCount*sizeof(RGBTRIPLE))); if (!pvBuf) { GdiSetLastError(ERROR_NOT_ENOUGH_MEMORY); return (FALSE); } // // Make a copy, here // RtlZeroMemory(pvBuf,ALIGN_DWORD(nCount*sizeof(RGBTRIPLE))); RtlCopyMemory(pvBuf,lpRGBTriple,nCount*sizeof(RGBTRIPLE)); if (IS_ICM_HOST(pdcattr->lIcmMode)) { // // we handle RGBTRIPLE array as nCount x 1 pixel bitmap. // bRet = (*fpCheckBitmapBits)( (HANDLE)GetColorTransformInDC(pdcattr), pvBuf, BM_RGBTRIPLETS, nCount,1, ALIGN_DWORD(nCount*sizeof(RGBTRIPLE)), dlpBuffer, NULL,0); } else // if (IS_ICM_DEVICE(pdcattr->lIcmMode)) { // // Call device driver via kernel. // bRet = NtGdiCheckBitmapBits( hdc, (HANDLE)GetColorTransformInDC(pdcattr), (PVOID)lpRGBTriple, (ULONG)BM_RGBTRIPLETS, nCount,1, ALIGN_DWORD(nCount*sizeof(RGBTRIPLE)), dlpBuffer); } LOCALFREE(pvBuf); } else { // // There is no valid color transform, // so it is assume ident. color transform, // then that every color in the gamut. // RtlZeroMemory(dlpBuffer,nCount); bRet = TRUE; } } else { WARNING("CheckColorsInGamut():ICM mode is invalid\n"); GdiSetLastError(ERROR_ICM_NOT_ENABLED); } } else { GdiSetLastError(ERROR_INVALID_PARAMETER); } return(bRet); } /******************************Public*Routine******************************\ * ColorMatchToTarget * * Arguments: * * hdc, * hdcTarget * uiAction * * Return Value: * * status * * History: * * Rewrite it: * 26-Jan-1997 -by- Hideyuki Nagase [hideyukn] * Write it: * 5-Jun-1996 -by- Mark Enstrom [marke] * \**************************************************************************/ BOOL META WINAPI ColorMatchToTarget( HDC hdc, HDC hdcTarget, DWORD uiAction ) { BOOL bRet = FALSE; PDC_ATTR pdcattrTarget; ICMAPI(("gdi32: ColorMatchToTarget\n")); FIXUP_HANDLE(hdcTarget); // // Verify Target DC. No ICM with Windows MetaFile. // if (IS_METADC16_TYPE(hdcTarget)) { GdiSetLastError(ERROR_INVALID_PARAMETER); return(bRet); } PSHARED_GET_VALIDATE(pdcattrTarget,hdcTarget,DC_TYPE); if (pdcattrTarget != NULL) { PCACHED_COLORSPACE pTargetColorSpace = NULL; PLDC pldcTarget = (PLDC)(pdcattrTarget->pvLDC); if (!IS_ICM_INSIDEDC(pdcattrTarget->lIcmMode)) { GdiSetLastError(ERROR_ICM_NOT_ENABLED); return (FALSE); } // // No Enhanced metafile DC as target DC. // if (pldcTarget && pldcTarget->iType == LO_METADC) { GdiSetLastError(ERROR_INVALID_PARAMETER); return(bRet); } // // ICMINFO should be exist. // if (!BEXIST_ICMINFO(pdcattrTarget)) { GdiSetLastError(ERROR_ICM_NOT_ENABLED); return(bRet); } if (uiAction == CS_ENABLE) { // // Hold critical section for color space to make sure pTargetColorSpace won't be deleted // ENTERCRITICALSECTION(&semColorSpaceCache); // // Target DC has LDC and ICMINFO, pick up colorspace data from there. // pTargetColorSpace = ((PGDI_ICMINFO)(pdcattrTarget->pvICM))->pDestColorSpace; // // Select it to target. the ref count of pTargetColorSpace will be incremented // if we suceed to select. // bRet = ColorMatchToTargetInternal(hdc,pTargetColorSpace,uiAction); LEAVECRITICALSECTION(&semColorSpaceCache); } else { bRet = ColorMatchToTargetInternal(hdc,NULL,uiAction); } } else { GdiSetLastError(ERROR_INVALID_PARAMETER); } return (bRet); } BOOL WINAPI ColorMatchToTargetInternal( HDC hdc, PCACHED_COLORSPACE pTargetColorSpace, DWORD uiAction ) { BOOL bRet = FALSE; BOOL bEhnMetafile = FALSE; PDC_ATTR pdcattr; FIXUP_HANDLE(hdc); // // Verify destination DC. No ICM with Windows MetaFile. // if (IS_METADC16_TYPE(hdc)) { GdiSetLastError(ERROR_INVALID_PARAMETER); return(FALSE); } PSHARED_GET_VALIDATE(pdcattr,hdc,DC_TYPE); if (pdcattr != NULL) { PLDC pldc = (PLDC)(pdcattr->pvLDC); // // Check ICM is enabled on hdc properly. // if (pldc && (pldc->iType == LO_METADC)) { // // ICM should be turned on "fakely" on metafile hdc // if (!IS_ICM_METAFILING_ON(pdcattr->lIcmMode)) { GdiSetLastError(ERROR_ICM_NOT_ENABLED); return (FALSE); } // // Mark we are recording into Enhanced metafile. // bEhnMetafile = TRUE; } else { if (!IS_ICM_INSIDEDC(pdcattr->lIcmMode)) { GdiSetLastError(ERROR_ICM_NOT_ENABLED); return (FALSE); } } switch (uiAction) { case CS_ENABLE: // // Fail, if we are in proofing mode, already. // if (!IS_ICM_PROOFING(pdcattr->lIcmMode)) { if (pTargetColorSpace) { if (bEhnMetafile) { // // Set the data to metafile. // bRet = MF_ColorMatchToTarget( hdc, uiAction, (PVOID) pTargetColorSpace, EMR_COLORMATCHTOTARGETW); } else { // // Set Target color space. // // (this increments ref count of pTargetColorSpace) // bRet = IcmSetTargetColorSpace(hdc,pTargetColorSpace,uiAction); } } } else { WARNING("ColorMatchToTargetInternal(): DC is proofing mode already\n"); GdiSetLastError(ERROR_INVALID_PARAMETER); } break; case CS_DISABLE: case CS_DELETE_TRANSFORM: if (IS_ICM_PROOFING(pdcattr->lIcmMode)) { if (bEhnMetafile) { // // Set the data to metafile. // bRet = MF_ColorMatchToTarget( hdc, uiAction, NULL, EMR_COLORMATCHTOTARGETW); } else { // // Reset Target color space // bRet = IcmSetTargetColorSpace(hdc,NULL,uiAction); } } else { // // we are not in proofing mode, never called with CS_ENABLE before. // WARNING("ColorMatchToTarget: DC is not proofing mode\n"); GdiSetLastError(ERROR_INVALID_PARAMETER); } break; default: WARNING("ColorMatchToTarget: uiAction is invalid\n"); GdiSetLastError(ERROR_INVALID_PARAMETER); } } else { GdiSetLastError(ERROR_INVALID_PARAMETER); WARNING("ColorMatchToTarget: invalid DC\n"); } return(bRet); } /******************************Public*Routine******************************\ * GetICMProfileA - get current profile from DC * * Arguments: * * hdc - DC * szBuffer - size of buffer * pBuffer - user buffer * * Return Value: * * status * * History: * * Rewrite it: * 05-Feb-1996 -by- Hideyuki Nagase [hideyukn] * Write it: * 5-Jun-1996 -by- Mark Enstrom [marke] * \**************************************************************************/ BOOL WINAPI GetICMProfileA( HDC hdc, LPDWORD pBufSize, LPSTR pszFilename ) { BOOL bRet = FALSE; WCHAR wchProfile[MAX_PATH]; DWORD BufSizeW = MAX_PATH; ICMAPI(("gdi32: GetICMProfileA\n")); if (pBufSize == NULL) { GdiSetLastError(ERROR_INVALID_PARAMETER); return(FALSE); } // // Call W version. // if (GetICMProfileW(hdc,&BufSizeW,wchProfile)) { CHAR chProfile[MAX_PATH]; DWORD BufSizeA = MAX_PATH; if (BufSizeW) { // // Unicode to Ansi convertion // BufSizeA = WideCharToMultiByte(CP_ACP,0, wchProfile,BufSizeW, chProfile,BufSizeA, NULL,NULL); if ((pszFilename == NULL) || (*pBufSize < BufSizeA)) { // // if the buffer is not given or not enough, return nessesary buffer size and error. // *pBufSize = BufSizeA; GdiSetLastError(ERROR_INSUFFICIENT_BUFFER); } else { // // copy converted string to buffer. // lstrcpyA(pszFilename,chProfile); *pBufSize = BufSizeA; bRet = TRUE; } } } return(bRet); } /******************************Public*Routine******************************\ * GetICMProfileW - read icm profile from DC * * Arguments: * * hdc - DC * szBuffer - size of user buffer * pszFilename - user W buffer * * Return Value: * * Boolean * * History: * * 5-Jun-1996 -by- Mark Enstrom [marke] * \**************************************************************************/ BOOL WINAPI GetICMProfileW( HDC hdc, LPDWORD pBufSize, LPWSTR pszFilename ) { PDC_ATTR pdcattr; ICMAPI(("gdi32: GetICMProfileW\n")); FIXUP_HANDLE(hdc); if (pBufSize == NULL) { GdiSetLastError(ERROR_INVALID_PARAMETER); return(FALSE); } PSHARED_GET_VALIDATE(pdcattr,hdc,DC_TYPE); if (pdcattr) { PGDI_ICMINFO pIcmInfo; PWSZ pwszProfile = NULL; ULONG ulSize = 0; // // Initialize ICMINFO // if ((pIcmInfo = INIT_ICMINFO(hdc,pdcattr)) == NULL) { WARNING("gdi32: GetICMProfileW: Can't init icm info\n"); return(FALSE); } if (IsColorDeviceContext(hdc)) { // // Load external ICM dll // LOAD_ICMDLL(FALSE); // // if there is no destination profile for the DC, then load // the defualt // IcmUpdateLocalDCColorSpace(hdc,pdcattr); if (pIcmInfo->pDestColorSpace) { // // Get profile name in destination colorspace. // pwszProfile = pIcmInfo->pDestColorSpace->LogColorSpace.lcsFilename; } } else { ICMMSG(("GetICMProfile(): for Mono-device\n")); // // There is no destination profile AS default, // *BUT* if Apps set it by calling SetICMProfile(), return it. // if (pIcmInfo->flInfo & ICM_VALID_CURRENT_PROFILE) { pwszProfile = pIcmInfo->DefaultDstProfile; } } if (pwszProfile) { ulSize = lstrlenW(pwszProfile) + 1; // + 1 for null-terminated } if (ulSize <= 1) { // // No profile, Or only NULL character. // GdiSetLastError(ERROR_PROFILE_NOT_FOUND); return(FALSE); } else if (*pBufSize >= ulSize) { // // There is enough buffer, copy filename. // lstrcpyW(pszFilename,pwszProfile); *pBufSize = ulSize; return (TRUE); } else { // // if buffer is not presented or it's too small, // returns the nessesary buffer size. // GdiSetLastError(ERROR_INSUFFICIENT_BUFFER); *pBufSize = ulSize; return (FALSE); } } // // something error. // GdiSetLastError(ERROR_INVALID_PARAMETER); return(FALSE); } /******************************Public*Routine******************************\ * SetICMProfileA - convert the profile string to WCHAR and save in DC * * Arguments: * * hdc - DC * pszFileName - Profile name * * Return Value: * * status * * History: * * Rewrite it: * 23-Jan-1996 -by- Hideyuki Nagase [hideyukn] * Write it: * 5-Jun-1996 -by- Mark Enstrom [marke] * \**************************************************************************/ BOOL META WINAPI SetICMProfileA( HDC hdc, LPSTR pszFileName ) { ICMAPI(("gdi32: SetICMProfileA\n")); return (SetICMProfileInternalA(hdc,pszFileName,NULL,0)); } BOOL SetICMProfileInternalA( HDC hdc, LPSTR pszFileName, PCACHED_COLORSPACE pColorSpace, DWORD dwFlags ) { BOOL bRet = FALSE; // // Check parameter either pColorSpace or pszFilename should be given. // if (pColorSpace) { ICMAPI(("gdi32: SetICMProfileA by ColorSpace (%ws):dwFlags - %d\n", pColorSpace->LogColorSpace.lcsFilename,dwFlags)); } else if (pszFileName) { ICMAPI(("gdi32: SetICMProfileA by profile name (%s):dwFlags - %x\n", pszFileName,dwFlags)); } else { GdiSetLastError(ERROR_INVALID_PARAMETER); return (FALSE); } if (IS_ALTDC_TYPE(hdc)) { PLDC pldc; if (IS_METADC16_TYPE(hdc)) return(bRet); DC_PLDC(hdc,pldc,bRet) if (pldc->iType == LO_METADC) { if (!MF_SetICMProfile(hdc, (LPBYTE)pszFileName, (PVOID)pColorSpace, EMR_SETICMPROFILEA)) { return((int)FALSE); } } } if (pColorSpace) { // // Select the given profile into DC. // // (this increments ref count of pColorSpace) // bRet = IcmSetDestinationColorSpace(hdc,NULL,pColorSpace,dwFlags); } else if (pszFileName) { ULONG ulSize = lstrlenA(pszFileName); if (ulSize && (ulSize < MAX_PATH)) { WCHAR pwszCapt[MAX_PATH]; // // let me count null-terminate char. // ulSize += 1; // // Convert to Unicode. // vToUnicodeN(pwszCapt,MAX_PATH,pszFileName,ulSize); // // Select the given profile into DC. // bRet = IcmSetDestinationColorSpace(hdc,pwszCapt,NULL,dwFlags); } else { GdiSetLastError(ERROR_INVALID_PARAMETER); } } return(bRet); } /******************************Public*Routine******************************\ * SetICMProfileW - set profile name into DC * * Arguments: * * Return Value: * * History: * * 5-Jun-1996 -by- Mark Enstrom [marke] * \**************************************************************************/ BOOL META WINAPI SetICMProfileW( HDC hdc, LPWSTR pwszFileName ) { ICMAPI(("gdi32: SetICMProfileW\n")); return (SetICMProfileInternalW(hdc,pwszFileName,NULL,0)); } BOOL SetICMProfileInternalW( HDC hdc, LPWSTR pwszFileName, PCACHED_COLORSPACE pColorSpace, DWORD dwFlags ) { BOOL bRet = FALSE; // // Check parameter either pColorSpace or pszFilename should be given. // if (pColorSpace) { ICMAPI(("gdi32: SetICMProfileW by ColorSpace (%ws):dwFlags - %x\n", pColorSpace->LogColorSpace.lcsFilename,dwFlags)); } else if (pwszFileName) { ICMAPI(("gdi32: SetICMProfileW by profile name (%ws):dwFlags - %d\n", pwszFileName,dwFlags)); } else { GdiSetLastError(ERROR_INVALID_PARAMETER); return (FALSE); } FIXUP_HANDLE(hdc); if (IS_ALTDC_TYPE(hdc)) { PLDC pldc; if (IS_METADC16_TYPE(hdc)) return(bRet); DC_PLDC(hdc,pldc,bRet) if (pldc->iType == LO_METADC) { if (!MF_SetICMProfile(hdc, (LPBYTE)pwszFileName, (PVOID)pColorSpace, EMR_SETICMPROFILEW)) { return((int)FALSE); } } } // // Select the given profile into DC. // // (this increments ref count of pColorSpace) // bRet = IcmSetDestinationColorSpace(hdc,pwszFileName,pColorSpace,dwFlags); return (bRet); } /******************************Public*Routine******************************\ * EnumICMProfilesA * * Arguments: * * hdc * lpEnumGamutMatchProc * lParam * * Return Value: * * History: * * Write it: * 13-Feb-1997 -by- Hideyuki Nagase [hideyukn] * \**************************************************************************/ int WINAPI EnumICMProfilesA( HDC hdc, ICMENUMPROCA lpEnumGamutMatchProc, LPARAM lParam ) { int iRet = -1; BOOL bRet; ICMAPI(("gdi32: EnumICMProfileA\n")); FIXUP_HANDLE(hdc); VALIDATE_HANDLE(bRet,hdc,DC_TYPE); if (bRet && (lpEnumGamutMatchProc != NULL)) { iRet = IcmEnumColorProfile(hdc,lpEnumGamutMatchProc,lParam,TRUE,NULL,NULL); } else { GdiSetLastError(ERROR_INVALID_PARAMETER); } return(iRet); } /******************************Public*Routine******************************\ * EnumICMProfilesW * * Arguments: * * hdc * lpEnumGamutMatchProc * lParam * * Return Value: * * History: * * Write it: * 13-Feb-1997 -by- Hideyuki Nagase [hideyukn] * \**************************************************************************/ int WINAPI EnumICMProfilesW( HDC hdc, ICMENUMPROCW lpEnumGamutMatchProc, LPARAM lParam ) { int iRet = -1; BOOL bRet; ICMAPI(("gdi32: EnumICMProfileW\n")); FIXUP_HANDLE(hdc); VALIDATE_HANDLE(bRet,hdc,DC_TYPE); if (bRet && (lpEnumGamutMatchProc != NULL)) { iRet = IcmEnumColorProfile(hdc,lpEnumGamutMatchProc,lParam,FALSE,NULL,NULL); } else { GdiSetLastError(ERROR_INVALID_PARAMETER); } return(iRet); } /******************************Public*Routine******************************\ * UpdateICMRegKeyW() * * History: * 8-Jan-1997 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ BOOL WINAPI UpdateICMRegKeyW( DWORD Reserved, PWSTR pwszICMMatcher, PWSTR pwszFileName, UINT Command ) { BOOL bRet = FALSE; int iRet; ICMAPI(("gdi32: UpdateICMRegKeyW\n")); if (Reserved != 0) { GdiSetLastError(ERROR_INVALID_PARAMETER); return(FALSE); } // // Load external ICM dlls // LOAD_ICMDLL(FALSE); switch (Command) { case ICM_ADDPROFILE: if (pwszFileName) { // // Call InstallColorProfileA() in mscms.dll // bRet = (*fpInstallColorProfileW)(NULL, pwszFileName); } else { GdiSetLastError(ERROR_INVALID_PARAMETER); } break; case ICM_DELETEPROFILE: if (pwszFileName) { // // Call UninstallColorProfileW() in mscms.dll // bRet = (*fpUninstallColorProfileW)(NULL, pwszFileName, FALSE); } else { GdiSetLastError(ERROR_INVALID_PARAMETER); } break; case ICM_QUERYPROFILE: if (pwszFileName) { PROFILECALLBACK_DATA QueryProfile; QueryProfile.pwszFileName = GetFileNameFromPath(pwszFileName); QueryProfile.bFound = FALSE; if (QueryProfile.pwszFileName != NULL) { // // Enumrate all registered profile to find this profile. // IcmEnumColorProfile(NULL,IcmQueryProfileCallBack,(LPARAM)(&QueryProfile),FALSE,NULL,NULL); // // Is that found ? // bRet = QueryProfile.bFound; } } else { GdiSetLastError(ERROR_INVALID_PARAMETER); } break; case ICM_SETDEFAULTPROFILE: // // Not supported. // GdiSetLastError(ERROR_CALL_NOT_IMPLEMENTED); break; case ICM_REGISTERICMATCHER: if (pwszICMMatcher && pwszFileName) { DWORD dwCMM = *((DWORD *)pwszICMMatcher); // // Call RegisterCMMW() in mscms.dll // bRet = (*fpRegisterCMMW)(NULL, IcmSwapBytes(dwCMM), pwszFileName); } else { GdiSetLastError(ERROR_INVALID_PARAMETER); } break; case ICM_UNREGISTERICMATCHER: if (pwszICMMatcher) { DWORD dwCMM = *((DWORD *)pwszICMMatcher); // // Call UnregisterCMMW() in mscms.dll // bRet = (*fpUnregisterCMMW)(NULL, IcmSwapBytes(dwCMM)); } else { GdiSetLastError(ERROR_INVALID_PARAMETER); } break; case ICM_QUERYMATCH: if (pwszFileName) { // // Find match profile. // iRet = IcmEnumColorProfile(NULL,NULL,0,FALSE,(PDEVMODEW)pwszFileName,NULL); // // Adjust return value, because IcmEnumColorProfile returns -1 if not found. // and 0 for error (since no callback function) // if (iRet > 0) { bRet = TRUE; } } else { GdiSetLastError(ERROR_INVALID_PARAMETER); } break; default: WARNING("gdi32!UpdateICMRegKeyW():Invalid Command\n"); GdiSetLastError(ERROR_INVALID_PARAMETER); break; } return bRet; } /******************************Public*Routine******************************\ * UpdateICMRegKeyA * * Arguments: * * Reserved * szICMMatcher * szFileName * Command * * Return Value: * * Status * * History: * * 8-Jan-1997 -by- Hideyuki Nagase [hideyukn] * \**************************************************************************/ BOOL WINAPI UpdateICMRegKeyA( DWORD Reserved, PSTR szICMMatcher, PSTR szFileName, UINT Command ) { BOOL bRet = FALSE; BOOL bError = FALSE; PWSTR pwszFileName = NULL; // // szICMMatcher points to 4 bytes CMM ID, actually it is not "string". // Ansi to Unicode conversion is not needed. // PWSTR pwszICMMatcher = (PWSTR) szICMMatcher; ULONG cjSize; ICMAPI(("gdi32: UpdateICMRegKeyA\n")); if (Reserved != 0) { GdiSetLastError(ERROR_INVALID_PARAMETER); return(FALSE); } switch (Command) { case ICM_ADDPROFILE: case ICM_DELETEPROFILE: case ICM_QUERYPROFILE: case ICM_REGISTERICMATCHER: // // szFileName should be presented. // if (szFileName) { // // szFileName points to ansi string, just convert to Unicode. // cjSize = lstrlenA(szFileName)+1; pwszFileName = LOCALALLOC((cjSize)*sizeof(WCHAR)); if (pwszFileName == NULL) { GdiSetLastError(ERROR_NOT_ENOUGH_MEMORY); return (bRet); } vToUnicodeN(pwszFileName,cjSize,szFileName,cjSize); } else { GdiSetLastError(ERROR_INVALID_PARAMETER); bError = TRUE; } break; case ICM_QUERYMATCH: // // szFileName should be presented. // if (szFileName) { // // szFileName points to DEVMODEA structure, convert it to DEVMODEW // pwszFileName = (PWSTR) GdiConvertToDevmodeW((DEVMODEA *)szFileName); } else { GdiSetLastError(ERROR_INVALID_PARAMETER); bError = TRUE; } break; case ICM_SETDEFAULTPROFILE: GdiSetLastError(ERROR_CALL_NOT_IMPLEMENTED); bError = TRUE; break; case ICM_UNREGISTERICMATCHER: // // Nothing to convert to Unicode. // ASSERTGDI(szFileName==NULL,"UpdateICMRegKeyA():szFileName is not null\n"); break; default: WARNING("GDI:UpdateICMRegKeyA():Command is invalid\n"); GdiSetLastError(ERROR_INVALID_PARAMETER); bError = TRUE; break; } if (!bError) { // // Call W version. // bRet = UpdateICMRegKeyW(Reserved,pwszICMMatcher,pwszFileName,Command); } if (pwszFileName) { LOCALFREE(pwszFileName); } return(bRet); } /******************************Public*Routine******************************\ * GetDeviceGammaRamp * * Arguments: * * hdc * lpGammaRamp * * Return Value: * * Status * * History: * * 5-Jun-1996 -by- Mark Enstrom [marke] * \**************************************************************************/ BOOL WINAPI GetDeviceGammaRamp( HDC hdc, LPVOID lpGammaRamp ) { BOOL bRet = FALSE; ICMAPI(("gdi32: GetDeviceGammaRamp\n")); if (lpGammaRamp == NULL) { GdiSetLastError(ERROR_INVALID_PARAMETER); } else { // // Call kernel to get current Gamma ramp array for this DC. // bRet = NtGdiGetDeviceGammaRamp(hdc,lpGammaRamp); } return(bRet); } /******************************Public*Routine******************************\ * SetDeviceGammaRamp * * Arguments: * * hdc * lpGammaRamp * * Return Value: * * Status * * History: * * 5-Jun-1996 -by- Mark Enstrom [marke] * \**************************************************************************/ BOOL WINAPI SetDeviceGammaRamp( HDC hdc, LPVOID lpGammaRamp ) { BOOL bRet = FALSE; ICMAPI(("gdi32: SetDeviceGammaRamp\n")); if (lpGammaRamp == NULL) { GdiSetLastError(ERROR_INVALID_PARAMETER); } else { // // Call kernel to set new Gamma ramp array for this DC. // bRet = NtGdiSetDeviceGammaRamp(hdc,lpGammaRamp); } return(bRet); } /******************************Public*Routine******************************\ * ColorCorrectPalette * * If this is not the default palette and ICM is turned on in the DC * then translate the specified palette entries according to the color * transform in the DC * * Arguments: * * hdc - DC handle * hpal - PALETTE handle * FirsrEntry - first entry in palette to translate * NumberOfEntries - number of entries to translate * * Return Value: * * Status * * History: * * Write it: * 13-Feb-1997 -by- Hideyuki Nagase [hideyukn] * \**************************************************************************/ BOOL META WINAPI ColorCorrectPalette( HDC hdc, HPALETTE hpal, ULONG FirstEntry, ULONG NumberOfEntries ) { BOOL bStatus = FALSE; PDC_ATTR pdcattr = NULL; ICMAPI(("gdi32: ColorCorrectPalette\n")); // // Parameter check (max entry of log palette is 0x65536) // if ((hdc == NULL) || (hpal == NULL) || (NumberOfEntries == 0) || (NumberOfEntries > 65536) || (FirstEntry >= 65536) || (65536 - NumberOfEntries < FirstEntry)) { GdiSetLastError(ERROR_INVALID_PARAMETER); return (FALSE); } // // default palette could not be changed... // if (hpal != (HPALETTE)GetStockObject(DEFAULT_PALETTE)) { // // metafile call // if (IS_ALTDC_TYPE(hdc)) { PLDC pldc; if (IS_METADC16_TYPE(hdc)) return(bStatus); DC_PLDC(hdc,pldc,bStatus); if (pldc->iType == LO_METADC) { if (!MF_ColorCorrectPalette(hdc,hpal,FirstEntry,NumberOfEntries)) { return(FALSE); } } } PSHARED_GET_VALIDATE(pdcattr,hdc,DC_TYPE); if (pdcattr) { // // Load external ICM dlls // LOAD_ICMDLL(FALSE); if (IS_ICM_HOST(pdcattr->lIcmMode)) { if (bNeedTranslateColor(pdcattr)) { PPALETTEENTRY ppalEntrySrc = NULL; PPALETTEENTRY ppalEntryDst = NULL; ULONG NumEntriesRetrieved = 0; // // Make sure palette can be color corrected, get requested entries // ULONG Index; ppalEntrySrc = LOCALALLOC((NumberOfEntries * sizeof(PALETTEENTRY)) * 2); if (ppalEntrySrc == NULL) { WARNING("ColorCorrectPalette: ppalEntry = NULL\n"); GdiSetLastError(ERROR_NOT_ENOUGH_MEMORY); return(bStatus); } NumEntriesRetrieved = NtGdiColorCorrectPalette(hdc, hpal, FirstEntry, NumberOfEntries, ppalEntrySrc, ColorPaletteQuery); if (NumEntriesRetrieved > 0) { ppalEntryDst = ppalEntrySrc + NumberOfEntries; // // Translate palette entry colors // IcmTranslatePaletteEntry(hdc,pdcattr,ppalEntrySrc,ppalEntryDst,NumEntriesRetrieved); // // set new palette entries // NumEntriesRetrieved = NtGdiColorCorrectPalette(hdc, hpal, FirstEntry, NumEntriesRetrieved, ppalEntryDst, ColorPaletteSet); if (NumEntriesRetrieved > 0) { bStatus = TRUE; } } else { GdiSetLastError(ERROR_INVALID_PARAMETER); } LOCALFREE(ppalEntrySrc); } else { // // Don't need to translate color. // bStatus = TRUE; } } else if (IS_ICM_DEVICE(pdcattr->lIcmMode)) { // // for device ICM, don't need to do anything. // bStatus = TRUE; } else { WARNING("ColorCorrectPalette():ICM mode is not enabled\n"); GdiSetLastError(ERROR_ICM_NOT_ENABLED); } } else { GdiSetLastError(ERROR_INVALID_PARAMETER); } } else { GdiSetLastError(ERROR_INVALID_PARAMETER); } return bStatus; } /******************************Public*Routine******************************\ * IcmTranslateColorObjects - called when there is a change in ICM color transfrom * state * * Arguments: * * hdc - input DC * pdcattr - DC's attrs * * Return Value: * * status * * History: * * Rewrite it: * 13-Feb-1997 -by- Hideyuki Nagase [hideyukn] * Write it: * 9-Jul-1996 -by- Mark Enstrom [marke] * \**************************************************************************/ BOOL IcmTranslateColorObjects( HDC hdc, PDC_ATTR pdcattr, BOOL bICMEnable ) { BOOL bStatus = TRUE; COLORREF OldColor; COLORREF NewColor; ICMAPI(("gdi32: IcmTranslateColorObjects\n")); // // Invalidate IcmPenColor/IcmBrushColor // pdcattr->ulDirty_ &= ~(ICM_PEN_TRANSLATED | ICM_BRUSH_TRANSLATED); if (bICMEnable) { if(bNeedTranslateColor(pdcattr)) { if (GetColorTransformInDC(pdcattr) == NULL) { WARNING("Error in IcmTranslateColorObjects: called when hcmXform == NULL"); return FALSE; } // // translate Foreground to new icm mode if not paletteindex // if (!(pdcattr->ulForegroundClr & 0x01000000)) { OldColor = pdcattr->ulForegroundClr; bStatus = IcmTranslateCOLORREF(hdc, pdcattr, OldColor, &NewColor, ICM_FORWARD); if (bStatus) { pdcattr->crForegroundClr = NewColor; } else { pdcattr->crForegroundClr = OldColor; } } // // translate Background to new icm mode if not paletteindex // if (!(pdcattr->ulBackgroundClr & 0x01000000)) { OldColor = pdcattr->ulBackgroundClr; bStatus = IcmTranslateCOLORREF(hdc, pdcattr, OldColor, &NewColor, ICM_FORWARD); if (bStatus) { pdcattr->crBackgroundClr = NewColor; } else { pdcattr->crBackgroundClr = OldColor; } } // // translate DCBrush to new icm mode if not paletteindex // if (!(pdcattr->ulDCBrushClr & 0x01000000)) { OldColor = pdcattr->ulDCBrushClr; bStatus = IcmTranslateCOLORREF(hdc, pdcattr, OldColor, &NewColor, ICM_FORWARD); if (bStatus) { pdcattr->crDCBrushClr = NewColor; } else { pdcattr->crDCBrushClr = OldColor; } } // // translate DCPen to new icm mode if not paletteindex // if (!(pdcattr->ulDCPenClr & 0x01000000)) { OldColor = pdcattr->ulDCPenClr; bStatus = IcmTranslateCOLORREF(hdc, pdcattr, OldColor, &NewColor, ICM_FORWARD); if (bStatus) { pdcattr->crDCPenClr = NewColor; } else { pdcattr->crDCPenClr = OldColor; } } // // set icm color of selected logical brush // IcmTranslateBrushColor(hdc,pdcattr,(HANDLE)pdcattr->hbrush); // // set icm color of selected logical pen/extpen // if (LO_TYPE(pdcattr->hpen) == LO_EXTPEN_TYPE) { IcmTranslateExtPenColor(hdc,pdcattr,(HANDLE)pdcattr->hpen); } else { IcmTranslatePenColor(hdc,pdcattr,(HANDLE)pdcattr->hpen); } } } else { PBRUSHATTR pbrushattr; // // ICM is off, restore colors (non device icm only) // pdcattr->crForegroundClr = pdcattr->ulForegroundClr & 0x13ffffff; pdcattr->crBackgroundClr = pdcattr->ulBackgroundClr & 0x13ffffff; pdcattr->crDCBrushClr = pdcattr->ulDCBrushClr & 0x13ffffff; pdcattr->crDCPenClr = pdcattr->ulDCPenClr & 0x13ffffff; // // set icm color of selected logical brush // PSHARED_GET_VALIDATE(pbrushattr,pdcattr->hbrush,BRUSH_TYPE); if (pbrushattr) { pdcattr->IcmBrushColor = pbrushattr->lbColor; } // // set icm color of selected logical pen // PSHARED_GET_VALIDATE(pbrushattr,pdcattr->hpen,BRUSH_TYPE); if (pbrushattr) { pdcattr->IcmPenColor = pbrushattr->lbColor; } } // // set DC dirty flags to force re-realization of color objects // pdcattr->ulDirty_ |= (DIRTY_BRUSHES|DC_BRUSH_DIRTY|DC_PEN_DIRTY); return(bStatus); } /******************************Public*Routine******************************\ * IcmCreateTemporaryColorProfile() * * History: * * Wrote it: * 7.May.1997 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ BOOL IcmCreateTemporaryColorProfile( LPWSTR TemporaryColorProfile, LPBYTE ProfileData, DWORD ProfileDataSize ) { BOOL bRet = FALSE; WCHAR TempPath[MAX_PATH]; WCHAR TempFile[MAX_PATH]; // // make temp file for profile, include name in lcspw // if (GetTempPathW(MAX_PATH,(LPWSTR)TempPath)) { BOOL bPathOK = TRUE; if (TemporaryColorProfile[0] != UNICODE_NULL) { wcscpy(TempFile,TempPath); wcscat(TempFile,TemporaryColorProfile); } else { bPathOK = GetTempFileNameW((LPWSTR)TempPath,L"ICM",0,(LPWSTR)TempFile); } if (bPathOK) { if (ProfileDataSize == 0) { // // Nothing needs to save, just return with created filename // lstrcpyW(TemporaryColorProfile,TempFile); bRet = TRUE; } else { HANDLE hFile = CreateFileW((LPWSTR)TempFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile != INVALID_HANDLE_VALUE) { ULONG ulWritten; if (WriteFile(hFile,ProfileData,ProfileDataSize,&ulWritten,NULL)) { // // Put the created file name into LOGCOLORSPACE // lstrcpyW(TemporaryColorProfile,TempFile); // // Close file handle // CloseHandle(hFile); // // Everything O.K. // bRet = TRUE; } else { ICMWRN(("IcmCreateTemporaryColorProfile(): Failed WriteFile\n")); // // Failed, close handle and delete it. // CloseHandle(hFile); DeleteFileW(TempFile); } } else { ICMWRN(("IcmCreateTemporaryColorProfile(): Failed CreateFile\n")); } } } else { ICMWRN(("IcmCreateTemporaryColorProfile(): Failed CreateTempFileName\n")); } } else { ICMWRN(("IcmCreateTemporayColorProfile(): Failed GetTempPath\n")); } return (bRet); } /******************************Public*Routine******************************\ * IcmGetBitmapColorSpace() * * History: * * Wrote it: * 13.March.1997 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ BOOL IcmGetBitmapColorSpace( LPBITMAPINFO pbmi, LPLOGCOLORSPACEW plcspw, PPROFILE pColorProfile, PDWORD pdwFlags ) { BOOL bBitmapColorSpace = FALSE; ICMAPI(("gdi32: IcmGetBitmapColorSpace\n")); // // Init output buffers with zero. // *pdwFlags = 0; ZeroMemory(plcspw,sizeof(LOGCOLORSPACE)); ZeroMemory(pColorProfile,sizeof(PROFILE)); // // check for BITMAPV4 OR BITMAPV5 // if (pbmi->bmiHeader.biSize == sizeof(BITMAPV4HEADER)) { PBITMAPV4HEADER pbmih4 = (PBITMAPV4HEADER)&pbmi->bmiHeader; ICMMSG(("IcmGetBitmapColorSpace: BITMAPV4HEADER\n")); // // if CIEXYZ endpoints are given, create a new color transform // to use. // plcspw->lcsSignature = LCS_SIGNATURE; plcspw->lcsVersion = 0x400; plcspw->lcsSize = sizeof(LOGCOLORSPACEW); plcspw->lcsCSType = pbmih4->bV4CSType; plcspw->lcsIntent = LCS_GM_IMAGES; plcspw->lcsEndpoints = pbmih4->bV4Endpoints; plcspw->lcsGammaRed = pbmih4->bV4GammaRed; plcspw->lcsGammaGreen = pbmih4->bV4GammaGreen; plcspw->lcsGammaBlue = pbmih4->bV4GammaBlue; if (pbmih4->bV4CSType == LCS_CALIBRATED_RGB) { ICMMSG(("IcmGetBitmapColorSpace: BITMAPv4 CALIBRATED RGB\n")); ICMMSG((" lcspw.lcsCSType = %x\n",pbmih4->bV4CSType)); ICMMSG((" lcspw.lcsIntent = %d\n",LCS_GM_IMAGES)); ICMMSG((" lcspw.lcsGammaRed = %d\n",pbmih4->bV4GammaRed)); ICMMSG((" lcspw.lcsGammaGreen = %d\n",pbmih4->bV4GammaGreen)); // // There is no profile specified. // plcspw->lcsFilename[0] = UNICODE_NULL; bBitmapColorSpace = TRUE; } else // any other CSType { DWORD dwSize = MAX_PATH; ICMMSG(("IcmGetBitmapColorSpace: BITMAPv4 lcsType = %x\n",pbmih4->bV4CSType)); // // Load external ICM dlls. // LOAD_ICMDLL((int)FALSE); // // Get corresponding colorspace profile. // bBitmapColorSpace = (*fpGetStandardColorSpaceProfileW)(NULL, pbmih4->bV4CSType, plcspw->lcsFilename, &dwSize); } } else if (pbmi->bmiHeader.biSize == sizeof(BITMAPV5HEADER)) { PBITMAPV5HEADER pbmih5 = (PBITMAPV5HEADER)&pbmi->bmiHeader; ICMMSG(("IcmGetBitmapColorSpace: BITMAPV5HEADER\n")); ICMMSG((" lcspw.lcsCSType = %x\n",pbmih5->bV5CSType)); ICMMSG((" lcspw.lcsIntent = %d\n",pbmih5->bV5Intent)); // // fill in common logcolorspace info // plcspw->lcsSignature = LCS_SIGNATURE; plcspw->lcsVersion = 0x400; plcspw->lcsSize = sizeof(LOGCOLORSPACEW); plcspw->lcsCSType = pbmih5->bV5CSType; plcspw->lcsIntent = pbmih5->bV5Intent; plcspw->lcsEndpoints = pbmih5->bV5Endpoints; plcspw->lcsGammaRed = pbmih5->bV5GammaRed; plcspw->lcsGammaGreen = pbmih5->bV5GammaGreen; plcspw->lcsGammaBlue = pbmih5->bV5GammaBlue; // // validate Intent // if ((plcspw->lcsIntent != LCS_GM_BUSINESS) && (plcspw->lcsIntent != LCS_GM_GRAPHICS) && (plcspw->lcsIntent != LCS_GM_IMAGES) && (plcspw->lcsIntent != LCS_GM_ABS_COLORIMETRIC)) { // // Intent is invalid, just use LCS_GM_IMAGES // plcspw->lcsIntent = LCS_GM_IMAGES; } // // If a profile is linked or embedded then use it. // otherwise: // If CIEXYZ endpoints are given, create a new color transform // to use. // if (pbmih5->bV5CSType == PROFILE_EMBEDDED) { PVOID pProfileEmbedded = NULL; ICMMSG(("IcmGetBitmapColorSpace: Embedded profile\n")); // // Update CSType to Calibrated_RGB from Profile_Embedded // plcspw->lcsCSType = LCS_CALIBRATED_RGB; // // Get pointer to embeded profile. // pProfileEmbedded = (PVOID)((PBYTE)pbmi + pbmih5->bV5ProfileData); if (pProfileEmbedded) { // // Fill up PROFILE structure for "on memory" profile. // pColorProfile->dwType = PROFILE_MEMBUFFER; pColorProfile->pProfileData = pProfileEmbedded; pColorProfile->cbDataSize = pbmih5->bV5ProfileSize; // // Mark as on memory profile. // *pdwFlags |= ON_MEMORY_PROFILE; } else { // // This bitmap marked as "Embedded", but no profile there, just go with LOGCOLORSPACE. // ICMWRN(("IcmGetBitmapColorSpace(): Embedded profile, but no profile embedded\n")); } bBitmapColorSpace = TRUE; } else if (pbmih5->bV5CSType == PROFILE_LINKED) { WCHAR LinkedProfile[MAX_PATH]; ICMMSG(("IcmGetBitmapColorSpace(): linked profile\n")); // // Update CSType to Calibrated_RGB from Profile_Linked // plcspw->lcsCSType = LCS_CALIBRATED_RGB; // // Convert profile name to Unicode. // vToUnicodeN( LinkedProfile, MAX_PATH, (CONST CHAR *)((PBYTE)pbmih5 + pbmih5->bV5ProfileData), strlen((CONST CHAR *)((PBYTE)pbmih5 + pbmih5->bV5ProfileData))+1 ); // // Normalize profile path. // BuildIcmProfilePath(LinkedProfile,plcspw->lcsFilename,MAX_PATH); ICMMSG(("lcspw.lcsFilename = %ws\n",plcspw->lcsFilename)); bBitmapColorSpace = TRUE; } else if (pbmih5->bV5CSType == LCS_CALIBRATED_RGB) { ICMMSG(("IcmGetBitmapColorSpace(): calibrated RGB\n")); ICMMSG((" lcspw.lcsGammaRed = %d\n",pbmih5->bV5GammaRed)); ICMMSG((" lcspw.lcsGammaGreen = %d\n",pbmih5->bV5GammaGreen)); ICMMSG((" lcspw.lcsGammaBlue = %d\n",pbmih5->bV5GammaBlue)); // // There is profile specified. // plcspw->lcsFilename[0] = UNICODE_NULL; bBitmapColorSpace = TRUE; } else // any other CSType { DWORD dwSize = MAX_PATH; ICMMSG(("IcmGetBitmapColorSpace: BITMAPv5 lcsType = %x\n",pbmih5->bV5CSType)); // // Load external ICM dlls. // LOAD_ICMDLL((int)FALSE); // // Get corresponding colorspace profile. // bBitmapColorSpace = (*fpGetStandardColorSpaceProfileW)(NULL, pbmih5->bV5CSType, plcspw->lcsFilename, &dwSize); } } else { ICMMSG(("IcmGetBitmapColorSpace(): no color space specified\n")); } return (bBitmapColorSpace); } /******************************Public*Routine******************************\ * IcmGetTranslateInfo() * * History: * * Wrote it: * 13.March.1997 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ BOOL IcmGetTranslateInfo( PDC_ATTR pdcattr, LPBITMAPINFO pbmi, PVOID pvBits, ULONG cjBits, DWORD dwNumScan, PDIB_TRANSLATE_INFO pdti, DWORD dwFlags ) { BMFORMAT ColorType; PVOID pOutput; ULONG nColors; ULONG cjTranslateBits; PBITMAPINFO pbmiNew = NULL; BOOL bCMYKColor = IS_CMYK_COLOR(pdcattr->lIcmMode); ICMAPI(("gdi32: IcmGetTranslateInfo\n")); ICMAPI(("-----: CMYK Color = %s\n",(bCMYKColor ? "Yes" : "No"))); ICMAPI(("-----: Backward = %s\n",((dwFlags & ICM_BACKWARD) ? "Yes" : "No"))); UNREFERENCED_PARAMETER(dwFlags); if (dwNumScan == (DWORD)-1) { dwNumScan = ABS(pbmi->bmiHeader.biHeight); } // // determine whether this is a palettized DIB // if (pbmi->bmiHeader.biCompression == BI_RGB) { if (pbmi->bmiHeader.biBitCount > 8) { // // we will translate bitmap, pvBits should be presented. // if (pvBits == NULL) { return (FALSE); } // // must translate DIB, standard 16,24,32 format // if (pbmi->bmiHeader.biBitCount == 16) { ICMMSG(("IcmGetTranslateInfo():BI_RGB 16 bpp\n")); ColorType = BM_x555RGB; } else if (pbmi->bmiHeader.biBitCount == 24) { ICMMSG(("IcmGetTranslateInfo():BI_RGB 24 bpp\n")); ColorType = BM_RGBTRIPLETS; } else if (pbmi->bmiHeader.biBitCount == 32) { ICMMSG(("IcmGetTranslateInfo():BI_RGB 32 bpp\n")); ColorType = BM_xRGBQUADS; } else { ICMMSG(("IcmGetTranslateInfo():BI_RGB Invalid bpp\n")); return (FALSE); } // // Fill up source bitmap information. // pdti->SourceWidth = pbmi->bmiHeader.biWidth; pdti->SourceHeight = dwNumScan; pdti->SourceBitCount = pbmi->bmiHeader.biBitCount; pdti->SourceColorType = ColorType; pdti->pvSourceBits = pvBits; pdti->cjSourceBits = cjBits; // // CMYK Color ? // if (bCMYKColor) { pdti->TranslateType = (TRANSLATE_BITMAP|TRANSLATE_HEADER); // // CMYK bitmap color bitmap is 32 BPP (4 bytes per pixel). // cjTranslateBits = (pdti->SourceWidth * 4) * pdti->SourceHeight; // // We need new bitmap info header for CMYK. // pbmiNew = LOCALALLOC(pbmi->bmiHeader.biSize); if (!pbmiNew) { WARNING("IcmGetTranslateInfo():LOCALALLOC() failed\n"); return (FALSE); } // // Make a copy of source, first. // RtlCopyMemory(pbmiNew,pbmi,pbmi->bmiHeader.biSize); // // Update header for CMYK color. // pbmiNew->bmiHeader.biBitCount = 32; pbmiNew->bmiHeader.biCompression = BI_CMYK; pbmiNew->bmiHeader.biSizeImage = cjTranslateBits; pbmiNew->bmiHeader.biClrUsed = 0; pbmiNew->bmiHeader.biClrImportant = 0; // // We have new BITMAPINFO header // pdti->TranslateBitmapInfo = pbmiNew; pdti->TranslateBitmapInfoSize = pbmi->bmiHeader.biSize; // // Translate bitmap color type is CMYK. // pdti->TranslateColorType = BM_KYMCQUADS; } else { pdti->TranslateType = TRANSLATE_BITMAP; // // Translate bitmap size is same as source. // cjTranslateBits = cjBits; // // Translate bitmap color type is same source. // pdti->TranslateColorType = ColorType; pdti->TranslateBitmapInfo = NULL; pdti->TranslateBitmapInfoSize = 0; } // // Allocate translate buffer // pOutput = LOCALALLOC(cjTranslateBits); if (!pOutput) { if (pbmiNew) { LOCALFREE(pbmiNew); } WARNING("IcmGetTranslateInfo():LOCALALLOC() failed\n"); return (FALSE); } // // Setup translation buffer. // pdti->pvTranslateBits = pOutput; pdti->cjTranslateBits = cjTranslateBits; } else if ( ((pbmi->bmiHeader.biBitCount == 8) || (pbmi->bmiHeader.biBitCount == 4) || (pbmi->bmiHeader.biBitCount == 1)) ) { ULONG nMaxColors = (1 << pbmi->bmiHeader.biBitCount); ICMMSG(("IcmGetTranslateInfo():BI_RGB 8/4/1 bpp\n")); // // validate number of colors // nColors = pbmi->bmiHeader.biClrUsed; if ((nColors == 0) || (nColors > nMaxColors)) { nColors = nMaxColors; } // // Allocate new bitmap info header and color table. // pbmiNew = LOCALALLOC(pbmi->bmiHeader.biSize + (nColors * sizeof(RGBQUAD))); if (!pbmiNew) { WARNING("IcmGetTranslateInfo():LOCALALLOC() failed\n"); return (FALSE); } // // Copy source BITMAPINFO to new // RtlCopyMemory(pbmiNew,pbmi,pbmi->bmiHeader.biSize); pdti->TranslateType = TRANSLATE_HEADER; pdti->SourceColorType = BM_xRGBQUADS; pdti->SourceWidth = nColors; pdti->SourceHeight = 1; pdti->SourceBitCount = sizeof(RGBQUAD); pdti->TranslateBitmapInfo = pbmiNew; pdti->TranslateBitmapInfoSize = 0; // size will not change from original pdti->pvSourceBits = (PBYTE)pbmi + pbmi->bmiHeader.biSize; pdti->cjSourceBits = nColors; pdti->pvTranslateBits = (PBYTE)pbmiNew + pbmiNew->bmiHeader.biSize; pdti->cjTranslateBits = nColors * sizeof(RGBQUAD); if (bCMYKColor) { pdti->TranslateColorType = BM_KYMCQUADS; // // Update header for CMYK color. // pbmiNew->bmiHeader.biCompression = BI_CMYK; } else { pdti->TranslateColorType = BM_xRGBQUADS; } } else { ICMWRN(("IcmGetTranslateInfo: Illegal biBitCount\n")); return (FALSE); } } else if ( (pbmi->bmiHeader.biCompression == BI_BITFIELDS) && ( (pbmi->bmiHeader.biBitCount == 16) || (pbmi->bmiHeader.biBitCount == 32) ) ) { PULONG pulColors = (PULONG)pbmi->bmiColors; ICMMSG(("IcmGetTranslateInfo():BI_BITFIELDS 16/32 bpp\n")); // // we will translate bitmap, pvBits should be presented. // if (pvBits == NULL) { return (FALSE); } if (pbmi->bmiHeader.biBitCount == 32) { if ((pulColors[0] == 0x0000ff) && /* Red */ (pulColors[1] == 0x00ff00) && /* Green */ (pulColors[2] == 0xff0000)) /* Blue */ { ColorType = BM_xBGRQUADS; } else if ((pulColors[0] == 0xff0000) && /* Red */ (pulColors[1] == 0x00ff00) && /* Green */ (pulColors[2] == 0x0000ff)) /* Blue */ { ColorType = BM_xRGBQUADS; } else { ICMWRN(("IcmGetTranslateInfo: Illegal Bitfields fields for 32 bpp\n")); return (FALSE); } } else { if ((pulColors[0] == 0x007c00) && (pulColors[1] == 0x0003e0) && (pulColors[2] == 0x00001f)) { ColorType = BM_x555RGB; } else if ((pulColors[0] == 0x00f800) && (pulColors[1] == 0x0007e0) && (pulColors[2] == 0x00001f)) { ColorType = BM_565RGB; } else { ICMWRN(("IcmGetTranslateInfo: Illegal Bitfields fields for 16 bpp\n")); return (FALSE); } } // // Fill up source bitmap information. // pdti->SourceWidth = pbmi->bmiHeader.biWidth; pdti->SourceHeight = dwNumScan; pdti->SourceBitCount = pbmi->bmiHeader.biBitCount; pdti->SourceColorType = ColorType; pdti->pvSourceBits = pvBits; pdti->cjSourceBits = cjBits; // // CMYK Color ? // if (bCMYKColor) { pdti->TranslateType = (TRANSLATE_BITMAP|TRANSLATE_HEADER); // // CMYK bitmap color bitmap is 32 BPP (4 bytes per pixel). // cjTranslateBits = (pdti->SourceWidth * 4) * pdti->SourceHeight; // // We need new bitmap info header for CMYK. // pbmiNew = LOCALALLOC(pbmi->bmiHeader.biSize); if (!pbmiNew) { WARNING("IcmGetTranslateInfo():LOCALALLOC() failed\n"); return (FALSE); } // // Make a copy of source, first. // RtlCopyMemory(pbmiNew,pbmi,pbmi->bmiHeader.biSize); // // Update header for CMYK color. // pbmiNew->bmiHeader.biBitCount = 32; pbmiNew->bmiHeader.biCompression = BI_CMYK; pbmiNew->bmiHeader.biSizeImage = cjTranslateBits; pbmiNew->bmiHeader.biClrUsed = 0; pbmiNew->bmiHeader.biClrImportant = 0; // // We have new BITMAPINFO header // pdti->TranslateBitmapInfo = pbmiNew; pdti->TranslateBitmapInfoSize = pbmi->bmiHeader.biSize; // // Translate bitmap color type is CMYK. // pdti->TranslateColorType = BM_KYMCQUADS; } else { pdti->TranslateType = TRANSLATE_BITMAP; // // Translate bitmap size is same as source. // cjTranslateBits = cjBits; // // Translate bitmap color type is same source. // pdti->TranslateColorType = ColorType; pdti->TranslateBitmapInfo = NULL; pdti->TranslateBitmapInfoSize = 0; } // // Allocate translate buffer // pOutput = LOCALALLOC(cjTranslateBits); if (!pOutput) { if (pbmiNew) { LOCALFREE(pbmiNew); } WARNING("IcmGetTranslateInfo():LOCALALLOC() failed\n"); return (FALSE); } // // Setup translation buffer. // pdti->pvTranslateBits = pOutput; pdti->cjTranslateBits = cjTranslateBits; } else if ( (pbmi->bmiHeader.biCompression == BI_RLE8) || (pbmi->bmiHeader.biCompression == BI_RLE4) ) { // // translate 256 for RLE8, 16 for RLE4 entry color palette // ULONG nMaxColors; if (pbmi->bmiHeader.biCompression == BI_RLE8) { ICMMSG(("IcmGetTranslateInfo():BI_RLE 8\n")); nMaxColors = 256; } else { ICMMSG(("IcmGetTranslateInfo():BI_RLE 4\n")); nMaxColors = 16; } // // validate number of colors // nColors = pbmi->bmiHeader.biClrUsed; if ((nColors == 0) || (nColors > nMaxColors)) { nColors = nMaxColors; } // // Allocate new bitmap info header and color table. // pbmiNew = LOCALALLOC(pbmi->bmiHeader.biSize + (nColors * sizeof(RGBQUAD))); if (!pbmiNew) { WARNING("IcmGetTranslateInfo():LOCALALLOC() failed\n"); return (FALSE); } // // Copy source BITMAPINFO to new // RtlCopyMemory(pbmiNew,pbmi,pbmi->bmiHeader.biSize); pdti->TranslateType = TRANSLATE_HEADER; pdti->SourceColorType = BM_xRGBQUADS; pdti->SourceWidth = nColors; pdti->SourceHeight = 1; pdti->SourceBitCount = sizeof(RGBQUAD); pdti->TranslateBitmapInfo = pbmiNew; pdti->TranslateBitmapInfoSize = 0; // size will not change from original pdti->pvSourceBits = (PBYTE)pbmi + pbmi->bmiHeader.biSize; pdti->cjSourceBits = nColors; pdti->pvTranslateBits = (PBYTE)pbmiNew + pbmiNew->bmiHeader.biSize; pdti->cjTranslateBits = nColors * sizeof(RGBQUAD); if (bCMYKColor) { pdti->TranslateColorType = BM_KYMCQUADS; // // Update header for CMYK color. // if (pbmi->bmiHeader.biCompression == BI_RLE8) { ICMMSG(("IcmGetTranslateInfo():BI_CMYKRLE 8\n")); pbmiNew->bmiHeader.biCompression = BI_CMYKRLE8; } else { ICMMSG(("IcmGetTranslateInfo():BI_CMYKRLE 4\n")); pbmiNew->bmiHeader.biCompression = BI_CMYKRLE4; } } else { pdti->TranslateColorType = BM_xRGBQUADS; } } else { WARNING("IcmGetTranslateInfo():Illegal bitmap format\n"); return (FALSE); } return (TRUE); } /******************************Public*Routine******************************\ * IcmTranslateDIB * * History: * * Rewrote it for CMYK color support: * 13-Mar-1997 -by- Hideyuki Nagase [hideyukn] * Wrote it: * 3-Jul-1996 -by- Mark Enstrom [marke] * \**************************************************************************/ BOOL IcmTranslateDIB( HDC hdc, PDC_ATTR pdcattr, ULONG cjBits, PVOID pBitsIn, PVOID *ppBitsOut, PBITMAPINFO pbmi, PBITMAPINFO *ppbmiNew, DWORD *pcjbmiNew, DWORD dwNumScan, UINT iUsage, DWORD dwFlags, PCACHED_COLORSPACE *ppColorSpace, // used only for device ICM case. PCACHED_COLORTRANSFORM *ppCXform // used only for device ICM case. ) { // // translate DIB or color table // BOOL bStatus = TRUE; DWORD dwColorSpaceFlags = 0; PCACHED_COLORSPACE pBitmapColorSpace = NULL; LOGCOLORSPACEW LogColorSpace; PROFILE ColorProfile; DIB_TRANSLATE_INFO TranslateInfo; PCACHED_COLORTRANSFORM pCXform; PGDI_ICMINFO pIcmInfo; UNREFERENCED_PARAMETER(iUsage); ICMAPI(("gdi32: IcmTranslateDIB\n")); // // Parameter check // if (pbmi == NULL) { WARNING("gdi32: IcmTranslateDIB(): pbmi is NULL\n"); return FALSE; } // // Load external ICM dlls. // LOAD_ICMDLL(FALSE); // // Initialize ICMINFO // if ((pIcmInfo = GET_ICMINFO(pdcattr)) == NULL) { WARNING("gdi32: IcmTranslateDIB: Can't init icm info\n"); return FALSE; } // // Initialized returned info. // if (ppColorSpace) *ppColorSpace = NULL; if (ppCXform) *ppCXform = NULL; // // Get LOGCOLORSPACE from bitmap if specified. // if (IcmGetBitmapColorSpace(pbmi,&LogColorSpace,&ColorProfile,&dwColorSpaceFlags)) { // // Find ColorSpace from cache. // pBitmapColorSpace = IcmGetColorSpaceByColorSpace( (HGDIOBJ)hdc, &LogColorSpace, &ColorProfile, dwColorSpaceFlags); if (pBitmapColorSpace == NULL) { // // Create new cache. // pBitmapColorSpace = IcmCreateColorSpaceByColorSpace( (HGDIOBJ)hdc, &LogColorSpace, &ColorProfile, dwColorSpaceFlags); } } // // Create Color Transform, if nessesary. // if (IS_ICM_DEVICE(pdcattr->lIcmMode)) { // // just create a new hcmXform for use with BITMAPV4 AND BITMAPV5s. // if (pBitmapColorSpace) { ICMMSG(("IcmTranslateDIB():Bitmap color space used for DEVICE ICM\n")); if ((ppCXform != NULL) && (ppColorSpace != NULL)) { // // for DEVICE managed ICM, call device driver to create a temp xform // pCXform = IcmCreateColorTransform(hdc,pdcattr,pBitmapColorSpace,dwFlags); if (pCXform == NULL) { WARNING("IcmTranslateDIB():Fail to create temporay Xfrom with V4V5 Bitmap\n"); // // Failed to create color transfrom, release bitmap color space, // and null-color transform. // IcmReleaseColorSpace(NULL,pBitmapColorSpace,FALSE); bStatus = FALSE; } else { if (pCXform == IDENT_COLORTRANSFORM) { // // Source and destination color space are same, so no color transform is // required, and of course we don't need to keep bitmap color space. // IcmReleaseColorSpace(NULL,pBitmapColorSpace,FALSE); } else { // // Return to the color transform to callee... // (these should be deleted by callee) // *ppCXform = pCXform; *ppColorSpace = pBitmapColorSpace; } bStatus = TRUE; } } else { WARNING("IcmTranslateDIB():No device ICM will happen for this V4V5 Bitmap\n"); IcmReleaseColorSpace(NULL,pBitmapColorSpace,FALSE); bStatus = TRUE; } return (bStatus); } else { ICMMSG(("IcmTranslateDIB():DC color space used for DEVICE ICM\n")); // // We don't need to create new transform, just use the transform in DC. // return (TRUE); } } else if (IS_ICM_HOST(pdcattr->lIcmMode)) { HANDLE hcmXform = NULL; if (pBitmapColorSpace) { ICMMSG(("IcmTranslateDIB():Bitmap color space used for HOST ICM\n")); pCXform = IcmCreateColorTransform(hdc,pdcattr,pBitmapColorSpace,dwFlags); if ((pCXform == IDENT_COLORTRANSFORM) || (pCXform == NULL)) { // // unable or not nessesary to translate DIB // ICMWRN(("Bitmap V4 or V5: CreateColorTransform failed or ident.\n")); goto TranslateDIB_Cleanup; } else { hcmXform = pCXform->ColorTransform; } } else { ICMMSG(("IcmTranslateDIB():DC color space used for HOST ICM\n")); if (dwFlags & ICM_BACKWARD) { ICMMSG(("IcmTranslateDIB():Backward Color transform\n")); // // If there is cached handle, use that. // if (pIcmInfo->pBackCXform) { ICMMSG(("IcmTranslateDIB():Use cached transform for Backward Color transform\n")); hcmXform = pIcmInfo->pBackCXform->ColorTransform; } else { PCACHED_COLORTRANSFORM pCXform; ICMMSG(("IcmTranslateDIB():Create cached transform for Backward Color transform\n")); // // Create backward color transform. // pCXform = IcmCreateColorTransform(hdc, pdcattr, NULL, ICM_BACKWARD); if ((pCXform == NULL) || (pCXform == IDENT_COLORTRANSFORM)) { ICMWRN(("IcmTranslateDIB():ColorTransform is NULL or ident.\n")); goto TranslateDIB_Cleanup; } // // Cache created color transform. // pIcmInfo->pBackCXform = pCXform; // // We will delete this cached transform, when we don't need this anymore. // hcmXform = pCXform->ColorTransform; } } else { // // Use DC's colortransform // hcmXform = pdcattr->hcmXform; } } if (hcmXform == NULL) { // // if we don't have any colortransform, we will not translate anything. // just fail and let use original image. // ICMWRN(("IcmTranslateDIB():No colortransform, might be ident.\n")); goto TranslateDIB_Cleanup; } // // Get bitmap translate information. // bStatus = IcmGetTranslateInfo(pdcattr,pbmi,pBitsIn,cjBits,dwNumScan,&TranslateInfo,dwFlags); if (bStatus) { LONG nLineBytes = ((TranslateInfo.SourceWidth * TranslateInfo.SourceBitCount) + 7) / 8; bStatus = (*fpTranslateBitmapBits)( hcmXform, TranslateInfo.pvSourceBits, TranslateInfo.SourceColorType, TranslateInfo.SourceWidth, TranslateInfo.SourceHeight, ALIGN_DWORD(nLineBytes), TranslateInfo.pvTranslateBits, TranslateInfo.TranslateColorType, // 0, // We need pass 0 here, to let Kodak CMM works // NULL,0); if (bStatus) { // // Pass new bitmap and/or header to caller. // if (TranslateInfo.TranslateType & TRANSLATE_BITMAP) { if (ppBitsOut) { *ppBitsOut = TranslateInfo.pvTranslateBits; } else { // // Overwrite original (when input color and output color type is same) // if (TranslateInfo.SourceColorType == TranslateInfo.TranslateColorType) { RtlCopyMemory(TranslateInfo.pvSourceBits, TranslateInfo.pvTranslateBits, TranslateInfo.cjTranslateBits); } else { WARNING("IcmTranslateDIB():Input color != Output color\n"); } LOCALFREE(TranslateInfo.pvTranslateBits); } } if (TranslateInfo.TranslateType & TRANSLATE_HEADER) { if (ppbmiNew) { *ppbmiNew = TranslateInfo.TranslateBitmapInfo; } else { // // Overwrite original (when input color and output color type is same) // if (TranslateInfo.SourceColorType == TranslateInfo.TranslateColorType) { RtlCopyMemory(TranslateInfo.pvSourceBits, TranslateInfo.pvTranslateBits, TranslateInfo.cjTranslateBits); } else { WARNING("IcmTranslateDIB():Input color != Output color\n"); } LOCALFREE(TranslateInfo.TranslateBitmapInfo); } if (pcjbmiNew) { *pcjbmiNew = TranslateInfo.TranslateBitmapInfoSize; } } } else { WARNING("IcmTranslateDIB():Fail TranslateBitmapBits\n"); // // Free memory which allocated inside IcmGetTranslateInfo(). // if (TranslateInfo.TranslateType & TRANSLATE_BITMAP) { LOCALFREE(TranslateInfo.pvTranslateBits); } if (TranslateInfo.TranslateType & TRANSLATE_HEADER) { LOCALFREE(TranslateInfo.TranslateBitmapInfo); } } } TranslateDIB_Cleanup: // // Free temp transform and temp file // // Only delete hcmXform when it based on bitmap colorspace. // if (pBitmapColorSpace) { if (hcmXform) { IcmDeleteColorTransform(pCXform,FALSE); } IcmReleaseColorSpace(NULL,pBitmapColorSpace,FALSE); } } return(bStatus); } /******************************Public*Routine******************************\ * IcmGetFirstNonUsedColorTransform() * * History: * * Write it: * 12-Mar-1998 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ PCACHED_COLORTRANSFORM IcmGetFirstNonUsedColorTransform( VOID ) { PCACHED_COLORTRANSFORM pCXform = NULL; PLIST_ENTRY p; ICMAPI(("gdi32: IcmGetFirstNonUsedColorTransform\n")); ENTERCRITICALSECTION(&semColorTransformCache); p = ListCachedColorTransform.Flink; while(p != &ListCachedColorTransform) { pCXform = CONTAINING_RECORD(p,CACHED_COLORTRANSFORM,ListEntry); if (pCXform->cRef == 0) { ICMMSG(("IcmGetFirstNonUsedColorTransform():Find non-used color transform in cache !\n")); // // No one use this color transform at this moment. // break; } p = p->Flink; pCXform = NULL; } LEAVECRITICALSECTION(&semColorTransformCache); return (pCXform); } /******************************Public*Routine******************************\ * IcmGetColorTransform() * * History: * * Write it: * 21-Apr-1997 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ PCACHED_COLORTRANSFORM IcmGetColorTransform( HDC hdcRequest, PCACHED_COLORSPACE pSource, PCACHED_COLORSPACE pDestination, PCACHED_COLORSPACE pTarget, BOOL bNeedDeviceXform ) { PCACHED_COLORTRANSFORM pCXform = NULL; PLIST_ENTRY p; ICMAPI(("gdi32: IcmGetColorTransform\n")); ENTERCRITICALSECTION(&semColorTransformCache); p = ListCachedColorTransform.Flink; while(p != &ListCachedColorTransform) { pCXform = CONTAINING_RECORD(p,CACHED_COLORTRANSFORM,ListEntry); if (IcmSameColorSpace(pSource,pCXform->SourceColorSpace) && IcmSameColorSpace(pDestination,pCXform->DestinationColorSpace) && IcmSameColorSpace(pTarget,pCXform->TargetColorSpace)) { // // If callee needs device color tansform, // of course, we should return device color transform. // if ((bNeedDeviceXform ? 1 : 0) == ((pCXform->flInfo & DEVICE_COLORTRANSFORM) ? 1 : 0)) { // // if Cached color transform depends on specific DC, check it. // if ((pCXform->hdc == NULL) || (pCXform->hdc == hdcRequest)) { ICMMSG(("IcmGetColorTransform():Find in cache !\n")); // // Match !, use this color transform, increment ref. count // pCXform->cRef++; break; } } } p = p->Flink; pCXform = NULL; } LEAVECRITICALSECTION(&semColorTransformCache); return (pCXform); } /******************************Public*Routine******************************\ * IcmCreateColorTransform * * Decide whether to call the device driver or mscms.dll to delete a * color transform. * * Arguments: * * hdc * pdcattr * pLogColorSpaceW * * Return Value: * * handle of new transform * * History: * * Write it: * 24-Jan-1996 -by- Hideyuki Nagase [hideyukn] * \**************************************************************************/ PCACHED_COLORTRANSFORM IcmCreateColorTransform( HDC hdc, PDC_ATTR pdcattr, PCACHED_COLORSPACE pInputColorSpace, DWORD dwFlags ) { PCACHED_COLORTRANSFORM pCXform = NULL; PCACHED_COLORSPACE pSourceColorSpace = NULL; BOOL bDCSourceColorSpace = (pInputColorSpace == NULL ? TRUE : FALSE); BOOL bAnyNewColorSpace = FALSE; PGDI_ICMINFO pIcmInfo; ICMAPI(("gdi32: IcmCreateColorTransform\n")); ASSERTGDI(pdcattr != NULL,"IcmCreateColorTransform: pdcattr == NULL\n"); // // If this is Lazy color correction case, the destination surface // will have image in source color space, so the color transform // is identical. // if (IS_ICM_LAZY_CORRECTION(pdcattr->lIcmMode)) { return (IDENT_COLORTRANSFORM); } // // Load external ICM dlls. // LOAD_ICMDLL(NULL); // // Initialize ICMINFO // if ((pIcmInfo = GET_ICMINFO(pdcattr)) == NULL) { WARNING("gdi32: IcmCreateColorTransform: Can't init icm info\n"); return(NULL); } if (bDCSourceColorSpace && (pIcmInfo->pSourceColorSpace == NULL)) { // // If we haven't gotton DC source color space, get it there. // LOGCOLORSPACEW LogColorSpaceW; ICMMSG(("IcmCreateColorTransform(): Call getobject to get source color space in DC\n")); // // Filled with zero. // RtlZeroMemory(&LogColorSpaceW,sizeof(LOGCOLORSPACEW)); // // Find ColorSpace from cache. // pSourceColorSpace = IcmGetColorSpaceByHandle( (HGDIOBJ)hdc, (HANDLE)pdcattr->hColorSpace, &LogColorSpaceW,0); // // If we can not find from cache, but succeeded to obtain // valid logcolorspace from handle, create new one. // if ((pSourceColorSpace == NULL) && (LogColorSpaceW.lcsSignature == LCS_SIGNATURE)) { // // Create new cache. // pSourceColorSpace = IcmCreateColorSpaceByColorSpace( (HGDIOBJ)hdc, &LogColorSpaceW, NULL, 0); // // we are using new color space // bAnyNewColorSpace = TRUE; } // // And this is DC's color space, keep it for cache. // pIcmInfo->pSourceColorSpace = pSourceColorSpace; } else if (bDCSourceColorSpace) { ICMMSG(("IcmCreateColorTransform(): Use cached source color space in DC\n")); // // Get this from client cache ! // pSourceColorSpace = pIcmInfo->pSourceColorSpace; } else { ICMMSG(("IcmCreateColorTransform(): Use given source color space\n")); // // Just use given color space. // pSourceColorSpace = pInputColorSpace; } if (pSourceColorSpace) { HANDLE hColorTransform = NULL; PCACHED_COLORSPACE pDestColorSpace = pIcmInfo->pDestColorSpace; PCACHED_COLORSPACE pTargetColorSpace = NULL; // // if we are in proofing mode, consider target profile. // if (IS_ICM_PROOFING(pdcattr->lIcmMode)) { pTargetColorSpace = pIcmInfo->pTargetColorSpace; } #if DBG_ICM // // Dump current color space for the DC. // if ((pSourceColorSpace->LogColorSpace.lcsFilename[0]) != UNICODE_NULL) { ICMMSG(("IcmCreateColorTransform(): Source Profile = %ws\n", pSourceColorSpace->LogColorSpace.lcsFilename)); } if ((pDestColorSpace) && ((pDestColorSpace->LogColorSpace.lcsFilename[0]) != UNICODE_NULL)) { ICMMSG(("IcmCreateColorTransform(): Destination Profile = %ws\n", pDestColorSpace->LogColorSpace.lcsFilename)); } if ((pTargetColorSpace) && ((pTargetColorSpace->LogColorSpace.lcsFilename[0]) != UNICODE_NULL)) { ICMMSG(("IcmCreateColorTransform(): Target Profile = %ws\n", pTargetColorSpace->LogColorSpace.lcsFilename)); } ICMMSG(("IcmCreateColorTransform(): Intent = %d\n", pSourceColorSpace->ColorIntent)); #endif // DBG // // At this moment, we have any source colorspace. // if (IcmSameColorSpace(pSourceColorSpace,pDestColorSpace)) { if (pTargetColorSpace) { if (IcmSameColorSpace(pSourceColorSpace,pTargetColorSpace)) { ICMMSG(("IcmCreateColorTransform(): Src == Dest == Trg colorspace\n")); // // Source ColorSpace == Destination ColorSpace == Target ColorSpace // No color transform needed. // return (IDENT_COLORTRANSFORM); } } else { ICMMSG(("IcmCreateColorTransform(): Src == Dest colorspace\n")); // // Source ColorSpace == Destination ColorSpace, // and there is no target profile. // That means we don't need translate color // return (IDENT_COLORTRANSFORM); } } // // We need to have proper colortransform to adjust color between each colorspace. // if (dwFlags & ICM_BACKWARD) { // // This is backward transform. (swap source and destination) // PCACHED_COLORSPACE pSwapColorSpace; pSwapColorSpace = pSourceColorSpace; pSourceColorSpace = pDestColorSpace; pDestColorSpace = pSwapColorSpace; } // // At this moment, at least, we should have Source and Destination color space. // And target color space is optional. // if (pDestColorSpace) { if (!bAnyNewColorSpace) { // // Find colortransform from cache // // if this is device ICM, hdc also should matched. // pCXform = IcmGetColorTransform( hdc, pSourceColorSpace, pDestColorSpace, pTargetColorSpace, (IS_ICM_DEVICE(pdcattr->lIcmMode))); if (pCXform) { return (pCXform); } } // // Allocate CACHED_COLORTRANSFORM // pCXform = LOCALALLOC(sizeof(CACHED_COLORTRANSFORM)); if (pCXform) { ENTERCRITICALSECTION(&semColorSpaceCache); // // Make sure all color space has been realized // if (IcmRealizeColorProfile(pSourceColorSpace,TRUE) && IcmRealizeColorProfile(pDestColorSpace,TRUE) && IcmRealizeColorProfile(pTargetColorSpace,TRUE)) { // // call ICM dll or device driver to create a color transform // if (IS_ICM_HOST(pdcattr->lIcmMode)) { DWORD ahIntents[3]; HPROFILE ahProfiles[3]; DWORD chProfiles = 0; ICMMSG(("Creating Host ICM Transform...\n")); // // Put source profile in first entry. // ahIntents[chProfiles] = INTENT_RELATIVE_COLORIMETRIC; ahProfiles[chProfiles] = pSourceColorSpace->hProfile; chProfiles++; ahIntents[chProfiles] = pSourceColorSpace->ColorIntent; // // If target profile (proofing) is used, insert it // between source and destination. // if (pTargetColorSpace) { ahProfiles[chProfiles] = pTargetColorSpace->hProfile; chProfiles++; ahIntents[chProfiles] = INTENT_ABSOLUTE_COLORIMETRIC; } // // Finally, set destination profile. // ahProfiles[chProfiles] = pDestColorSpace->hProfile; chProfiles++; // // Call MSCMS to create color transform. // hColorTransform = (*fpCreateMultiProfileTransform)( ahProfiles, chProfiles, ahIntents, chProfiles, NORMAL_MODE | ENABLE_GAMUT_CHECKING, INDEX_DONT_CARE); } else if (IS_ICM_DEVICE(pdcattr->lIcmMode)) { CLIENT_SIDE_FILEVIEW fvwSrcProfile; CLIENT_SIDE_FILEVIEW fvwDstProfile; CLIENT_SIDE_FILEVIEW fvwTrgProfile; ICMMSG(("Creating Device ICM Transform...\n")); // // Invalidate FILEVIEW. // RtlZeroMemory(&fvwSrcProfile,sizeof(CLIENT_SIDE_FILEVIEW)); RtlZeroMemory(&fvwDstProfile,sizeof(CLIENT_SIDE_FILEVIEW)); RtlZeroMemory(&fvwTrgProfile,sizeof(CLIENT_SIDE_FILEVIEW)); // // Map color profile(s) into memory. // if (pSourceColorSpace->ColorProfile.dwType == PROFILE_FILENAME) { if (!bMapFileUNICODEClideSide( (PWSTR)(pSourceColorSpace->ColorProfile.pProfileData), &fvwSrcProfile,FALSE)) { WARNING("IcmCreateColorTransform(): Fail to map source profile\n"); goto IcmCreateColorTransform_Cleanup; } } else if (pSourceColorSpace->ColorProfile.dwType == PROFILE_MEMBUFFER) { ICMMSG(("Source Profile is memory buffer\n")); fvwSrcProfile.pvView = pSourceColorSpace->ColorProfile.pProfileData; fvwSrcProfile.cjView = pSourceColorSpace->ColorProfile.cbDataSize; } else { WARNING("IcmCreateColorTransform():src profile type is not supported\n"); goto IcmCreateColorTransform_Cleanup; } if (pDestColorSpace->ColorProfile.dwType == PROFILE_FILENAME) { if (!bMapFileUNICODEClideSide( (PWSTR)(pDestColorSpace->ColorProfile.pProfileData), &fvwDstProfile,FALSE)) { WARNING("IcmCreateColorTransform(): Fail to map destination profile\n"); goto IcmCreateColorTransform_Cleanup; } } else if (pDestColorSpace->ColorProfile.dwType == PROFILE_MEMBUFFER) { ICMMSG(("Destination Profile is memory buffer\n")); fvwDstProfile.pvView = pDestColorSpace->ColorProfile.pProfileData; fvwDstProfile.cjView = pDestColorSpace->ColorProfile.cbDataSize; } else { WARNING("IcmCreateColorTransform():dst profile type is not supported\n"); goto IcmCreateColorTransform_Cleanup; } // // Target color space is optional // if (pTargetColorSpace) { if (pTargetColorSpace->ColorProfile.dwType == PROFILE_FILENAME) { if (!bMapFileUNICODEClideSide( (PWSTR)(pTargetColorSpace->ColorProfile.pProfileData), &fvwTrgProfile,FALSE)) { WARNING("IcmCreateColorTransform(): Fail to map target profile\n"); goto IcmCreateColorTransform_Cleanup; } } else if (pTargetColorSpace->ColorProfile.dwType == PROFILE_MEMBUFFER) { ICMMSG(("Target Profile is memory buffer\n")); fvwTrgProfile.pvView = pTargetColorSpace->ColorProfile.pProfileData; fvwTrgProfile.cjView = pTargetColorSpace->ColorProfile.cbDataSize; } else { WARNING("IcmCreateColorTransform():trg profile type is not supported\n"); goto IcmCreateColorTransform_Cleanup; } } // // Call kernel. // hColorTransform = NtGdiCreateColorTransform(hdc, &(pSourceColorSpace->LogColorSpace), fvwSrcProfile.pvView, // Source Profile memory mapped file. fvwSrcProfile.cjView, fvwDstProfile.pvView, // Destination Profile memory mapped file. fvwDstProfile.cjView, fvwTrgProfile.pvView, // Target Profile memory mapped file. fvwTrgProfile.cjView); IcmCreateColorTransform_Cleanup: // // if we mapped file, unmap here. // if (fvwSrcProfile.hSection) { vUnmapFileClideSide(&fvwSrcProfile); } if (fvwDstProfile.hSection) { vUnmapFileClideSide(&fvwDstProfile); } if (fvwTrgProfile.hSection) { vUnmapFileClideSide(&fvwTrgProfile); } } } // // Once after create tranform, we don't need realized color space, // so just unrealize it. // IcmUnrealizeColorProfile(pSourceColorSpace); IcmUnrealizeColorProfile(pDestColorSpace); IcmUnrealizeColorProfile(pTargetColorSpace); LEAVECRITICALSECTION(&semColorSpaceCache); if (hColorTransform) { BOOL bCacheable = TRUE; // // Initialize CACHED_COLORTRANSFORM with zero // RtlZeroMemory(pCXform,sizeof(CACHED_COLORTRANSFORM)); // // Fill up CACHED_COLORTRANSFORM // pCXform->ColorTransform = hColorTransform; pCXform->SourceColorSpace = pSourceColorSpace; pCXform->DestinationColorSpace = pDestColorSpace; pCXform->TargetColorSpace = pTargetColorSpace; if (IS_ICM_DEVICE(pdcattr->lIcmMode)) { // // if this is device colortransform, mark it and // put DC in CACHED_COLORTRANSFORM strcuture // pCXform->flInfo |= DEVICE_COLORTRANSFORM; // // And device color transform is not cacheable. // bCacheable = FALSE; } ENTERCRITICALSECTION(&semColorSpaceCache); // // Increment transform ref. count in each color space. // if (pSourceColorSpace) { pSourceColorSpace->cRef++; if (bCacheable) { // // Check this color space is cacheable. // bCacheable &= IcmIsCacheable(pSourceColorSpace); } } if (pDestColorSpace) { pDestColorSpace->cRef++; if (bCacheable) { // // Check this color space is cacheable. // bCacheable &= IcmIsCacheable(pDestColorSpace); } } if (pTargetColorSpace) { pTargetColorSpace->cRef++; if (bCacheable) { // // Check this color space is cacheable. // bCacheable &= IcmIsCacheable(pTargetColorSpace); } } LEAVECRITICALSECTION(&semColorSpaceCache); // // Initialize ref. counter. // pCXform->cRef = 1; // // Set cache-able bit, if possible. // if (bCacheable) { ICMMSG(("IcmCreateColorTransform(): ColorTransform is cacheable\n")); pCXform->flInfo |= CACHEABLE_COLORTRANSFORM; } else { ICMMSG(("IcmCreateColorTransform(): ColorTransform is *NOT* cacheable\n")); // // If this is not cacheable, make sure this get deleted when DC gone. // pCXform->hdc = hdc; } // // Insert new CACHED_COLORTRANSFORM to list // ENTERCRITICALSECTION(&semColorTransformCache); InsertTailList(&ListCachedColorTransform,&(pCXform->ListEntry)); cCachedColorTransform++; LEAVECRITICALSECTION(&semColorTransformCache); } else { ICMWRN(("IcmCreateColorTransform(): Fail to create color transform\n")); // // Fail to get transform handle // LOCALFREE(pCXform); pCXform = NULL; } } else { WARNING("IcmCreateColorTransform(): LOCALALLOC() failed\n"); } } else { WARNING("IcmCreateColorTransform(): Dest color space is required\n"); } } else { WARNING("IcmCreateColorTransform(): Fail to get source colorspace\n"); } return(pCXform); } /******************************Public*Routine******************************\ * IcmTranslateCOLORREF * * Arguments: * * hdc * pdcattr * ColorIn * *ColorOut * * Return Value: * * Status * * History: * * Write it: * 13-Feb-1997 -by- Hideyuki Nagase [hideyukn] * \**************************************************************************/ BOOL IcmTranslateCOLORREF( HDC hdc, PDC_ATTR pdcattr, COLORREF ColorIn, COLORREF *ColorOut, DWORD Flags ) { COLORREF OldColor = ColorIn; COLORREF NewColor; BOOL bStatus = TRUE; ICMAPI(("gdi32: IcmTranslateCOLORREF\n")); ASSERTGDI(ColorOut != NULL,"IcmTranslateCOLORREF(): ColorOut == NULL\n"); if (bNeedTranslateColor(pdcattr)) { PGDI_ICMINFO pIcmInfo; LOAD_ICMDLL(FALSE); if ((pIcmInfo = GET_ICMINFO(pdcattr)) == NULL) { WARNING("gdi32: IcmTranslateCOLORREF: Can't init icm info\n"); return((int)FALSE); } else { ULONG SrcColorFormat; ULONG DstColorFormat; HANDLE hcmXform = NULL; if (Flags & ICM_BACKWARD) { ICMMSG(("IcmTranslateCOLORREF():Backward Color transform\n")); // // AnyColorFormat ----> COLORREF (0x00bbggrr) // // Setup src & dest color type. // SrcColorFormat = pIcmInfo->pDestColorSpace->ColorFormat; DstColorFormat = BM_xBGRQUADS; // // If there is cached handle, use that. // if (pIcmInfo->pBackCXform) { ICMMSG(("IcmTranslateCOLORREF():Use cached transform for Backward Color transform\n")); hcmXform = pIcmInfo->pBackCXform->ColorTransform; } else { PCACHED_COLORTRANSFORM pCXform; ICMMSG(("IcmTranslateCOLORREF():Create cached transform for Backward Color transform\n")); // // Create backward color transform. // pCXform = IcmCreateColorTransform(hdc, pdcattr, NULL, ICM_BACKWARD); if ((pCXform == NULL) || (pCXform == IDENT_COLORTRANSFORM)) { return (FALSE); } // // Cache created color transform. // pIcmInfo->pBackCXform = pCXform; // // We will delete this cached transform, when we don't need this anymore. // hcmXform = pCXform->ColorTransform; } } else { // // COLORREF (0x00bbggrr) ----> AnyColorFormat // // Setup src & dest color type. // SrcColorFormat = BM_xBGRQUADS; DstColorFormat = pIcmInfo->pDestColorSpace->ColorFormat; // // Use foaward color transform. // hcmXform = GetColorTransformInDC(pdcattr); // // Source is COLORREF. then, Mask off gdi internal infomation. // // COLORREF = 0x00bbggrr; // OldColor &= 0x00ffffff; } if (hcmXform) { // // We handle COLORREF as 1x1 pixel bitmap data. // bStatus = (*fpTranslateBitmapBits)(hcmXform, (PVOID)&OldColor, SrcColorFormat, 1,1, ALIGN_DWORD(sizeof(COLORREF)), (PVOID)&NewColor, DstColorFormat, // 0, // We need pass 0 here, to let Kodak CMM works // NULL,0); } else { // // It seems hcmXform is invalid // ICMWRN(("IcmTranslateCOLORREF():hcmXform is invalid\n")); bStatus = FALSE; } if (bStatus) { if (Flags & ICM_BACKWARD) { // // OldColor: AnyColorFormat // NewColor: COLORREF (0x00bbggrr) // // [NOTE:] // We could not restore flags. // *ColorOut = NewColor; } else { // // OldColor: COLORREF (0x00bbggrr) // NewColor: AnyColorFormat // if (!(IS_32BITS_COLOR(pdcattr->lIcmMode))) { // // The distination is not 32Bits Color, Restore assign and preserve flags. // *ColorOut = (NewColor & 0x00ffffff) | (ColorIn & 0xff000000); } else { // // The distination is 32bits color. // // [NOTE:] // We will lost flags here. // *ColorOut = NewColor; ICMMSG(("IcmTranslateCOLORREF(): 32 bits color !\n")); } } } else { WARNING("IcmTranslateCOLORREF():Fail TranslateBitmapBits()\n"); } } } else { // // Just return original color // *ColorOut = ColorIn; bStatus = TRUE; } return(bStatus); } /******************************Public*Routine******************************\ * IcmTranslateTRIVERTEX * * Translate TRIVERTEX in place. No need for a general routine with * separate input and output pointers * * Arguments: * * hdc - hdc * pdcattr - verified dcattr * pVertex - input and output pointer * * Return Value: * * Status * * History: * * Write it: * 13-Feb-1997 -by- Hideyuki Nagase [hideyukn] * \**************************************************************************/ BOOL IcmTranslateTRIVERTEX( HDC hdc, PDC_ATTR pdcattr, PTRIVERTEX pVertex, ULONG nVertex ) { BOOL bStatus = TRUE; ICMAPI(("gdi32: IcmTranslateTRIVERTEX\n")); ASSERTGDI(pVertex != NULL,"IcmTranslateTrivertex(): pVertex == NULL\n"); if (bNeedTranslateColor(pdcattr)) { PGDI_ICMINFO pIcmInfo; LOAD_ICMDLL(FALSE); if ((pIcmInfo = GET_ICMINFO(pdcattr)) == NULL) { WARNING("gdi32: IcmTranslateTRIVERTEX: Can't init icm info\n"); return((int)FALSE); } else { // // Use foaward color transform. // if (GetColorTransformInDC(pdcattr)) { // // use 16 bit per channel COLOR_RGB to translate trivertex // while (nVertex--) { COLOR Color; Color.rgb.red = pVertex->Red; Color.rgb.green = pVertex->Green; Color.rgb.blue = pVertex->Blue; bStatus = (*fpTranslateColors)( (HANDLE)GetColorTransformInDC(pdcattr), &Color, 1, COLOR_RGB, &Color, COLOR_RGB); if (bStatus) { // // assign output // pVertex->Red = Color.rgb.red; pVertex->Green = Color.rgb.green; pVertex->Blue = Color.rgb.blue; } else { WARNING("IcmTranslateTRIVERTEX():Fail TranslateColors()\n"); break; } pVertex++; } } else { // // It seems hcmXform is invalid // ICMWRN(("IcmTranslateTRIVERTEX():hcmXform is invalid\n")); bStatus = FALSE; } } } else { bStatus = TRUE; } return(bStatus); } /******************************Public*Routine******************************\ * IcmTranslatePaletteEntry * * Arguments: * * hdc * pdcattr * ColorIn * pColorOut * * Return Value: * * Status * * History: * * Rewrite it: * 21-Jan-1997 -by- Hideyuki Nagase [hideyukn] * Write it: * 5-Aug-1996 -by- Mark Enstrom [marke] * \**************************************************************************/ BOOL IcmTranslatePaletteEntry( HDC hdc, PDC_ATTR pdcattr, PALETTEENTRY *pColorIn, PALETTEENTRY *pColorOut, UINT NumberOfEntries ) { BOOL bStatus = FALSE; ICMAPI(("gdi32: IcmTranslatePaletteEntry\n")); if (bNeedTranslateColor(pdcattr)) { PGDI_ICMINFO pIcmInfo = GET_ICMINFO(pdcattr); if (pIcmInfo) { LOAD_ICMDLL(FALSE); // // We handle PALETTEENTRYs as NumberOfEntries x 1 pixels bitmap data. // bStatus = (*fpTranslateBitmapBits)((HANDLE)GetColorTransformInDC(pdcattr), (PVOID)pColorIn, // BM_xBGRQUADS, // PALETTEENTRY is 0x00bbggrr format // NumberOfEntries,1, ALIGN_DWORD(NumberOfEntries*sizeof(COLORREF)), (PVOID)pColorOut, // pIcmInfo->pDestColorSpace->ColorFormat, // BM_xBGRQUADS or BM_KYMCQUADS // // 0, // We need pass 0 here, to let Kodak CMM works // NULL,0); if (!bStatus) { WARNING("IcmTranslatePaletteEntry():Fail TranslateBitmapBits()\n"); } } } else { // // Just return original color. // RtlCopyMemory(pColorIn,pColorOut,sizeof(PALETTEENTRY) * NumberOfEntries); bStatus = TRUE; } return(bStatus); } /******************************Public*Routine******************************\ * IcmDeleteColorTransform * * Decide whether to call the device driver or mscms.dll to delete a * color transform. * * Arguments: * * Return Value: * * History: * * Mar.12.1998 -by- Hideyuki Nagase [hideyukn] * \**************************************************************************/ BOOL IcmDeleteColorTransform( PCACHED_COLORTRANSFORM pCXform, BOOL bForceDelete ) { BOOL bStatus = TRUE; ICMAPI(("gdi32: IcmDeleteColorTransform\n")); if (pCXform) { ENTERCRITICALSECTION(&semColorTransformCache); // // Decrement ref. counter. // pCXform->cRef--; if ((pCXform->cRef == 0) || bForceDelete) { PCACHED_COLORTRANSFORM pCXformVictim = NULL; if ((pCXform->flInfo & CACHEABLE_COLORTRANSFORM) && !bForceDelete) { if (cCachedColorTransform < MAX_COLORTRANSFORM_CACHE) { ICMMSG(("IcmDeleteColorTransform(): colortransform can be cached !\n")); // // The color transform can be cached. so just keep it in list. // And don't need to delete anything here. // pCXformVictim = NULL; } else { // // Find any cache can delete from list. // if ((pCXformVictim = IcmGetFirstNonUsedColorTransform()) == NULL) { ICMMSG(("IcmDeleteColorTransform(): colortransform cache is full, delete myself\n")); // // Nothing can be deleted from list, so delete myself. // pCXformVictim = pCXform; } else { ICMMSG(("IcmDeleteColorTransform(): colortransform cache is full, delete victim\n")); } } } else { // // The colortransform can not be kept, or force delete, so just delete this. // pCXformVictim = pCXform; } if (pCXformVictim) { // // Unref color space count. // if (pCXformVictim->SourceColorSpace) { IcmReleaseColorSpace(NULL,pCXformVictim->SourceColorSpace,FALSE); } if (pCXformVictim->DestinationColorSpace) { IcmReleaseColorSpace(NULL,pCXformVictim->DestinationColorSpace,FALSE); } if (pCXformVictim->TargetColorSpace) { IcmReleaseColorSpace(NULL,pCXformVictim->TargetColorSpace,FALSE); } // // Delete color transform // if (pCXformVictim->flInfo & DEVICE_COLORTRANSFORM) { // // call device driver to delete transform. // bStatus = NtGdiDeleteColorTransform(pCXformVictim->hdc,pCXformVictim->ColorTransform); } else { // // call color match dll to delete transform. // bStatus = (*fpDeleteColorTransform)(pCXformVictim->ColorTransform); } // // Remove from list // RemoveEntryList(&(pCXformVictim->ListEntry)); cCachedColorTransform--; // // free CACHED_COLORTRANSFORM // LOCALFREE(pCXformVictim); } } LEAVECRITICALSECTION(&semColorTransformCache); } return(bStatus); } /******************************Public*Routine******************************\ * IcmDeleteDCColorTransforms * * Arguments: * * Return Value: * * History: * * Feb.17.1997 Hideyuki Nagase [hideyukn] \**************************************************************************/ BOOL IcmDeleteDCColorTransforms( PGDI_ICMINFO pIcmInfo ) { ICMAPI(("gdi32: IcmDeleteDCColorTransforms\n")); ASSERTGDI(pIcmInfo != NULL,"IcmDeleteDCColorTransform():pIcmInfo == NULL\n"); // // Delete transform selected in DC. // if (pIcmInfo->pCXform) { IcmDeleteColorTransform(pIcmInfo->pCXform,FALSE); } if (pIcmInfo->pBackCXform) { IcmDeleteColorTransform(pIcmInfo->pBackCXform,FALSE); } if (pIcmInfo->pProofCXform) { IcmDeleteColorTransform(pIcmInfo->pProofCXform,FALSE); } // // Invalidate colortransforms // pIcmInfo->pCXform = pIcmInfo->pBackCXform = pIcmInfo->pProofCXform = NULL; return (TRUE); } /******************************Public*Routine******************************\ * IcmDeleteCachedColorTransforms * * Arguments: * * Return Value: * * History: * * May.06.1997 Hideyuki Nagase [hideyukn] \**************************************************************************/ BOOL IcmDeleteCachedColorTransforms( HDC hdc ) { PCACHED_COLORTRANSFORM pCXform = NULL; PLIST_ENTRY p; ICMAPI(("gdi32: IcmDeleteCachedColorTransforms\n")); ENTERCRITICALSECTION(&semColorTransformCache); p = ListCachedColorTransform.Flink; while(p != &ListCachedColorTransform) { // // Get cached color transform // pCXform = CONTAINING_RECORD(p,CACHED_COLORTRANSFORM,ListEntry); // // Let 'p' points next cell. (this prefer to be done BEFORE un-chain this cell) // p = p->Flink; // // Is this color transform is specific to this DC ? // if (pCXform->hdc == hdc) { ICMMSG(("IcmDeleteCachedColorTransform():Delete colortransform in cache !\n")); // // Delete color transform (this call will un-chain this cell) // IcmDeleteColorTransform(pCXform,TRUE); } } LEAVECRITICALSECTION(&semColorTransformCache); return (TRUE); } /******************************Public*Routine******************************\ * IcmIsCacheable * * Arguments: * * Return Value: * * History: * * Mar.12.1998 Hideyuki Nagase [hideyukn] \**************************************************************************/ BOOL IcmIsCacheable( PCACHED_COLORSPACE pColorSpace ) { // // If this color space can not be cached, don't cache it. // if (pColorSpace->flInfo & NOT_CACHEABLE_COLORSPACE) { return (FALSE); } // // If this is any GDI object specific color space, also can not cache. // if (pColorSpace->hObj) { return (FALSE); } return (TRUE); } /******************************Public*Routine******************************\ * IcmReleaseCachedColorSpace * * Arguments: * * Return Value: * * History: * * May.06.1997 Hideyuki Nagase [hideyukn] \**************************************************************************/ BOOL IcmReleaseCachedColorSpace( HGDIOBJ hObj ) { PCACHED_COLORSPACE pColorSpace = NULL; PLIST_ENTRY p; ICMAPI(("gdi32: IcmReleaseCachedColorSpace\n")); ENTERCRITICALSECTION(&semColorSpaceCache); p = ListCachedColorSpace.Flink; while(p != &ListCachedColorSpace) { // // Get cached color space // pColorSpace = CONTAINING_RECORD(p,CACHED_COLORSPACE,ListEntry); // // Let 'p' points next cell. (this prefer to be done BEFORE un-chain this cell) // p = p->Flink; // // Is this color transform is related to this DC ? // if (pColorSpace->hObj == hObj) { ICMMSG(("IcmReleaseCachedColorSpace():Delete colorspace in cache !\n")); // // Delete color space (this call will un-chain this cell) // IcmReleaseColorSpace(hObj,pColorSpace,TRUE); } } LEAVECRITICALSECTION(&semColorSpaceCache); return (TRUE); } /******************************Public*Routine******************************\ * IcmReleaseColorSpace * * Arguments: * * Return Value: * * History: * * Feb.17.1997 -by- Hideyuki Nagase [hideyukn] * \**************************************************************************/ VOID IcmReleaseColorSpace( HGDIOBJ hObj, /* Must be given if bForceDelete is TRUE */ PCACHED_COLORSPACE pColorSpace, BOOL bForceDelete ) { ICMAPI(("gdi32: IcmReleaseColorSpace\n")); if (pColorSpace) { ENTERCRITICALSECTION(&semColorSpaceCache); // // Decrement ref. counter. // pColorSpace->cRef--; // // If this profile associated with other GDI objects (driver, metafile or bitmap) // we won't delete until the object is deleted // if ( (pColorSpace->flInfo & HGDIOBJ_SPECIFIC_COLORSPACE) && (bForceDelete == FALSE) ) { ICMWRN(("IcmReleaseColorSpace: Delay Delete for Metafile/Driver/Bitmap profile - %ws\n",\ (pColorSpace->LogColorSpace.lcsFilename[0] ? \ pColorSpace->LogColorSpace.lcsFilename : L"no profile"))); } else { if ((pColorSpace->cRef == 0) // No one uses this profile. || // OR (bForceDelete && IsColorSpaceOwnedByGDIObject(pColorSpace,hObj)) // DC or Owner GDI object is going to delete and // colorspace is designed for this GDI object. ) { ICMMSG(("IcmReleaseColorSpace: Delete - %ws\n", \ (pColorSpace->LogColorSpace.lcsFilename[0] ? \ pColorSpace->LogColorSpace.lcsFilename : L"no profile"))); if (pColorSpace->hProfile) { IcmUnrealizeColorProfile(pColorSpace); } if (pColorSpace->flInfo & NEED_TO_FREE_PROFILE) { ICMMSG(("IcmReleaseColorSpace: Free on memory profile\n")); GlobalFree(pColorSpace->ColorProfile.pProfileData); } if (pColorSpace->flInfo & NEED_TO_DEL_PROFILE) { ICMMSG(("IcmReleaseColorSpace: Delete TempFile - %ws\n", pColorSpace->LogColorSpace.lcsFilename)); DeleteFileW(pColorSpace->LogColorSpace.lcsFilename); } // // Remove from list // RemoveEntryList(&(pColorSpace->ListEntry)); cCachedColorSpace--; // // Free colorspace. // LOCALFREE(pColorSpace); } else { ICMWRN(("IcmReleaseColorSpace: Still in USE - %ws\n", \ (pColorSpace->LogColorSpace.lcsFilename[0] ? \ pColorSpace->LogColorSpace.lcsFilename : L"no profile"))); } } LEAVECRITICALSECTION(&semColorSpaceCache); } } /******************************Public*Routine******************************\ * IcmReleaseDCColorSpace * * Arguments: * * Return Value: * * History: * * Feb.17.1997 -by- Hideyuki Nagase [hideyukn] * \**************************************************************************/ VOID IcmReleaseDCColorSpace( PGDI_ICMINFO pIcmInfo, BOOL bReleaseDC ) { INT i = 0; HDC hdc = pIcmInfo->hdc; PCACHED_COLORSPACE DeleteColorSpaces[4]; ICMAPI(("gdi32: IcmReleaseDCColorSpace\n")); ASSERTGDI(pIcmInfo != NULL,"IcmReleaseDCColorSpace pIcmInfo == NULL\n"); // // Fill up the table to delete color color spaces. // DeleteColorSpaces[i++] = pIcmInfo->pSourceColorSpace; if (bReleaseDC) { ICMMSG(("IcmReleaseDCColorSpace: Force Delete\n")); // // If we are in "force deletion" mode, don't delete twice. // since if the color space owned by this HDC, and this DC is going to be // deleted, we will delete the color space forcely. // if (IsColorSpaceOwnedByGDIObject(pIcmInfo->pDestColorSpace,hdc) && IcmSameColorSpace(pIcmInfo->pSourceColorSpace,pIcmInfo->pDestColorSpace)) { ICMMSG(("IcmReleaseDCColorSpace: Force Delete - skip destination (same as source)\n")); } else { DeleteColorSpaces[i++] = pIcmInfo->pDestColorSpace; } if (IsColorSpaceOwnedByGDIObject(pIcmInfo->pTargetColorSpace,hdc) && (IcmSameColorSpace(pIcmInfo->pSourceColorSpace,pIcmInfo->pTargetColorSpace) || IcmSameColorSpace(pIcmInfo->pDestColorSpace,pIcmInfo->pTargetColorSpace))) { ICMMSG(("IcmReleaseDCColorSpace: Force Delete - skip target (same as source/dest)\n")); } else { DeleteColorSpaces[i++] = pIcmInfo->pTargetColorSpace; } } else { DeleteColorSpaces[i++] = pIcmInfo->pDestColorSpace; DeleteColorSpaces[i++] = pIcmInfo->pTargetColorSpace; } DeleteColorSpaces[i] = NULL; for (i = 0; DeleteColorSpaces[i] != NULL; i++) { IcmReleaseColorSpace((HGDIOBJ)hdc,DeleteColorSpaces[i],bReleaseDC); } pIcmInfo->pSourceColorSpace = NULL; pIcmInfo->pDestColorSpace = NULL; pIcmInfo->pTargetColorSpace = NULL; } /******************************Public*Routine******************************\ * IcmInitIcmInfo() * * Arguments: * * Return Value: * * History: * * Jan.31,1997 -by- Hideyuki Nagase [hideyukn] * \**************************************************************************/ PGDI_ICMINFO IcmInitIcmInfo( HDC hdc, PDC_ATTR pdcattr ) { ICMAPI(("gdi32: IcmInitIcmInfo\n")); if (pdcattr == NULL) { WARNING("IcmInitIcmInfo():pdcattr is NULL\n"); return (NULL); } if (pdcattr->pvICM == NULL) { PGDI_ICMINFO pIcmInfo = NULL; PLDC pldc = (PLDC) pdcattr->pvLDC; BOOL bDisplay = ((pldc && pldc->hSpooler) ? FALSE : TRUE); BOOL bInsertList = bDisplay; ENTERCRITICALSECTION(&semListIcmInfo); // // First try to get ICMINFO from list. if not nothing can be re-used, // allocate new one. // if (bDisplay) { if ((pIcmInfo = IcmGetUnusedIcmInfo(hdc)) != NULL) { LIST_ENTRY ListEntry; // // Save ListEntry. // ListEntry = pIcmInfo->ListEntry; // // Init with zero. // RtlZeroMemory(pIcmInfo,sizeof(GDI_ICMINFO)); // // Restore ListEntry // pIcmInfo->ListEntry = ListEntry; // // This ICMInfo already on list, don't need to insert. // bInsertList = FALSE; // // Mark this cell in on ListIcmInfo. // pIcmInfo->flInfo = ICM_ON_ICMINFO_LIST; ICMMSG(("IcmInitIcmInfo():Get unused ICMINFO structure = %p\n",pIcmInfo)); } } if (pIcmInfo == NULL) { // // ICMINFO is not allocated, yet. then allocate it. // pIcmInfo = (PGDI_ICMINFO) LOCALALLOC(sizeof(GDI_ICMINFO)); // // Init with zero. // if (pIcmInfo != NULL) { RtlZeroMemory(pIcmInfo,sizeof(GDI_ICMINFO)); } ICMMSG(("IcmInitIcmInfo():Allocate new ICMINFO structure = %p\n",pIcmInfo)); } if (pIcmInfo) { PDEVMODEW pDevModeW = NULL; // // Set owner information (hdc and pdcattr). // pIcmInfo->hdc = hdc; pIcmInfo->pvdcattr = (PVOID) pdcattr; // // initialize LIST_ENTRY for saved icm info. // InitializeListHead(&(pIcmInfo->SavedIcmInfo)); // // Default is LCS_DEFAULT_INTENT (aka LCS_GM_IMAGES) // pIcmInfo->dwDefaultIntent = LCS_DEFAULT_INTENT; // // If this is printer, set default Intent from devmode. // if (pldc && pldc->hSpooler) { PVOID pvFree = NULL; if (pldc->pDevMode) { pDevModeW = pldc->pDevMode; } else { pDevModeW = pdmwGetDefaultDevMode(pldc->hSpooler,NULL,&pvFree); } if (pDevModeW && (pDevModeW->dmFields & DM_ICMINTENT)) { DWORD dwIntent = pDevModeW->dmICMIntent; ICMMSG(("IcmInitIcmInfo():Intent in devmode = %d\n",dwIntent)); // // Convert intent for devmode to intent for LOGCOLORSPACE. // switch (dwIntent) { case DMICM_SATURATE: pIcmInfo->dwDefaultIntent = LCS_GM_BUSINESS; break; case DMICM_COLORIMETRIC: pIcmInfo->dwDefaultIntent = LCS_GM_GRAPHICS; break; case DMICM_ABS_COLORIMETRIC: pIcmInfo->dwDefaultIntent = LCS_GM_ABS_COLORIMETRIC; break; case DMICM_CONTRAST: default: pIcmInfo->dwDefaultIntent = LCS_DEFAULT_INTENT; break; } } ICMMSG(("IcmInitIcmInfo():Default Intent = %d\n",pIcmInfo->dwDefaultIntent)); // // Free devmode buffer. // if (pvFree) { LOCALFREE(pvFree); } } // // Only ICMINFO for Display ICM put on to the list. // if (bInsertList) { // // This ICMINFO is newly allocated, so put this on list. // InsertTailList(&ListIcmInfo,&(pIcmInfo->ListEntry)); // // Mark this cell in on ListIcmInfo. // pIcmInfo->flInfo |= ICM_ON_ICMINFO_LIST; } } // // Store pointer to ICMINFO to DC_ATTR. // pdcattr->pvICM = (PVOID) pIcmInfo; LEAVECRITICALSECTION(&semListIcmInfo); } return ((PGDI_ICMINFO)(pdcattr->pvICM)); } /******************************Public*Routine******************************\ * IcmGetUnusedIcmInfo() * * ATTENTION: semListIcmInfo should be held by caller * * History: * 17-Feb-1999 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ PGDI_ICMINFO IcmGetUnusedIcmInfo( HDC hdcNew ) { PLIST_ENTRY p; PGDI_ICMINFO pInvalidIcmInfo = NULL; ICMAPI(("gdi32: IcmGetUnusedIcmInfo\n")); p = ListIcmInfo.Flink; // // First Loop - Find ICMINFO which has same hdc. // while(p != &ListIcmInfo) { pInvalidIcmInfo = CONTAINING_RECORD(p,GDI_ICMINFO,ListEntry); if (pInvalidIcmInfo->flInfo & ICM_IN_USE) { // // Skip this one, since it's under initializing. // } else { // // If this is same hdc, break. // if (pInvalidIcmInfo->hdc == hdcNew) { ICMMSG(("IcmGetUnusedIcmInfo(): ICMINFO at %p is invalid (same hdc)\n", pInvalidIcmInfo)); // // break loop. // break; } } // // Move on next. // p = p->Flink; pInvalidIcmInfo = NULL; } // // If not find in first loop, go to second loop. // if (pInvalidIcmInfo == NULL) { p = ListIcmInfo.Flink; // // Second Loop - Find unused ICMINFO. // while(p != &ListIcmInfo) { pInvalidIcmInfo = CONTAINING_RECORD(p,GDI_ICMINFO,ListEntry); if (pInvalidIcmInfo->flInfo & ICM_IN_USE) { // // Skip this one, since it's under initializing. // } else { PDC_ATTR pdcattr; // // Make sure this ICMINFO and hdc is stil effective. // // // Check below by calling PSHARED_GET_VALIDATE. // // 1) Is this DC handle ? // 2) Is this DC handle belonging to this process ? // 3) Does this DC has valid user mode DC_ATTR ? // PSHARED_GET_VALIDATE(pdcattr,pInvalidIcmInfo->hdc,DC_TYPE); if (pdcattr == NULL) { ICMMSG(("IcmGetUnusedIcmInfo(): ICMINFO at %p is invalid (no pdcattr)\n", pInvalidIcmInfo)); // // break loop. // break; } else { // // Make sure the pointer points each other. // if ((pdcattr->pvICM != pInvalidIcmInfo ) || (pdcattr != pInvalidIcmInfo->pvdcattr)) { ICMMSG(("IcmGetUnusedIcmInfo(): ICMINFO at %p is invalid (pointer mismatch)\n", pInvalidIcmInfo)); // // break loop. // break; } } } // // Move on next. // p = p->Flink; pInvalidIcmInfo = NULL; } } if (pInvalidIcmInfo) { // // This ICMINFO is invalid, clean up this ICMINFO. // IcmCleanupIcmInfo(NULL,pInvalidIcmInfo); } else { ICMMSG(("IcmGetUnusedIcmInfo(): Unused ICMINFO is not in list\n")); } return (pInvalidIcmInfo); } /******************************Public*Routine******************************\ * IcmInitDC() * * Arguments: * * Return Value: * * History: * * Jan.31.1997 -by- Hideyuki Nagase [hideyukn] * \**************************************************************************/ BOOL IcmInitLocalDC( HDC hdc, HANDLE hPrinter, CONST DEVMODEW *pdm, BOOL bReset ) { BOOL bRet = TRUE; PDC_ATTR pdcattr; PLDC pldc; ICMAPI(("gdi32: IcmInitLocalDC\n")); // // all these stuff is for only Printer. // if (hPrinter == NULL) { return (TRUE); } PSHARED_GET_VALIDATE(pdcattr,hdc,DC_TYPE); if (!pdcattr) { WARNING("IcmInitDC(): pdcattr is NULL\n"); return (FALSE); } if (bReset) { // // Release existing ICMINFO // if (ghICM || BEXIST_ICMINFO(pdcattr)) { // // Delete ICM stuff in this DC. // IcmDeleteLocalDC(hdc,pdcattr,NULL); } } if (!pdm) { // // DEVMODE are not presented. // ICMMSG(("IcmInitLocalDC():DEVMODE is not presented\n")); return (TRUE); } // // Check pointer to DEVMODE is valid or not. Check validation until // DEVMODE.dmSize first, then check whole devmode size specified in dmSize. // if (IsBadReadPtr((CONST VOID *)pdm, offsetof(DEVMODEW,dmDriverExtra)) || IsBadReadPtr((CONST VOID *)pdm, pdm->dmSize)) { WARNING("IcmInitLocalDC(): Invalid pointer given as PDEVMODEW\n"); return (FALSE); } // // Check color or mono mode. // if ((pdm->dmFields & DM_COLOR) && (pdm->dmColor == DMCOLOR_MONOCHROME)) { // // This is monochrome mode, don't enable ICM as default. // And NEVER enable ICM. // ICMMSG(("IcmInitLocalDC():DEVMODE says MONOCHROME mode\n")); return (TRUE); } // // ATTENTION: AFTER HERE, WE HAVE A DEVMODE WHICH POSSIBLE TO ENABLE ICM LATER OR NOW. // // // Check DM fields // if (!(pdm->dmFields & DM_ICMMETHOD)) { // // DEVMODE does not have ICMMETHOD. // ICMMSG(("IcmInitLocalDC():DEVMODE does not have ICMMETHOD\n")); return (TRUE); } // // NOTE: // // DEVMODEW structure. // // ... [omitted] // DWORD dmDisplayFrequency; // #if(WINVER >= 0x0400) // DWORD dmICMMethod; // Windows 95 only / Windows NT 5.0 // DWORD dmICMIntent; // Windows 95 only / Windows NT 5.0 // DWORD dmMediaType; // Windows 95 only / Windows NT 5.0 // .... // // Then DEVMODE structure should be larger than offset of dmMediaType // to access ICM stuff. // if (pdm->dmSize < offsetof(DEVMODEW,dmMediaType)) { // // DEVMODE version might not matched. // WARNING("IcmInitLocalDC():DEVMODE is small\n"); return (TRUE); } // // Check requested ICM mode. // switch (pdm->dmICMMethod) { case DMICMMETHOD_NONE: ICMMSG(("IcmInitDC(): ICM is disabled by default\n")); // // ICM is not enabled at this time. // // no more process is needed, just return here... // return (TRUE); case DMICMMETHOD_SYSTEM: ICMMSG(("IcmInitDC(): HOST ICM is requested\n")); // // ICM on Host, is requested. // SET_HOST_ICM_DEVMODE(pdcattr->lIcmMode); break; case DMICMMETHOD_DRIVER: case DMICMMETHOD_DEVICE: ICMMSG(("IcmInitDC(): DEVICE ICM is requested\n")); // // ICM on device, is requested. // SET_DEVICE_ICM_DEVMODE(pdcattr->lIcmMode); break; default: // // And we treat as Device ICM greater DMICMMETHOD_USER also. // if (pdm->dmICMMethod >= DMICMMETHOD_USER) { ICMMSG(("IcmInitDC(): DEVICE ICM (USER) is requested\n")); // // ICM on device (user defined), is requested. // SET_DEVICE_ICM_DEVMODE(pdcattr->lIcmMode); } else { ICMMSG(("IcmInitDC(): Unknown ICM mode\n")); // // return with error. // return (FALSE); } break; } // // Finally, enabled ICM. // bRet = SetICMMode(hdc,ICM_ON); if (!bRet) { ICMWRN(("InitLocalDC():FAILED to turn on ICM\n")); } return (bRet); } /******************************Public*Routine******************************\ * IcmUpdateDCColorInfo() * * Arguments: * * Return Value: * * History: * * May.28.1997 -by- Hideyuki Nagase [hideyukn] * \**************************************************************************/ BOOL IcmUpdateDCColorInfo( HDC hdc, PDC_ATTR pdcattr ) { BOOL bRet = TRUE; PGDI_ICMINFO pIcmInfo; ICMAPI(("gdi32: IcmUpdateDCColorInfo\n")); pIcmInfo = GET_ICMINFO(pdcattr); ASSERTGDI(pIcmInfo != NULL,"IcmUpdateDCColorInfo(): pIcmInfo == NULL\n"); // // Get the ColorSpace for this DC. // if (!IcmUpdateLocalDCColorSpace(hdc,pdcattr)) { return (FALSE); } if ((pIcmInfo->pCXform == NULL) || (pdcattr->ulDirty_ & DIRTY_COLORTRANSFORM)) { // // if TRUE in above, new color space (or no) has been selected, // then updates color transforms. // PCACHED_COLORTRANSFORM pCXform; // // At this momernt, we should have destination color space. // if this is null, we may fail to update color space in // IcmUpdateLocalDCColorSpace() // if (pIcmInfo->pDestColorSpace) { // // Create the color transform. // pCXform = IcmCreateColorTransform(hdc,pdcattr,NULL,ICM_FORWARD); if (pCXform) { if (pCXform == IDENT_COLORTRANSFORM) { ICMMSG(("IcmUpdateDCInfo():Input & Output colorspace is same\n")); // // Input and Output colorspace is same, could be optimize. // // // Set new color transform to DC. // IcmSelectColorTransform(hdc,pdcattr,NULL, bDeviceCalibrate(pIcmInfo->pDestColorSpace)); // // Delete cached dirty color transform, if we have. // IcmDeleteDCColorTransforms(pIcmInfo); // // Set new color transform to ICMINFO. // pIcmInfo->pCXform = NULL; } else { // // Select the color transform to DC. // IcmSelectColorTransform(hdc,pdcattr,pCXform, bDeviceCalibrate(pCXform->DestinationColorSpace)); // // Delete cached dirty color transform, if we have. // IcmDeleteDCColorTransforms(pIcmInfo); // // Set new color transform to ICMINFO. // pIcmInfo->pCXform = pCXform; // // Translate all DC objects to ICM colors. Must // force brush/pens to be re-realized when used next // IcmTranslateColorObjects(hdc,pdcattr,TRUE); } } else { WARNING("IcmUpdateDCInfo():CreateColorTransform failed\n"); // // Fail to create new transform, keep as is. // bRet = FALSE; } } else { WARNING("IcmUpdateDCInfo():No destination color space\n"); bRet = FALSE; } } else { ICMMSG(("IcmUpdateDCColorInfo(): Color space does not change or not found\n")); } return (bRet); } /******************************Public*Routine******************************\ * IcmUpdateLocalDCColorSpace * * Arguments: * * Return Value: * * History: * * 26.Feb.1997 -by- Hideyuki Nagase [hideyukn] * \**************************************************************************/ BOOL IcmUpdateLocalDCColorSpace( HDC hdc, PDC_ATTR pdcattr ) { BOOL bRet = FALSE; BOOL bDirtyXform = FALSE; PLDC pldc; PGDI_ICMINFO pIcmInfo; WCHAR ProfileName[MAX_PATH]; DWORD dwColorSpaceFlag; PCACHED_COLORSPACE pNewColorSpace = NULL; ICMAPI(("gdi32: IcmUpdateLocalDCColorSpace\n")); ASSERTGDI(pdcattr != NULL,"IcmUpdateLocalDCColorSpace(): pdcattr == NULL\n"); pldc = pdcattr->pvLDC; pIcmInfo = GET_ICMINFO(pdcattr); ASSERTGDI(pIcmInfo != NULL,"IcmUpdateLocalDCColorSpace(): pIcmInfo == NULL\n"); // // if the DC already has a destination colorspace, then return TRUE // if ((pIcmInfo->pDestColorSpace == NULL) || (pdcattr->ulDirty_ & DIRTY_COLORSPACE)) { HCOLORSPACE hDIBColorSpace; // // Invalidate profilename. // ProfileName[0] = UNICODE_NULL; dwColorSpaceFlag = 0; hDIBColorSpace = NULL; // // if the target DC has DIBSection. it will be DIBsection's color space // OR sRGB color space. // if (bDIBSectionSelected(pdcattr)) { ENTERCRITICALSECTION(&semColorSpaceCache); if (pdcattr->dwDIBColorSpace) { ICMMSG(("IcmUpdateLocalDCColorSpace(): DIB section in DC (V4/V5)\n")); // // The DIB currently selected, has thier own color space. // This case happens when CreateDIBSection called with // BITMAPV4/V5 header. // pNewColorSpace = (PCACHED_COLORSPACE) pdcattr->dwDIBColorSpace; // // Inc. ref. count. // pNewColorSpace->cRef++; } else { ICMMSG(("IcmUpdateLocalDCColorSpace(): DIB section in DC (no color space)\n")); // [This is Win98 compatible behave] // // If the DIBitmap does not have any specific color space, // keep same color space as current DC. // } LEAVECRITICALSECTION(&semColorSpaceCache); } else if ((pdcattr->ulDirty_ & DC_PRIMARY_DISPLAY) && (PrimaryDisplayProfile[0] != UNICODE_NULL)) { // // Use cached color profile. // lstrcpyW(ProfileName,PrimaryDisplayProfile); } else if (pIcmInfo->flInfo & ICM_VALID_DEFAULT_PROFILE) { // // Use cached color profile. // lstrcpyW(ProfileName,pIcmInfo->DefaultDstProfile); } else { int iRet; // // Still couldn't find yet ??. Ask MSCMS to find out profile. (go slow way) // iRet = IcmEnumColorProfile(hdc,IcmFindProfileCallBack, (LPARAM)ProfileName,FALSE,NULL,&dwColorSpaceFlag); // // if you could not find any profile for this DC, just use sRGB. // if ((iRet == -1) || (ProfileName[0] == UNICODE_NULL)) { ULONG ulSize = MAX_PATH; if (!(*fpGetStandardColorSpaceProfileW)(NULL,LCS_sRGB,ProfileName,&ulSize)) { ICMMSG(("IcmUpdateLocalDCColorSpace():Fail to SCS(sRGB), use hardcode\n")); // // If error, use hardcoded profile name. // wcscpy(ProfileName,sRGB_PROFILENAME); } } // // Create cache for next usage // if ((pdcattr->ulDirty_ & DC_PRIMARY_DISPLAY) && (PrimaryDisplayProfile[0] == UNICODE_NULL)) { lstrcpyW(PrimaryDisplayProfile,ProfileName); } else // otherwise put it into default profile. { lstrcpyW(pIcmInfo->DefaultDstProfile,ProfileName); pIcmInfo->flInfo |= (ICM_VALID_DEFAULT_PROFILE| ICM_VALID_CURRENT_PROFILE); } } // // If default device profile could be found, associate it into this DC. // if ((ProfileName[0] != UNICODE_NULL) || (pNewColorSpace != NULL)) { #if DBG if (ProfileName[0] != UNICODE_NULL) { ICMMSG(("IcmUpdateLocalDCColorSpace():Default Device Profile = %ws\n",ProfileName)); } #endif // // try to find desired color space from cache. // if (pNewColorSpace == NULL) { pNewColorSpace = IcmGetColorSpaceByName( (HGDIOBJ)hdc, ProfileName, pIcmInfo->dwDefaultIntent, dwColorSpaceFlag); if (pNewColorSpace == NULL) { // // create new one. // pNewColorSpace = IcmCreateColorSpaceByName( (HGDIOBJ)hdc, ProfileName, pIcmInfo->dwDefaultIntent, dwColorSpaceFlag); } } if (pNewColorSpace) { // // Is this same destination color space as currently selected in DC ? // if (IcmSameColorSpace(pNewColorSpace,pIcmInfo->pDestColorSpace)) { ICMMSG(("IcmUpdateLocalDCColorSpace():Same color space is selected already\n")); // // Color space does NOT changed. // IcmReleaseColorSpace(NULL,pNewColorSpace,FALSE); bRet = TRUE; } else { // // Notify new color format to kernel. // if (NtGdiSetIcmMode(hdc,ICM_CHECK_COLOR_MODE,pNewColorSpace->ColorFormat)) { // // if we have some color space currently selected, delete it. // if (pIcmInfo->pDestColorSpace) { IcmReleaseColorSpace(NULL,pIcmInfo->pDestColorSpace,FALSE); } // // DC can accept this color space, Set new colorspace to destination. // pIcmInfo->pDestColorSpace = pNewColorSpace; // // Color space is changed. so color transform should be updated. // bDirtyXform = TRUE; bRet = TRUE; } else { WARNING("ICM:Detected colorspace was not accepted by target DC\n"); // // This color space does not match to this DC. // IcmReleaseColorSpace(NULL,pNewColorSpace,FALSE); } } } else { WARNING("Failed IcmUpdateLocalDCColorSpace(), Failed to create new color space.\n"); } } else { WARNING("Failed IcmUpdateLocalDCColorSpace(), no device profile is detected.\n"); } } else { ICMMSG(("IcmUpdateLocalDCColoSpace(): Destination Color Space cache is valid\n")); bRet = TRUE; } // // [Only for Printer] // // If we haven't asked default source color profile for this Printer DC, // Now is the time to ask it. Only do this when apps does NOT specified // thier own color space. // if (bRet && pldc && pldc->hSpooler) { if ((pdcattr->hColorSpace == GetStockObject(PRIV_STOCK_COLORSPACE)) && (pIcmInfo->hDefaultSrcColorSpace == NULL)) { PDEVMODEW pDevModeW = NULL; PVOID pvFree = NULL; BOOL bRetSource = FALSE; // // Default is no DC specific source color space (= INVALID_COLORSPACE), // this also make sure we will not come here again. // pIcmInfo->hDefaultSrcColorSpace = INVALID_COLORSPACE; // // Invalidate profilename. // ProfileName[0] = UNICODE_NULL; dwColorSpaceFlag = 0; if (pldc->pDevMode) { ICMMSG(("IcmUpdateLocalDCColorSpace():Cached DEVMODE used\n")); pDevModeW = pldc->pDevMode; } else { ICMMSG(("IcmUpdateLocalDCColorSpace():Get default DEVMODE\n")); pDevModeW = pdmwGetDefaultDevMode(pldc->hSpooler,NULL,&pvFree); } if (pDevModeW) { // // Get source color proflie from driver. // if (IcmAskDriverForColorProfile(pldc,QCP_SOURCEPROFILE, pDevModeW,ProfileName,&dwColorSpaceFlag) <= 0) { // // No source profile specified. // ProfileName[0] = UNICODE_NULL; } } // // Free devmode buffer. // if (pvFree) { LOCALFREE(pvFree); } // // 1) If default source profile could be found, or // 2) the default intent in devmode is different from LCS_DEFAULT_INTENT, // // we need to create new source color space, then associate it into this DC. // if ((ProfileName[0] != UNICODE_NULL) || (pIcmInfo->dwDefaultIntent != LCS_DEFAULT_INTENT)) { HCOLORSPACE hColorSpace = NULL; ICMMSG(("IcmUpdateLocalDCColorSpace():Default devmode Intent = %d\n", pIcmInfo->dwDefaultIntent)); // // If no color profile specified, use sRGB. // if (ProfileName[0] == UNICODE_NULL) { ULONG ulSize = MAX_PATH; if (!(*fpGetStandardColorSpaceProfileW)(NULL,LCS_sRGB,ProfileName,&ulSize)) { ICMMSG(("IcmUpdateLocalDCColorSpace():Fail to SCS(sRGB), use hardcode\n")); // // If error, use hardcoded profile name. // wcscpy(ProfileName,sRGB_PROFILENAME); } } ICMMSG(("IcmUpdateLocalDCColorSpace():Default Source Profile = %ws\n",ProfileName)); // // Find from cache first. // pNewColorSpace = IcmGetColorSpaceByName( (HGDIOBJ)hdc, ProfileName, pIcmInfo->dwDefaultIntent, dwColorSpaceFlag); if (pNewColorSpace == NULL) { // // create new one. // pNewColorSpace = IcmCreateColorSpaceByName( (HGDIOBJ)hdc, ProfileName, pIcmInfo->dwDefaultIntent, dwColorSpaceFlag); } if (pNewColorSpace) { // // Create kernel-mode handle. // hColorSpace = CreateColorSpaceW(&(pNewColorSpace->LogColorSpace)); if (hColorSpace) { // // Select this into DC. // if (IcmSetSourceColorSpace(hdc,hColorSpace,pNewColorSpace,0)) { // // IcmSetSourceColorSpace increments ref. count of colorspace. // but we have done it by Icm[Get|Create]ColorSpaceByName, so // decrement ref count of color space here. // IcmReleaseColorSpace(NULL,pNewColorSpace,FALSE); // // Keep these into ICMINFO. // pIcmInfo->hDefaultSrcColorSpace = hColorSpace; // // This color space should be deleted later. // pIcmInfo->flInfo |= ICM_DELETE_SOURCE_COLORSPACE; // // Source color space has been changed. // (color transform is updated inside IcmSetSourceColorSpace(). // so not nessesary to set bDirtyXfrom to TRUE) // bRetSource = TRUE; } else { WARNING("Failed IcmUpdateLocalDCColorSpace(), Failed to select new source color space.\n"); } } else { WARNING("Failed IcmUpdateLocalDCColorSpace(), Failed to create new source color space.\n"); } } else { WARNING("Failed IcmUpdateLocalDCColorSpace(), Failed to create new source color space cache.\n"); } if (!bRetSource) { if (hColorSpace) { DeleteColorSpace(hColorSpace); } if (pNewColorSpace) { IcmReleaseColorSpace(NULL,pNewColorSpace,FALSE); } } } else { ICMMSG(("IcmUpdateLocalDCColoSpace(): No default source color Space cache specified\n")); } } } // // Now color space is valid. // if (bRet) { pdcattr->ulDirty_ &= ~DIRTY_COLORSPACE; } if (bDirtyXform) { pdcattr->ulDirty_ |= DIRTY_COLORTRANSFORM; } return (bRet); } /******************************Public*Routine******************************\ * IcmCleanupIcmInfo() * * ATTENTION: semListIcmInfo must be hold by caller * * History: * 16-Feb-1999 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ BOOL IcmCleanupIcmInfo( PDC_ATTR pdcattr, // This can be NULL for clean up case. PGDI_ICMINFO pIcmInfo // This can *NOT* be NULL at any rate. ) { if (ghICM) { // // Delete Saved ICMINFO data (if present) // IcmRestoreDC(pdcattr,1,pIcmInfo); } // // If there is any default source profile (kernel-side), do something here. // if ((pIcmInfo->hDefaultSrcColorSpace != NULL) && (pIcmInfo->hDefaultSrcColorSpace != INVALID_COLORSPACE)) { ICMMSG(("IcmCleanupIcmInfo():Delete/Unselect default source color space\n")); if (pdcattr) { // // If it is currently selected into this DC, un-select it. // if (pIcmInfo->hDefaultSrcColorSpace == pdcattr->hColorSpace) { NtGdiSetColorSpace(pIcmInfo->hdc,GetStockObject(PRIV_STOCK_COLORSPACE)); } } // // And it should be delete it. // if (pIcmInfo->flInfo & ICM_DELETE_SOURCE_COLORSPACE) { DeleteColorSpace(pIcmInfo->hDefaultSrcColorSpace); } pIcmInfo->hDefaultSrcColorSpace = NULL; } if (ghICM) { // // Delete Color transforms // IcmDeleteDCColorTransforms(pIcmInfo); // // Delete Cached color transform related to this DC. // (like device color transform) // IcmDeleteCachedColorTransforms(pIcmInfo->hdc); // // Free ICM colorspace datas. // IcmReleaseDCColorSpace(pIcmInfo,TRUE); // // Delete Cached color space which related to this DC. // (like color space in metafile) // IcmReleaseCachedColorSpace((HGDIOBJ)(pIcmInfo->hdc)); } pIcmInfo->hdc = NULL; pIcmInfo->pvdcattr = NULL; pIcmInfo->flInfo = 0; return(TRUE); } /******************************Public*Routine******************************\ * IcmDeleteLocalDC() * * Arguments: * * Return Value: * * History: * * Jan.31.1997 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ BOOL IcmDeleteLocalDC( HDC hdc, PDC_ATTR pdcattr, PGDI_ICMINFO pIcmInfo ) { ICMAPI(("gdi32: IcmDeleteLocalDC\n")); ASSERTGDI(pdcattr != NULL,"IcmDeleteLocalDC():pdcattr == NULL\n"); // // If callee does not provide ICMINFO, get it from pdcattr. // if (pIcmInfo == NULL) { pIcmInfo = GET_ICMINFO(pdcattr); } // // Invalidate current color tansform. // // (but the cache in ICMINFO is still valid, and will be delete // inside IcmDeleteDCColorTransforms() called from IcmCleanupIcmInfo().) // IcmSelectColorTransform(hdc,pdcattr,NULL,TRUE); if (IS_ICM_INSIDEDC(pdcattr->lIcmMode)) { // // Tell the kernel to disable ICM before delete client side data. // NtGdiSetIcmMode(hdc,ICM_SET_MODE,REQ_ICM_OFF); } // // Clean up ICMINFO. // if (pIcmInfo != NULL) { ENTERCRITICALSECTION(&semListIcmInfo); if (pIcmInfo->flInfo & ICM_ON_ICMINFO_LIST) { // // Remove this ICMINFO from list. (since this will be deleted). // RemoveEntryList(&(pIcmInfo->ListEntry)); } // // Clean up ICMINFO. // IcmCleanupIcmInfo(pdcattr,pIcmInfo); // // Invalidate ICM info in DC_ATTR. // pdcattr->pvICM = NULL; LEAVECRITICALSECTION(&semListIcmInfo); // // Free ICM structure. // LOCALFREE(pIcmInfo); } return(TRUE); } /******************************Public*Routine******************************\ * BOOL IcmSelectColorTransform (HDC, PDC_ATTR, PCACHED_COLORTRANSFORM) * * History: * 23-Sep-1997 -by- Hideyuki Nagase [hideyukn] * Wrote it. \**************************************************************************/ BOOL IcmSelectColorTransform( HDC hdc, PDC_ATTR pdcattr, PCACHED_COLORTRANSFORM pCXform, BOOL bDeviceCalibrate) { if (pCXform) { BMFORMAT ColorFormat = pCXform->DestinationColorSpace->ColorFormat; // LATER : // // if (GET_COLORTYPE(pdcattr->lIcmMode) != IcmConvertColorFormat(ColorFormat)) // if (TRUE) { if (!NtGdiSetIcmMode(hdc,ICM_SET_COLOR_MODE,ColorFormat)) { // // The transform color format is not accepted by DC. // return (FALSE); } } // // Select into the color transform to DC_ATTR. // pdcattr->hcmXform = pCXform->ColorTransform; } else { // // If curent color type is not RGB, call kernel to reset. // if (GET_COLORTYPE(pdcattr->lIcmMode) != DC_ICM_RGB_COLOR) { // // Reset current color mode to RGB (default). // NtGdiSetIcmMode(hdc,ICM_SET_COLOR_MODE,BM_xBGRQUADS); } // // Select null-color transfrom into the DC_ATTR. // pdcattr->hcmXform = NULL; } // // If device calibration mode need to updated, call kernel to update it. // if ((bDeviceCalibrate ? 1 : 0) != (IS_ICM_DEVICE_CALIBRATE(pdcattr->lIcmMode) ? 1 : 0)) { NtGdiSetIcmMode(hdc,ICM_SET_CALIBRATE_MODE,bDeviceCalibrate); } // // Remove dirty transform flag. // pdcattr->ulDirty_ &= ~DIRTY_COLORTRANSFORM; return(TRUE); } /******************************Public*Routine******************************\ * HBRUSH IcmSelectBrush (HDC hdc, HBRUSH hbrush) * * History: * 04-June-1995 -by- Lingyun Wang [lingyunW] * Wrote it. \**************************************************************************/ HBRUSH IcmSelectBrush ( HDC hdc, PDC_ATTR pdcattr, HBRUSH hbrushNew) { HBRUSH hbrushOld = pdcattr->hbrush; ICMAPI(("gdi32: IcmSelectBrush\n")); // // Mark brush as dirty, select new brush in dcattr. // Color translation may fail, but still select brush // pdcattr->ulDirty_ |= DC_BRUSH_DIRTY; pdcattr->hbrush = hbrushNew; if (bNeedTranslateColor(pdcattr)) { IcmTranslateBrushColor(hdc,pdcattr,hbrushNew); } return (hbrushOld); } /******************************Public*Routine******************************\ * HBRUSH IcmTranslateBrushColor(HDC hdc, PDC_ATTR pdcattr, HBRUSH hbrush) * * History: * 10-Apr-1997 -by- Hideyuki Nagase [hideyukn] * Wrote it. \**************************************************************************/ BOOL IcmTranslateBrushColor( HDC hdc, PDC_ATTR pdcattr, HBRUSH hbrush) { BOOL bStatus = FALSE; COLORREF OldColor; COLORREF NewColor; PBRUSHATTR pbra; // // Invalidate BRUSH_TRANSLATED // pdcattr->ulDirty_ &= ~ICM_BRUSH_TRANSLATED; PSHARED_GET_VALIDATE(pbra,hbrush,BRUSH_TYPE); if (pbra) { // // translate to new icm mode if not paletteindex // OldColor = pbra->lbColor; if (!(OldColor & 0x01000000)) { bStatus = IcmTranslateCOLORREF(hdc, pdcattr, OldColor, &NewColor, ICM_FORWARD); if (bStatus) { pdcattr->IcmBrushColor = NewColor; } else { pdcattr->IcmBrushColor = OldColor; } } else { pdcattr->IcmBrushColor = OldColor; } // // Somehow, IcmBrushColor is initialized. // pdcattr->ulDirty_ |= ICM_BRUSH_TRANSLATED; } else { LOGBRUSH lbrush; // // stock brush or bitmap/hatch/dib brush // if(GetObjectW(hbrush,sizeof(LOGBRUSH),&lbrush)) { if ((lbrush.lbStyle == BS_SOLID) || (lbrush.lbStyle == BS_HATCHED)) { // // try to translate color // OldColor = lbrush.lbColor; if (!(OldColor & 0x01000000)) { bStatus = IcmTranslateCOLORREF(hdc, pdcattr, OldColor, &NewColor, ICM_FORWARD); if (bStatus) { pdcattr->IcmBrushColor = NewColor; } else { pdcattr->IcmBrushColor = OldColor; } } else { pdcattr->IcmBrushColor = OldColor; } // // IcmBrushColor is initialized. // pdcattr->ulDirty_ |= ICM_BRUSH_TRANSLATED; } else if (lbrush.lbStyle == BS_DIBPATTERN) { PBITMAPINFO pbmiDIB; // // Allocate temorary bitmap info header to get brush bitmap // pbmiDIB = (PBITMAPINFO)LOCALALLOC(sizeof(BITMAPINFO)+((256-1)*sizeof(RGBQUAD))); if (pbmiDIB) { ULONG iColorUsage; BOOL bAlreadyTran; BOOL bStatus; PVOID pvBits = NULL; ULONG cjBits = 0; // // Get brush bitmap information, colortype, size, etc. // bStatus = NtGdiIcmBrushInfo(hdc, hbrush, pbmiDIB, pvBits, &cjBits, &iColorUsage, &bAlreadyTran, IcmQueryBrush); if (bStatus) { if ((iColorUsage == DIB_RGB_COLORS) && (!bAlreadyTran) && (cjBits)) { pvBits = (PVOID) LOCALALLOC(cjBits); if (pvBits) { // // Get brush bitmap bits. // bStatus = NtGdiIcmBrushInfo(hdc, hbrush, pbmiDIB, pvBits, &cjBits, NULL, NULL, IcmQueryBrush); if (bStatus) { // // IcmTranslateDIB may create new copy of bitmap bits and/or // bitmap info header, if nessesary. // PVOID pvBitsNew = NULL; PBITMAPINFO pbmiDIBNew = NULL; bStatus = IcmTranslateDIB(hdc, pdcattr, cjBits, pvBits, &pvBitsNew, pbmiDIB, &pbmiDIBNew, NULL, (DWORD)-1, iColorUsage, ICM_FORWARD, NULL,NULL); if (bStatus) { if (pvBitsNew != NULL) { // // IcmTranslateDIB creates new bitmap buffer, then // free original buffer and set new one. // LOCALFREE(pvBits); pvBits = pvBitsNew; } if (pbmiDIBNew != NULL) { // // If bitmapInfo header is updated, use new one. // And, need to compute bitmap bits size based // on new bitmap header. // LOCALFREE(pbmiDIB); pbmiDIB = pbmiDIBNew; // // Calculate bitmap bits size based on BITMAPINFO and nNumScans // cjBits = cjBitmapBitsSize(pbmiDIB); } // // Set ICM-translated DIB into brush // bStatus = NtGdiIcmBrushInfo(hdc, hbrush, pbmiDIB, pvBits, &cjBits, NULL, NULL, IcmSetBrush); if (bStatus) { // // The color is translated. // bAlreadyTran = TRUE; } else { WARNING("IcmSelectBrush():NtGdiIcmBrushInfo(SET) Failed\n"); } } else { WARNING("IcmSelectBrush():IcmTranslateDIB() Failed\n"); } } else { WARNING("IcmSelectBrush():NtGdiIcmBrushInfo(GET) Failed\n"); } LOCALFREE(pvBits); } else { WARNING("IcmSelectBrush(): LOCALALLOC(pvBits) failed\n"); } } if (bAlreadyTran) { // // Eventually, IcmBrushColor is initialized. // pdcattr->ulDirty_ |= ICM_BRUSH_TRANSLATED; } } else { ICMWRN(("IcmSelectBrush(): Fail to get brush bitmap size or bitmap is DIB_PAL_COLORS\n")); } LOCALFREE(pbmiDIB); } else { WARNING("IcmSelectBrush(): LOCALALLOC(pbmi) failed\n"); } } else { ICMMSG(("IcmSelectBrush(): ICM will not done for this style - %d\n",lbrush.lbStyle)); } } else { WARNING("IcmSelectBrush(): GetObject failed on hbrush\n"); pdcattr->IcmBrushColor = CLR_INVALID; } } return (bStatus); } /******************************Public*Routine******************************\ * IcmSelectPen() * * History: * * Wrote it: * 31-Jul-1996 -by- Mark Enstrom [marke] \**************************************************************************/ HPEN IcmSelectPen( HDC hdc, PDC_ATTR pdcattr, HPEN hpenNew ) { HPEN hpenOld = pdcattr->hpen; ICMAPI(("gdi32: IcmSelectPen\n")); pdcattr->ulDirty_ |= DC_PEN_DIRTY; pdcattr->hpen = hpenNew; if (bNeedTranslateColor(pdcattr)) { IcmTranslatePenColor(hdc,pdcattr,hpenNew); } return (hpenOld); } /******************************Public*Routine******************************\ * BOOL IcmTranslatePenColor(HDC hdc, PDC_ATTR pdcattr, HBRUSH hbrush) * * History: * 10-Apr-1997 -by- Hideyuki Nagase [hideyukn] * Wrote it. \**************************************************************************/ BOOL IcmTranslatePenColor( HDC hdc, PDC_ATTR pdcattr, HPEN hpen ) { BOOL bStatus = FALSE; COLORREF OldColor; COLORREF NewColor; PBRUSHATTR pbra; // // Invalidate PEN_TRANSLATED // pdcattr->ulDirty_ &= ~ICM_PEN_TRANSLATED; PSHARED_GET_VALIDATE(pbra,hpen,BRUSH_TYPE); if (pbra) { OldColor = pbra->lbColor; // // translate to new icm mode if not paletteindex // if (!(OldColor & 0x01000000)) { bStatus = IcmTranslateCOLORREF(hdc, pdcattr, OldColor, &NewColor, ICM_FORWARD); if (bStatus) { pdcattr->IcmPenColor = NewColor; } else { pdcattr->IcmPenColor = OldColor; } } else { pdcattr->IcmPenColor = OldColor; } // // IcmPenColor is initialized. // pdcattr->ulDirty_ |= ICM_PEN_TRANSLATED; } else { LOGPEN logpen; // // stock brush or bitmap/hatch/dib brush // if(GetObjectW(hpen,sizeof(LOGPEN),&logpen)) { if (logpen.lopnStyle != PS_NULL) { // // try to translate color // OldColor = logpen.lopnColor; if (!(OldColor & 0x01000000)) { bStatus = IcmTranslateCOLORREF(hdc, pdcattr, OldColor, &NewColor, ICM_FORWARD); if (bStatus) { pdcattr->IcmPenColor = NewColor; } else { pdcattr->IcmPenColor = OldColor; } } else { pdcattr->IcmPenColor = OldColor; } // // IcmPenColor is initialized. // pdcattr->ulDirty_ |= ICM_PEN_TRANSLATED; } else { ICMMSG(("IcmSelectPen():Pen style is PS_NULL\n")); pdcattr->IcmPenColor = CLR_INVALID; } } else { WARNING("GetObject failed on hbrush\n"); pdcattr->IcmPenColor = CLR_INVALID; } } return(bStatus); } /******************************Public*Routine******************************\ * IcmSelectExtPen() * * History: * * Wrote it: * 11-Mar-1997 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ HPEN IcmSelectExtPen( HDC hdc, PDC_ATTR pdcattr, HPEN hpenNew ) { HPEN hpenOld; ICMAPI(("gdi32: IcmSelectExtPen\n")); // // Invalidate PEN_TRANSLATED // pdcattr->ulDirty_ &= ~ICM_PEN_TRANSLATED; // // Call kernel to select this object. // hpenOld = NtGdiSelectPen(hdc,hpenNew); if (hpenOld && bNeedTranslateColor(pdcattr)) { IcmTranslateExtPenColor(hdc,pdcattr,hpenNew); } return (hpenOld); } /******************************Public*Routine******************************\ * BOOL IcmTranslateExtPenColor(HDC hdc, PDC_ATTR pdcattr, HBRUSH hbrush) * * History: * 10-Apr-1997 -by- Hideyuki Nagase [hideyukn] * Wrote it. \**************************************************************************/ BOOL IcmTranslateExtPenColor( HDC hdc, PDC_ATTR pdcattr, HPEN hpen ) { BOOL bStatus = FALSE; COLORREF OldColor; COLORREF NewColor; EXTLOGPEN logpenLocal; EXTLOGPEN *plogpen = &logpenLocal; if (!GetObjectW(hpen,sizeof(EXTLOGPEN),plogpen)) { ULONG cbNeeded; // // It might be PS_USERSTYLE (go slow way...) // cbNeeded = GetObjectW(hpen,0,NULL); if (cbNeeded) { plogpen = LOCALALLOC(cbNeeded); if (plogpen) { if (!GetObjectW(hpen,cbNeeded,plogpen)) { LOCALFREE(plogpen); plogpen = NULL; } } } else { plogpen = NULL; } } if (plogpen) { if ((plogpen->elpBrushStyle == BS_SOLID) || (plogpen->elpBrushStyle == BS_HATCHED)) { ICMMSG(("IcmSelectExtPen:BS_SOLID or BS_HATCHED\n")); // // try to translate color // OldColor = plogpen->elpColor; if (!(OldColor & 0x01000000)) { bStatus = IcmTranslateCOLORREF(hdc, pdcattr, OldColor, &NewColor, ICM_FORWARD); if (bStatus) { pdcattr->IcmPenColor = NewColor; } else { pdcattr->IcmPenColor = OldColor; } } else { pdcattr->IcmPenColor = OldColor; } // // Somehow, IcmPenColor is initialized. // pdcattr->ulDirty_ |= ICM_PEN_TRANSLATED; } else if ((plogpen->elpBrushStyle == BS_DIBPATTERN) || (plogpen->elpBrushStyle == BS_DIBPATTERNPT)) { PBITMAPINFO pbmiDIB; ICMMSG(("IcmSelectExtPen:BS_DIBPATTERN or BS_DIBPATTERNPT\n")); // // Allocate temorary bitmap info header to get brush bitmap // pbmiDIB = (PBITMAPINFO)LOCALALLOC(sizeof(BITMAPINFO)+((256-1)*sizeof(RGBQUAD))); if (pbmiDIB) { ULONG iColorUsage; BOOL bAlreadyTran; PVOID pvBits = NULL; ULONG cjBits = 0; // // Get brush bitmap information, colortype, size, etc. // bStatus = NtGdiIcmBrushInfo(hdc, (HBRUSH)hpen, pbmiDIB, pvBits, &cjBits, &iColorUsage, &bAlreadyTran, IcmQueryBrush); if (bStatus) { if ((iColorUsage == DIB_RGB_COLORS) && (!bAlreadyTran) && (cjBits)) { pvBits = (PVOID) LOCALALLOC(cjBits); if (pvBits) { // // Get brush bitmap bits. // bStatus = NtGdiIcmBrushInfo(hdc, (HBRUSH)hpen, pbmiDIB, pvBits, &cjBits, NULL, NULL, IcmQueryBrush); if (bStatus) { // // must make a copy of the DIB data // DWORD dwNumScan = ABS(pbmiDIB->bmiHeader.biHeight); ULONG nColors = pbmiDIB->bmiHeader.biWidth * dwNumScan * (pbmiDIB->bmiHeader.biBitCount/8); // // IcmTranslateDIB may create new copy of bitmap bits and/or // bitmap info header, if nessesary. // PVOID pvBitsNew = NULL; PBITMAPINFO pbmiDIBNew = NULL; bStatus = IcmTranslateDIB(hdc, pdcattr, nColors, pvBits, &pvBitsNew, pbmiDIB, &pbmiDIBNew, NULL, dwNumScan, iColorUsage, ICM_FORWARD, NULL,NULL); if (bStatus) { if (pvBitsNew != NULL) { // // IcmTranslateDIB creates new bitmap buffer, then // free original buffer and set new one. // LOCALFREE(pvBits); pvBits = pvBitsNew; } if (pbmiDIBNew != NULL) { // // If bitmapInfo header is updated, use new one. // And, need to compute bitmap bits size based // on new bitmap header. // LOCALFREE(pbmiDIB); pbmiDIB = pbmiDIBNew; // // Calculate bitmap bits size based on BITMAPINFO and nNumScans // cjBits = cjBitmapBitsSize(pbmiDIB); } // // Set ICM-translated DIB into brush // bStatus = NtGdiIcmBrushInfo(hdc, (HBRUSH)hpen, pbmiDIB, pvBits, &cjBits, NULL, NULL, IcmSetBrush); if (bStatus) { // // Translated. // bAlreadyTran = TRUE; } else { WARNING("IcmSelectExtPen():NtGdiIcmBrushInfo(SET) Failed\n"); } } else { WARNING("IcmSelectBrush():IcmTranslateDIB() Failed\n"); } } else { WARNING("IcmSelectExtPen():NtGdiIcmBrushInfo(GET) Failed\n"); } LOCALFREE(pvBits); } else { WARNING("IcmSelectExtPen(): LOCALALLOC(pvBits) failed\n"); } } if (bAlreadyTran) { // // Eventually, IcmPenColor is initialized. // pdcattr->ulDirty_ |= ICM_PEN_TRANSLATED; } } else { ICMWRN(("IcmSelectBrush(): Fail to get brush bitmap size or bitmap is DIB_PAL_COLORS\n")); } LOCALFREE(pbmiDIB); } else { WARNING("IcmSelectExtPen(): LOCALALLOC(pbmi) failed\n"); } } else { #if DBG_ICM DbgPrint("IcmSelectExtPen:ICM does not support this style (%d), yet\n",plogpen->elpBrushStyle); #endif } if (plogpen != &logpenLocal) { LOCALFREE(plogpen); } } else { WARNING("IcmSelectExtPen():GetObjectW() failed on hextpen\n"); } return(bStatus); } /******************************Public*Routine******************************\ * IcmGetProfileColorFormat() * * History: * * Write it: * 12-Feb-1997 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ BMFORMAT IcmGetProfileColorFormat( HPROFILE hProfile ) { // // defaut is RGB // ULONG ColorFormat = BM_xBGRQUADS; PROFILEHEADER ProfileHeader; ICMAPI(("gdi32: IcmGetProfileColorFormat\n")); // // Get profile header information. // if (((*fpGetColorProfileHeader)(hProfile,&ProfileHeader))) { DWORD ColorSpace; // // Yes, we succeed to get profile header. // ColorSpace = ProfileHeader.phDataColorSpace; // // Figure out color format from color space. // switch (ColorSpace) { case SPACE_CMYK: ICMMSG(("IcmGetProfileColorFormat(): CMYK Color Space\n")); // // Output format is CMYK color. // ColorFormat = BM_KYMCQUADS; break; case SPACE_RGB: ICMMSG(("IcmGetProfileColorFormat(): RGB Color Space\n")); // // Output format is same as COLORREF (0x00bbggrr) // ColorFormat = BM_xBGRQUADS; break; default: WARNING("IcmGetProfileColorFormat(): Unknown color space\n"); ColorFormat = 0xFFFFFFFF; break; } } return (ColorFormat); } /******************************Public*Routine******************************\ * IcmEnumColorProfile() * * History: * * Write it: * 12-Feb-1997 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ int IcmEnumColorProfile( HDC hdc, PVOID pvCallBack, LPARAM lParam, BOOL bAnsiCallBack, PDEVMODEW pDevModeW, DWORD *pdwColorSpaceFlag ) { int iRet = -1; // -1 means fail. int iRetFromCMS = -1; BYTE StackDeviceData[MAX_PATH*2*sizeof(WCHAR)]; WCHAR StackProfileData[MAX_PATH]; WCHAR StackTempBuffer[MAX_PATH]; CHAR StackTempBufferA[MAX_PATH]; PVOID pvFree = NULL; PWSTR ProfileNames = StackProfileData; DWORD cjAllocate = 0; LPWSTR pDeviceName = NULL; DWORD dwDeviceClass = 0L; PLDC pldc = NULL; DWORD bDontAskDriver = FALSE; DWORD dwSize; ICMAPI(("gdi32: IcmEnumColorProfile\n")); // // Load external ICM dlls // LOAD_ICMDLL(iRet); // // Try to identify device name, class and devmode (if hdc is given) // if (hdc) { pldc = GET_PLDC(hdc); if (pldc && pldc->hSpooler) { DWORD cbFilled; // // This is printer. // dwDeviceClass = CLASS_PRINTER; // // Get current DEVMODE for printer (if devmode is not given) // if (!pDevModeW) { if (pldc->pDevMode) { ICMMSG(("IcmEnumColorProfile():Cached DEVMODE used\n")); pDevModeW = pldc->pDevMode; } else { ICMMSG(("IcmEnumColorProfile():Get default DEVMODE\n")); // // UNDER_CONSTRUCTION: NEED TO USE CURRENT DEVMODE, NOT DEFAULT DEVMODE. // pDevModeW = pdmwGetDefaultDevMode(pldc->hSpooler,NULL,&pvFree); } } // // Get printer device name, Try level 1 information. // if ((*fpGetPrinterW)(pldc->hSpooler,1, (BYTE *) &StackDeviceData,sizeof(StackDeviceData), &cbFilled)) { PRINTER_INFO_1W *pPrinterInfo1 = (PRINTER_INFO_1W *) &StackDeviceData; // // Device name is in there. // pDeviceName = pPrinterInfo1->pName; } else { ICMMSG(("IcmEnumColorProfile():FAILED on GetPrinterW(INFO_1) - %d\n",GetLastError())); // // Failed on GetPrinter, So get device name from DEVMODE // (this will be limited to 32 character, but better than nothing.) // if (pDevModeW) { pDeviceName = pDevModeW->dmDeviceName; } } // // Get configuration about we need to ask driver for profile or not. // dwSize = sizeof(DWORD); if ((*fpInternalGetDeviceConfig)(pDeviceName, CLASS_PRINTER, MSCMS_PROFILE_ENUM_MODE, &bDontAskDriver, &dwSize)) { ICMMSG(("IcmEnumColorProfile():EnumMode = %d\n",bDontAskDriver)); } else { bDontAskDriver = FALSE; // if error, set back as default. } } else if (GetDeviceCaps(hdc,TECHNOLOGY) == DT_RASDISPLAY) { // // This is display. // dwDeviceClass = CLASS_MONITOR; // // Get monitor name for this DC. // if (NtGdiGetMonitorID(hdc,sizeof(StackDeviceData), (LPWSTR) StackDeviceData)) { pDeviceName = (LPWSTR) StackDeviceData; } else { WARNING("NtGdiGetMonitorID failed, use hardcoded data\n"); // // If failed, use "DISPLAY" // pDeviceName = L"DISPLAY"; } } } else if (pDevModeW) { pDeviceName = pDevModeW->dmDeviceName; } if (pDeviceName) { ICMMSG(("IcmEnumColorProfile() DeviceName = %ws\n",pDeviceName)); } // // If we have devmode, call printer driver UI first to obtain color profile. // if (pDevModeW && /* devmode should be given */ pdwColorSpaceFlag && /* no query context */ pldc && pldc->hSpooler && /* only for printer driver */ !bDontAskDriver) /* only when we need ask driver */ { // // Ask (Printer UI) driver for default device color profile // iRetFromCMS = IcmAskDriverForColorProfile(pldc,QCP_DEVICEPROFILE, pDevModeW,ProfileNames,pdwColorSpaceFlag); // // if iRet is greater then 0, driver have paticular color profile to use. // if (iRetFromCMS > 0) { if (pvCallBack) { // // Build ICM profile file path. // BuildIcmProfilePath(ProfileNames,StackTempBuffer,MAX_PATH); if (bAnsiCallBack) { bToASCII_N(StackTempBufferA,MAX_PATH, StackTempBuffer, wcslen(StackTempBuffer)+1); // // Callback application. // iRet = (*(ICMENUMPROCA)pvCallBack)(StackTempBufferA,lParam); } else { iRet = (*(ICMENUMPROCW)pvCallBack)(StackTempBuffer,lParam); } if (iRet > 0) { // // If iRet is positive value, continue to enumeration. // iRetFromCMS = -1; } } else { // // There is no call back function, just use return value from CMS. // iRet = iRetFromCMS; } } else { iRetFromCMS = -1; } } if (iRetFromCMS == -1) { ENUMTYPEW EnumType; // // Initialize with zero. // RtlZeroMemory(&EnumType,sizeof(ENUMTYPEW)); // // Fill up EnumType structure // EnumType.dwSize = sizeof(ENUMTYPEW); EnumType.dwVersion = ENUM_TYPE_VERSION; // // If device name is given use it, otherwise get it from DEVMODE. // if (pDeviceName) { EnumType.dwFields |= ET_DEVICENAME; EnumType.pDeviceName = pDeviceName; } // // Set DeviceClass (if hdc is given) // if (dwDeviceClass) { EnumType.dwFields |= ET_DEVICECLASS; EnumType.dwDeviceClass = dwDeviceClass; } // // Pick up any additional info from devmode (if we have) // if (pDevModeW) { // // Set MediaType is presented. // if (pDevModeW->dmFields & DM_MEDIATYPE) { EnumType.dwFields |= ET_MEDIATYPE; EnumType.dwMediaType = pDevModeW->dmMediaType; } if (pDevModeW->dmFields & DM_DITHERTYPE) { EnumType.dwFields |= ET_DITHERMODE; EnumType.dwDitheringMode = pDevModeW->dmDitherType; } if ((pDevModeW->dmFields & DM_PRINTQUALITY) && (pDevModeW->dmPrintQuality >= 0)) { EnumType.dwFields |= ET_RESOLUTION; EnumType.dwResolution[0] = pDevModeW->dmPrintQuality; if (pDevModeW->dmFields & DM_YRESOLUTION) { EnumType.dwResolution[1] = pDevModeW->dmYResolution; } else { EnumType.dwResolution[1] = pDevModeW->dmPrintQuality; } ICMMSG(("Resolution in devmode (%d,%d)\n", EnumType.dwResolution[0],EnumType.dwResolution[1])); } } // // Figure out how much memory we need. // iRetFromCMS = (*fpEnumColorProfilesW)(NULL,&EnumType,NULL,&cjAllocate,NULL); // // Buffer should be requested ,at least, more then 2 unicode-null. // if (cjAllocate > (sizeof(UNICODE_NULL) * 2)) { // // If the buffer on stack is not enough, allocate it. // if (cjAllocate > sizeof(StackProfileData)) { // // Allocate buffer to recieve data. // ProfileNames = LOCALALLOC(cjAllocate); if (ProfileNames == NULL) { GdiSetLastError(ERROR_NOT_ENOUGH_MEMORY); goto IcmEnumColorProfile_Cleanup; } } // // Enumurate profiles // iRetFromCMS = (*fpEnumColorProfilesW)(NULL,&EnumType,(PBYTE)ProfileNames,&cjAllocate,NULL); if (iRetFromCMS == 0) { // // There is no profile enumulated. // goto IcmEnumColorProfile_Cleanup; } if (pvCallBack) { PWSTR pwstr; // // Callback for each file. // pwstr = ProfileNames; while(*pwstr) { // // Build ICM profile file path. // BuildIcmProfilePath(pwstr,StackTempBuffer,MAX_PATH); if (bAnsiCallBack) { bToASCII_N(StackTempBufferA,MAX_PATH, StackTempBuffer, wcslen(StackTempBuffer)+1); // // Callback application. // iRet = (*(ICMENUMPROCA)pvCallBack)(StackTempBufferA,lParam); } else { iRet = (*(ICMENUMPROCW)pvCallBack)(StackTempBuffer,lParam); } if (iRet == 0) { // // Stop enumlation. // break; } // // Move pointer to next. // pwstr += (wcslen(pwstr)+1); } } else { // // There is no call back function, just use return value from CMS. // iRet = iRetFromCMS; } } IcmEnumColorProfile_Cleanup: if (ProfileNames && (ProfileNames != StackProfileData)) { LOCALFREE(ProfileNames); } } // // Free devmode buffer. // if (pvFree) { LOCALFREE(pvFree); } return (iRet); } /******************************Public*Routine******************************\ * IcmQueryProfileCallBack() * * History: * * Write it: * 19-Feb-1997 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ int CALLBACK IcmQueryProfileCallBack( LPWSTR lpFileName, LPARAM lAppData ) { PROFILECALLBACK_DATA *ProfileCallBack = (PROFILECALLBACK_DATA *)lAppData; if (lpFileName) { PWSZ FileNameOnly = GetFileNameFromPath(lpFileName); if (_wcsicmp(ProfileCallBack->pwszFileName,FileNameOnly) == 0) { // // Yes, found it. // ProfileCallBack->bFound = TRUE; // // stop enumuration. // return (0); } } // // Continue to enumuration. // return (1); } /******************************Public*Routine******************************\ * IcmFindProfileCallBack() * * History: * * Write it: * 19-Feb-1997 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ int CALLBACK IcmFindProfileCallBack( LPWSTR lpFileName, LPARAM lAppData ) { // // OK, just pick up first enumuration. // lstrcpyW((PWSZ)lAppData,lpFileName); // // And then stop enumuration. // return (0); } /******************************Public*Routine******************************\ * GetFileNameFromPath() * * History: * * Write it: * 19-Feb-1997 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ PWSTR GetFileNameFromPath( PWSTR pwszFileName ) { PWSTR FileNameOnly = NULL; // // Check for: C:\PathName\Profile.icm // FileNameOnly = wcsrchr(pwszFileName,L'\\'); if (FileNameOnly != NULL) { FileNameOnly++; // Skip '\\' } else { // // For: C:Profile.icm // FileNameOnly = wcschr(pwszFileName,L':'); if (FileNameOnly != NULL) { FileNameOnly++; // Skip ':' } else { // // Otherwise Profile.icm // FileNameOnly = pwszFileName; } } return (FileNameOnly); } /******************************Public*Routine******************************\ * IcmCreateProfileFromLCS() * * History: * * Write it: * 19-Feb-1997 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ BOOL IcmCreateProfileFromLCS( LPLOGCOLORSPACEW lpLogColorSpaceW, PVOID *ppvProfileData, PULONG pulProfileSize ) { BOOL bRet; ICMAPI(("gdi32: IcmCreateProfileFromLCS\n")); // // Call MSCMS.DLL to create Profile from LOGCOLORSPACE // bRet = (*fpCreateProfileFromLogColorSpaceW)(lpLogColorSpaceW, (PBYTE *)ppvProfileData); if (bRet && *ppvProfileData) { *pulProfileSize = (ULONG)GlobalSize(*ppvProfileData); } return (bRet); } /******************************Public*Routine******************************\ * BuildIcmProfilePath() * * History: * * Write it: * 07-Apr-1997 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ PWSZ BuildIcmProfilePath( PWSZ FileName, // IN PWSZ FullPathFileName, // OUT ULONG BufferSize ) { PWSZ FileNameOnly; // // BufferSize - need to be used for overrap check sometime later... // FileNameOnly = GetFileNameFromPath(FileName); if (FileName == FileNameOnly) { // It seems we don't have any specified path, just use color directory. const UINT c_cBufChars = MAX_PATH; // Use a temporary because FileName and FullPathFileName can be the same // and wcsncpy doesn't like that. WCHAR awchTemp[MAX_PATH]; int count = c_cBufChars; // Copy color directory first, then filename // wcsncpy does not append a NULL if the count is smaller than the // string. Do it manually so that wcsncat and wcslen work. wcsncpy(awchTemp, ColorDirectory, count); awchTemp[c_cBufChars-1] = 0; // Leave space for the NULL terminator. Note, because we append a // NULL terminator above, wcslen cannot return a number bigger than // BufferSize-1. Therefore the resulting count cannot be negative. count = c_cBufChars-wcslen(awchTemp)-1; ASSERT(count>=0); wcsncat(awchTemp,L"\\",count); // leave space for the NULL count = c_cBufChars-wcslen(awchTemp)-1; ASSERT(count>=0); wcsncat(awchTemp, FileNameOnly, count); // copy to the final destination and force NULL termination. wcsncpy(FullPathFileName, awchTemp, BufferSize); FullPathFileName[BufferSize-1] = 0; } else { // // Input path contains path, just use that. // if (FileName != FullPathFileName) { // // Source and destination buffer is different, need to copy. // wcsncpy(FullPathFileName,FileName,BufferSize); FullPathFileName[BufferSize-1] = 0; } } return (FileNameOnly); } /******************************Public*Routine******************************\ * IcmSameColorSpace() * * History: * * Write it: * 21-Apr-1997 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ BOOL IcmSameColorSpace( PCACHED_COLORSPACE pColorSpaceA, PCACHED_COLORSPACE pColorSpaceB ) { ICMAPI(("gdi32: IcmSameColorSpace\n")); if (pColorSpaceA == pColorSpaceB) { ICMMSG(("IcmSameColorSpace - Yes\n")); return (TRUE); } else { ICMMSG(("IcmSameColorSpace - No\n")); return (FALSE); } } /******************************Public*Routine******************************\ * IcmGetColorSpaceByColorSpace() * * History: * * Write it: * 21-Apr-1997 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ PCACHED_COLORSPACE IcmGetColorSpaceByColorSpace( HGDIOBJ hObjRequest, LPLOGCOLORSPACEW lpLogColorSpace, PPROFILE pColorProfile, DWORD dwColorSpaceFlags ) { PCACHED_COLORSPACE pCandidateColorSpace = NULL; PWSZ pProfileName; BOOL bNeedMatchHdc = FALSE; PLIST_ENTRY p; ICMAPI(("gdi32: IcmGetColorSpaceByColorSpace\n")); // // If this is "on memory" profile which size is larger than // maximum size of cachable profile withOUT filename, // don't search cache, since we never be able to find from cache. // if (pColorProfile && (pColorProfile->dwType == PROFILE_MEMBUFFER) && (pColorProfile->cbDataSize > MAX_SIZE_OF_COLORPROFILE_TO_CACHE) && (lpLogColorSpace->lcsFilename[0] == UNICODE_NULL)) { return (NULL); } // // If this is metafile color space, must match hdc. // if (GET_COLORSPACE_TYPE(dwColorSpaceFlags) == GET_COLORSPACE_TYPE(METAFILE_COLORSPACE)) { bNeedMatchHdc = TRUE; } pProfileName = lpLogColorSpace->lcsFilename; // // Search from cache. // ENTERCRITICALSECTION(&semColorSpaceCache); p = ListCachedColorSpace.Flink; while(p != &ListCachedColorSpace) { pCandidateColorSpace = CONTAINING_RECORD(p,CACHED_COLORSPACE,ListEntry); // // If this colorspace depends on specific gdi object, check it. // if (/* hdc is match */ (pCandidateColorSpace->hObj == hObjRequest) || /* candidate is not specific to hdc, and does not need to match hdc */ ((bNeedMatchHdc == FALSE) && (pCandidateColorSpace->hObj == NULL))) { LOGCOLORSPACEW *pCandidateLogColorSpace; PWSZ pCandidateProfileName; // // Get pointer to profile // pCandidateLogColorSpace = &(pCandidateColorSpace->LogColorSpace); pCandidateProfileName = pCandidateColorSpace->LogColorSpace.lcsFilename; // // Check lcsIntent. // if (pCandidateLogColorSpace->lcsIntent == lpLogColorSpace->lcsIntent) { // // Check profile name if given // if (*pProfileName && *pCandidateProfileName) { if (_wcsicmp(pProfileName,pCandidateProfileName) == 0) { ICMMSG(("IcmGetColorSpaceByColorSpace():Find in cache (by profile name)\n")); // // Find it ! then Increment ref. counter // pCandidateColorSpace->cRef++; break; } } else if ((*pProfileName == UNICODE_NULL) && (*pCandidateProfileName == UNICODE_NULL)) { if (pColorProfile == NULL) { // // Both of color space does not have color profile, check inside LOGCOLORSPACE. // if ((pCandidateLogColorSpace->lcsCSType == lpLogColorSpace->lcsCSType) && (pCandidateLogColorSpace->lcsGammaRed == lpLogColorSpace->lcsGammaRed) && (pCandidateLogColorSpace->lcsGammaGreen == lpLogColorSpace->lcsGammaGreen) && (pCandidateLogColorSpace->lcsGammaBlue == lpLogColorSpace->lcsGammaBlue) && (RtlCompareMemory(&(pCandidateLogColorSpace->lcsEndpoints), &(lpLogColorSpace->lcsEndpoints),sizeof(CIEXYZTRIPLE)) == sizeof(CIEXYZTRIPLE))) { ICMMSG(("IcmGetColorSpaceByColorSpace():Find in cache (by metrics)\n")); // // Find it ! then Increment ref. counter // pCandidateColorSpace->cRef++; break; } } else if ((pColorProfile->dwType == PROFILE_MEMBUFFER) && (pCandidateColorSpace->ColorProfile.dwType == PROFILE_MEMBUFFER)) { if (pCandidateColorSpace->ColorProfile.cbDataSize == pColorProfile->cbDataSize) { if (RtlCompareMemory(pCandidateColorSpace->ColorProfile.pProfileData, pColorProfile->pProfileData, pColorProfile->cbDataSize) == pColorProfile->cbDataSize) { ICMMSG(("IcmGetColorSpaceByColorSpace():Find in cache (by on memory profile)\n")); // // Find it ! then Increment ref. counter // pCandidateColorSpace->cRef++; break; } } } } } } p = p->Flink; pCandidateColorSpace = NULL; } LEAVECRITICALSECTION(&semColorSpaceCache); return (pCandidateColorSpace); } /******************************Public*Routine******************************\ * IcmGetColorSpaceByHandle() * * History: * * Write it: * 21-Apr-1997 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ PCACHED_COLORSPACE IcmGetColorSpaceByHandle( HGDIOBJ hObj, HCOLORSPACE hColorSpace, LPLOGCOLORSPACEW lpLogColorSpace, DWORD dwFlags ) { ULONG cRet; ICMAPI(("gdi32: IcmGetColorSpaceByHandle\n")); // // Get LOGCOLORSPACE from handle // cRet = NtGdiExtGetObjectW(hColorSpace,sizeof(LOGCOLORSPACEW),lpLogColorSpace); if (cRet >= sizeof(LOGCOLORSPACEW)) { if (lpLogColorSpace->lcsFilename[0] != UNICODE_NULL) { // // Normalize filename // BuildIcmProfilePath(lpLogColorSpace->lcsFilename,lpLogColorSpace->lcsFilename,MAX_PATH); } else { if (lpLogColorSpace->lcsCSType != LCS_CALIBRATED_RGB) { ULONG ulSize = MAX_PATH; // // if CSType is not LCS_CALIBRATED_RGB, we should go to MSCMS.DLL // to get color profile for corresponding LCSType, then any given // profile name from application is IGNORED. // if ((*fpGetStandardColorSpaceProfileW)( NULL, lpLogColorSpace->lcsCSType, lpLogColorSpace->lcsFilename, &ulSize)) { ICMMSG(("IcmGetColorSpaceByHandle():CSType %x = %ws\n", lpLogColorSpace->lcsCSType, lpLogColorSpace->lcsFilename)); } else { ICMWRN(("IcmGetColorSpaceByHandle():Error CSType = %x\n", lpLogColorSpace->lcsCSType)); return (NULL); } } } // // Find it ! // return (IcmGetColorSpaceByColorSpace(hObj,lpLogColorSpace,NULL,dwFlags)); } else { ICMWRN(("IcmGetColorSpaceByHandle():Failed on GetObject\n")); return (NULL); } } /******************************Public*Routine******************************\ * IcmGetColorSpaceByName() * * History: * * Write it: * 21-Apr-1997 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ PCACHED_COLORSPACE IcmGetColorSpaceByName( HGDIOBJ hObj, PWSZ ColorProfileName, DWORD dwIntent, DWORD dwFlags ) { ICMAPI(("gdi32: IcmGetColorSpaceByName (%ws)\n",(ColorProfileName ? ColorProfileName : L"null"))); if (ColorProfileName) { LOGCOLORSPACEW LogColorSpace; RtlZeroMemory(&LogColorSpace,sizeof(LOGCOLORSPACEW)); // // Put intent in LOGCOLORSPACE // LogColorSpace.lcsIntent = (LCSGAMUTMATCH) dwIntent; // // Normalize path name // BuildIcmProfilePath(ColorProfileName,LogColorSpace.lcsFilename,MAX_PATH); // // Find it ! // return (IcmGetColorSpaceByColorSpace(hObj,&LogColorSpace,NULL,dwFlags)); } else { return (NULL); } } /******************************Public*Routine******************************\ * IcmCreateColorSpaceByName() * * History: * * Write it: * 21-Apr-1997 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ PCACHED_COLORSPACE IcmCreateColorSpaceByName( HGDIOBJ hObj, PWSZ ColorProfileName, DWORD dwIntent, DWORD dwFlags ) { LOGCOLORSPACEW LogColorSpace; ICMAPI(("gdi32: IcmCreateColorSpaceByName\n")); RtlZeroMemory(&LogColorSpace,sizeof(LOGCOLORSPACEW)); // // Fill up LOGCOLORSPACE fields. // LogColorSpace.lcsSignature = LCS_SIGNATURE; LogColorSpace.lcsVersion = 0x400; LogColorSpace.lcsSize = sizeof(LOGCOLORSPACEW); LogColorSpace.lcsCSType = LCS_CALIBRATED_RGB; LogColorSpace.lcsIntent = (LCSGAMUTMATCH) dwIntent; // // Put profile file name in lcsFilename[] // lstrcpyW(LogColorSpace.lcsFilename,ColorProfileName); // // Create colorspace with LOGCOLORSPACE // return (IcmCreateColorSpaceByColorSpace(hObj,&LogColorSpace,NULL,dwFlags)); } /******************************Public*Routine******************************\ * IcmCreateColorSpaceByColorSpace() * * History: * * Write it: * 21-Apr-1997 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ PCACHED_COLORSPACE IcmCreateColorSpaceByColorSpace( HGDIOBJ hObj, LPLOGCOLORSPACEW lpLogColorSpace, PPROFILE pProfileData, DWORD dwFlags ) { PCACHED_COLORSPACE pColorSpace = NULL; ICMAPI(("gdi32: IcmCreateColorSpaceByColorSpace\n")); if (lpLogColorSpace) { // // If ICMDLL is not loaded, yet, Just Load ICMDLL regardless current ICM mode, // since we need it for handle this color profile. And apps can enable ICM // later at that time, the opened color profile mighted be used. // if ((ghICM == NULL) && (!IcmInitialize())) { ICMWRN(("IcmCreateColorSpace():Fail to load ICM dlls\n")); return (NULL); } // // Allocate CACHED_COLORSPACE // pColorSpace = LOCALALLOC(sizeof(CACHED_COLORSPACE)); if (pColorSpace) { // // Zero init CACHED_COLORSPACE // RtlZeroMemory(pColorSpace,sizeof(CACHED_COLORSPACE)); // // Copy LOGCOLORSPACE into CACHED_COLORSPACE // RtlCopyMemory(&(pColorSpace->LogColorSpace),lpLogColorSpace,sizeof(LOGCOLORSPACEW)); // // Default colorspace is RGB (BGR = 0x00bbggrr same as COLORREF format) // pColorSpace->ColorFormat = BM_xBGRQUADS; // // Map intent value for MSCMS from LOGCOLORSPACE. // switch (lpLogColorSpace->lcsIntent) { case LCS_GM_BUSINESS: pColorSpace->ColorIntent = INTENT_SATURATION; break; case LCS_GM_GRAPHICS: pColorSpace->ColorIntent = INTENT_RELATIVE_COLORIMETRIC; break; case LCS_GM_IMAGES: pColorSpace->ColorIntent = INTENT_PERCEPTUAL; break; case LCS_GM_ABS_COLORIMETRIC: pColorSpace->ColorIntent = INTENT_ABSOLUTE_COLORIMETRIC; break; default: ICMWRN(("IcmCreateColorSpace():Invalid intent value\n")); LOCALFREE(pColorSpace); return (NULL); } // // Keep flags // pColorSpace->flInfo = dwFlags; // // if the color space is specific to some GDI object, keep its handle. // // for DIBSECTION_COLORSPACE, CreateDIBSection calls us this hdc in hObj, // then later overwrite hObj with thier bitmap handle. this prevent from // this color space is shared with others. // if (dwFlags & HGDIOBJ_SPECIFIC_COLORSPACE) { pColorSpace->hObj = hObj; } // // If this is not LCS_CALIBRATED_RGB, get color profile name. // if (lpLogColorSpace->lcsCSType != LCS_CALIBRATED_RGB) { ULONG ulSize = MAX_PATH; // // if CSType is not LCS_CALIBRATED_RGB, we should go to MSCMS.DLL // to get color profile for corresponding LCSType, then any given // profile name from application is IGNORED. // if ((*fpGetStandardColorSpaceProfileW)( NULL, lpLogColorSpace->lcsCSType, pColorSpace->LogColorSpace.lcsFilename, &ulSize)) { ICMMSG(("IcmCreateColorSpace():CSType %x = %ws\n", lpLogColorSpace->lcsCSType, pColorSpace->LogColorSpace.lcsFilename)); } else { ICMWRN(("IcmCreateColorSpace():Error CSType = %x\n", lpLogColorSpace->lcsCSType)); LOCALFREE(pColorSpace); return (NULL); } } // // Use PROFILE if profile is given // if ((pProfileData != NULL) && (pProfileData->dwType == PROFILE_MEMBUFFER) && (pProfileData->pProfileData != NULL) && (pProfileData->cbDataSize != 0)) { ICMMSG(("IcmCreateColorSpace():Create ColorSpace cache by memory profile\n")); ASSERTGDI(dwFlags & ON_MEMORY_PROFILE, "IcmCreateColorSpace():dwFlags does not have ON_MEMORY_PROFILE"); if (!(dwFlags & NOT_CACHEABLE_COLORSPACE)) { // // Try to make a copy, if profile size is small enough, // so that we can cache this profile. // if (pProfileData->cbDataSize <= MAX_SIZE_OF_COLORPROFILE_TO_CACHE) { pColorSpace->ColorProfile.pProfileData = GlobalAlloc(GMEM_FIXED,pProfileData->cbDataSize); if (pColorSpace->ColorProfile.pProfileData) { ICMMSG(("IcmCreateColorSpace():Profile data can be cacheable\n")); pColorSpace->ColorProfile.dwType = PROFILE_MEMBUFFER; pColorSpace->ColorProfile.cbDataSize = pProfileData->cbDataSize; RtlCopyMemory(pColorSpace->ColorProfile.pProfileData, pProfileData->pProfileData, pProfileData->cbDataSize); // // Make sure it is cachable... // ASSERTGDI((pColorSpace->flInfo & NOT_CACHEABLE_COLORSPACE) == 0, "IcmCreateColorSpace():flInfo has NOT_CACHEABLE_COLORSPACE"); // // Profile memory need to be freed at deletion. // pColorSpace->flInfo |= NEED_TO_FREE_PROFILE; } } } // // If not able to cache, it the profile data in application. // if (pColorSpace->ColorProfile.pProfileData == NULL) { // // Use PROFILE data if it's given in parameter. // pColorSpace->ColorProfile = *pProfileData; // // We don't make a copy of profile data, so profile data possible to be // free by application, so this color space can not be cached // pColorSpace->flInfo |= NOT_CACHEABLE_COLORSPACE; } } else if (lpLogColorSpace->lcsFilename[0] != UNICODE_NULL) { PWSZ pszFileNameOnly; ICMMSG(("IcmCreateColorSpace():Create ColorSpace cache by file - %ws\n", lpLogColorSpace->lcsFilename)); // // Normalize filename // pszFileNameOnly = BuildIcmProfilePath(pColorSpace->LogColorSpace.lcsFilename, pColorSpace->LogColorSpace.lcsFilename,MAX_PATH); // // If this is sRGB (= sRGB Color Space Profile.icm) color profile, ... // if (_wcsicmp(pszFileNameOnly,sRGB_PROFILENAME) == 0) { // // Mark device_calibrate_colorspace flag. // pColorSpace->flInfo |= DEVICE_CALIBRATE_COLORSPACE; } // // Fill up PROFILE structure and open it. // pColorSpace->ColorProfile.dwType = PROFILE_FILENAME; pColorSpace->ColorProfile.pProfileData = pColorSpace->LogColorSpace.lcsFilename; pColorSpace->ColorProfile.cbDataSize = MAX_PATH * sizeof(WCHAR); } else // if we only have parameter in LOGCOLORSPACE but not lcsFileName. { BOOL bRet; // // Convert LOGCOLORSPACE to ICC Profile. // ICMMSG(("IcmCreateColorSpace():Create ColorSpace cache by LOGCOLRSPACE\n")); // // Fill up PROFILE structure. // pColorSpace->ColorProfile.dwType = PROFILE_MEMBUFFER; pColorSpace->ColorProfile.pProfileData = NULL; // // Call convert function. (LOGCOLORSPACE -> ICC PROFILE) // bRet = IcmCreateProfileFromLCS( &(pColorSpace->LogColorSpace), // source logColorSpace &(pColorSpace->ColorProfile.pProfileData), // receive pointer to profile image &(pColorSpace->ColorProfile.cbDataSize)); // receive size of profile image if ((bRet == FALSE) || (pColorSpace->ColorProfile.pProfileData == NULL) || (pColorSpace->ColorProfile.cbDataSize == 0)) { ICMWRN(("IcmCreateColorSpaceByColorSpace():IcmCreateProfileFromLCS() failed\n")); LOCALFREE(pColorSpace); return (NULL); } // // Mark pProfileData must be freed at deletion. // pColorSpace->flInfo |= NEED_TO_FREE_PROFILE; } // // At this point, we don't have color format yet, // so call IcmRealizeColorProfile with no color format checking. // if (IcmRealizeColorProfile(pColorSpace,FALSE)) { // // Get profile color format // pColorSpace->ColorFormat = IcmGetProfileColorFormat(pColorSpace->hProfile); // // Until create color transform, we don't need realized color space. // IcmUnrealizeColorProfile(pColorSpace); } else { ICMWRN(("IcmCreateColorSpace():Fail to realize color profile\n")); if (pColorSpace->flInfo & NEED_TO_FREE_PROFILE) { GlobalFree(pColorSpace->ColorProfile.pProfileData); } LOCALFREE(pColorSpace); return (NULL); } // // Initialize ref. counter // pColorSpace->cRef = 1; // // Put the created color space into the list // ENTERCRITICALSECTION(&semColorSpaceCache); InsertTailList(&ListCachedColorSpace,&(pColorSpace->ListEntry)); cCachedColorSpace++; LEAVECRITICALSECTION(&semColorSpaceCache); } else { WARNING("gdi32:IcmCreateColorSpace():LOCALALLOC failed\n"); } } return (pColorSpace); } /******************************Public*Routine******************************\ * ColorProfile on demand loading/unloading support functions * * History: * * Write it: * 29-Nov-1998 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ BOOL IcmRealizeColorProfile( PCACHED_COLORSPACE pColorSpace, BOOL bCheckColorFormat ) { ICMAPI(("gdi32: IcmRealizeColorProfile\n")); if (pColorSpace) { if ((pColorSpace->hProfile == NULL) && (pColorSpace->ColorProfile.pProfileData != NULL)) { HPROFILE hProfile = (*fpOpenColorProfileW)( &(pColorSpace->ColorProfile), PROFILE_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING); if (hProfile) { // // Make sure color format of color profile has not been changed. // if ((bCheckColorFormat == FALSE) || (pColorSpace->ColorFormat == IcmGetProfileColorFormat(hProfile))) { pColorSpace->hProfile = hProfile; } else { (*fpCloseColorProfile)(hProfile); } } } return ((BOOL)!!pColorSpace->hProfile); } else { return (TRUE); } } VOID IcmUnrealizeColorProfile( PCACHED_COLORSPACE pColorSpace ) { ICMAPI(("gdi32: IcmUnrealizeColorProfile\n")); if (pColorSpace && pColorSpace->hProfile) { (*fpCloseColorProfile)(pColorSpace->hProfile); pColorSpace->hProfile = NULL; } } /******************************Public*Routine******************************\ * Metafiling support functions * * History: * * Write it: * 23-May-1997 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ VOID IcmInsertMetafileList( PLIST_ENTRY pListHead, PWSZ pName ) { PMETAFILE_COLORPROFILE pData; pData = LOCALALLOC(sizeof(METAFILE_COLORPROFILE)); if (pData) { wcscpy(pData->ColorProfile,pName); InsertTailList(pListHead,&(pData->ListEntry)); } } BOOL IcmCheckMetafileList( PLIST_ENTRY pListHead, PWSZ pName ) { PLIST_ENTRY p; PMETAFILE_COLORPROFILE pData; p = pListHead->Flink; while (p != pListHead) { pData = (PVOID) CONTAINING_RECORD(p,METAFILE_COLORPROFILE,ListEntry); if (_wcsicmp(pData->ColorProfile,pName) == 0) { return TRUE; } p = p->Flink; } return FALSE; } VOID IcmFreeMetafileList( PLIST_ENTRY pListHead ) { PLIST_ENTRY p; PVOID pData; p = pListHead->Flink; while(p != pListHead) { pData = (PVOID) CONTAINING_RECORD(p,METAFILE_COLORPROFILE,ListEntry); // // Need to get pointer to next before free memory. // p = p->Flink; // // then free memory. // LOCALFREE(pData); } InitializeListHead(pListHead); } /******************************Public*Routine******************************\ * IcmStretchBlt() * * History: * * Write it: * 29-May-1997 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ BOOL IcmStretchBlt(HDC hdc, int x, int y, int cx, int cy, HDC hdcSrc, int x1, int y1, int cx1, int cy1, DWORD rop, PDC_ATTR pdcattr, PDC_ATTR pdcattrSrc) { int iRet = 0; PGDI_ICMINFO pIcmInfo; HBITMAP hbm; PVOID pvBits; PBITMAPINFO pbmi; ULONG cjBits; HCOLORSPACE hSourceColorSpace = NULL, hOldColorSpace = NULL; PCACHED_COLORSPACE pSourceColorSpace = NULL; POINT ptDevice[2]; UINT nNumScan, nNumWidth; UINT nStartScan, nStartWidth; BOOL bNoScaling; BYTE dibData[(sizeof(DIBSECTION)+256*sizeof(RGBQUAD))]; ICMAPI(("gdi32: IcmStretchBlt\n")); // // Convert Logical coord to Physical coord on source. // ptDevice[0].x = x1; ptDevice[0].y = y1; ptDevice[1].x = x1 + cx1; ptDevice[1].y = y1 + cy1; if (LPtoDP(hdcSrc,ptDevice,2) == FALSE) { // // can't handle, let callee handle this. // return (FALSE); } // // Compute new origin. // nStartWidth = ptDevice[0].x; nStartScan = ptDevice[0].y; nNumWidth = ptDevice[1].x - ptDevice[0].x; nNumScan = ptDevice[1].y - ptDevice[0].y; // // Check source bounds. // if (((INT)nStartWidth < 0) || ((INT)nStartScan < 0) || ((INT)nNumWidth < 0) || ((INT)nNumScan < 0)) { ICMWRN(("IcmStretchBlt: (x1,y1) is out of surface\n")); // // We can't handle this, let callee handle this. // return (FALSE); } // // Is there any scaling ? // bNoScaling = ((cx == (int)nNumWidth) && (cy == (int)nNumScan)); // // Get bitmap handle. // hbm = (HBITMAP) GetDCObject(hdcSrc, LO_BITMAP_TYPE); if (bDIBSectionSelected(pdcattrSrc)) { // // Get DIBSECTION currently selected in source DC. // if (GetObject(hbm, sizeof(DIBSECTION), &dibData) != (int)sizeof(DIBSECTION)) { WARNING("IcmStretchBlt: GetObject(DIBSECTION) failed\n"); return(FALSE); } // // Load color table and overwrite DIBSECTION structure from right after BITMAPINFOHEADER // if (((DIBSECTION *)&dibData)->dsBm.bmBitsPixel <= 8) { GetDIBColorTable(hdcSrc, 0, 256, (RGBQUAD *)&((DIBSECTION *)&dibData)->dsBitfields[0]); } pbmi = (PBITMAPINFO)&(((DIBSECTION *)&dibData)->dsBmih); // if ((nStartScan + nNumScan) > (((DIBSECTION *)&dibData)->dsBm.bmHeight)) // { // nNumScan = (((DIBSECTION *)&dibData)->dsBm.bmHeight - nStartScan); // } // // Setup color source/destination colorspaces // if (IS_ICM_INSIDEDC(pdcattrSrc->lIcmMode)) { // // if ICM is turned on source DC. we will use source DC's // destination color space as destination DC's source // color space. // pIcmInfo = GET_ICMINFO(pdcattrSrc); if (pIcmInfo && pIcmInfo->pDestColorSpace) { hSourceColorSpace = CreateColorSpaceW(&(pIcmInfo->pDestColorSpace->LogColorSpace)); pSourceColorSpace = pIcmInfo->pDestColorSpace; } } if (hSourceColorSpace == NULL) { // // if no colorspace, use sRGB. // hSourceColorSpace = GetStockObject(PRIV_STOCK_COLORSPACE); pSourceColorSpace = NULL; } } else if (IS_ICM_LAZY_CORRECTION(pdcattrSrc->lIcmMode)) { // // Get BITMAP currently selected in source DC. // if (GetObject(hbm, sizeof(BITMAP), &dibData) != (int)sizeof(BITMAP)) { WARNING("IcmStretchBlt: GetObject(BITMAP) failed\n"); return(FALSE); } // // Create bitmap info header // pbmi = (PBITMAPINFO) ((PBYTE)dibData+sizeof(BITMAP)); pbmi->bmiHeader.biSize = sizeof(BITMAPINFO); pbmi->bmiHeader.biHeight = ((BITMAP *)&dibData)->bmHeight; pbmi->bmiHeader.biWidth = ((BITMAP *)&dibData)->bmWidth; pbmi->bmiHeader.biPlanes = 1; pbmi->bmiHeader.biBitCount = 24; // 24bpp pbmi->bmiHeader.biCompression = BI_RGB; pbmi->bmiHeader.biSizeImage = 0; pbmi->bmiHeader.biXPelsPerMeter = 0; pbmi->bmiHeader.biYPelsPerMeter = 0; pbmi->bmiHeader.biClrUsed = 0; pbmi->bmiHeader.biClrImportant = 0; // if ((nStartScan + nNumScan) > pbmi->bmiHeader.biHeight) // { // nNumScan = pbmi->bmiHeader.biHeight - nStartScan; // } ASSERTGDI(IS_ICM_INSIDEDC(pdcattrSrc->lIcmMode), "IcmStretchBlt():Lazy color correction, but ICM is not enabled\n"); pIcmInfo = GET_ICMINFO(pdcattrSrc); if (pIcmInfo && pIcmInfo->pSourceColorSpace) { hSourceColorSpace = CreateColorSpaceW(&(pIcmInfo->pSourceColorSpace->LogColorSpace)); pSourceColorSpace = pIcmInfo->pSourceColorSpace; } else { // // Otherwise, just use Stcok color space (= sRGB) // hSourceColorSpace = GetStockObject(PRIV_STOCK_COLORSPACE); pSourceColorSpace = NULL; } } else { // // Can't handle here, let callee handle it. // return (FALSE); } // // Get bitmap size // cjBits = cjBitmapScanSize(pbmi,nNumScan); pvBits = LOCALALLOC(cjBits); if (pvBits) { // // Fix up the start scan (bottom-left). // nStartScan = (pbmi->bmiHeader.biHeight - nStartScan - nNumScan); // // Call NtGdiGetDIBitsInternal directly, because // we don't want to backward color correction to // source color space in hdcSrc. // if (NtGdiGetDIBitsInternal( hdcSrc,hbm, nStartScan,nNumScan, pvBits,pbmi, DIB_RGB_COLORS, cjBits,0) == 0) { WARNING("IcmStretchBlt(): Failed on GetDIBits()\n"); LOCALFREE(pvBits); pvBits = NULL; } // // Fix up the bitmap height, since pvBits only has nNumScan image. // pbmi->bmiHeader.biHeight = nNumScan; } if (pvBits) { if (hSourceColorSpace) { hOldColorSpace = IcmSetSourceColorSpace(hdc,hSourceColorSpace,pSourceColorSpace,0); } // // Draw the bitmap. // // Target - x,y (upper left). // Source - nStartWidth,0 (upper left). // if (bNoScaling && (rop == SRCCOPY)) { iRet = SetDIBitsToDevice(hdc,x,y,cx,cy,nStartWidth,0,0,nNumScan, pvBits,pbmi,DIB_RGB_COLORS); } else { iRet = StretchDIBits(hdc,x,y,cx,cy,nStartWidth,0,nNumWidth,nNumScan, pvBits,pbmi,DIB_RGB_COLORS,rop); } // // Back to original color space, if created // if (hOldColorSpace) { IcmSetSourceColorSpace(hdc,hOldColorSpace,NULL,0); } LOCALFREE(pvBits); } if (hSourceColorSpace) { DeleteColorSpace(hSourceColorSpace); } return (BOOL) !!iRet; } /******************************Public*Routine******************************\ * IcmGetColorSpaceforBitmap() * * History: * * Write it: * 29-May-1997 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ PCACHED_COLORSPACE IcmGetColorSpaceforBitmap(HBITMAP hbm) { ICMAPI(("gdi32: IcmGetColorSpaceforBitmap\n")); FIXUP_HANDLE(hbm); return ((PCACHED_COLORSPACE)NtGdiGetColorSpaceforBitmap(hbm)); } /******************************Public*Routine******************************\ * IcmEnableForCompatibleDC() * * History: * * Write it: * 13-Jun-1997 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ BOOL IcmEnableForCompatibleDC( HDC hdcCompatible, HDC hdcDevice, PDC_ATTR pdcaDevice ) { PDC_ATTR pdcaCompatible; ICMAPI(("gdi32: IcmEnableForCompatibleDC\n")); PSHARED_GET_VALIDATE(pdcaCompatible,hdcCompatible,DC_TYPE); if (pdcaCompatible) { PGDI_ICMINFO pIcmInfoCompatible; PGDI_ICMINFO pIcmInfoDevice; // Initialize ICMINFO // // for device DC, ICMINFO should be presented. // if ((pIcmInfoDevice = GET_ICMINFO(pdcaDevice)) == NULL) { WARNING("gdi32: IcmEnableForCompatibleDC: Can't init icm info\n"); return (FALSE); } // // for compatible DC, it was just created, ICMINFO is not exist, then create here. // if ((pIcmInfoCompatible = INIT_ICMINFO(hdcCompatible,pdcaCompatible)) == NULL) { WARNING("gdi32: IcmEnableForCompatibleDC: Can't init icm info\n"); return (FALSE); } // // Set Source color space as same as original DC // // Kernel side... // if (pdcaDevice->hColorSpace) { if (pdcaDevice->hColorSpace != GetStockObject(PRIV_STOCK_COLORSPACE)) { // // Call directly kernel to set the color space to DC. (don't need client stuff) // NtGdiSetColorSpace(hdcCompatible,(HCOLORSPACE)pdcaDevice->hColorSpace); } // // Keep it in ICMINFO, so that we can un-select it later. // pIcmInfoCompatible->hDefaultSrcColorSpace = pdcaDevice->hColorSpace; } // And client side... // ENTERCRITICALSECTION(&semColorSpaceCache); if (pIcmInfoDevice->pSourceColorSpace) { pIcmInfoCompatible->pSourceColorSpace = pIcmInfoDevice->pSourceColorSpace; pIcmInfoCompatible->pSourceColorSpace->cRef++; } // // Set destination color space as same as original DC // if (pIcmInfoDevice->pDestColorSpace) { pIcmInfoCompatible->pDestColorSpace = pIcmInfoDevice->pDestColorSpace; pIcmInfoCompatible->pDestColorSpace->cRef++; } LEAVECRITICALSECTION(&semColorSpaceCache); // // copy default profile name (if they has) // if (pIcmInfoDevice->DefaultDstProfile[0] != UNICODE_NULL) { wcscpy(pIcmInfoCompatible->DefaultDstProfile,pIcmInfoDevice->DefaultDstProfile); pIcmInfoCompatible->flInfo |= (ICM_VALID_DEFAULT_PROFILE| ICM_VALID_CURRENT_PROFILE); } // // Make sure we have valid color space. // pdcaCompatible->ulDirty_ &= ~DIRTY_COLORSPACE; // // And we don't have valid color transform. // pdcaCompatible->ulDirty_ |= DIRTY_COLORTRANSFORM; if (IS_ICM_INSIDEDC(pdcaDevice->lIcmMode)) { // // For compatible DC, use host ICM anytime... // ULONG ReqIcmMode = REQ_ICM_HOST; // // Turn ICM on for this compatible DC. // if (!NtGdiSetIcmMode(hdcCompatible,ICM_SET_MODE,ReqIcmMode)) { // // something wrong... we are fail to enable ICM. // return (FALSE); } // // Update color transform. // if (!IcmUpdateDCColorInfo(hdcCompatible,pdcaCompatible)) { // // Fail to create new transform // NtGdiSetIcmMode(hdcCompatible,ICM_SET_MODE,REQ_ICM_OFF); return (FALSE); } } } return (TRUE); } /******************************Public*Routine******************************\ * IcmAskDriverForColorProfile * * History: * 08-Oct-1997 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ int IcmAskDriverForColorProfile( PLDC pldc, ULONG ulQueryMode, PDEVMODEW pDevMode, PWSTR pProfileName, DWORD *pdwColorSpaceFlag ) { INT iRet; BYTE TempProfileData[MAX_PATH]; PVOID pvProfileData = (PVOID) TempProfileData; ULONG cjProfileSize = sizeof(TempProfileData); FLONG flProfileFlag = 0; ICMAPI(("gdi32: IcmAskDriverForColorProfile\n")); // // Call driver to get device profile data. // iRet = QueryColorProfileEx(pldc, pDevMode, ulQueryMode, pvProfileData, &cjProfileSize, &flProfileFlag); if (iRet == -1) { ICMMSG(("gdi32: IcmAskDriverForColorProfile():Driver does not hook color profile\n")); // // Driver does not support profile hook. // return iRet; } else if ((iRet == 0) && (cjProfileSize > sizeof(TempProfileData)) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) { ICMMSG(("gdi32: IcmAskDriverForColorProfile():Allocate larger memory\n")); // // Buffer is not enough, so allocate it. // pvProfileData = LOCALALLOC(cjProfileSize); if (pvProfileData) { iRet = QueryColorProfileEx(pldc, pDevMode, ulQueryMode, pvProfileData, &cjProfileSize, &flProfileFlag); } } if ((iRet > 0) && (pvProfileData != NULL) && (cjProfileSize != 0)) { if (flProfileFlag == QCP_PROFILEDISK) { ICMMSG(("gdi32: IcmAskDriverForColorProfile():Profiles - %ws\n",pvProfileData)); // // pvProfileData contains filename in Unicode. // wcsncpy(pProfileName,(PWSTR)pvProfileData,MAX_PATH); } else if (flProfileFlag == QCP_PROFILEMEMORY) { // // pvProfileData contains color profile itself. // // // No desired name. // *pProfileName = UNICODE_NULL; // // Create temporary color profile. // if (IcmCreateTemporaryColorProfile(pProfileName,pvProfileData,cjProfileSize)) { ICMMSG(("gdi32: IcmAskDriverForColorProfile():Profiles - %ws\n",pProfileName)); // // Mark this as temporary file, so that when this is not used // the file will be deleted. // *pdwColorSpaceFlag = (DRIVER_COLORSPACE | NEED_TO_DEL_PROFILE); } else { ICMMSG(("gdi32: IcmAskDriverForColorProfile():Failed to create temp file\n")); // // failed to create temporary color profile. // iRet = 0; } } else { // // Unknown data type. // iRet = 0; } } else { iRet = 0; } if (pvProfileData && (pvProfileData != TempProfileData)) { LOCALFREE(pvProfileData); } return (iRet); } /******************************Public*Routine******************************\ * GdiConvertBitmapV5 * * pbBitmapData - pointer to BITMAPV4/V5 data * iSizeOfBitmapData - size of buffer * uConvertFormat - either of CF_DIB or CF_BITMAP * * History: * 12-Dec-1997 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ HANDLE GdiConvertBitmapV5( LPBYTE pbBitmapData, int iSizeOfBitmapData, HPALETTE hPalette, UINT uConvertFormat ) { HANDLE hRet = NULL; UNREFERENCED_PARAMETER(hPalette); ICMAPI(("gdi32: GdiConvertBitmapV5\n")); if (pbBitmapData && iSizeOfBitmapData) { BITMAPINFO *pbmi = (BITMAPINFO *)pbBitmapData; BITMAPINFOHEADER *pbmih = &(pbmi->bmiHeader); PVOID pvBits = NULL; ULONG ulColorTableSize = (ULONG)-1; BOOL bTransColorTable = FALSE; BOOL bMoveColorMasks = FALSE; // // Load external ICM dlls. // LOAD_ICMDLL(NULL); // // Find the bitmap bits pointer. // try { // // Calculate color table size. // if (pbmih->biCompression == BI_BITFIELDS) { // // Bitfields are a part of BITMAPV4/V5 header. // ulColorTableSize = 0; bMoveColorMasks = TRUE; } else if (pbmih->biCompression == BI_RGB) { if (pbmih->biClrUsed) { ulColorTableSize = (pbmih->biClrUsed * sizeof(RGBQUAD)); if (pbmih->biBitCount <= 8) { bTransColorTable = TRUE; } } else if (pbmih->biBitCount <= 8) { ulColorTableSize = ((1 << pbmih->biBitCount) * sizeof(RGBQUAD)); bTransColorTable = TRUE; } else { ulColorTableSize = 0; } } else if (pbmih->biCompression == BI_RLE4) { ulColorTableSize = 16 * sizeof(RGBQUAD); bTransColorTable = TRUE; } else if (pbmih->biCompression == BI_RLE8) { ulColorTableSize = 256 * sizeof(RGBQUAD); bTransColorTable = TRUE; } else { // // BI_JPEG, BI_PNG, and others can not convert // ICMWRN(("GdiConvertBitmapV5: " "given data is BI_JPEG, BI_PNG, or unkown\n")); } if (ulColorTableSize != (ULONG)-1) { // // Make sure given data is either BITMAPV4 or V5 header. // if (pbmih->biSize == sizeof(BITMAPV5HEADER)) { pvBits = (BYTE *)pbmi + sizeof(BITMAPV5HEADER) + ulColorTableSize + ((LPBITMAPV5HEADER)pbmi)->bV5ProfileSize; } else if (pbmih->biSize != sizeof(BITMAPV4HEADER)) { pvBits = (BYTE *)pbmi + sizeof(BITMAPV4HEADER) + ulColorTableSize; } else { ICMWRN(("GdiConvertBitmapV5: given data is not bitmapV4/V5\n")); } } } except(EXCEPTION_EXECUTE_HANDLER) { pvBits = NULL; } if (pvBits) { if (uConvertFormat == CF_DIB) { ULONG cjBitmapBits; ICMMSG(("GdiConvertBitmapV5(): CF_DIBV5 -----> CF_DIB\n")); // // Calculate size of bitmap bits // try { cjBitmapBits = cjBitmapBitsSize(pbmi); } except(EXCEPTION_EXECUTE_HANDLER) { cjBitmapBits = 0; } if (cjBitmapBits) { // // Allocate buffer for color translation // hRet = GlobalAlloc(GHND,sizeof(BITMAPINFOHEADER) + (bMoveColorMasks ? (3 * sizeof(DWORD)) : \ (ulColorTableSize)) + cjBitmapBits); if (hRet) { PBYTE pjSrc = (PBYTE)pbmi; PBYTE pjDest = GlobalLock(hRet); BOOL bTransformError = FALSE; if (pjDest) { PROFILE sRGBColorProfileData; LOGCOLORSPACEW LogColorSpaceW; PROFILE ColorProfile; DWORD dwFlags = 0; HANDLE hColorTransform = NULL; HANDLE hsRGBColorProfile = NULL; HANDLE hBitmapColorProfile = NULL; PCACHED_COLORSPACE pColorSpace = NULL; try { // // Extract color space from BITMAPV4/V5 header. // bTransformError = !(IcmGetBitmapColorSpace( pbmi, &LogColorSpaceW, &ColorProfile, &dwFlags)); } except(EXCEPTION_EXECUTE_HANDLER) { bTransformError = TRUE; } if (!bTransformError) { // // Create color space and color transform // if ((LogColorSpaceW.lcsCSType == LCS_sRGB) || (LogColorSpaceW.lcsCSType == LCS_WINDOWS_COLOR_SPACE)) { ICMMSG(("GdiConvertBitmapV5(): Original bitmap is sRGB\n")); // // No color translarion required. // hColorTransform = NULL; } else { // // Get source color space (if bitmap has color space) // // // First, find ColorSpace from cache. // pColorSpace = IcmGetColorSpaceByColorSpace( (HGDIOBJ)NULL, &LogColorSpaceW, &ColorProfile, dwFlags); if (pColorSpace == NULL) { pColorSpace = IcmCreateColorSpaceByColorSpace( (HGDIOBJ)NULL, &LogColorSpaceW, &ColorProfile, dwFlags); } if (pColorSpace && IcmRealizeColorProfile(pColorSpace,TRUE)) { hBitmapColorProfile = pColorSpace->hProfile; } // // Open sRGB color space profile as destination color space. // sRGBColorProfileData.dwType = PROFILE_FILENAME; sRGBColorProfileData.pProfileData = (PVOID)sRGB_PROFILENAME; sRGBColorProfileData.cbDataSize = MAX_PATH * sizeof(WCHAR); hsRGBColorProfile = (*fpOpenColorProfileW)( &sRGBColorProfileData, PROFILE_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING); if (hBitmapColorProfile && hsRGBColorProfile) { DWORD ahIntents[2]; HPROFILE ahProfiles[2]; ahIntents[0] = INTENT_RELATIVE_COLORIMETRIC; ahIntents[1] = pColorSpace->ColorIntent; ahProfiles[0] = hBitmapColorProfile; ahProfiles[1] = hsRGBColorProfile; hColorTransform = (*fpCreateMultiProfileTransform)( ahProfiles, 2, ahIntents, 2, NORMAL_MODE | ENABLE_GAMUT_CHECKING, INDEX_DONT_CARE); } if (!hColorTransform) { bTransformError = TRUE; } } if (!bTransformError) { // // Copy the bitmap to target with proper color space conversion. // try { BITMAPV5HEADER *pbm5h = (BITMAPV5HEADER *)pbmi; // // Copy bitmap header to target. // RtlCopyMemory(pjDest,pjSrc,sizeof(BITMAPINFOHEADER)); // // Adjust bmHeader.biSize // ((BITMAPINFOHEADER *)pjDest)->biSize = sizeof(BITMAPINFOHEADER); // // Move src and dest pointers // pjSrc += pbmih->biSize; pjDest += sizeof(BITMAPINFOHEADER); // // Copy bit mask or color table. // if (bMoveColorMasks) { // // Move color masks. cast it to pointer to BITMAPV5HEADER // since same offset on BITMAPV4HEADER too. // *(DWORD *)pjDest = pbm5h->bV5RedMask; pjDest += sizeof(DWORD); *(DWORD *)pjDest = pbm5h->bV5GreenMask; pjDest += sizeof(DWORD); *(DWORD *)pjDest = pbm5h->bV5BlueMask; pjDest += sizeof(DWORD); } else { if (ulColorTableSize) { if (bTransColorTable && hColorTransform) { bTransformError = !(*fpTranslateBitmapBits)( hColorTransform, pjSrc, BM_xRGBQUADS, ulColorTableSize/sizeof(RGBQUAD), 1, 0, pjDest, BM_xRGBQUADS, 0,NULL,0); } else { RtlCopyMemory(pjDest,pjSrc,ulColorTableSize); } pjSrc += ulColorTableSize; pjDest += ulColorTableSize; } } if (bTransColorTable || (hColorTransform == NULL)) { // // All the color information is in the color table. and // it has been translated, so just copy bitmap bits. // RtlCopyMemory(pjDest,pvBits,cjBitmapBits); } else { // // Translate bitmap bits. // BMFORMAT bmColorType; // // Get BMFORMAT based on bitmap format. // if (pbmih->biBitCount == 16) { if (pbmih->biCompression == BI_RGB) { bmColorType = BM_x555RGB; } else if (pbmih->biCompression == BI_BITFIELDS) { if ((pbm5h->bV5RedMask == 0x007c00) && (pbm5h->bV5GreenMask == 0x0003e0) && (pbm5h->bV5BlueMask == 0x00001f)) { bmColorType = BM_x555RGB; } else if ((pbm5h->bV5RedMask == 0x00f800) && (pbm5h->bV5GreenMask == 0x0007e0) && (pbm5h->bV5BlueMask == 0x00001f)) { bmColorType = BM_565RGB; } else { ICMWRN(("GdiConvertBitmapV5: Bad Bitfields Mask for 16 bpp\n")); bTransformError = TRUE; } } else { ICMWRN(("GdiConvertBitmapV5: Bad biCompression for 16 bpp\n")); bTransformError = TRUE; } } else if (pbmih->biBitCount == 24) { bmColorType = BM_RGBTRIPLETS; } else if (pbmih->biBitCount == 32) { if (pbmih->biCompression == BI_RGB) { bmColorType = BM_xRGBQUADS; } else if (pbmih->biCompression == BI_BITFIELDS) { if ((pbm5h->bV5RedMask == 0x0000ff) && /* Red */ (pbm5h->bV5GreenMask == 0x00ff00) && /* Green */ (pbm5h->bV5BlueMask == 0xff0000)) /* Blue */ { bmColorType = BM_xBGRQUADS; } else if ((pbm5h->bV5RedMask == 0xff0000) && /* Red */ (pbm5h->bV5GreenMask == 0x00ff00) && /* Green */ (pbm5h->bV5BlueMask == 0x0000ff)) /* Blue */ { bmColorType = BM_xRGBQUADS; } else { ICMWRN(("GdiConvertBitmapV5: Bad Bitfields Mask for 32 bpp\n")); bTransformError = TRUE; } } else { ICMWRN(("GdiConvertBitmapV5: Bad biCompression for 32 bpp\n")); bTransformError = TRUE; } } else { ICMWRN(("GdiConvertBitmapV5: Bad biBitCount\n")); bTransformError = TRUE; } if (!bTransformError) { bTransformError = !(*fpTranslateBitmapBits)( hColorTransform, pvBits, bmColorType, pbmih->biWidth, ABS(pbmih->biHeight), 0, pjDest, bmColorType, 0,NULL,0); } } } except(EXCEPTION_EXECUTE_HANDLER) { bTransformError = TRUE; } } // // Clean up used color transform and color profile handles // if (hColorTransform) { (*fpDeleteColorTransform)(hColorTransform); } if (hsRGBColorProfile) { (*fpCloseColorProfile)(hsRGBColorProfile); } if (pColorSpace) { IcmReleaseColorSpace(NULL,pColorSpace,FALSE); } } } GlobalUnlock(hRet); if (bTransformError) { GlobalFree(hRet); hRet = NULL; } } else { ICMWRN(("GdiConvertBitmapV5: Fail on GlobalAlloc()\n")); } } else { ICMWRN(("GdiConvertBitmapV5: cjBitmapBits is 0\n")); } return (hRet); } else if (uConvertFormat == CF_BITMAP) { HDC hDC = GetDC(NULL); HBITMAP hBitmap = NULL; if (hDC) { ICMMSG(("GdiConvertBitmapV5(): CF_DIBV5 -----> CF_BITMAP\n")); // // Set destination color space as sRGB, and enable ICM. // if (IcmSetDestinationColorSpace(hDC,sRGB_PROFILENAME,NULL,0) && SetICMMode(hDC,ICM_ON)) { try { // // Create bitmap handle with given bitmap V5 data. // hBitmap = CreateDIBitmap(hDC, pbmih, CBM_INIT, pvBits, pbmi, DIB_RGB_COLORS); } except(EXCEPTION_EXECUTE_HANDLER) { hBitmap = NULL; } if (!hBitmap) { ICMWRN(("GdiConvertBitmapV5: Fail on CreateDIBitmap()\n")); } } // // Clean up DC // SetICMMode(hDC,ICM_OFF); ReleaseDC(NULL,hDC); } return ((HANDLE)hBitmap); } else { ICMWRN(("GdiConvertBitmapV5(): CF_DIBV5 -----> Unknown\n")); } } } return (hRet); } /******************************Public*Routine******************************\ * IcmSetTargetColorSpace() * * History: * 8-Jun-1998 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ BOOL IcmSetTargetColorSpace( HDC hdc, PCACHED_COLORSPACE pTargetColorSpace, DWORD uiAction ) { BOOL bRet = FALSE; PDC_ATTR pdcattr; PGDI_ICMINFO pIcmInfo; ICMAPI(("gdi32: IcmSetTargetColorSpace\n")); FIXUP_HANDLE(hdc); PSHARED_GET_VALIDATE(pdcattr,hdc,DC_TYPE); if (pdcattr == NULL) { return (FALSE); } if ((pIcmInfo = GET_ICMINFO(pdcattr)) == NULL) { return (FALSE); } switch (uiAction) { case CS_ENABLE: { // // Check validation of given Target color space. // if (pTargetColorSpace != NULL) { PCACHED_COLORTRANSFORM pCXform; BOOL bDeleteOldCXform = FALSE; // // Mark we are in proofing mode. // SET_ICM_PROOFING(pdcattr->lIcmMode); if ((pIcmInfo->pProofCXform != NULL) && IcmSameColorSpace(pTargetColorSpace,pIcmInfo->pTargetColorSpace)) { ICMMSG(("IcmSetTargetColorSpace():Use Cached Proof Transform\n")); ENTERCRITICALSECTION(&semColorTransformCache); // // the cached proofing transform is still valid. // pCXform = pIcmInfo->pProofCXform; if (pCXform) { // // Increment ref count of it. // pCXform->cRef++; } LEAVECRITICALSECTION(&semColorTransformCache); } else { ICMMSG(("IcmSetTargetColorSpace():Create New Proof Transform\n")); // // We don't have cached color space or it is no longer valid. // // // Check we still have cached color space and it's still valid ? // if (pIcmInfo->pTargetColorSpace && IcmSameColorSpace(pTargetColorSpace,pIcmInfo->pTargetColorSpace)) { // // Cached target color space are still valid, keep as is. // } else { // // Release old target color space. // IcmReleaseColorSpace(NULL,pIcmInfo->pTargetColorSpace,FALSE); // // Increment ref count of it. // IcmReferenceColorSpace(pTargetColorSpace); // // set target destination profile into current DC as target profile // pIcmInfo->pTargetColorSpace = pTargetColorSpace; } // // create new transform // pCXform = IcmCreateColorTransform(hdc,pdcattr,NULL,ICM_FORWARD); // // Marks as need to delete old color transform if we have. // bDeleteOldCXform = pIcmInfo->pProofCXform ? TRUE : FALSE; } if ((pCXform == IDENT_COLORTRANSFORM) || (pCXform == NULL)) { // // Invalidate color transform // IcmSelectColorTransform(hdc,pdcattr,NULL, bDeviceCalibrate(pIcmInfo->pDestColorSpace)); // // Delete old color transform. // if (bDeleteOldCXform) { // // Delete cached proofing color transform // IcmDeleteColorTransform(pIcmInfo->pProofCXform,FALSE); } // // Set null color transform to ICMINFO // pIcmInfo->pProofCXform = NULL; if (pCXform == IDENT_COLORTRANSFORM) { ICMMSG(("IcmSetTargetColorSpace():Input & Output colorspace is same\n")); // // Input & Destination & Target color space is same, there is // no color translation needed. // bRet = TRUE; } else { ICMWRN(("IcmSetTargetColorSpace():Fail to create color transform\n")); } // // Translate back to DC color object to original // IcmTranslateColorObjects(hdc,pdcattr,FALSE); } else { // // Select the color transform to DC. // IcmSelectColorTransform(hdc,pdcattr,pCXform, bDeviceCalibrate(pCXform->DestinationColorSpace)); // // Delete old color transform. // if (bDeleteOldCXform) { // // Delete cached proofing color transform // IcmDeleteColorTransform(pIcmInfo->pProofCXform,FALSE); } // // Set new color transform to ICMINFO. // pIcmInfo->pProofCXform = pCXform; // // Initialize color attributes in this DC. // IcmTranslateColorObjects(hdc,pdcattr,TRUE); bRet = TRUE; } } else { GdiSetLastError(ERROR_INVALID_PARAMETER); WARNING("IcmSetTargetColorSpace: target color space is NULL\n"); // // Anyway, just re-initialize without target profile. // IcmTranslateColorObjects(hdc,pdcattr,TRUE); } if (!bRet) { // // if failed, mask off as we are not in proofing mode // CLEAR_ICM_PROOFING(pdcattr->lIcmMode); if (pIcmInfo->pTargetColorSpace) { // // Release target color space. // IcmReleaseColorSpace(NULL,pIcmInfo->pTargetColorSpace,FALSE); // // Disable target profile. // pIcmInfo->pTargetColorSpace = NULL; } } break; } case CS_DISABLE: case CS_DELETE_TRANSFORM: { // // We are going to be out of proofing mode. // CLEAR_ICM_PROOFING(pdcattr->lIcmMode); if (pdcattr->ulDirty_ & DIRTY_COLORTRANSFORM) { if (uiAction == CS_DELETE_TRANSFORM) { if (pIcmInfo->pTargetColorSpace) { // // Release target color space. // IcmReleaseColorSpace(NULL,pIcmInfo->pTargetColorSpace,FALSE); // // Disable target profile. // pIcmInfo->pTargetColorSpace = NULL; } } // // While DC is in proofing mode, the source or // destination color space has been changed by // SetColorSpace() or SetICMProfile(). So, // we will reset all color transform in this // DC. // if (IcmUpdateDCColorInfo(hdc,pdcattr)) { bRet = TRUE; } else { GdiSetLastError(ERROR_DELETING_ICM_XFORM); } } else { // // We are leaving proofing mode, Select back the normal colortransform into DC. // IcmSelectColorTransform(hdc,pdcattr,pIcmInfo->pCXform, bDeviceCalibrate(pIcmInfo->pDestColorSpace)); // // The color transform cache will effective... // if (uiAction == CS_DELETE_TRANSFORM) { if (pIcmInfo->pTargetColorSpace) { // // Release target color space. // IcmReleaseColorSpace(NULL,pIcmInfo->pTargetColorSpace,FALSE); // // Disable target profile. // pIcmInfo->pTargetColorSpace = NULL; } // // Delete ONLY proofing color transform (if it is) // if (pIcmInfo->pProofCXform) { if (!IcmDeleteColorTransform(pIcmInfo->pProofCXform,FALSE)) { GdiSetLastError(ERROR_DELETING_ICM_XFORM); return (FALSE); } // // There is no proofing transform in this ICMINFO. // pIcmInfo->pProofCXform = NULL; } } bRet = TRUE; } if (bRet) { // // Initialize color attributes in this DC. // IcmTranslateColorObjects(hdc,pdcattr,TRUE); } break; } default: { WARNING("IcmSetTargetColorSpace: uiAction is invalid\n"); GdiSetLastError(ERROR_INVALID_PARAMETER); } } return (bRet); } /******************************Public*Routine******************************\ * IcmSetDestinationColorSpace() * * History: * 17-Jul-1998 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ BOOL IcmSetDestinationColorSpace( HDC hdc, LPWSTR pwszFileName, PCACHED_COLORSPACE pColorSpace, DWORD dwFlags ) { BOOL bRet = FALSE; PDC_ATTR pdcattr; ULONG FileNameSize; if (pColorSpace) { ICMAPI(("gdi32: IcmSetDestinationColorSpace by ColorSpace (%ws):dwFlags - %d\n", pColorSpace->LogColorSpace.lcsFilename,dwFlags)); } else if (pwszFileName) { ICMAPI(("gdi32: IcmSetDestinationColorSpace by profile name (%ws):dwFlags - %x\n", pwszFileName,dwFlags)); // // Check filename // if (pwszFileName) { FileNameSize = lstrlenW(pwszFileName); } if ((FileNameSize == 0) || (FileNameSize > MAX_PATH)) { ICMWRN(("IcmSetDestinatonColorSpace - no or too long profile name\n")); return FALSE; } } else { ICMAPI(("gdi32: IcmSetDestinationColorSpace - invalid parameter\n")); return FALSE; } FIXUP_HANDLE(hdc); // // We are going to try to select this color space into thisDC, // default is false. // bRet = FALSE; PSHARED_GET_VALIDATE(pdcattr,hdc,DC_TYPE); // // Profile filename or pColorSpace should be presented. // if (pdcattr) { PGDI_ICMINFO pIcmInfo; // // Initialize ICMINFO // if ((pIcmInfo = INIT_ICMINFO(hdc,pdcattr)) == NULL) { WARNING("gdi32: IcmSetDestinationColorSpace: Can't init icm info\n"); return(FALSE); } if (IsColorDeviceContext(hdc)) { PCACHED_COLORSPACE pNewColorSpace = NULL; // // Load external ICM dlls. // LOAD_ICMDLL(FALSE); if (pColorSpace == NULL) { // // Find colorspace from cache // pNewColorSpace = IcmGetColorSpaceByName( (HGDIOBJ)hdc, pwszFileName, pIcmInfo->dwDefaultIntent, dwFlags); if (pNewColorSpace == NULL) { ICMMSG(("IcmSetDestinationColorSpace():This is new color space, create it\n")); // // Can not find, Create new one // pNewColorSpace = IcmCreateColorSpaceByName( (HGDIOBJ)hdc, pwszFileName, pIcmInfo->dwDefaultIntent, dwFlags); } } else { // // Increment ref count of given color space // IcmReferenceColorSpace(pColorSpace); // // Use pColorSpace from parameter. // pNewColorSpace = pColorSpace; } // // We are going to select this colorspace onto DC. and free previous profile. // if (pNewColorSpace) { PCACHED_COLORSPACE pOldColorSpace = pIcmInfo->pDestColorSpace; // // Is this same destination color space currently selected in DC ? // if (IcmSameColorSpace(pNewColorSpace,pIcmInfo->pDestColorSpace)) { // // Yes, early-out. We don't need new color space. // IcmReleaseColorSpace(NULL,pNewColorSpace,FALSE); return (TRUE); } // // Before change destination color space, we need to flush batched gdi functions. // CHECK_AND_FLUSH(hdc,pdcattr); // // Check new color format is accepted by this DC or not. // if (!NtGdiSetIcmMode(hdc,ICM_CHECK_COLOR_MODE,pNewColorSpace->ColorFormat)) { ICMWRN(("IcmSetDestinationColorSpace(): DC does not accept this color format\n")); GdiSetLastError(ERROR_INVALID_PROFILE); } else { // // Set new color space into DC. // pIcmInfo->pDestColorSpace = pNewColorSpace; // // Remove dirty transform flag. // pdcattr->ulDirty_ &= ~DIRTY_COLORSPACE; if (IS_ICM_INSIDEDC(pdcattr->lIcmMode) && !IS_ICM_PROOFING(pdcattr->lIcmMode)) { PCACHED_COLORTRANSFORM pCXform; // // create new color transform base on new colorspace // pCXform = IcmCreateColorTransform(hdc,pdcattr,NULL,ICM_FORWARD); if (pCXform == IDENT_COLORTRANSFORM) { // // Select null color transform to DC. // IcmSelectColorTransform(hdc,pdcattr,NULL, bDeviceCalibrate(pIcmInfo->pDestColorSpace)); // // delete old color transform in DC. // IcmDeleteDCColorTransforms(pIcmInfo); // // Select null color transform to ICMINFO. // pIcmInfo->pCXform = NULL; // // back it to original color (non-ICMed color). // IcmTranslateColorObjects(hdc,pdcattr,FALSE); // // And, everything O.K. // bRet = TRUE; } else if (pCXform) { // // Select the colortransform into DC. // if (IcmSelectColorTransform( hdc,pdcattr,pCXform, bDeviceCalibrate(pCXform->DestinationColorSpace))) { // // delete old color transform in DC. // IcmDeleteDCColorTransforms(pIcmInfo); // // Select it to ICMINFO. // pIcmInfo->pCXform = pCXform; // // Adjust to new color transform. // IcmTranslateColorObjects(hdc,pdcattr,TRUE); // // And, everything O.K. // bRet = TRUE; } else { // // Failed to select it to the DC in client side. // so delete it and invalidate pCXform. // IcmDeleteColorTransform(pCXform,FALSE); pCXform = NULL; } } if (pCXform == NULL) { // // Failed to create/select color stransform, // so put back previous color space. // pIcmInfo->pDestColorSpace = pOldColorSpace; } } else { // // if ICM is not turned on currently, we just mark // cached color transform is no longer valid. // pdcattr->ulDirty_ |= DIRTY_COLORTRANSFORM; // For ColorMatchToTarget() // // While color matching to the target is enabled by setting // uiAction to CS_ENABLE, application changes to the color // space or gamut matching method are ignored. // Those changes then take effect when color matching to // the target is disabled. // if (IS_ICM_PROOFING(pdcattr->lIcmMode)) { ICMMSG(("IcmSetDestinationColorSpace():In Proofing mode, lazy setting...\n")); } bRet = TRUE; } } if (bRet) { // // We are succeeded to select new color space, then // close and free references to old color space. // IcmReleaseColorSpace(NULL,pOldColorSpace,FALSE); } else { // // We will not use this color space as destination color space, // because 1) DC does not accept this color space, 2) Fail to // create color transform based on this color space. // IcmReleaseColorSpace(NULL,pNewColorSpace,FALSE); } } else { GdiSetLastError(ERROR_PROFILE_NOT_FOUND); } } else { ICMMSG(("IcmSetDestinationColorSpace(): for Mono-device\n")); // // Just copy Apps specifyed profile to internal buffer, which will // be return to app by GetICMProfile(), but it is NEVER used for // non-color device other than that case, since there is no ICM // happen. // wcsncpy(pIcmInfo->DefaultDstProfile,pwszFileName,MAX_PATH); // // This is not default profile, but current profile. // pIcmInfo->flInfo &= ~ICM_VALID_DEFAULT_PROFILE; pIcmInfo->flInfo |= ICM_VALID_CURRENT_PROFILE; } } else { GdiSetLastError(ERROR_INVALID_PARAMETER); } return(bRet); } /******************************Public*Routine******************************\ * IcmSetSourceColorSpace() * * History: * 17-Jul-1998 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ HCOLORSPACE IcmSetSourceColorSpace( HDC hdc, HCOLORSPACE hColorSpace, PCACHED_COLORSPACE pColorSpace, DWORD dwFlags) { HANDLE hRet = NULL; PDC_ATTR pdcattr; ICMAPI(("gdi32: IcmSetSourceColorSpace\n")); FIXUP_HANDLE(hdc); FIXUP_HANDLE(hColorSpace); // // validate and access hdc // PSHARED_GET_VALIDATE(pdcattr,hdc,DC_TYPE); if (pdcattr) { PGDI_ICMINFO pIcmInfo; // // Initialize ICMINFO // if ((pIcmInfo = INIT_ICMINFO(hdc,pdcattr)) == NULL) { WARNING("gdi32: IcmSetSourceColorSpace: Can't init icm info\n"); return(NULL); } if (pdcattr->hColorSpace != hColorSpace) { // // Before change source color space, we need to flush batched gdi functions. // CHECK_AND_FLUSH(hdc,pdcattr); // // Return Old (currently selected) color space handle. // hRet = pdcattr->hColorSpace; // // set new color space, call kernel to keep reference count tracking // of colospace object // if (NtGdiSetColorSpace(hdc,hColorSpace)) { if (IsColorDeviceContext(hdc)) { PCACHED_COLORSPACE pNewColorSpace; LOGCOLORSPACEW LogColorSpaceW; RtlZeroMemory(&LogColorSpaceW,sizeof(LOGCOLORSPACEW)); // // Load external ICM dlls. // LOAD_ICMDLL(NULL); if (pColorSpace == NULL) { // // Check if there is client-cached colorspace for this or not. // pNewColorSpace = IcmGetColorSpaceByHandle( (HGDIOBJ)hdc, hColorSpace, &LogColorSpaceW,dwFlags); // // If we can not find from cache, but succeeded to obtain // valid logcolorspace from handle, create new one. // if ((pNewColorSpace == NULL) && (LogColorSpaceW.lcsSignature == LCS_SIGNATURE)) { // // Create new one. // pNewColorSpace = IcmCreateColorSpaceByColorSpace( (HGDIOBJ)hdc, &LogColorSpaceW, NULL, dwFlags); } } else { // // Increment ref count of given color space // IcmReferenceColorSpace(pColorSpace); // // Use pColorSpace from parameter. // pNewColorSpace = pColorSpace; } // // Update current source color space to new one. // if (pNewColorSpace) { PCACHED_COLORSPACE pOldColorSpace = pIcmInfo->pSourceColorSpace; // // Check the colorspace is same one as currently selected ? // if (IcmSameColorSpace(pNewColorSpace,pIcmInfo->pSourceColorSpace)) { // // This is the "actually" same color space, but differrent handle, // don't need to update // IcmReleaseColorSpace(NULL,pNewColorSpace,FALSE); return (hRet); } // // Source color space should be RGB color space. // if (pNewColorSpace->ColorFormat != BM_xBGRQUADS) { ICMWRN(("IcmSetSourceColorSpace():Source color space is not RGB\n")); // // Set back previous color space. (can't fail these calls) // IcmReleaseColorSpace(NULL,pNewColorSpace,FALSE); NtGdiSetColorSpace(hdc,hRet); GdiSetLastError(ERROR_INVALID_COLORSPACE); return (NULL); } // // And set new color space. // pIcmInfo->pSourceColorSpace = pNewColorSpace; // // if ICM is enabled, needs update color transform, right now. // if (IS_ICM_INSIDEDC(pdcattr->lIcmMode) && !IS_ICM_PROOFING(pdcattr->lIcmMode)) { PCACHED_COLORTRANSFORM pCXform; // // create new color transform // pCXform = IcmCreateColorTransform(hdc,pdcattr,NULL,ICM_FORWARD); if (pCXform == IDENT_COLORTRANSFORM) { ICMMSG(("IcmSetSourceColorSpace():Input & Output colorspace is same\n")); // // select NULL transform into DC. // IcmSelectColorTransform(hdc,pdcattr,NULL, bDeviceCalibrate(pIcmInfo->pDestColorSpace)); // // delete old colorspace/transform from ICMINFO. // IcmDeleteDCColorTransforms(pIcmInfo); // // select NULL tranform to ICMINFO. // pIcmInfo->pCXform = NULL; // // Set DC objects color to non-ICMed color. // IcmTranslateColorObjects(hdc,pdcattr,FALSE); } else if (pCXform) { // // Select the color transform to DC. // if (IcmSelectColorTransform( hdc,pdcattr,pCXform, bDeviceCalibrate(pCXform->DestinationColorSpace))) { // // delete old colorspace/transform from ICMINFO. // IcmDeleteDCColorTransforms(pIcmInfo); // // select new color transform to ICMINFO. // pIcmInfo->pCXform = pCXform; // // Succeed to select into DC, Validate DC color objects // IcmTranslateColorObjects(hdc,pdcattr,TRUE); } else { // // Failed to select it to the DC in client side. // so delete it and invalidate pCXform. // IcmDeleteColorTransform(pCXform,FALSE); pCXform = NULL; } } if (pCXform == NULL) { ICMMSG(("IcmSetSourceColorSpace():Fail to create/select color transform\n")); // // Set back previous color space. (can't fail these calls) // pIcmInfo->pSourceColorSpace = pOldColorSpace; NtGdiSetColorSpace(hdc,hRet); hRet = NULL; } } else { // // Otherwise, we just mark color transform might be dirty. // Because new color space was selected. // pdcattr->ulDirty_ |= DIRTY_COLORTRANSFORM; // For ColorMatchToTarget() // // While color matching to the target is enabled by setting // uiAction to CS_ENABLE, application changes to the color // space or gamut matching method are ignored. // Those changes then take effect when color matching to // the target is disabled. // if (IS_ICM_PROOFING(pdcattr->lIcmMode)) { ICMMSG(("IcmSetSourceColorSpace():In Proofing mode, lazy setting...\n")); } } if (hRet) { // // Succeed to select new color space, then delete old one. // IcmReleaseColorSpace(NULL,pOldColorSpace,FALSE); } else { IcmReleaseColorSpace(NULL,pNewColorSpace,FALSE); } } } else { ICMMSG(("IcmSetSourceColorSpace(): for Mono-device\n")); // // For monochrome device case, just return kernel color space // handle, then just don't create client-side representitive, // since there is no ICM for monochrome device. // } } else { WARNING("Error: hdc and hColorSpace check out but NtGdi call failed\n"); hRet = NULL; } } else { // // Same color space was selected, just return current. // hRet = hColorSpace; } } if (hRet == NULL) { GdiSetLastError(ERROR_INVALID_COLORSPACE); } return (hRet); } /******************************Public*Routine******************************\ * IcmSaveDC() * * History: * 7-Dec-1998 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ BOOL IcmSaveDC( HDC hdc, PDC_ATTR pdcattr, PGDI_ICMINFO pIcmInfo) { BOOL bRet = TRUE; ICMAPI(("gdi32: IcmSaveDC\n")); if (pdcattr && pIcmInfo) { // // Get currect saved level. // DWORD dwCurrentSavedDepth; if (NtGdiGetDCDword(hdc,DDW_SAVEDEPTH,&dwCurrentSavedDepth)) { PSAVED_ICMINFO pSavedIcmInfo = LOCALALLOC(sizeof(SAVED_ICMINFO)); if (pSavedIcmInfo) { PCACHED_COLORSPACE pSourceColorSpace = pIcmInfo->pSourceColorSpace; PCACHED_COLORSPACE pDestColorSpace = pIcmInfo->pDestColorSpace; PCACHED_COLORSPACE pTargetColorSpace = pIcmInfo->pTargetColorSpace; PCACHED_COLORTRANSFORM pCXform = pIcmInfo->pCXform; PCACHED_COLORTRANSFORM pBackCXform = pIcmInfo->pBackCXform; PCACHED_COLORTRANSFORM pProofCXform = pIcmInfo->pProofCXform; // // Increment reference count of color spaces in DC. // IcmReferenceColorSpace(pSourceColorSpace); IcmReferenceColorSpace(pDestColorSpace); IcmReferenceColorSpace(pTargetColorSpace); // // Increment reference count of color transform in DC. // IcmReferenceColorTransform(pCXform); IcmReferenceColorTransform(pBackCXform); IcmReferenceColorTransform(pProofCXform); // // Save color spaces. // pSavedIcmInfo->pSourceColorSpace = pSourceColorSpace; pSavedIcmInfo->pDestColorSpace = pDestColorSpace; pSavedIcmInfo->pTargetColorSpace = pTargetColorSpace; // // Save color transforms. // pSavedIcmInfo->pCXform = pCXform; pSavedIcmInfo->pBackCXform = pBackCXform; pSavedIcmInfo->pProofCXform = pProofCXform; // // Put current saved level in DC. // pSavedIcmInfo->dwSavedDepth = dwCurrentSavedDepth; // // Insert saved data to list. // InsertHeadList(&(pIcmInfo->SavedIcmInfo),&(pSavedIcmInfo->ListEntry)); ICMMSG(("gdi32: IcmSaveDC() - Saved Depth = %d\n",dwCurrentSavedDepth)); } else { WARNING("IcmSaveDC():Failed on LOCALALLOC()\n"); bRet = FALSE; } } else { WARNING("IcmSaveDC():Failed on NtGdiGetDCDword(DDW_SAVEDEPTH)\n"); bRet = FALSE; } } return (bRet); } /******************************Public*Routine******************************\ * IcmRestoreDC() * * History: * 7-Dec-1998 -by- Hideyuki Nagase [hideyukn] \**************************************************************************/ VOID IcmRestoreDC( PDC_ATTR pdcattr, int iLevel, PGDI_ICMINFO pIcmInfo) { ICMAPI(("gdi32: IcmRestoreDC - iLevel = %d\n",iLevel)); if (pIcmInfo) { // // Still have same ICMINFO. // PLIST_ENTRY p = pIcmInfo->SavedIcmInfo.Flink; BOOL bContinue = TRUE; while (bContinue && (iLevel != 0) && (p != &(pIcmInfo->SavedIcmInfo))) { PSAVED_ICMINFO pSavedIcmInfo = CONTAINING_RECORD(p,SAVED_ICMINFO,ListEntry); if (iLevel > 0) { // // iLevel is absolute saved depth to restore // if (iLevel == (int) pSavedIcmInfo->dwSavedDepth) { bContinue = FALSE; } } else { // // iLevel is relative saved depth to restore // if (++iLevel == 0) { bContinue = FALSE; } } if (bContinue == FALSE) { PCACHED_COLORSPACE pSourceColorSpace = pIcmInfo->pSourceColorSpace; PCACHED_COLORSPACE pDestColorSpace = pIcmInfo->pDestColorSpace; PCACHED_COLORSPACE pTargetColorSpace = pIcmInfo->pTargetColorSpace; PCACHED_COLORTRANSFORM pCXform = pIcmInfo->pCXform; PCACHED_COLORTRANSFORM pBackCXform = pIcmInfo->pBackCXform; PCACHED_COLORTRANSFORM pProofCXform = pIcmInfo->pProofCXform; // // Restore this saved data to DC. // pIcmInfo->pSourceColorSpace = pSavedIcmInfo->pSourceColorSpace; pIcmInfo->pDestColorSpace = pSavedIcmInfo->pDestColorSpace; pIcmInfo->pTargetColorSpace = pSavedIcmInfo->pTargetColorSpace; pIcmInfo->pCXform = pSavedIcmInfo->pCXform; pIcmInfo->pBackCXform = pSavedIcmInfo->pBackCXform; pIcmInfo->pProofCXform = pSavedIcmInfo->pProofCXform; // // Release color space which *WAS* selected in DC. // IcmReleaseColorSpace(NULL,pSourceColorSpace,FALSE); IcmReleaseColorSpace(NULL,pDestColorSpace,FALSE); IcmReleaseColorSpace(NULL,pTargetColorSpace,FALSE); // // Delete color transform which *WAS* selected in DC. // IcmDeleteColorTransform(pCXform,FALSE); IcmDeleteColorTransform(pBackCXform,FALSE); IcmDeleteColorTransform(pProofCXform,FALSE); if (pdcattr) { // // Validate flags. // pdcattr->ulDirty_ &= ~(DIRTY_COLORSPACE | DIRTY_COLORTRANSFORM); } } else { // // Decrement ref count of color space. // IcmReleaseColorSpace(NULL,pSavedIcmInfo->pSourceColorSpace,FALSE); IcmReleaseColorSpace(NULL,pSavedIcmInfo->pDestColorSpace,FALSE); IcmReleaseColorSpace(NULL,pSavedIcmInfo->pTargetColorSpace,FALSE); // // Decrement ref count of color transform. // IcmDeleteColorTransform(pSavedIcmInfo->pCXform,FALSE); IcmDeleteColorTransform(pSavedIcmInfo->pBackCXform,FALSE); IcmDeleteColorTransform(pSavedIcmInfo->pProofCXform,FALSE); } // // Get pointer to next. // p = p->Flink; // // Remove from list. // RemoveEntryList(&(pSavedIcmInfo->ListEntry)); // // Free SAVED_ICMINFO. // LOCALFREE(pSavedIcmInfo); } } }