Microsoft KB Archive/319484

= INFO: Retrieving Information from a Color Profile =

Article ID: 319484

Article Last Modified on 2/12/2007

-

APPLIES TO

 Microsoft Platform Software Development Kit-January 2000 Edition, when used with:  Microsoft Windows XP Professional

 Microsoft Windows Millennium Edition

 Microsoft Windows 2000 Standard Edition

 Microsoft Windows 98 Second Edition</li></ul> </li> Microsoft Windows XP Professional for Itanium-based systems</li></ul>

-

<div class="notice_section">

This article was previously published under Q319484

<div class="summary_section">

SUMMARY
An International Color Consortium (ICC) profile is a file that describes the color characteristics of a device (such as a monitor, a scanner, or a printer). The Microsoft Image Color Matching (ICM) component, or more specifically, the color management module (CMM), uses files of this type to obtain reasonable color consistency across devices.

ICC profiles contain data that is used to convert the colors of a device to a common color space. This common color space is known as a Profile Connection Space (PCS).

ICM 2.0 includes a small set of image color matching (ICM) application programming interfaces (APIs) that allow you to parse the specific data in the ICC profiles. The code sample in this article demonstrates how to call these functions and how to use these functions to extract some basic profile data.

The location of the ICM profiles varies depending on the version of Windows that you use. You can use the GetColorDirectory function to find the location of the ICM profiles. Typically, ICC profiles are distributed with the device drivers for a particular device.

For more information about how to create your own ICC profile, see the &quot;References&quot; section.

<div class="moreinformation_section">

MORE INFORMATION
The sample code that follows demonstrates only how to call these functions correctly. The code creates a dump file for only the selected header, the tag, and the tag data information.
 * 1) include <Windows.H>
 * 2) include <StdIO.H>
 * 3) include <locale.h>
 * 4) include &quot;icm.h&quot;


 * 1) define ROWLEN 40 // row length for text/desc field formatting

void PrintTagData(DWORD dw, BYTE *pBuffer, BOOL bReference, DWORD dwLen); void PrintError(DWORD dwError, LPCSTR lpString);

/************************************************************************\ \************************************************************************/ int main( int argc, char *argv[] ) { BOOL bFlag; DWORD dwLen; PROFILE profile; HPROFILE hProfile = NULL; TAGTYPE tt; DWORD dw; DWORD dwNumElements = 0; BYTE *pBuffer = NULL; BOOL bReference; PROFILEHEADER ph;
 * FUNCTION:   main
 * COMMENTS:   Entry point for the console application
 * COMMENTS:   Entry point for the console application
 * COMMENTS:   Entry point for the console application

// 1 argument -> color profile filename. if (argc != 2) {   printf(&quot;Syntax: %s \n&quot;, argv[0]); return 0; }

// Try to open the color profile that is specified. ZeroMemory(&profile, sizeof(PROFILE)); profile.cbDataSize = (_tcslen(argv[1]) + 1) * sizeof(TCHAR); profile.dwType = PROFILE_FILENAME; profile.pProfileData = argv[1]; hProfile = OpenColorProfile(&profile, PROFILE_READ,               FILE_SHARE_READ, OPEN_EXISTING); if (!hProfile) {   PrintError(GetLastError, &quot;OpenColorProfile&quot;); goto ABORT; }

// Get the profile header information. ZeroMemory(&ph, sizeof(PROFILEHEADER)); ph.phSize = sizeof(PROFILEHEADER); bFlag = GetColorProfileHeader(hProfile, &ph); if (!bFlag) {   PrintError(GetLastError, &quot;GetColorProfileHeader&quot;); goto ABORT; }

// Output (print) a selection of header diagnostics. printf(&quot;Color Profile \&quot;%s\&quot;...\n\n&quot;, argv[1]); printf(&quot;Profile Class:   '%c%c%c%c'\n&quot;,          HIBYTE(HIWORD(ph.phClass)),          LOBYTE(HIWORD(ph.phClass)),          HIBYTE(LOWORD(ph.phClass)),          LOBYTE(LOWORD(ph.phClass))); printf(&quot;Profile Platform: '%c%c%c%c'\n&quot;,         HIBYTE(HIWORD(ph.phPlatform)),          LOBYTE(HIWORD(ph.phPlatform)),          HIBYTE(LOWORD(ph.phPlatform)),          LOBYTE(LOWORD(ph.phPlatform))); printf(&quot;Color Space:     '%c%c%c%c'\n&quot;,          HIBYTE(HIWORD(ph.phDataColorSpace)),          LOBYTE(HIWORD(ph.phDataColorSpace)),          HIBYTE(LOWORD(ph.phDataColorSpace)),          LOBYTE(LOWORD(ph.phDataColorSpace))); printf(&quot;Connection Space: '%c%c%c%c'\n&quot;,         HIBYTE(HIWORD(ph.phConnectionSpace)),          LOBYTE(HIWORD(ph.phConnectionSpace)),          HIBYTE(LOWORD(ph.phConnectionSpace)),          LOBYTE(LOWORD(ph.phConnectionSpace)));

// Query the number of tagged elements in the opened profile. bFlag = GetCountColorProfileElements(hProfile, &dwNumElements); if (!bFlag) {   PrintError(GetLastError, &quot;GetCountColorProfileElements&quot;); goto ABORT; }

// Print the tag count. printf(&quot;\nGetCountColorProfileElements reported %i tags.\n\n&quot;,     dwNumElements, argv[1]); printf(&quot;Tags follow. Tag data is displayed below for DESC and TEXT tags only...\n\n&quot;);

// For every 1-based index. for (dw = 1; dw <= dwNumElements; dw++) {   // Get the tag name. bFlag = GetColorProfileElementTag(hProfile, dw, &tt); if (!bFlag) {     PrintError(GetLastError, &quot;GetColorProfileElementTag&quot;); goto ABORT; }

// Determine that space that is needed for the tag data. bFlag = GetColorProfileElement(hProfile, tt, 0, &dwLen,                   NULL, &bReference); if ((dwLen == 0) || (GetLastError != ERROR_INSUFFICIENT_BUFFER)) {     PrintError(GetLastError, &quot;GetColorProfileElement&quot;); goto ABORT; }

// Allocate space for the tag data. pBuffer = (void *)GlobalAlloc(GPTR, dwLen); if (pBuffer == NULL) {     PrintError(GetLastError, &quot;GlobalAlloc&quot;); goto ABORT; }

// Get the tag data. bFlag = GetColorProfileElement(hProfile, tt, 0, &dwLen, <BR/>                                  pBuffer, &bReference); if (!bFlag) {     PrintError(GetLastError, &quot;GetColorProfileElement&quot;); goto ABORT; }

// Print the tag name (and the actual data for TEXT and DESC tags). PrintTagData(dw, pBuffer, bReference, dwLen);

// Free the tag data buffer. GlobalFree(pBuffer); pBuffer = NULL; }

ABORT: if (hProfile) CloseColorProfile(hProfile); if (pBuffer) GlobalFree(pBuffer); return 0; }

// Utility function: outputs info about the retrieved tag and tag data. void PrintTagData(DWORD dwIndex, BYTE *pBuffer, BOOL bReference, DWORD dwLen) { DWORD dw;

printf(&quot; Tag %i (%i bytes%s): Signature = \&quot;%s\&quot;\n&quot;, dwIndex, dwLen,        (bReference ? &quot;,ref&quot; : &quot;&quot;), (LPTSTR)pBuffer);

// For text and desc tags, print the data in a somewhat readable way. if ((lstrcmpi(pBuffer, &quot;text&quot;) == 0) ||      (lstrcmpi(pBuffer, &quot;desc&quot;) == 0)) {   printf(&quot;   Data: &quot;); for (dw = 5; dw < dwLen; dw++) {     if (isprint(pBuffer[dw])) printf(&quot;%c&quot;, pBuffer[dw]); else printf(&quot;.&quot;);

if (((dw-4) % ROWLEN == 0) && (dw < dwLen)) printf(&quot;\n        &quot;); } }  printf(&quot;\n\n&quot;); }

// Utility function: displays an error msg based on system error code. void PrintError(DWORD dwError, LPCSTR lpString) { char  *msgBuf; DWORD cMsgLen;
 * 1) define MAX_MSG_BUF_SIZE 512

cMsgLen = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |                          FORMAT_MESSAGE_ALLOCATE_BUFFER |                           40,                          NULL, dwError,                           MAKELANGID(0, SUBLANG_ENGLISH_US),                           (LPTSTR) &msgBuf, MAX_MSG_BUF_SIZE,                          NULL);

printf(&quot;%s Error [%d]:: %s\n&quot;, lpString, dwError, msgBuf);

LocalFree( msgBuf ); }
 * 1) undef MAX_MSG_BUF_SIZE

<div class="references_section">