KCMS CMM Developer's Guide

Chapter 1 Class Descriptions

In This Chapter

This chapter introduces you to the KCMS framework classes. The chapter assumes your familiarity with the KCMS architecture. See Figure 1-1 .

As a brief review, the KCMS architecture consists of components supplied by SunSoft (shown in gray in the figure) and other components (shown in white) that the developer can add. Towards the top of the figure, you see the KCMS "C" application programming interface (API). It consists of a group of functions that allow an application to communicate with the KCMS framework to manipulate profiles in a device-independent manner. The KCMS "C"API is described in detail in the SDK manual KCMS Application Developer's Guide. This manual assumes that you are familiar with the API functions.

The color management module (CMM), shown below the KCMS framework, is the component that ultimately does the color management. The default CMM includes all the classes described in this chapter.

Other CMMs use different techniques for evaluating color data, which can result in differences in quality, profile size, and speed of color manipulations. To add a new third-party CMM to the framework, you can only derive from four of the classes described in this chapter and you can extend one. Collectively, these classes are referred to as the C++ CMM interface in the figure. Although you can only derive from a few classes, you need to understand the inner workings of all the classes to understand what is being inherited in the implementation of the CMM you write.

Figure 1-1 KCMS Architecture

Graphic

KCMS Class Hierarchy

Figure 1-2 shows all relevant classes in the KCMS framework. Each class is described in this chapter.

For descriptions of the enumerations and protected and public members of each class, see the KCMS CMM Reference Manual

Note that, when you write a CMM, you can only derive from the KcsIO, KcsProfile, KcsProfileFormat, and KcsXform classes, and you can extend KcsStatus. How you can use these particular classes in the design of your CMM is described in greater detail in subsequent chapters in this manual. The remainder of the classes your CMM uses are the default classes.

Figure 1-2 KCMS Class Hierarchy

Graphic

KcsShareable Class

The KcsShareable class allows derivatives to be shared by other objects in the system. This class uses reference counting. It follows all of the typical C++ semantics, except you should use the dettach()() method instead of calling the destructor ~KcsShareable()(). The dettach()() method calls the destructor only if it is the last object sharing the derivative.

Using a shareable derivative is similar to using a non-shareable objects with the following exceptions:

The abstraction provided by this class is simple yet powerful. With only a few methods you can share objects. Every time you want to share an object, the usage count is incremented. Any time a shared object is detached, the usage count is decremented.

KcsLoadable Class

The KcsLoadable class allows derivatives to be saved and generated from a static store and possibly minimized and regenerated from that original store at a later time.

If a class cannot regenerate itself at runtime, it must generate itself fully on construction. With KcsLoadable class derivatives, you must allocate and deallocate loadable objects if those objects require regeneration and are not supported by the contained class.

All derived objects return KCS_NOT_RUNTIME_LOADABLE whenever regeneration is unsupported. KCS_NOT_RUNTIME_LOADABLE indicates that you must use the constructor and destructor methods to regenerate at runtime.

To relax the requirements on a derivative, assume it is loadable and do not provide any special generation support. That is, allocate the object, load it when necessary, unload it when it is not needed and assume everything worked. In this case, ignore the KCS_NOT_RUNTIME_LOADABLE status message returned by the load()() and unload()() methods.

If the object does not support regeneration it returns KCS_NOT_RUNTIME_LOADABLE when issued a load()() or unload()() command. The object remains loaded in memory so it is not necessary to observe this protocol unless more flexibility is required for performance reasons.

UIDs and Sharing

All KcsLoadable classes have unique identifiers (UIDs). The combination of a chunkSet and a chunkId allows you to save the state of KcsLoadable derivatives for later use. To do this, either minimize and regenerate by calling unload()() and load()(), or save the UID of the instance and reallocate the instance with the UID-based constructor.

Because classes that contain other loadable objects use the same chunkSet, you must save the chunkId within your own data store. To explain this further, an example with an KcsXform class is used; see Chapter 7, KcsXform Derivative " for more information. For example, a sequence transformation saves its array of transform chunkIds in the same chunkset as it does its own state. The KcsXformSeq class has an array of pointers to KcsXforms when it is allocated in memory.

Since all of these transforms have unique identifiers, the KcsXformSeq class places the UID of each transform in an array and saves it. Once this sequence is constructed and told to load, (the chunkId is passed into the constructor) it gets the chunk and, for each transform chunkId, it calls the KcsXform::createXform(uid)() constructor. This constructor allocates the transform associated with that chunkId.

All loadable derivatives should support construction based on this chunkSet and chunkId combination. Loadable objects are shared by using a UID map table kept in the static KcsLoadable data member. When a new loadable object is created, this UID map table is searched first to see if an object with a particular ChunkSet and ChunkId has already been instantiated. If so, the pointer to that object is returned; if not, a new object is created and entered into the table.

Example

*aStat

= KcsLoadable::LoadCreator(Kcs2Id('P', 'f', 'm', 't'),  Kcs2Id('K', 'C', 'M',

'S'), Kcs2Id('0', '1', '\0', '\0'),  Kcs2Id('B', 'l', 'n', 'k'),  (void *

(**)())&sCreateFunction,

&sDLHandle);

This LoadCreator()() example returns a function pointer in sCreateFunction that is cast and called with the arguments as follows:

KcsProfileFormat::KcsProfileFormat(KcsStatus

*aStat,  	KcsId aCmmId, KcsVersion aCmmVersion, KcsId aProfileId,  	KcsVersion

aProfVersion)

KcsEkPfmticc30.so.1 is a KcsProfileFormat derivative whose method's object code is contained in the file mapped from the arguments to the LoadCreator()() method. The B, l, n, and k arguments are qualifiers for the constructor to use. In this case it is the Id-based constructor that generates a blank profile format. This call makes runtime loadabilty of derivatives platform independent. If aDerivId is a non-ASCII printable character, it is treated as BCD for these reasons: the ICC identifies their versions in BCD, and the runtime derivatives naming conventions need to conform to file naming conventions. Therefore, the operating system cannot use anything nonprintable to name files. If available, the method calls the initialization entry points upon the first load of the sharable. Currently, when an object is loaded, it is not unloaded until the program exits. The dlopen(3x) call returns a pointer to the same handle when it is opened.

Derivatives

Use a KcsIO class derivative for a static store. These derivatives can be memory based, disk based, and network based. The object does not care where the information is actually stored. The KcsIO base class has a file-like interface. Loadable derivatives also use the KcsChunkSet abstraction. This provides a random access bit bucket that is built on top of the KcsIO hierarchy.

Once a loadable object is minimized (or unloaded), a derived object regenerates or reloads itself in the manner described below.

The derivation implements the unload()() method to minimize the state of the object in memory. Then in the load()() method, it restores the state of the object to that described by the chunkSet and iChunkId member fields of the loadable base class. If in the unloaded state, it returns an error to signal that a load()() call in this state is not adequate for all methods. Additionally, for methods that need access to the state, it loads the minimum state according to the specific derivative's load hints. Then it continues the original method's functionality.

It is assumed that if hints are allowed for loading, the derivative overloads the load()() method to allow the hints to be passed to its contained object's load()() method.

KcsIO Class

The KcsIO class provides a generic input/output (I/O) interface to access data in a static store like files on a disk or in memory. The KcsIO class provides a common interface for device-, platform-, and transport-independent I/O operations such as read and write. It is a derivative of the KcsShareable class. The KcsFile, KcsMemoryBlock, KcsSolarisFile, and KcsXwindow are derivatives of the KcsIO class that provide I/O for more specific types of data storage.

The KcsIO class is primarily provided for operating system vendors to access profiles in devices that cannot be created by deriving from other classes in the system. For example, you may require access to profiles in a printer that have properties not accessible in other classes--if you could not mmap(2) the printer memory.


Note -

You must derive from the KcsIO class if you require device-, platform- or transport-dependent I/O operations.


See Chapter 4, KcsIO Derivative " for detailed information.

KcsFile Class

The KcsFile class is a KcsIO base class derivative that allows an implementation of the I/O interface to store its data on a physical disk mounted on the platform in use. It takes an open file as the argument for its constructor and allows sequential and random access file manipulation.

KcsFile is useful for embedding profiles in other files.

KcsMemoryBlock Class

The KcsMemoryBlock class is a KcsIO base class derivative that allows you to read from and write to a block of memory.

KcsSolarisFile Class

The KcsSolarisFile class is a KcsIO base class derivative that supports searching for profiles located in known directories and accessing files located on remote machines. It also loads and saves profiles. This class contains a pointer to a KcsIO object of type KcsFile or KcsRemoteFile. This pointer is then used in all of the I/O methods for the class.

KcsSolarisFile cannot be used for embedding profiles and is dynamically loaded at runtime.

KcsXWindow Class

The KcsXWindow class is a KcsIO base class derivative that provides the interface between X11 Window System visuals and corresponding profile data. This class takes as arguments a pointer to a display structure, a pointer to a visual structure, and a screen number. It translates this information into either a local or remote display and creates a KcsFile or KcsRemoteFile pointer. The I/O pointer is then used in all of the derived I/O methods for the class.

KcsXWindow is dynamically loaded at runtime.

KcsChunkSet Class

The KcsChunkSet class provides an interface to access chunks (or blocks) of data in a static store (such as a file on disk).

Chunks are separated blocks of data that contain any type of data. The KcsChunkSet class does not know what the data is in the blocks. It provides functions to manipulate the blocks, such as arranging and resizing them.

A chunk set has two components: a chunk map and the chunks. As shown in Figure 1-3 , the chunk map is a table containing an array of descriptions of each chunk. Each chunk map entry contains the chunk Id (a unique identifier for that block), the offset, and the chunk size.

Figure 1-3 Chunk Set Layout

Graphic

The ICC profile format is directly analogous to the KcsChunkSet.

Some KcsChunkSet class features are:

The KcsChunkSet method can be used for various reasons. For example, you need the chunk Id(s) to access data directly. Use KcsChunkSet to read or write a particular chunk Id. You do not need the specific offsets within the static store, but you do need to know the chunk Id(s). You can also specify to write a chunk at a specific static store location. You may want to do this for format conventions that require specific data be stored at a specific location within the static store. In this case, KcsChunkSet moves other chunks to accommodate this request.

KcsProfile Class

The KcsProfile class is a base class that represents a color profile. It is a set of attributes that describe the profile and a set of transformations that allow it to perform the appropriate color changes.

The KcsProfile class is hierarchically derived from the KcsLoadable and KcsShareable classes. This means that profiles can be shared by other objects, and are loadable.

The hierarchy below the base KcsProfile class represents different types of profiles in terms of their techniques, rather than their type. For example, both of the different profile types--Effects Color Profile (ECP) and Device Color Profile (DCP)--can be represented by the same derivative. However, a KCMS profile that uses multi-channel linear interpolation must be a different derivative than an XYZ profile that uses XYZ-based transformations and techniques. Profile types can easily be differentiated by the combination and actual values of the attributes contained within the data. The KcsProfile class determines which transformation technologies a specific profile needs and instantiates the appropriate KcsXform derivatives. For a list of attributes and their possible values see the SDK manual KCMS Application Developer's Guide and the ICC specification located on-line in /opt/SUNWsdk/kcms/doc/icc.ps. For the most current version of the ICC specification, see the web site at http://www.color.org

The KcsProfile class provides data and necessary KcsXforms to describe, characterize, and calibrate a color-managed input and output device or any point-processible special effect, such as an image filter. It coordinates and determines the loading, saving, and execution of the transformation for all profile types.


Note -

You must derive from the KcsProfile class if you want your ICC profiles containing your CMM Id to be used as a loadable module instead of the default profile format.


See Chapter 5, KcsProfile Derivative " for detailed information.

KcsProfileFormat Class

The KcsProfileFormat class allows any of its derivatives to map a profile from a static store into the traditional pieces that make up a profile. All of these pieces are presented to its users as objects in the KCMS framework. Therefore, you can load, set, and get these profile-based objects without regard to the actual format of the data in the store.


Note -

You can define your own profile format with this class. If you are using ICC profiles, it is recommended that you use the KcsProfileFormatInterColor3_0 class, because it deals with ICC profiles.


See Chapter 6, KcsProfileFormat Derivative " for more information.

KcsAttributeSet Class


Note -

KcsAttributeSet is an alias to the KcsTags class as indicated in kcstags.h. This is for historical reasons only.


The KcsAttributeSet class provides a general-purpose interface for an attribute-value pair array. You can associate attributes with different structures.

This object is an associative array--a way of mapping unique identifiers to a variety of data structures. A KcsAttributeSet object stores and deletes attributes. Attributes are identifiers and associated data. For a complete discussion of attributes and their properties, see the SDK document KCMS Application Developer's Guide and the ICC Profile Format Specification.

The KcsAttributeSet class is a subclass of the KcsLoadable class.

The KcsAttributeSet class does not override any functionality provided by its parent, but it does provide additional functionality. All access to a KcsAttributeSet object is controlled through a set of public methods of the KcsAttributeSet class.

The KcsAttributeSet class contains a pointer to a ChunkSet object that stores the KcsAttributeSet data. The KcsAttributeSet object uses its ChunkSet, if one is supplied when a KcsAttributeSet object is created, to read and write data to whatever static store is being accessed by the supplied ChunkSet.

Using a KcsAttributeSet Object

A KcsAttributeSet object is created when you need to map identifiers to variable data structures such as ICC tags (that is, integers, floats, strings, and dates). There are two ways to create a non-empty KcsAttributeSet object. The method you choose depends on the origin of the data used to populate the KcsAttributeSet object. The origin can be a supplied chunk or character buffer.

If you do not want to create a KcsAttributeSet object with data from a chunk, you can create a KcsAttributeSet object using a character buffer (the KcsAttributeSet object contains a null chunk set). The only issue you must be aware of in this case is that, in order to save the KcsAttributeSet object, you need to have set the internal chunk set pointer of that KcsAttributeSet object to a valid chunk set and gotten a chunk Id from that chunk set. If the chunk has not been set, then attempting to save the KcsAttributeSet object results in a KCS_UNINITIALIZED_CHUNKSET error.

Using a KcsAttributeSet object, you can perform the following operations:

All three operations performed on the KcsAttributeSet data are accomplished by calling setAttribute()(), a public method of the KcsAttributeSet class. The operation performed is decided by the parameters supplied to the setAttribute()() method and the state of the KcsAttributeSet object when the method is called. Conceptually, only two parameters to the method are important: an identifier and a structure used to contain the variable data associated with that identifier.

To insert new data into a KcsAttributeSet object call setAttribute()() with an identifier not currently used and information stored within the KcsAttributeSet object. For example, assume the structure contains the character string "today is my birthday" as variable data and that the identifier equals 30. After successful completion of a call to setAttribute()(), an association between "today is my birthday" and 30 is stored within the object.

To remove data from a KcsAttributeSet object call setAttribute()() with the identifier of the data you want to delete and assign the information structure parameter to NULL.

To update data in a KcsAttributeSet object call setAttribute()() with an identifier currently used and new information stored within the information structure. For example, assume that the information structure contains the integer data "100 200 300" as variable data and that the identifier is set to 30. After successful completion of a call to setAttribute()(), the association of 30 with "today is my birthday" would be replaced with the association of 30 with "100 200 300" in the object.

Several methods give you information about the KcsAttributeSet data as a whole, as well as information about specific associations that make up the KcsAttributeSet data. The returnCurrentNumberOfAttributes()() method provides the number of associations currently stored within a KcsAttributeSet object. The getAttribute()() method provides information associated with a specific identifier. The getTag()() method returns the nth identifier stored within the data. The setChunkSet()() method allows the chunk pointer associated with an instance of a KcsAttributeSet object to be reassigned to a new or different chunk; this method is needed to save KcsAttributeSet data for a KcsAttributeSet object with which no chunk has been supplied. The getAttributeInfo()() method provides detailed information associated with an identifier such as the type of data (for example, string, integer, float) and the number of tokens found within the variable data.

KcsAttributeSet data is loaded into a KcsAttributeSet object when a non-empty KcsAttributeSet object is constructed. The save()() method is used to store the KcsAttributeSet data. As mentioned earlier, a KcsAttributeSet object must have a valid chunk in order for the KcsAttributeSet data to be saved.

See the KCMS CMM Reference Manual for detailed information on all of the KcsAttributeSet class member functions.

KcsXform Class

The KcsXform class represents a set of classes that perform n->m component transformations. These transformations do not need to conform to any single type of transformation. The implementation of a KcsXform derivative is irrelevant as long as the derivative transforms in compliance with the base class interface. Some of the most helpful methods are:

All transformations have a number of properties and methods. When using a transform derivative, you can: construct it, load it, save it, associate and inquire storage information, set and retrieve attributes and information about the transform, compose another transformation from it, and most importantly evaluate or transform data.


Note -

You must derive from the KcsXform class to augment color data processing on the KCMS framework.


See Chapter 7, KcsXform Derivative " for more information.

KcsXformSeq Class

The KcsXformSeq class is a KcsXform base class that allows other incompatible KcsXform derivatives to connect for serial evaluations. It has methods to append()() and insert()() transformations into an existing sequence and constructors that can instantiate from an array of KcsXform pointers. The derivation from the KcsXform base class allows a sequence of KcsXforms to act like a single KcsXform from the perspective of the rest of the architecture.

KcsStatus Class

The KcsStatus class provides communication of status codes, errors, and customizable textual descriptions of the state. You can dynamically add your own error messages with internationalized text strings associated with them.

You can extend methods in this class to add your own error messages. See Chapter 8, KcsStatus Extension ," for information on how to add your own error messages.

KcsSwapObj Class

The KcsSwapObj class provides an interface to swap data between BIG_ENDIAN and LITTLE_ENDIAN hardware architectures. Use this interface for cross-platform compatibility.