Chapter 3. Profile Management

This chapter describes how to manipulate ICC profiles with the Coloratura CMS. Profiles contain the data required to perform color manipulations.

This chapter does not describe the profile format, which is covered in the ICC Profile Format Specification. The format of the profile on disk is irrelevant in any case, because when the Coloratura CMS loads a profile from disk, it stores the data in an opaque data structure, which is then used in all subsequent interactions with the profile data. Details about interacting with profile data are covered in Chapter 4, "Tag Management."

This chapter discusses profile data structures and accessor functions in the following sections:

Identifying a Profile

The first task you face in a Coloratura application is to identify the profiles you need. There are three ways to specify profiles:

  • predefined information

  • default profiles

  • profile iteration

You can use predefined information when you know which device profile you need. For example, if you are writing an Impressario™ model file for a printer, the profile will have a name matching the device name, and the profile can be embedded directly in the model file. Another useful place to put profile names is in an X resource file.

The constants CMS_DEFAULT_MONITOR and CMS_DEFAULT_CMYK specify default profile names. You can specify preferred values for these parameters, if you do not want to use those set in cms.h. Alternatively, you can use the default filenames, but use versions in directories controlled by the environment variable CMS_DEFAULT_PATH. For more information on CMS_DEFAULT_PATH, see "Loading Profile Data: cmsOpenProfile()".

If you do not know the profile you need and do not want to use a default, you can examine the profiles available on your system and select one. The technique for doing this is profile iteration. Typically, you select a profile based on its header information, and then open it, that is, load the data into a Coloratura data structure for further interaction. You can also use profile iteration to make a list for a profile selection menu. For example, you could create a list of all the profiles for a device type or make a list of all profiles that use a given profile connection space.

Profile Iteration: Pseudocode Example

To perform a profile iteration, you first create a CMSProfileIterator by calling cmsStartProfileIteration(), and then repeatedly call cmsNextProfileIteration(). If there is another profile in the iteration sequence, cmsNextProfileIteration() sets a pointer to its filename. When there are no more profiles on disk, cmsNextProfileIteration() returns NULL.

To efficiently select a profile or display a set of profiles in a menu, you typically need only the minimal information kept in profile headers, which are only 128 bytes. Use cmsGetHeaderProfileSpec() to query a profile on disk for header information.

When there are no more profiles available, you dispose of the iterator by calling cmsEndProfileIteration().

The following code fragment illustrates a profile iteration. In the interest of clarity, the proper error checking is not shown.

char               *pspec;
CMSProfileIterator  theIterator;
icHeader            header;
 
cmsStartProfileIteration(context, &theIterator);
while (cmsNextProfileIteration(context, theIterator, &pspec) !=  
        NULL) {
 
    cmsGetProfileSpecHeader(context, spec, &header);
    if (/* tests on fields in header pass */) {
        /* code to add profile to the application */
    }
    free(pspec);
}
cmsEndProfileIteration(context, theIterator); 

The next sections detail the data structures and function calls in this example, and introduce related functions.

The data structure icHeader is not discussed because it is not a Coloratura structure; it is the profile header data structure defined by the ICCColor Profile Format Specification. icHeader is defined in ic.h. Since icHeader is of fixed size, you are responsible for allocating and freeing storage for it, as discussed in "Managing Memory".

Data Structure for Profile Iteration: CMSProfileIterator

The pointer CMSProfileIterator refers to an opaque data structure that keeps track of position in a list of profiles during an iteration. This is the data type declaration:

typedef struct _CMSProfileIterator  *CMSProfileIterator;

Starting Profile Iteration: cmsStartProfileIteration()

The function cmsStartProfileIteration() starts a profile iteration and creates a CMSProfileIterator.

  • This is the prototype for cmsStartProfileIteration():

    int32  cmsStartProfileIteration(CMSContext ctxt,
                                    CMSProfileIterator *iterator);

  • These are the arguments ofcmsStartProfileIteration():

    ctxt 

    The context initialized by cmsOpen().

    iterator 

    The newly generated iterator.

  • This is the error code returned by cmsStartProfileIteration():

    CMS_PROFILE_NOT_FOUND 


    There are no profiles available on the system.

Stepping Through Profiles: cmsNextProfileIteration()

The function cmsNextProfileIteration() finds the next filename in a profile iteration. When the iteration is complete, the function returns NULL.

  • This is the prototype for cmsNextProfileIteration():

    int32 cmsNextProfileIteration(CMSContext ctxt,
                                  CMSProfileIterator profIterator,
                                  char **spec);

  • These are the arguments of cmsNextProfileIteration():

    ctxt 

    The context initialized by cmsOpen().

    profIterator 

    The profile iterator.

    spec 

    The filename of the next profile.

  • These are the error codes returned by cmsNextProfileIteration():

    CMS_OUT_OF_MEMORY 


    There is insufficient memory for the next iteration.

    CMS_NO_MORE_PROFILES 


    There are no more profiles over which to iterate.

Examining Headers of Profiles on Disk: cmsGetProfileSpecHeader()

The function cmsGetProfileHeader() reads the ICC profile header from a profile on disk.

You can also read a profile header from an open profile, one that has been read into a Coloratura data structure; see "Getting Open-Profile Header Information: cmsGetProfileHeader()".

  • This is the prototype for cmsGetProfileSpecHeader():

    int32 cmsGetProfileSpecHeader(CMSContext ctxt,
                                  char *spec,
                                  icHeader *pHeader);

  • These are the arguments of cmsGetProfileSpecHeader():

    ctxt 

    The context initialized by cmsOpen().

    spec 

    The filename of the profile.

    pHeader 

    A pointer to the data structure in which the profile header is to be stored.

  • The error code cmsGetProfileSpecHeader() returns is

    CMS_PROFILE_NOT_FOUND 


    Is self-explanatory.

Stopping a Profile Iteration: cmsEndProfileIteration()

The function cmsEndProfileIteration() ends a profile iteration and disposes of the iterator.

  • This is the prototype for cmsEndProfileIteration():

    int32 cmsEndProfileIteration(CMSContext ctxt,
                 CMSProfileIterator profIterator);

  • These are the arguments of cmsEndProfileIteration():

    ctxt 

    The context initialized by cmsOpen().

    profIterator 

    The iterator to be disposed of.

  • This is the error code returned by cmsEndProfileIteration():

    CMS_FAILURE 


    Occurs if you have an invalid profile iterator.

Opening, Closing, and Deleting Profiles

After you identify the profiles you need, you must open them to place the data in appropriate data structures and make the information available to Coloratura functions. Interactions with profile data then occur via the pointer CMSProfile, which refers to an opaque Coloratura data structure that holds the profile data; you cannot make any assumptions about the data structure.

To make profile data available to the Coloratura CMS, call cmsOpenProfile(), which places the data in a CMSProfile data structure. When you are done working with the profile, call cmsCloseProfile() to allow the framework to recover some memory. To completely remove a profile from the file system, call cmsDeleteProfile().

The following sections provide more detail about CMSProfile and the open, close, and delete functions.

Data Structure for Profiles: CMSProfile

The pointer CMSProfile refers to an opaque data structure that stores profile data. All of your program's interactions with profile data are mediated by a CMSProfile.

  • This is the prototype for CMSProfile:

    typedef struct _CMSProfile  *CMSProfile;

Loading Profile Data: cmsOpenProfile()

You call the function cmsOpenProfile() to provide Coloratura functions with access to profile data that are on disk. Only after the profile is open can your application read from it, write to it, or include it in a transform. The function cmsOpenProfile() needs a filename to get the data from disk, but all subsequent references to the profile data are through the CMSProfile pointer set by cmsOpenProfile().

  • This is the prototype for cmsOpenProfile():

    int32  cmsOpenProfile(CMSContext ctxt, char *spec,
                          CMSProfile *prof);

  • These are the arguments of cmsOpenProfile():

    ctxt 

    The context initialized by cmsOpen().

    spec 

    The input filename. This need not include a full pathname. The Coloratura CMS searches for a file sequentially in the directories specified by the environment variable CMS_DEFAULT_PATH, which is a colon-separated list of pathnames similar to that used in the environment variable MANPATH.

    The value of CMS_DEFAULT_PATH defined in cms.h is "/var/cms/profiles/local:/var/cms/profiles:.", which allows you to place profiles you prefer in /var/cms/profiles/local, and generic profiles, which might have the same names, in /var/cms/profiles or your working directory.

    prof 

    A pointer to the newly created profile data structure.

  • These are the error codes returned by cmsOpenProfile():

    CMS_OUT_OF_MEMORY 


    The Coloratura CMS cannot allocate memory for the CMSProfile data structure.

    CMS_PROFILE_NOT_FOUND 


    Is self-explanatory.

Terminating Access to Profile Data: cmsCloseProfile()

The function cmsCloseProfile() closes the copy of a profile in memory, that is, a CMSProfile data structure, and frees the memory allocated. If you want to remove the profile data from disk, use cmsDeleteProfile(), discussed below.

The function cmsCloseProfile() does not automatically save the CMSProfile data to disk. To save changes to a profile before you call cmsCloseProfile(), call cmsSaveProfile(), which is discussed in "Saving Profile Changes to Disk: cmsSaveProfile()", or cmsSaveProfileAs(), which is discussed in "Saving to a New File on Disk: cmsSaveProfileAs()".

  • This is the prototype for cmsCloseProfile():

    int32  cmsCloseProfile(CMSContext ctxt, CMSProfile prof);

  • These are the arguments of cmsCloseProfile():

    ctxt 

    The context initialized by cmsOpen().

    prof 

    The profile to be closed.

Deleting a Profile from Disk: cmsDeleteProfile()

The function cmsDeleteProfile() deletes a profile from the file system. The usual IRIX permission system applies; you might not have permission to delete a given profile.

  • This is the prototype for cmsDeleteProfile():

    int32  cmsDeleteProfile (CMSContext ctxt, char *name);

  • These are the arguments ofcmsDeleteProfile():

    ctxt 

    The context initialized by cmsOpen().

    name 

    The profile name.

  • If cmsDeleteProfile() cannot find the profile, it will return the error

    CMS_PROFILE_NOT_FOUND 


    The named profile cannot be found to be deleted.

Creating New Profiles, Getting and Setting Headers, and Saving Edits

To calibrate devices such as scanners, monitors, or printers, or to fine tune an existing profile, you often need to create and modify profiles. You create new profiles by calling cmsCreateProfile().

The function cmsSetProfileHeader() sets new header values for an open profile: a profile you just created, or a profile you have edited whose header information you want to change. To inspect the header of an open profile, you can call cmsGetProfileHeader(). This returns the same information as cmsGetProfileSpecHeader() (see "Examining Headers of Profiles on Disk: cmsGetProfileSpecHeader()"), but it uses the CMSProfile, rather than the filename, to identify the profile data.

If you want to change other data in the profile, see Chapter 4, "Tag Management," which describes the calls you use to create or modify a profile's tag data.

To save a modified version of a profile to disk and retain the original, call cmsSaveProfileAs(). Typically, you call this function when you want to do one of the following:

  • save an edited profile under a new name

  • save changes to a newly created profile

To overwrite the original version of a profile on disk that you have opened and edited, use cmsSaveProfile().

Creating a New Profile: cmsCreateProfile()

The cmsCreateProfile() function creates a new CMSProfile data structure that contains no tag data. The new profile is not available to the file system until you save it with a call to cmsSaveProfileAs(), which is discussed in "Saving to a New File on Disk: cmsSaveProfileAs()".

  • This is the prototype for cmsCreateProfile():

    int32  cmsCreateProfile(CMSContext ctxt, CMSProfile *prof);

  • These are the arguments of cmsCreateProfile():

    ctxt 

    The context initialized by cmsOpen().

    prof 

    A pointer to the new CMSProfile.

  • This is the error code returned by cmsCreateProfile():

    CMS_OUT_OF_MEMORY 


    There is not enough memory available to create a new profile data structure.

Getting Open-Profile Header Information: cmsGetProfileHeader()

The function cmsGetProfileHeader() returns the same information as cmsGetProfileSpecHeader() (see "Examining Headers of Profiles on Disk: cmsGetProfileSpecHeader()"), but differs in that it takes a CMSProfile, rather than a filename.

cmsGetProfileHeader() gets the header information from an open profile and returns a pointer to an icHeader data structure, which is declared in ic.h (see the ICC Device Profile Format Specification for a definition of what is stored in an icHeader structure). Since icHeader is of fixed size, you must allocate and free storage for it, as discussed in "Managing Memory".

  • This is the prototype for cmsGetProfileHeader():

    int32  cmsGetProfileHeader(CMSContext ctxt, CMSProfile prof,
                               icHeader *pHeader);

  • These are the arguments of cmsGetProfileHeader():

    ctxt 

    The context initialized by cmsOpen().

    prof 

    The CMSProfile where the header data come from.

    pHeader 

    A pointer to the data structure in which to store the information.

  • This is the error code returned by cmsGetProfileHeader():

    CMS_FAILURE 

Setting Profile Header Information: cmsSetProfileHeader()

The function cmsSetProfileHeader() stores a header in an open profile. Typically, you use cmsSetProfileHeader() to put a header in a new profile.

The Coloratura CMS does not provide a function to update selected fields of a header, which it reads or writes as a whole. To update a specific field, you should first read the header into an icHeader structure, using cmsGetProfileHeader(). Then update the field with your own code and write the header to the profile with cmsSetProfileHeader().

The header file ic.h defines icHeader. Since icHeader is of fixed size, you must allocate and free storage for it. See the ICC Profile Format Specification for a definition of what is stored in a header.

  • This is the prototype for cmsSetProfileHeader():

    int32 cmsSetProfileHeader(CMSContext ctxt, CMSProfile prof,
                              icHeader *pHeader);

  • These are the arguments of cmsSetProfileHeader():

    ctxt 

    The context initialized by cmsOpen().

    prof 

    The profile whose header you want to set.

    pHeader 

    A pointer to the data structure from which to read the information.

  • This is the error code returned by cmsSetProfileHeader():

    CMS_OUT_OF_MEMORY 


    There is not enough memory to add the header data to the profile.

Saving Profile Changes to Disk: cmsSaveProfile()

The cmsSaveProfile() function saves an open profile to permanent storage, making it available to the file system. It does not remove the CMSProfile data structure from memory; the data remains available for further editing. Use cmsCloseProfile() to delete the CMSProfile data structure.

  • This is the prototype for cmsSaveProfile():

    int32  cmsSaveProfile(CMSContext ctxt, CMSProfile prof);

  • These are the arguments of cmsSaveProfile():

    ctxt 

    The context initialized by cmsOpen().

    prof 

    The profile.

  • The function cmsSaveProfile() returns an error if you try to save a profile that does not have a filename. Use cmsSaveProfileAs() to save a profile and attach a name to it. These are the error codes returned by cmsSaveProfile():

    CMS_FAILURE 


    Something went wrong; no further diagnostic information is available.

    CMS_OUT_OF_MEMORY 


    There is not enough memory for the profile.

Saving to a New File on Disk: cmsSaveProfileAs()

The function cmsSaveProfileAs() is similar to cmsSaveProfile(), in that it writes a profile to permanent storage, but it creates a new file with a filename you specify.

  • This is the prototype for cmsSaveProfileAs():

    int32 cmsSaveProfileAs(CMSContext ctxt, CMSProfile prof, char*spec);

  • These are the arguments ofcmsSaveProfileAs():

    ctxt 

    The context initialized by cmsOpen().

    prof 

    The profile to be saved.

    spec 

    The filename of the saved profile.

  • These are the error codes returned by cmsSaveProfileAs():

    CMS_FAILURE 


    Something went wrong; no further diagnostic information is available.

    CMS_OUT_OF_MEMORY 


    There is not enough memory for the new profile.

    CMS_EXACT_PROFILE_EXISTS 


    A profile already exists with the name spec.

Importing and Exporting Embedded Profiles

The ICCColor Profile Format Specification prescribes a way to embed ICC profiles in image data. This allows you to move color data to different computers and operating systems without concern for whether the necessary profiles are present at the destination.

The functions cmsExportProfile() and cmsImportProfile() exchange data between a CMSProfile data structure and data in the ICC format. This simplifies interactions with image data that include embedded profiles. You free storage for the exported data with cmsFreeProfileExport().

Creating an ICC Profile in a Buffer: cmsExportProfile()

The function cmsExportProfile() converts the data in a CMSProfile data structure to the ICC file format. Storage for the exported data is allocated by the Coloratura CMS, so it must be freed by calling cmsFreeProfileExport().

  • This is the prototype for cmsExportProfile():

    int32  cmsExportProfile(CMSContext ctxt, CMSProfile prof,
                            uint32 *length,  void **outputData);

  • These are the arguments of cmsExportProfile():

    ctxt 

    The context initialized by cmsOpen().

    prof 

    The CMSProfile data structure to be converted.

    length 

    The size of exported data, in bytes.

    outputData 

    A buffer of data in the ICC format.

  • This is the error code returned by cmsExportProfile():

    CMS_OUT_OF_MEMORY 


    There is not enough memory to allocate outputData.

Deleting an ICC Profile Buffer: cmsFreeProfileExport()

The function cmsFreeProfileExport() frees the output data storage created by cmsExportProfile().

  • This is the prototype for cmsFreeProfileExport():

    int32  cmsFreeProfileExport(CMSContext ctxt, void *outputData);

  • These are the arguments of cmsFreeProfileExport():

    ctxt 

    The context initialized by cmsOpen().

    outputData 

    The buffer of data to be freed.

Importing an ICC Profile from a Buffer: cmsImportProfile()

To create a CMSProfile data structure from a data buffer that is in the ICC format, typically obtained from an embedded profile, call cmsImportProfile(). You provide a CMSProfile, which cmsImportProfile() initializes to locate the newly constructed profile data structure.

  • This is the prototype for cmsImportProfile():

    int32  cmsImportProfile(CMSContext ctxt, 
                            uint32 length, void *inputData,
                            CMSProfile *profile);

  • These are the arguments of cmsImportProfile():

    ctxt 

    The context initialized by cmsOpen().

    length 

    The size, in bytes, of the input data.

    inputData 

    A buffer of data in the ICC format.

    profile 

    The profile to be initialized.

  • This is the error code returned by cmsImportProfile():

    CMS_OUT_OF_MEMORY 


    There is not enough memory to create a CMSProfile data structure from the profile data.

    CMS_WRONG_DATA 


    The data do not conform to the ICC file format.