The alternate CMM API
Created Date: 16 Mar, 2022 14:17
Last Modifed Date: 16 Mar, 2022 14:17
This page applies to Harlequin v13.1r0 and later; both Harlequin Core and Harlequin MultiRIP
Alternate CMMs are discovered by the Skin and registered with the RIP at start-up.
As part of the registration process, a structure defining the instance of CMM will be passed from the skin to the RIP. This structure contains pointers to the functions implementing the CMM via a CMM interface that is common to all alternate CMMs. (For more details on the discovery/registration see Registering an alternate CMM with the Harlequin RIP The OEM is required to write “glue” code that implements the interface and marshals data as appropriate to the alternate CMM.
structure describes a CMM implementation (a class). Before use, an instance of that class must be created.
() and finish() methods in
are used to prepare the implementation. These calls will surround all other calls to the API. The
() call passes parameters (such as a memory allocation API pointer) that are common to all instances of the CMM API.
The construct() and destruct() methods in
are used to construct and destroy an instance of the CMM API. Normally, there will only be one instance of the CMM API constructed.
The structure defining the CMM contains a name to be used for internal purposes. This name is passed to a PostScript language pagedevice key from a configuration file which tells the RIP which instance of CMM to use for the coming page.
The following example PostScript language fragment achieves this:
<< /AlternateCMM (CMMname) >> setpagedevice
was passed in the name field of
The default value of /AlternateCMM is null, which means the built-in CMM will be used.
NOTE: The setpagedevice key obeys PostScript language gsave/grestore semantics as defined in the PostScript language reference manual. This means that the current alternate CMM remains in force until an older pagedevice is restored, or until a future setpagedevice call specifies a different alternate CMM. The alternate CMM has been placed in the pagedevice because it ensures that no more than one alternate CMM is active on any given page. (Swapping alternate CMMs in the middle of a page would cause unnecessary confusion because, when compositing, some device pixels might be affected by objects color managed with different CMMs.)
When the RIP processes an ICC transform and discovers that it should be handled by an alternate CMM, the RIP will make calls into the CMM Interface to satisfy the required color conversions. The calls will follow this pattern.
for (all profiles in the transform) open_profile() open_transform() for (all color conversions) invoke_transform() close_transform() for (all profiles in the transform) close_profile ()
The precise timing of these calls are subject to some variation as a result of caching strategies that are employed by the RIP in any given environment.
For performance reasons, the default behavior of most CMMs is to create what is effectively a devicelink profile from a color transform of more than one ICC profile. The exact conversions from each component of the color transform is only used to populate the grid points in the devicelink. Given the architecture of the Harlequin RIP, where there are color conversion steps outside of ICC color management, the RIP will create its own devicelink around all color conversion steps. The RIP must therefore attempt to disable this feature of alternate CMM to avoid unnecessary resource utilization.
It is possible that a job will require many ICC transforms due to the combination of multiple rendering intents, Input profiles and Output profiles required by the job. The RIP may have many of these transforms open and active at any one time. It is the responsibility of the OEM glue code to manage multiple transforms if the alternate CMM itself does not do so.
The RIP may have multiple threads actively converting colors using the same or different transforms. It is the responsibility of the OEM glue code to synchronize threads if the alternate CMM does not itself support multi-threading.
For custom colorspace transforms,
() is used instead of
(). There is no
() will be used for both profile types. For example:
for (all profiles in the transform) open_custom_colorspace() open_transform() for (all color conversions) invoke_transform() close_transform() for (all profiles in the transform) close_profile ()