A transform converts pixel data from an input color space to an output color space; it is the central processing step in a color management application. You build a transformation algorithm by specifying a sequence of one or more primitive color manipulations, described by profiles, and a CMM. You then apply the transform to pixel data.
For example, a common two-profile transform converts from an input color space to an output color space; typically the input profile is a monitor profile and the output is a printer profile. A useful three-profile transform simulates on one device the output of another device. The sequence of profiles is first the input, second the simulated device, and third the simulating device: for example, first a scanner, second a printer, and third a monitor.
These are sections of this chapter:
This section introduces the features of the Coloratura transform tools.
The color manipulation module that the Coloratura CMS uses determines the details of the transformation algorithm. Different CMMs can give different results from the same input image and set of profiles, depending on how the CMMs interpret the discrete, and perhaps sparse, data in each profile. When you create a transform, you can select a CMM explicitly, or you can use the default CMM that is included in the Coloratura CMS or, if you have other CMMs, you can have the Coloratura CMS let the profiles determine which CMM to use.
You can save a transform, which is convenient if you have a sequence of profiles that you use repeatedly. For example, if you commonly transform data from your monitor to output on a specific printer, you can build a device-link profile, which does not represent a particular device, but provides a one-profile characterization of the transformation between devices.
As discussed earlier, the set of possible colors for a device is called its color gamut. A central concern for color management is a mismatch between the gamuts of an input and output device. The severity of this mismatch and the distribution of mismatches over an image affect the appearance of your output. A fairly common gamut mismatch is that between a monitor and a printer; any monitor typically has a gamut larger than most printers.
Output devices necessarily have rules to handle out-of-gamut data. If you do not like the results, you can modify the source image data or, conceivably, develop an abstract profile to perform a gamut mapping to adjust out-of-gamut image data. How you accommodate out-of-gamut image data is a substantial component of an acceptable color conversion, and much of the art of the process.
Before applying a transform, you may want to know how much of the transformed image is out of gamut, rather than observe the effects on the output image. The Coloratura CMS provides gamut-checking tools to give you that information.
To create a transform with the Coloratura CMS, you supply a list of profiles and a CMM specifier to the function cmsCreateTfm(). You then call cmsApplyTfm() to apply the transform to a pixel buffer.
During the process of developing a transform, you probably need to delete a current version. You delete a transform by calling cmsDeleteTfm(). To save a transform, use cmsTFMToLUT(). The applications mkdevlink and applydevlink in /usr/cms/examples/ illustrate how to use the output of cmsTFMToLUT().
The pointer CMSTfm refers to an opaque structure that stores transform data. This is the data type declaration:
typedef struct _CMSTfm *CMSTfm; |
Transforms operate on CMSPixelBuffer data structures, which hold color image data. The two Coloratura functions that accept a CMSPixelBuffer argument are cmsCheckGamut() and cmsApplyTfm().
The Coloratura CMS makes the following assumptions about the storage of image data included in a CMSPixelBuffer:
All the channels for a single pixel are stored together.
Each channel aligns to byte boundaries. Any padding is in the most significant bits.
The data is encoded according to one of the valid color ICC encodings.
If a pixel holds non-color information, such as the OpenGL opacity parameter alpha, then the number of bytes per pixel will be greater than the number of bytes in the image channel data. When implementing transforms, the Coloratura CMS preserves without modification the additional information.
The Coloratura CMS does not store color encoding formats. For the Coloratura CMS to manipulate data with a particular encoding, there must be at least one profile in storage that has that encoding. For example, if no profile has the HSV encoding, the Coloratura CMS cannot process an image in HSV format.
This is the data type declaration for CMSPixelBuffer:
typedef struct _CMSPixelBuffer { uint32 width; uint32 height; uint32 bitsPerChannel; uint32 bytesPerPixel; uint32 channels; uint32 encode; unsigned void *data; } CMSPixelBuffer; |
These are the fields in the declaration for CMSPixelBuffer:
width | The width of the image in pixels. | |
height | The height of the image in pixels. | |
bitsPerChannel | The number of bits may range from 1 to 12. | |
bytesPerPixel | The number of bytes must align on 32-bit boundaries. | |
channels | The number of color channels. Possible values are: 1, 3, 4, 5, or 6. | |
encode | These are the possible color space signatures. They correspond to a the values of the enumerated type icColorSpaceSignature, which is defined in the header file ic.h. | |
data | A pointer to the image data. |
The function cmsCreateTfm() translates a set of profiles into a transformation algorithm. The algorithm is defined by a CMM and a sequence of profiles. The transformation is built from profiles in the sequence in which they are supplied: the first profile defines the first step in the transformation, typically from your input device, and the last profile defines the final step, typically to your output device.
This is the prototype for cmsCreateTfm():
int32 cmsCreateTfm(CMSContext ctxt, int32 profileCount, CMSProfile *profs, icSignature cmm, CMSTfm *ptfm); |
These are the arguments of cmsCreateTfm():
These are the error codes returned by cmsCreateTfm():
CMS_OUT_OF_MEMORY |
| |
CMS_WRONG_DATA |
| |
CMS_BAD_INPLACE_CONVERT |
| |
CMS_BAD_ENCODE |
| |
CMS_BAD_CONTEXT |
CMS_TOO_MANY_CHANNELS |
| |
CMS_CMM_NOT_AVAILABLE |
|
Once you have created a transform, call cmsApplyTfm() to apply the transform to pixel data. This function transforms a pixel buffer with one profile to a buffer associated with another profile.
Note that you may not always be able to perform in-place conversions; for example, if the output format requires more space than the input format (RGB to CMYK), or if the CMM does not support in-place conversions. cmsApplyTfm() returns an error if you attempt an in-place conversion for one of these cases.
If you are concerned about maintaining interactivity, you may want to transform an image piece-by-piece, to avoid the possibly slow process of transforming a whole image.
This is the prototype for cmsApplyTfm():
int32 cmsApplyTfm(CMSContext ctxt, CMSTfm tfm, CMSPixelBuffer *psrc, CMSPixelBuffer *pdest); |
These are the arguments of cmsApplyTfm():
ctxt | The context initialized by cmsOpen(). | |
tfm | The transform to use. | |
psrc | The pixel buffer to be transformed. | |
pdest | The resulting output pixel buffer. |
These are the error codes returned by cmsApplyTfm():
CMS_WRONG_DATA |
| |
CMS_BAD_TFM |
| |
CMS_BAD_PIXEL_BUF |
| |
CMS_CONVERT_ERROR |
|
The function cmsTfmToLUT() allows you to save transform information in a tag format, the AToB0Tag described in the ICC Profile Format Specification. To recover the transform from the tag data produced by cmsTfmToLUT(), do the following:
Create a profile by calling cmsCreateProfile(), which is discussed in "Creating New Profiles, Getting and Setting Headers, and Saving Edits". You can specify any rendering intent for the profile when you create the profile header.
Set the tag value by calling cmsSetTag(), which is discussed in "Setting Tag Data: cmsSetTag()". You can save the profile for later use by calling cmsSaveProfileAs(), which is discussed in "Saving to a New File on Disk: cmsSaveProfileAs()".
Create a transform from the profile, by calling cmsCreateTfm().
The application mkdevlink in /usr/cms/examples illustrates the first two steps. The application applydevlink in the same directory illustrates the last step, and applies the transform to input data.
This is the prototype for cmsTfmToLUT():
int32 cmsTfmToLUT(CMSContext ctxt, CMSTfm tfm, uint32 *psize, void **pdata); |
These are the arguments of cmsTfmToLUT():
tfm | The transform to save. | |
psize | The size of the tag data. | |
pdata | The tag data. |
This is the error code returned by cmsTfmToLUT():
CMS_NOT_SUPPORTED |
|
You can perform a test for which output pixels have data that lies out of gamut, rather than apply a transformation and observe the effects of out-of-gamut image data. This helps you quantify the severity of your gamut mapping problem and to see clearly how out-of-gamut data affect your image. It may help you to develop a gamut mapping strategy.
To examine the gamut mismatch, you create a gamut check with cmsCreateGamutCheck(), which takes the same arguments as cmsCreateTfm(). You then perform the check with cmsCheckGamut(). This function examines the pixel data stored in a CMSPixelBuffer data structure, and returns an unsigned char array to indicate how each pixel is mapped; zero values indicates the image pixel is in gamut, non-zero indicates out of gamut.
The function cmsCreateGamutCheck() takes the same set of arguments as cmsCreateTfm(); it uses a CMM and a set of profiles to create a gamut checking transform. The gamut check is built from the profiles in the sequence in which they are supplied: the first profile defines the first step in the transformation, typically from your input device, and the last profile defines the final step, typically to your output device.
This is the prototype for cmsCreateGamutCheck():
int32 cmsCreateGamutCheck(CMSContext ctxt, int32 profileCount, CMSProfile *profs, icSignature cmm, CMSTfm *ptfm); |
These are the arguments of cmsCreateGamutCheck():
ctxt | The context initialized by cmsOpen(). | |
profileCount | The number of profiles in a transform. | |
profs | An array of profiles for the transform. | |
cmm | The CMM to use. If you do not directly specify the CMM with a valid icSignature, use one of the following two constants to direct CMM selection: CMS_USE_DEFAULT_CMM selects the default CMM. CMS_USE_PROFILE_CMM prompts the Coloratura CMS to search the CMMs specified by the profiles in the transform until it finds one that can perform the transformation. See the next section "Creating a Transform: cmsCreateTfm()" for more details | |
ptfm | The gamut-checking transform. |
These are the error codes returned by cmsCreateGamutCheck():
CMS_OUT_OF_MEMORY |
| |
CMS_WRONG_DATA |
| |
CMS_BAD_ENCODE |
CMS_BAD_CONTEXT |
CMS_TOO_MANY_CHANNELS |
| |
CMS_CMM_NOT_AVAILABLE |
|
Given a transform and set of pixels, the function cmsCheckGamut() tests whether the transform maps the pixels within the gamut of the output device. The order of the output bytes follows the order of the input pixels. A value of zero indicates that an output pixel is in gamut; a non-zero value indicates that the pixel is out of gamut.
If you are concerned about maintaining interactivity, you may want to check the gamut mapping of an image piece-by-piece, to avoid the possibly slow process of checking the whole image. The cmsCheckGamut() function runs at a rate comparable to that of the transform whose effect it reports.
This is the prototype for cmsCheckGamut():
int32 cmsCheckGamut(CMSContext ctxt, CMSTfm tfm, CMSPixelBuffer *psrc, unsigned char pgamutmap); |
These are the arguments of cmsCheckGamut():
ctxt | The context initialized by cmsOpen(). | |
tfm | The transform to check. | |
psrc | The input pixel buffer. | |
pgamutmap | The resulting gamut-map buffer. |
These are the error codes returned by cmsCheckGamut():
CMS_OUT_OF_MEMORY |
| |
CMS_BAD_PIXEL_BUF |
| |
CMS_BAD_GAMUT_MAP |
| |
CMS_BAD_TFM |
| |
CMS_CONVERT_ERROR |
|