KCMS Application Developer's Guide

Chapter 4 Functions

In This Chapter

This chapter describes in detail each "C" API function you can use in applications. It describes each function's signature, use, arguments, and return values. For several functions, the chapter provides code examples. The functions are defined in the kcs.h header file and are presented in alphabetical order.

All constants, definitions, macros, and data types are defined in Chapter 3, Data Structures, Chapter 5, KCMS Profile Attributes, and in the ICC profile format specification. By default, the ICC specification is located on-line in the SUNWsdk/kcms/doc directory. For the latest version of the specification, see the web site at http://www.color.org.

These API functions support error and warning messages returned by the operating system. See Chapter 6, Warning and Error Messages, for all error and warning messages returned by these functions.

KcsAvailable()

KcsStatusId
 KcsAvailable(long *response)

Purpose

The KcsAvailable() function determines if the KCMS framework has been installed on the system. This function is provided primarily for cross-platform compatibility.

Arguments

Table 4-1 KcsAvailable() Arguments

Argument 

Description 

response

A pointer to a long for temporary use in the KcsAvailable() function.

Returns

Table 4-2 KcsAvailable() Return Strings

KCS_SUCCESS

KCS_SUCCESS is always returned in the Solaris environment.

KcsConnectProfiles()

KcsStatusId
 KcsConnectProfiles(KcsProfileId *resultProfileId,
         unsigned long profileCount,
         KcsProfileId *profileSequence,
         KcsOperationType operationLoadSet,
         unsigned long *failedProfileIndex)

Purpose

Use KcsConnectProfiles() to combine several existing profiles into a new complete profile, or to restrict the functionality of a single existing profile to make it more efficient.

If KcsConnectProfiles() returns successfully, it generates a new profile from the sequence of existing profiles. The reference (profile Id) to this new profile is stored in the resultProfileId argument. With this reference, you can free the resources of the existing profiles in profileSequence if they are no longer required. Use KcsFreeProfile() to release the resources.


Note -

If you have minimized a profile's load operation or state with operationLoadSet or with KcsOptimizeProfile() ("KcsOptimizeProfile()"), only that load operation or state is saved with KcsSaveProfile(). Therefore, operations not included in the profile are not available the next time the profile is loaded.


If the last profile in a sequence to be connected includes a gamut transform, the operation hint KcsOpGamutTest (see "Operation Hint Constants") may be requested for that profile. The result of KcsEvaluate() with this gamut hint is a bit map image that contains 1 bit for each pixel in the original image. In the bit map, 0 means the color is in the gamut of the device requested by the final profile, and FF means the color is out of gamut (that is, the color cannot be represented by the device).

Arguments

Table 4-3 KcsConnectProfiles() Arguments

Argument 

Description 

resultProfileId

The identifier of the profile returned if this function executes successfully.  

profileCount

The number of profiles to be connected. 

profileSequence

An array of the Ids of the profiles to be connected. 

operationLoadSet

One or more flags symbolizing the kind of information in the resultant profile. It also describes what, how, when, and where to load and unload the resulting resultProfileId. See "KcsLoadHints" for more information.

failedProfileIndex

KcsConnectProfiles() returns an integer in failedProfileIndex. This value has meaning only when KcsConnectProfiles() returns a value other than KCS_SUCCESS. If the function fails, this index helps you identify which input profile caused the failure. If the index = 0, the first profile in profileSequence failed; if index = 1, the second profile in profileSequence failed, and so on. A common problem when making the resultant profile is that the profiles specified in profileSequence could not be connected. In this case, the index returns an integer symbolizing the latter profile in a failed connection pair. For example, if the first profile and second profile in the sequence were mismatched, the index contains 1 (for the second profile).

Returns

Table 4-4 KcsConnectProfiles() Return Strings

KCS_SUCCESS

KCS_PROF_ID_BAD

KCS_MEM_ALLOC_ERROR

KCS_CONNECT_PRECISION_UNACCEPTABLE

KCS_MISMATCHED_COLORSPACES

KCS_CONNECT_OPT_FORCED_DATA_LOSS

Example


Example 4-1 KcsConnectProfiles()

KcsProfileDesc                scannerDesc, monitorDesc, completeDesc;
 KcsProfileId                scannerProfile, monitorProfile;
 KcsProfileId                profileSequence[2], completeProfile;
 KcsStatusId                status;
 KcsErrDesc                 errDesc;
 u_long                failedProfileNum;
 KcsOperationType=(KcsOpForward+KcsContImage);
 /*file names input a program arguments */

 scannerDesc.type = KcsSolarisProfile;
 scannerDesc.desc.solarisFile.fileName = argv[1];
 scannerDesc.desc.solarisFile.hostName = NULL;
 scannerDesc.desc.solarisFile.oflag = O_RDONLY;
 scannerDesc.desc.solarisFile.mode = 0;
 
 monitorDesc.type = KcsSolarisProfile;
 monitorDesc.desc.solarisFile.fileName = argv[2];
 monitorDesc.desc.solarisFile.hostName = NULL;
 monitorDesc.desc.solarisFile.oflag = O_RDONLY;
 monitorDesc.desc.solarisFile.mode = 0;

 status = KcsLoadProfile(&scannerProfile, &scannerDesc, KcsLoadAllNow);

 if(status != KCS_SUCCESS) {
     KcsGetLastError(&errDesc);
     printf("Scanner LoadProfile error: %s\n", errDesc.desc);
     exit(1);
 }

 status = KcsLoadProfile(&monitorProfile, &monitorDesc, KcsLoadAllNow);

 if(status != KCS_SUCCESS) {
     KcsGetLastError(&errDesc);
     printf("Monitor LoadProfile error: %s\n", errDesc.desc);
     exit(1);
 }

 /* See if we can combine them */
 profileSequence[0] = scannerProfile;
 profileSequence[1] = monitorProfile;

 status = KcsConnectProfiles(&completeProfile, 2, profileSequence, op,
         &failedProfileNum);

 if(status != KCS_SUCCESS) {
     KcsGetLastError(&errDesc);
     printf("ConnectProfile error: %s\n", errDesc.desc);
     fprintf(stderr, "Failed in profile number %d\n", failedProfileNum);
     exit(1);
 }

KcsCreateProfile()


KcsStatusId
 KcsCreateProfile(KcsProfileId *resultProfileId,
         KcsCreationDesc *desc)

Purpose

Use KcsCreateProfile() to create an empty profile. The profile will contain neither attributes nor CMM-specific data.


Note -

Currently, your application cannot call KcsGetAttribute() for a list of the installed and available CMMs. The workaround is to load all available profiles and call K()csGetAttribute() for each individual CMM type.


Arguments

Table 4-5 KcsCreateProfile() Arguments

Argument 

Description 

resultProfileId

The reference to the resultant profile, returned if the function executes successfully.

desc

This is a pointer to a KcsCreationDesc (see "KcsCreationDesc") structure that describes the static store used to save the profile and an extendable union of profile information used to create the profile. The id member of the union describes which CMM and version to use, and the profile format and version to use.

If desc is NULL the default CMM and profile format are used.

Returns

Table 4-6 KcsCreateProfile() Return Strings

KCS_SUCCESS

KCS_MEM_ALLOC_ERROR

Example


Example 4-2 KcsCreateProfile()

KcsProfileDesc                                desc;
 KcsCreationDesc                                c_desc;
 KcsProfileId                                profileid;
 KcsStatusId                                status;
 KcsErrDesc                                errDesc;
 /* The filename is a command line argument */
 /* Create a new profile with the default CMM */

 desc.type = KcsSolarisProfile;
 desc.desc.solarisFile.fileName = argv[1];
 desc.desc.solarisFile.hostName = NULL;
 desc.desc.solarisFile.oflag = O_RDWR|O_CREAT|O_TRUNC;
 desc.desc.solarisFile.mode = 0666;
 c_desc.profileDesc = &desc;
 c_desc.desc.id.cmmId = 0;
 c_desc.desc.id.cmmVersionId = 0;
 c_desc.desc.id.profileId = 0;
 c_desc.desc.id.profileVersionId = 0;
 status = KcsCreateProfile(&profileid, &c_desc);
 if(status != KCS_SUCCESS) {
     KcsGetLastError(&errDesc);
     printf("CreateProfile error: %s\n", errDesc.desc);
 }


Note -

Other required fields in the profile must be set with KcsSetAttribute().


KcsEvaluate()

KcsStatusId
 KcsEvaluate(
         KcsProfileId profile,
         KcsOperationType operation,
         KcsPixelLayout *srcData,
         KcsPixelLayout *destData)

Purpose

Use KcsEvaluate() to apply a color profile to input color data to produce color-corrected output data.

See "KcsPixelLayout" for more information about using pixel layouts in this context.

Arguments

Table 4-7 KcsEvaluate() Arguments

Argument 

Description 

profile

The identifier of the profile to be applied to the input data. (If the operation specified when the profile was created in KcsConnectProfiles() does not match the operation specified in KcsEvaluate(), the status string KCS_EVAL_ONLY_ONE_OP_ALLOWED is returned. If, for example, your application wants to evaluate forward (specifies KcsOpForward in KcsEvaluate()) with a profile it creates with KcsConnectProfiles() to simulate (uses KcsOpSimulate in KcsConnectProfiles()), this particular status string would be returned.

operation

The kind of data to be operated on, and the kind of profile evaluation to be performed on, the data. (See "Operation Hint Constants" and "Content Hint Constants" more information.) Note that only 1 bit can be set for KcsEvaluate().

srcData

The description of the source color data to be transformed by the profile. 

destData

The description of the area (the destination) to which the transformed data is written. 

Returns

Table 4-8 KcsEvaluate() Return Strings

KCS_SUCCESS

KCS_OPERATION_CANCELLED

KCS_PROF_ID_BAD

KCS_MEM_ALLOC_ERROR

KCS_EVAL_ONLY_ONE_OP_ALLOWED

KCS_EVAL_TOO_MANY_CHANNELS

KCS_EVAL_BUFFER_OVERFLOW

KCS_LAYOUT_INVALID

KCS_LAYOUT_UNSUPPORTED

KCS_LAYOUT_MISMATCH

Example


Example 4-3 KcsEvaluate()

int                     op;
 KcsPixelLayout                    pixelLayoutIn, pixelLayoutOut;
 KcsProfileId                     scannerProfile, monitorProfile;
 KcsProfileId                    profileSequence[2], completeProfile;

 /* Load and connect profiles. */
 /* Load input and output pixel layout structures with appropriate data. */

 status = KcsEvaluate(completeProfile, op, &pixelLayoutIn,
             &pixelLayoutOut);

KcsFreeProfile()

KcsStatusId
 KcsFreeProfile(
         KcsProfileId    profile)

Purpose

Use KcsFreeProfile() to release all resources a loaded profile is using. A loaded profile uses memory and additional types of resources.

The KCMS framework does not automatically save profile changes when your application terminates. To save profile changes, your application must call KcsSaveProfile().


Note -

If the application passes a KcsFileProfile type of KcsProfileDesc as an argument, KcsFreeProfile() does not close the KcsFileId contained in the file entry of the KcsProfileDesc union.


Arguments

Table 4-9 KcsFreeProfile() Arguments

Argument 

Description 

profile

The identifier of a loaded profile. 

Returns

Table 4-10 KcsConnectProfiles() Return Strings

KCS_SUCCESS

KCS_PROF_ID_BAD

Example


Example 4-4 KcsFreeProfile()

KcsProfileId                        profile;

 /* Complete all processing. */

 KcsFreeProfile(profile);

KcsGetAttribute()

KcsStatusId
 KcsGetAttribute(KcsProfileId profile, KcsAttributeName name,
         KcsAttributeValue *value)

Purpose

Use KcsGetAttribute() to find the value of a particular attribute of the given profile. (See Chapter 5, KCMS Profile Attributes for more information on attributes.)

Arguments

Table 4-11 KcsGetAttribute() Arguments

Argument 

Description  

profile

The identifier of the loaded profile. 

name

The attribute name. See "List of All Attributes" for the names of all the attributes KCMS allows your application to specify in a call to this function.

value

A pointer to the structure to hold the value of the profile's attribute. Your application needs to set the countSupplied field in the value argument. If your application does not set it, the warning KCS_ATTR_LARGE_CT_SUPPLIED or the error KCS_ATTR_CT_ZERO_OR_NEG may be returned.

Returns

Table 4-12 KcsGetAttribute() Return Strings

KCS_SUCCESS

KCS_PROF_ID_BAD

KCS_ATTR_NAME_OUT_OF_RANGE

KCS_ATTR_CT_ZERO_OR_NEG

KCS_ATTR_LARGE_CT_SUPPLIED (warning)

Example


Example 4-5 KcsGetAttribute()

#include "./kcms_utils.h"

 KcsProfileId                            profileid;
 KcsAttributeValue                        *attrValue;
 int                                size;
 void print_header(icHeader *hdr);

 size = sizeof(KcsAttributeBase) + sizeof(icHeader);
 attrValue = (KcsAttributeValue *)malloc(size);

 /* Get the header */
 attrValue->base.type = icSigHeaderType;
 attrValue->base.sizeOfType = sizeof(icHeader);
 attrValue->base.countSupplied = 1;
 KcsGetAttribute(profileid, icSigHeaderTag, attrValue);
 ...
 print_header(&attrValue->val.icHeader);
 ...

 void
 print_header(icHeader *hdr)
 {
     char            charstring[5];

     printf("Size in bytes = %d\n", hdr->size);
     printf("CMM Id = 0x%x\n", hdr->cmmId);
     printf("Major version number = 0x%x\n", hdr->version>>24);
     printf("Minor version number = 0x%x\n", (hdr->version&0x00FF0000)>>16);

     switch(hdr->deviceClass) {
     case icSigInputClass :
         printf("deviceClass = input\n");
         break;
     case icSigDisplayClass :
         printf("deviceClass = display\n");
         break;
     case icSigOutputClass :
         printf("deviceClass = output\n");
         break;
     case icSigLinkClass :
         printf("deviceClass = link\n");
         break;
     case icSigAbstractClass :
         printf("deviceClass = abstract\n");
         break;
     case icSigColorSpaceClass :
         printf("deviceClass = colorspace\n");
         break;
     default :
         printf("Unknown\n");
         break;
    
     }

     memset(charstring, 0 ,5);
     memcpy(charstring, &hdr->colorSpace, 4);
     printf("colorspace = %s\n", charstring);

     memset(charstring, 0 ,5);
     memcpy(charstring, &hdr->pcs, 4);
     printf("profile connection space = %s\n", charstring);

     printf("date = %d/%d/%d,  ", hdr->date.day,hdr->date.month,
             hdr->date.year);
     printf("time = %d:%d:%d\n", hdr->date.hours,hdr->date.minutes,
             hdr->date.seconds);

     memset(charstring, 0 ,5);
     memcpy(charstring, &hdr->magic, 4);
     printf("magic number = %s\n", charstring);

     switch(hdr->platform) {
     case icSigMacintosh :
         printf("platform = Macintosh\n");
         break;
     case icSigMicrosoft :
         printf("platform = Microsoft\n");
         break;
     case icSigSolaris :
         printf("platform = Solaris\n");
         break;
     case icSigSGI :
         printf("platform = SGI\n");
         break;
     case icSigTaligent :
         printf("platform = Taligent\n");
         break;
     default :
         printf("Unknown\n");
         break;
     }

     if(hdr->flags && icEmbeddedProfileTrue)
         printf("Embedded profile.\n");
     else
         printf("Non-embedded profile\n");

     if(hdr->flags && icUseWithEmbeddedDataOnly)
         printf("If this profile is embedded, it is not allowed to strip
                     it out and use it independently.\n");
     else
         printf("OK to strip embedded profile out and use> > # end of Para

KcsGetLastError()

KcsStatusId
 KcsGetLastError (KcsErrDesc *errDesc)

Purpose

Use KcsGetLastError() to find information about the most recent error.

Arguments

Table 4-13 KcsGetLastError() Arguments

Argument 

Description 

errDesc

A pointer to the structure holding information about the last error. 

If an operating-system-defined error occurs, the sysErrNo field is set.

The desc field contains the description of the particular statId. This is either a string in Table 6-1 or Table 6-2, or the literal string "Internal Color Processor Error" or "No description for this status id number". See "Localizing Status Messages", in Chapter 6, Warning and Error Messages, for information on using KcsGetLastError() to localize KcsStatusId.

Returns

Table 4-14 KcsGetLastError() Return Strings

KCS_SUCCESS

Example


Example 4-6 KcsGetLastError()

KcsErrDesc                errDesc;

 status = KcsLoadProfile(&profile, &profileDesc,
             KcsLoadAttributesNow);
 if (status != KCS_SUCCESS) {
     status = KcsGetLastError(&errDesc);
     fprintf(stderr,"%s KcsLoadProfile failed error = %s\n",
                 errDesc.desc);
     exit(1);
 }

KcsLoadProfile()

KcsStatusId
 KcsLoadProfile(KcsProfileId *profile,
         KcsProfileDesc *desc, KcsLoadHints loadHints)

Purpose

Use KcsLoadProfile() to load a profile and all of its resources into the system.

The function uses desc to determine where to get the data to generate the profile's resources in the system. (See "KcsProfileDesc" for an in-depth description of KcsProfileDesc.) It uses profile to return a reference to the loaded profile. This reference is needed by other API functions.

Your application can determine the length of the data read from the file by calling KcsGetAttribute() and supplying the icHeader attribute. The value of size in the icHeader structure is the size of the profile. (For the format of the icHeader structure, see "icHeader".)

With the loadHints argument, KcsLoadProfile() allows the application to suggest how the KCMS framework manages the memory and other resources associated with a loaded profile. Although this is a flexible mechanism, these caveats apply:


Note -

If you use the KcsFileId entry in the file part of the KcsProfileDesc union, KcsFileId marks the current position within an open file. After a call to KcsLoadProfile(), the current position is undefined. The application must reset the pointer before doing any other I/O.


After your application is finished with the profile, it should call KcsFreeProfile() to release the resources allocated by the profile.

Arguments

Table 4-15 KcsLoadProfile() Arguments

Argument 

Description 

profile

The identifier of the profile returned after the profile is loaded into memory. This value serves as an argument to all other functions, such as KcsEvaluate().

desc

The location of the profile's static storage, needed to obtain the data required to generate the profile's resources. It is specified as a union of independent static storage mechanisms. The KcsProfileDesc structure (see "KcsProfileDesc") has a field that identifies which storage mechanism to use.

loadHints

The set of bits describing what, how, when, and where to load and unload profile. See "KcsLoadHints" for information on the KcsLoadHints data type. Also see "Operation Hint Constants" for constraints on the operations your application can specify to this function.

Returns

Table 4-16 KcsConnectProfiles() Return Strings

KCS_SUCCESS

KCS_MEM_ALLOC_ERROR

KCS_IO_READ_ERR

KCS_IO_SEEK_ERR

KCS_SOLARIS_FILE_NOT_OPENED

KCS_SOLARIS_FILE_RO

KCS_SOLARIS_FILE_LOCKED

KCS_SOLARIS_FILE_NAME_NULL

KCS_X11_DATA_NULL

KCS_X11_PROFILE_NOT_LOADED

KCS_X11_PROFILE_RO

Example


Example 4-7 KcsLoadProfile()

    KcsFileId        scannerFd, monitorFd, completeFd;
     KcsProfileDesc    scannerDesc, monitorDesc, completeDesc;
     KcsProfileId     scannerProfile, monitorProfile;
     KcsProfileId    profileSequence[2], completeProfile;
     KcsStatusId        status;
     KcsAttributeValue    attrValue;
     KcsAttributeName    i;
     KcsOperationType    op = (KcsOpForward+KcsContImage);
     u_long        failedProfileNum;
     extern void        kcs_timer(int);

     if (argc > 4) {
     fprintf(stderr,"Usage : kcstest profile_1 profile_2 [save_profile]\n");
     exit(1);
     }

 #ifdef FILE_DESC
     /* Open up the files from disk */
     scannerDesc.type = KcsFileProfile;
     scannerFd = open(argv[1], O_RDONLY);
     if (scannerFd == -1) {
     perror("Failed to open scanner profile");
     exit(1);
     }
     scannerDesc.desc.file.openFileId = scannerFd;
     scannerDesc.desc.file.offset = 0;

     monitorDesc.type = KcsFileProfile;
     monitorFd = open(argv[2], O_RDONLY);
     if (monitorFd == -1) {
     perror("Failed to open monitor profile");
     exit(1);
     }
     monitorDesc.desc.file.openFileId = monitorFd;
     monitorDesc.desc.file.offset = 0;
 #endif

 #ifdef FILE_NAME
     scannerDesc.type = KcsSolarisProfile;
     scannerDesc.desc.solarisFile.fileName = argv[1];
     scannerDesc.desc.solarisFile.hostName = NULL;
     scannerDesc.desc.solarisFile.oflag = O_RDONLY;
     scannerDesc.desc.solarisFile.mode = 0;

     monitorDesc.type = KcsSolarisProfile;
     monitorDesc.desc.solarisFile.fileName = argv[2];
     monitorDesc.desc.solarisFile.hostName = NULL;
     monitorDesc.desc.solarisFile.oflag = O_RDONLY;
     monitorDesc.desc.solarisFile.mode = 0;
 #endif

     /* Load the profiles */
     printf("Load scanner profile\n");
     kcs_timer(START);
     status = KcsLoadProfile(&scannerProfile, &scannerDesc, KcsLoadAllNow);
     kcs_timer(STOP);
     if (status != KCS_SUCCESS) {
     fprintf(stderr,"Scanner KcsLoadProfile failed error = 0x%x\n", status);
 #ifdef FILE_DESC
     close(scannerFd);
     close(monitorFd);
 #endif
     exit(1);
     }

     printf("Load monitor profile\n");
     kcs_timer(START);
     status = KcsLoadProfile(&monitorProfile, &monitorDesc, KcsLoadAllNow);
     kcs_timer(STOP);
     if (status != KCS_SUCCESS) {
     fprintf(stderr,"MonitoKcsLoadProfile failed error = 0x%x\n", status);
 #ifdef FILE_DESC
     close(scannerFd);
     close(monitorFd);
 #endif
     exit(1);
     }

KcsModifyLoadHints()

KcsStatusId
 KcsModifyLoadHints(KcsProfileId profile,
         KcsLoadHints newHints)

Purpose

KcsModifyLoadHints() applies a new set of load hints to a profile already loaded. If, for example, your application no longer needs to simulate a profile and available memory is limited, it can use this function to unload the simulation portion of the profile immediately, making more memory available for it to run.

Typically you would use this function to load the operation hints (transforms) for a profile whose attributes only were previously loaded. (For details on operation hints, see "Operation Hint Constants".)


Note -

Remember that the load hints are just that--hints to the KCMS framework. Although the KCMS framework tries to accomplish what is specified, and typically does, it cannot guarantee everything exactly as hinted. It is subject to what the CMM supports.


Arguments

Table 4-17 KcsModifyLoadHints() Arguments

Argument 

Description 

profile

The identifier of the loaded profile.  

newHints

The set of bits describing what, how, when, and where to load and unload profile. See "KcsLoadHints" for more information.

Returns

Table 4-18 KcsModifyLoadHints() Return Strings

KCS_SUCCESS

KCS_PROF_ID_BAD

KCS_MEM_ALLOC_ERROR

Example


Example 4-8 KcsModifyLoadHints()

KcsProfileId                         profileid;
 KcsErrDesc                        errDesc;
 KcsProfileDesc                        profileDesc;
 KcsProfileId                         profile;
 KcsStatusId                        status;
 KcsLoadHints                        newhints;

 /* profile name is a command line argument */

 profileDesc.type = KcsSolarisProfile;
 profileDesc.desc.solarisFile.fileName = argv[1];
 profileDesc.desc.solarisFile.hostName = NULL;
 profileDesc.desc.solarisFile.mode = 0;
 profileDesc.desc.solarisFile.oflag = NULL;

 status = KcsLoadProfile(&profile, &profileDesc, KcsLoadAttributesNow);
 if (status != KCS_SUCCESS) {
     status = KcsGetLastError(&errDesc);
     fprintf(stderr,"%s KcsLoadProfile failed error = %s\n",
             argv[optind], errDesc.desc);
     exit(1);
 }

 /* suppose it was determined that this is the profile we want to *
  * use for evaluating data. We want to load it all in now. */

 newhints = KcsLoadAllNow;
 status = KcsModifyLoadHints(profile, newhints);
 if (status != KCS_SUCCESS) {
     status = KcsGetLastError(&errDesc);
     fprintf(stderr," ModifyHints failed error = %s\n", errDesc.desc);
     exit(1);
 }

KcsOptimizeProfile()

KcsStatusId
 KcsOptimizeProfile(KcsProfileId profile,
         KcsOptimizationType optimizationType,
         KcsLoadHints operationLoadSet)

Purpose

Use KcsOptimizeProfile() to optimize the profile by:

Optimization is CMM dependent. The CMM always interprets the load hints in terms of the particular situation.


Note -

If your application has minimized a profile's load operation or state with operationLoadSet or with KcsOptimizeProfile(), only that load operation or state is saved with KcsSaveProfile(). Therefore, operations not included in the profile are not available the next time the profile is loaded.


Arguments

Table 4-19 KcsOptimizeProfile() Arguments

Argument 

Description 

profile

The identifier of the profile. 

optimizationType

The kinds of optimization (size, speed, and accuracy) your application wants to perform on the profile. (See "KcsOptimizationType" for more information.) When a combination of values is specified, it is up to the CMM to determine which value is more important.

operationLoadSet

One or more flags symbolizing the kind of information wanted in profile. It also describes what, how, when, and where to load and unload profile. See "KcsLoadHints" for more information.

Returns

Table 4-20 KcsOptimizeProfile() Return Strings

KCS_SUCCESS

KCS_OPERATION_CANCELLED

KCS_MEM_ALLOC_ERROR

KCS_PROF_ID_BAD

Example


Example 4-9 KcsOptimizeProfile()

KcsProfileId                monitorProfile, scannerProfile, completeProfile;
 KcsStatusId                status;
 KcsErrDesc                errDesc;

 /* The monitor profile and scanner profile have been loaded and connected *
  * to become a complete profile, now optimize. */

 status = KcsOptimizeProfile(completeProfile, KcsOptSpeed, KcsLoadAllNow);
 if (status != KCS_SUCCESS) {
     status = KcsGetLastError(&errDesc);
     fprintf(stderr,"KcsOptimizeProfile failed error = %s\n", errDesc.desc);
     KcsFreeProfile(monitorProfile);
     KcsFreeProfile(scannerProfile);
     return(-1);
 }

KcsSaveProfile()

KcsStatusId
 KcsSaveProfile (KcsProfileId profile, KcsProfileDesc *desc)

Purpose

Use KcsSaveProfile() to save a loaded profile, and any changes to its attributes or profile data, to the mechanism described by desc.

If supported by the mechanism, a profile's state can be saved at an offset. For example, if the mechanism indicates a file, the following two situations are applicable:

KcsSaveProfile() writes information, but does not free the profile. Even after saving the profile, the application can continue to use it. In fact, the application must call KcsFreeProfile() to free all resources associated with the profile.

Arguments

Table 4-21 KcsSaveProfile() Arguments

Argument  

Description 

profile

The identifier of the loaded profile.Typically, your application obtains this value when it calls KcsLoadProfile() or KcsConnectProfiles().

desc

The location of the profile's static storage mechanism, needed to obtain the data required to generate the profile's resources. It is specified as a union of independent static storage mechanisms. This argument has a field that identifies which storage mechanism to use. If this field is NULL, the profile is saved through the same mechanism from which it was loaded. (See "KcsProfileId" for more information.)

Returns

Table 4-22 KcsSaveProfile() Return Strings

KCS_SUCCESS

KCS_IO_WRITE_ERR

KCS_IO_READ_ERR

KCS_IO_SEEK_ERR

KCS_SOLARIS_FILE_NOT_OPENED

KCS_SOLARIS_FILE_RO

KCS_SOLARIS_FILE_LOCKED

KCS_SOLARIS_FILE_NAME_NULL

KCS_X11_DATA_NULL

KCS_X11_PROFILE_NOT_LOADED

KCS_X11_PROFILE_RO

Example


Example 4-10 KcsSaveProfile()

KcsProfileDesc                        desc;
 KcsProfileId                        profileid;
 KcsStatusId                        status;
 KcsErrDesc                         errDesc;

 /*see example kcms_update.c for a full example code */

 desc.type = KcsSolarisProfile;
 desc.desc.solarisFile.fileName = argv[1];
 desc.desc.solarisFile.hostName = NULL;
 desc.desc.solarisFile.mode = 0;
 desc.desc.solarisFile.oflag = O_RDWR
 status = KcsSaveProfile(profileid, &desc);
 if(status != KCS_SUCCESS) {
     status = KcsGetLastError(&errDesc);
     fprintf(stderr,"KcsSaveProfile failed error = %s\n", errDesc.desc);
 }
 KcsFreeProfile(profileid);


Note -

If you are saving a new profile, use the following assignments instead of the assignments in Example 4-10.


desc.desc.solarisFile.mode = 0666;
desc.desc.solarisFile.oflag = O_RDWR | O_CREAT | O_TRUNC;

KcsSetAttribute()

KcsStatusId
 KcsSetAttribute(KcsProfileId profile,
         KcsAttributeName name,
         KcsAttributeValue *value)

Purpose

Use KcsSetAttribute() to create, to modify, or to delete a specific attribute in a profile. See Chapter 5, KCMS Profile Attributes for details on attributes.


Note -

KcsSetAttribute() cannot be used to modify the value of the icSigProfileSequenceDescriptionTag attribute. The attribute is read only.


Arguments

Table 4-23 KcsSetAttribute() Arguments

Argument  

Description  

profile

The identifier of the profile.  

name

The name of the attribute to be created, modified, or deleted. If this attribute is already used in the profile, this function overwrites its value. If this attribute does not already exist, the function creates it. See "List of All Attributes" for the names of all the attributes KCMS allows your application to specify in a call to this function.

value

A pointer to the value for the attribute. If the attribute already exists, value becomes the attribute's new value. If the attribute does not already exist, this function creates it and sets its original value to value. To delete an existing attribute, set value to NULL.


Note -

For this function to execute correctly, your application must check what needs to be set in the KcsAttributeBase structure (part of the KcsAttributeValue structure). A valid type and number of tokens found in the attribute must be set.


Returns

Table 4-24 KcsConnectProfiles() Return Strings

KCS_SUCCESS

KCS_MEM_ALLOC_ERROR

KCS_PROF_ID_BAD

KCS_ATTR_NAME_OUT_OF_RANGE

KCS_ATTR_TYPE_UNKNOWN

KCS_ATTR_NEG_CT_SUPPLIED

KCS_ATTR_LARGE_CT_SUPPLIED

Example


Example 4-11 KcsSetAttribute()

#include "kcms_utils.h"
 #define SAMPLE_WORDS "A profile created using kcms_create"

 KcsProfileId                    profileid;
 KcsStatusId                    status;
 KcsAttributeValue                    attrValue;
 KcsAttributeValue                    *attrValue2;
 KcsAttributeValue                    *attrValuePtr;
 KcsErrDesc                    errDesc;
 int                    sizemeas, size, nvalues, i, j;
 time_t                    clocktime;
 struct tm                    *datetime;
 size_t                    rc;
 char                    *description;
 char                    attr[256];
 double                    test_double[3];

 /* Fill out the measurement structures - The illuminant must be D50 */
 test_double[0] = 0.9642;
 test_double[1] = 1.0;
 test_double[2] = 0.8249;

 /*  open or create a profile, then set some attributes */
 if ((description = (char *)malloc(strlen(SAMPLE_WORDS) + 1)) == NULL) {
     perror("malloc failed : ");
     KcsFreeProfile(profileid);
     exit(1);
 }
 memset(description, 0, strlen(SAMPLE_WORDS) + 1);
 strcpy(description, SAMPLE_WORDS);
 /* the function used below can be found in kcms_utils.c in appendix */
 if ((attrValue2 = string2icTextAttrValue(description)) == NULL) {
     fprintf(stderr, "conversion to AttrValue failed \n");
     KcsFreeProfile(profileid);
     exit(1);
 }
 if (KcsSetAttribute(profileid, icSigProfileDescriptionTag, attrValue2)
     != KCS_SUCCESS) {
     KcsGetLastError(&errDesc);
     printf("Set Attribute error: %s\n", errDesc.desc);
     exit(1);
 }
 free(attrValue2);
 free(description);
 size = sizeof(KcsAttributeBase) + sizeof(icHeader);
 attrValuePtr = (KcsAttributeValue *)malloc(size);

 /* Build the header */
 attrValuePtr->base.type = icSigHeaderType;
 attrValuePtr->base.sizeOfType = sizeof(icHeader);
 attrValuePtr->base.countSupplied = 1;
 KcsGetAttribute(profileid, icSigHeaderTag, attrValuePtr);
 attrValuePtr->val.icHeader.size = 0;

 /* The following three values do not have to be set if you do a
  * GetAttribute on the header, since the Create should set them for you.
  * If you do not do a GetAttribute of the header, you must set these:
  *   attrValuePtr->val.icHeader.cmmId = 0x4b434d53;
  *   attrValuePtr->val.icHeader.version =icVersionNumber;
  *   attrValuePtr->val.icHeader.magic = icMagicNumber;
 */
 attrValuePtr->val.icHeader.deviceClass = icSigDisplayClass;
 attrValuePtr->val.icHeader.colorSpace = icSigRgbData;
 attrValuePtr->val.icHeader.pcs = icSigXYZData;

 /* Get the time from the system */
 clocktime = time(NULL);
 datetime = localtime(&clocktime);

 attrValuePtr->val.icHeader.date.seconds =
         (icUInt16Number)datetime->tm_sec;
 attrValuePtr->val.icHeader.date.minutes =
         (icUInt16Number)datetime->tm_min;
 attrValuePtr->val.icHeader.date.hours =
         (icUInt16Number)datetime->tm_hour;
 attrValuePtr->val.icHeader.date.day =
         (icUInt16Number)datetime->tm_mday;
 attrValuePtr->val.icHeader.date.month =
         (icUInt16Number)datetime->tm_mon + 1;
 attrValuePtr->val.icHeader.date.year =
         (icUInt16Number)datetime->tm_year;
 attrValuePtr->val.icHeader.platform = icSigSolaris;
 attrValuePtr->val.icHeader.flags =
         icEmbeddedProfileFalse || icUseAnywhere;
 strcpy(description,"SUNW ");
 memcpy(&attrValuePtr->val.icHeader.manufacturer, description, 4);
 attrValuePtr->val.icHeader.model = 0;
 attrValuePtr->val.icHeader.attributes[0] = 0;
 attrValuePtr->val.icHeader.attributes[1] = 0;
 attrValuePtr->val.icHeader.renderingIntent = icPerceptual;
 attrValuePtr->val.icHeader.illuminant.X =
         double2icfixed(test_double[0], icSigS15Fixed16ArrayType);
 attrValuePtr->val.icHeader.illuminant.Y =
         double2icfixed(test_double[1], icSigS15Fixed16ArrayType);
 attrValuePtr->val.icHeader.illuminant.Z =
         double2icfixed(test_double[2], icSigS15Fixed16ArrayType);
 rc = KcsSetAttribute(profileid, icSigHeaderTag, attrValuePtr);
 if(rc != KCS_SUCCESS) {
     rc =KcsGetLastError(&errDesc);
     fprintf(stderr, "unable to set header: %s\n", errDesc.desc);
     KcsFreeProfile(profileid);
     return(-1)

KcsSetCallback()

KcsStatusId
 KcsSetCallback (KcsFunction function,
         KcsCallbackFunction callback, void *userDefinedData)

Purpose

Use KcsSetCallback() to associate a callback function with any set of API functions that supports callbacks. Those functions are listed in KcsFunction (see Table 3-1). If KcsSetCallback() is not called for particular values of KcsFunction, no callback is issued.

This function allocates resources. To release those resources, your application must set all callback functions to NULL, for example,

KcsSetCallback(KcsAllFunc, NULL, NULL);

Arguments

Table 4-25 KcsSetCallback() Arguments

Argument  

Description  

function  

A set of API functions. See Table 3-1 for the list of functions.

callback  

The application-supplied function to be called when the variable function needs to report progress.

userDefinedData  

Any user-defined data. 

Returns

Table 4-26 KcsSetCallback() Return Strings

KCS_SUCCESS

KCS_MEM_ALLOC_ERROR 

Example


Example 4-12 KcsSetCallback()

/* template function declaration */

 int myProgressCallback(KcsProfileId profileid, unsigned long
             current, unsigned long total, KcsFunction
             operation, void *userDefinedData);

 KcsProfileId                        completeProfile;
 KcsPixelLayout     pixelLayoutIn;

 /* the profiles have been loaded and connected, now set up the
 * callback to be active for both the optimize and evaluate
 * functions */

 status = KcsSetCallback(KcsOptFunc + KcsEvalFunc,
             (KcsCallbackFunction)myProgressCallback, NULL );
 if (status != KCS_SUCCESS) {
     fprintf(stderr, "Callback function call failed\n");
 }
 
 printf("Optimizing the complete profile \n");
 status = KcsOptimizeProfile(completeProfile, KcsOptSpeed, KcsLoadAllNow);
 /* check status here*/
 /* set up the pixel layout */
 status = KcsEvaluate(completeProfile, op, &pixelLayoutIn, &pixelLayoutIn);
 /* check status here*/

 /* This is my callback function */

 int myProgressCallback(KcsProfileId profileid, unsigned long current,
         unsigned long total, KcsFunction operation, void *userDefinedData)

 {
     int            pcent;
 
     pcent = (int) (((float)current/ (float)total) *100.0);
     fprintf(stderr,"Optimize+Evaluate is %3d percent complete\n", pcent);
     fflush(stderr);
     return(KCS_SUCCESS);
 /* Free callback resources*/
 KcsSetCallback (KcsOptFunc+KcsEvalFunc, NULL, NULL);
 }

KcsUpdateProfile()

KcsStatusId
 KcsUpdateProfile(KcsProfileId profile,
         KcsCharacterizationData *charact,
         KcsCalibrationData *calib, void *CMMSpecificData)

Purpose

Use KcsUpdateProfile() to change the profile data in the loaded profile according to the supplied measurement data.

The data supplied to this call depends on the type of device the profile represents. The default CMM currently supports scanners and monitors. Printer profiles are not currently supported. The "C" API also will be used for printers, when implemented by the default or alternative CMMs. The data required for this call depends on whether the profile is calibrated or characterized.

Characterization refers to defining the generic color response of all devices of the same make and model (normally by making measurements on a number of sample devices to find an average response). Characterization requires colorimetric measurements. Example 4-13 shows how these measurements are used to update a profile.

Calibration refers to fine-tuning a specific device's color response. It changes the profile data so that it can be color managed to produce the same color response as other devices of the same make and model.

The charact argument to this function refers to a set of color sample measurements where sample is a color patch on a test target.

For a scanner, the test target is a target that is scanned. In this case, each color sample in the measurement set consists of an input that is the CIEXYZ value of the color patch, as measured. The sample output is the RGB value that the scanner produced when scanning the color patch. In addition, each sample contains fields for the sample weight, standard deviation, and sample type. The weight is a hint indicating the importance of the sample color. The default should equal 1.0. The standard deviation is used to indicate the statistics of a set of measurements of the sample color that have been reduced to a single sample. The sample type is used to indicate that a color sample represents either black, white, other, neutral, or chromatic color. For best results, the sample type field should be correctly set for each color sample. For example, the KcsFluorescent sample type can be used to tag special color samples with this property. The sample type is a hint passed by the KCMS framework to the CMM.

Note that CIEXYZ values are to be scaled in the range 0.0 to 100.0 and that RGB values are to be scaled in range 0.0 to 1.0. For additional details, see "KcsCharacterizationData".

For a monitor, the charact argument is not used. Pointer *charact should be set to NULL when KcsUpdateProfile() is called for a monitor profile. Characterization data consists of the following profile attributes:

These attributes must be set and valid prior to calling KcsUpdateProfile(). Your application must use KcsSetAttribute() to set these attributes.

Arguments

Table 4-27 KcsUpdateProfile() Arguments

Argument 

Description 

profile

The identifier of the profile to be updated. 

*charact

A set of color sample measurements where sample is a color patch on a test target. 

*calib

The linearization tables needed to calibrate the profile. These tables are required to calibrate all device types. They are also required when calling KcsUpdateProfile() to characterize a scanner or monitor. Both the input and output spaces are KcsRGB for a scanner and monitor. The RGB samples are scaled in the range of 0.0 to 1.0.

*CMMSpecificData 

A pointer to any additional data needed by a specific CMM to update the profile. Refer to the CMM documentation for any specific data required. For use with the default CMM, your application should set this argument to NULL.

Returns

Table 4-28 KcsUpdateProfile() Return Strings

KCS_SUCCESS

KCS_MEM_ALLOC_ERROR

KCS_CC_UPDATE_NEEDS_MORE_DATA

KCS_CC_UPDATE_INVALID_DATA

Example

To call KcsUpdateProfile() successfully, the profile must contain a small number of attributes that identify the type of device the profile represents. It is assumed that the profile already contains these attributes.

An example is given of how to allocate and fill out the arguments required to call KcsUpdateProfile().


Example 4-13 KcsUpdateProfile()

#pragma ident "@(#) kcms_update.c"
 /* kcs_update.c */
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <math.h>
 #include <kcms/kcs.h>
 #include <kcms/kcstypes.h>
 #include <kcms/kcsattrb.h>

 float            Luminance_float_out[3][256];

 /* test code to check profile calibration * /
 main(int argc, char **argv)
 {
 KcsCalibrationData            *calData;
 KcsProfileDesc                x_desc, desc;
 KcsProfileId                  profileid;
 KcsStatusId                   status;
 KcsAttributeValue             attrValue;
 KcsErrDesc                    errDesc;
 int                           levels = 256, channels = 3;
 int                           sizemeas, nvalues, i, j;
 FILE                          *simfile;
 float                         input_val;
 size_t                        rc;
 
 /* Read in the measured calibration data from a file */
 /* file lum_out should be located in demo directory with this program */

 if ((simfile = fopen("lum_out", "r")) == NULL) {
     fprintf(stderr,"cannot open output luminance file\n");
     exit(1);
     }

 for (i=0; i<channels; i++)
     for (j=0; j<levels; j++)
             Luminance_float_out[i][j] = 0.0;
 nvalues = levels * channels;
 rc = fread(Luminance_float_out, sizeof(float), nvalues, simfile);
 fclose(simfile);

 /* Fill out the measurement structures */
 sizemeas = (int) (sizeof(KcsMeasurementBase) + sizeof(long) + levels);
         
 calData = (KcsCalibrationData *) malloc(sizemeas);

 calData->base.countSupplied = levels;
 calData->base.numInComp = 3;
 calData->base.numOutComp = 3;
 calData->base.inputSpace = KcsRGB;
 calData->base.outputSpace = KcsRGB;
 for (i=0; i< levels; i++) {
     calData->val.patch[i].weight = 1.0;
     calData->val.patch[i].standardDeviation = 0.0;
     calData->val.patch[i].sampleType = KcsChromatic;

     calData->val.patch[i].input[KcsRGB_R] = (float)i/255;
     calData->val.patch[i].input[KcsRGB_G] = (float)i/255;
     calData->val.patch[i].input[KcsRGB_B] = (float)i/255;
     calData->val.patch[i].input[3] = 0.0;

     calData->val.patch[i].output[KcsRGB_R] = Luminance_float_out[0][i];
     calData->val.patch[i].output[KcsRGB_G] = Luminance_float_out[1][i];
     calData->val.patch[i].output[KcsRGB_B] = Luminance_float_out[2][i];
     calData->val.patch[i].output[3] = 0.0;
     }

 calData->val.patch[0].sampleType = KcsBlack;
 calData->val.patch[255].sampleType = KcsWhite;

 if (!argv[1]) {
     fprintf(stderr, "Usage kcms_update profile_in [profile_out]\n");
     exit(1);
     }
  /* Let the library open the file */
 x_desc.type = KcsSolarisProfile;
 x_desc.desc.solarisFile.fileName = argv[optind];
 x_desc.desc.solarisFile.hostName = NULL;
 x_desc.desc.solarisFile.oflag = O_RDWR;
 x_desc.desc.solarisFile.mode = 0;

 status = KcsLoadProfile(&profileid, &x_desc, KcsLoadAllNow);
 if(status != KCS_SUCCESS) {
     status = KcsGetLastError(&errDesc);
     printf("LoadProfile error: %s\n", errDesc.desc);
     }

 status = KcsUpdateProfile(profileid, NULL, calData, NULL);
 if(status != KCS_SUCCESS) {
     status = KcsGetLastError(&errDesc);
     printf("UpdateProfile error: %s\n", errDesc.desc);
     KcsFreeProfile(profileid);
     exit(1);
     }

 if (argv[2]) {
     /* Save to an output file */
     desc.type = KcsSolarisProfile;
     desc.desc.solarisFile.fileName = argv[2];
     desc.desc.solarisFile.hostName = NULL;
     desc.desc.solarisFile.oflag = O_RDWR|O_CREAT|O_TRUNC;