INFO: Retrieving Information from a Color Profile (319484)



The information in this article applies to:

  • Microsoft Platform Software Development Kit (SDK) 1.0, when used with:
    • the operating system: Microsoft Windows XP
    • the operating system: Microsoft Windows Millennium Edition
    • the operating system: Microsoft Windows 2000
    • the operating system: Microsoft Windows 98 Second Edition
  • the operating system: Microsoft Windows XP 64-Bit Edition

This article was previously published under Q319484

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 "References" 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.
#include <Windows.H>
#include <StdIO.H>
#include <locale.h>
#include "icm.h"

#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);

/************************************************************************\ 
*
*  FUNCTION:    main
*
*  COMMENTS:    Entry point for the console application
*
\************************************************************************/ 
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;

  // 1 argument -> color profile filename.
  if (argc != 2)
  {
    printf("Syntax: %s <color profile>\n", 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(), "OpenColorProfile");
    goto ABORT;
  }

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

  // Output (print) a selection of header diagnostics.
  printf("Color Profile \"%s\"...\n\n", argv[1]);
  printf("Profile Class:    '%c%c%c%c'\n",
          HIBYTE(HIWORD(ph.phClass)),
          LOBYTE(HIWORD(ph.phClass)),
          HIBYTE(LOWORD(ph.phClass)),
          LOBYTE(LOWORD(ph.phClass)));
  printf("Profile Platform: '%c%c%c%c'\n",
          HIBYTE(HIWORD(ph.phPlatform)),
          LOBYTE(HIWORD(ph.phPlatform)),
          HIBYTE(LOWORD(ph.phPlatform)),
          LOBYTE(LOWORD(ph.phPlatform)));
  printf("Color Space:      '%c%c%c%c'\n",
          HIBYTE(HIWORD(ph.phDataColorSpace)),
          LOBYTE(HIWORD(ph.phDataColorSpace)),
          HIBYTE(LOWORD(ph.phDataColorSpace)),
          LOBYTE(LOWORD(ph.phDataColorSpace)));
  printf("Connection Space: '%c%c%c%c'\n",
          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(), "GetCountColorProfileElements");
    goto ABORT;
  }

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

  // For every 1-based index.
  for (dw = 1; dw <= dwNumElements; dw++)
  {
    // Get the tag name.
    bFlag = GetColorProfileElementTag(hProfile, dw, &tt);
    if (!bFlag)
    {
      PrintError(GetLastError(), "GetColorProfileElementTag");
      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(), "GetColorProfileElement");
      goto ABORT;
    }

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

    // Get the tag data.
    bFlag = GetColorProfileElement(hProfile, tt, 0, &dwLen, <BR/>
                                   pBuffer, &bReference);
    if (!bFlag)
    {
      PrintError(GetLastError(), "GetColorProfileElement");
      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(" Tag %i (%i bytes%s): Signature = \"%s\"\n", dwIndex, dwLen,
         (bReference ? ",ref" : ""), (LPTSTR)pBuffer);

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

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


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

  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("%s Error [%d]:: %s\n", lpString, dwError, msgBuf);

  LocalFree( msgBuf );
#undef MAX_MSG_BUF_SIZE
}
				

REFERENCES

For more information about image color matching, see the Help documentation for Win32 SDK and Windows DDK.

For more information about ICC profiles and color management, see the ICC Web site at http://www.color.org.

Modification Type:MinorLast Reviewed:5/17/2006
Keywords:kbDSWGDI2003Swept kbinfo KB319484