Harlequin RIP SDK
Color management module interface - custom color space (CCS-CMM)

The alternate color management module (CCS-CMM) API allows customer-supplied code to implement custom color spaces. More...

Files

file  swccs.h
 Header file defining the Color management module interface - custom color space (CCS-CMM).
 

Data Structures

struct  sw_ccs_custom_colorspace
 A structure containing information about a custom color space. More...
 
struct  sw_ccs_instance
 An instance structure for the CCS API implementation. More...
 
struct  sw_ccs_init_params
 Collection structure for initialization parameters. More...
 
struct  sw_ccs_api
 The definition of an implementation of the custom color space interface. More...
 

Typedefs

typedef HqnResult sw_ccs_result
 Type of return values from sw_ccs_api functions. More...
 
typedef struct sw_ccs_custom_colorspace sw_ccs_custom_colorspace
 A structure containing information about a custom color space.
 
typedef void * sw_ccs_transform
 An opaque structure defined by the custom color space implementation to represent transforms.
 
typedef struct sw_ccs_api sw_ccs_api
 Type definition of the custom color space interface implementation.
 
typedef struct sw_ccs_instance sw_ccs_instance
 An instance structure for the CCS API implementation. More...
 
typedef struct sw_ccs_init_params sw_ccs_init_params
 Collection structure for initialization parameters.
 

Enumerations

enum  { SW_CCS_API_VERSION_20251001 = 10 }
 Version numbers defined for the CCS API. More...
 
enum  SW_CCS_RESULT {
  SW_CCS_SUCCESS = HQN_RESULT_SUCCESS , SW_CCS_ERROR = 1 , SW_CCS_ERROR_IOERROR , SW_CCS_ERROR_MEMORY ,
  SW_CCS_ERROR_INVALID , SW_CCS_ERROR_UNSUPPORTED , SW_CCS_ERROR_VERSION
}
 Return values for sw_ccs_api functions. More...
 

Functions

HqnResult swccs_result_translate (sw_ccs_result result)
 Translate a CCS API-specific error code to a generic HqnResult error code. More...
 
sw_api_result SwRegisterCCS (sw_ccs_api *implementation)
 This routine makes a custom color space implementation known to the rip. More...
 

Detailed Description

The alternate color management module (CCS-CMM) API allows customer-supplied code to implement custom color spaces.

When converting a color to the output device, the RIP will create a color pipeline according to the configuration. This pipeline will consist of one or multiple transforms. If an individual transform consists of a single custom colorspace, it is a candidate for being handled by the Custom color space CMM.

Each transform in the color pipeline is treated independently for the purpose of its compatibility with the Custom colorspace CMM.

The alternate color management module interface

The sw_ccs_api structure type describes a CCS-CMM abstraction (a class). The skin registers a concrete implementation of this structure for each selectable CCS-CMM. The RIP will create an instance structure (a sw_ccs_instance) to represent the configured and selected CCS-CMM in use.

Calls to the CCS-CMM interface follow these stages:

Module registration

Each CCS-CMM module is identified by an internal name, for use in configuring the RIP, and an additional UTF-8 name for display purposes.

CCS-CMM modules may be registered at any time after the RIP is started by calling SwRegisterCCS() using an instance of the sw_ccs_api structure. This function performs some validation checks on the API structure, and then registers it in RDR as a named RDR, in the RDR_NAMES_CMMAPI namespace, using the internal name provided in the structure. This internal name is also used to select the CCS-CMM module. You may register CCS-CMM modules in RDR directly before the RIP is started, but doing so will not perform the validation checks that SwRegisterCCS() performs. If you miss out a required callback function pointer, selecting your CCS-CMM may crash the RIP. You may also de-register CCS-CMM modules from RDR by calling SwDeregisterNamedRDR(), if you have access to the pointer and length that the module was registered with.

Module initialization

Before any other calls are made to the CCS-CMM module, the RIP will call the optional sw_ccs_api::init() to initialize data. It is called at most once per module. This call is provided with a parameters structure that contains a pointer to a memory callback API instance. The CCS-CMM module should save the memory callback API instance pointer and use it to allocate any data it needs. It is called lazily before the first call to sw_ccs_api::construct() for the module.

Module configuration

A registered CCS-CMM module is activated by calling the PostScript configuration operator setcustomcolorspacecmm from a configuration file, using the internal name defined in the sw_ccs_api::info.name field:

(ccs-cmm-name) setcustomcolorspacecmm

The RIP then calls sw_ccs_api::construct() to construct a CCS-CMM module instance (sw_ccs_instance). Normally, only one module has an instance constructed at any one time.

If the sw_ccs_api::declare_custom_colorspace() method pointer is non-NULL, the RIP will repeatedly call it to enumerate and validate the custom colorspaces supported by the module.

Colorspace selection

When a colorspace is selected, the RIP will create a color pipeline consisting of one or multiple transforms that convert the colorspace to the output colorspace according to the configuration.

For each transform consisting of a custom colorspace that is compatible with the CCS-CMM, a transform handle will be created for it.

Custom colorspace selection

CMM custom colorspaces are only used within the color configuration operators, setinterceptcolorspace and setreproduction. When one is used, the RIP will find the matching colorspace by iteratively calling sw_ccs_api::declare_custom_colorspace(). The selected custom colorspace will be used later when constructing the transform.

Transform construction

The selected custom colorspace is used to create a transform when the RIP calls sw_ccs_api::open_transform().

Transforms opened using sw_ccs_api::open_transform() will be later closed by calling sw_ccs_api::close_transform().

Transform invocation

When required, the RIP will invoke the transform to convert color values by calling sw_ccs_api::invoke_transform().

The RIP may have multiple threads actively converting colors using the same or different transforms. The RIP will optionally serialise calls to guarantee thread-safety with the loss of some performance. The CCS-CMM may choose to perform its own synchronization of threads as necessary.

Colorspace deselection

When the graphics state containing a colorspace goes out of scope, the transforms associated with them will be closed when the RIP calls sw_ccs_api::close_transform().

Instance destruction

When the graphics state containing a CCS-CMM configuration goes out of scope, normally when the job has completed, the RIP calls sw_ccs_api::destruct() to destroy the API instance created by sw_ccs_api::construct().

Module finalization

When the RIP shuts down, and after all other calls are made to the CCS-CMM module, the optional sw_ccs_api::finish() is called to allow it to finalize data. The module should free any data it allocated.

Color caching

The RIP makes extensive use of color caching for performance reasons. As a result:

Transform pseudocode for a CCS-CMM custom colorspace

This pseudocode describes the pattern of calls to the CCS-CMM API when a custom colorspace transform is created. The precise timing of these calls may vary widely due to caching strategies employed by the RIP. It is only the order of calls for any one transform that is fixed.

// Find the desired custom color space.
for (each custom color space until its name matches the request)
css = declare_custom_colorspace()
open_transform()
for (all uncached color conversions)
invoke_transform()
close_transform()
close_profile()

Typedef Documentation

◆ sw_ccs_instance

An instance structure for the CCS API implementation.

This is the definition of a custom color space instance. The RIP allocates memory for the instances, fills in the implementation and memory instance fields, and calls the implementation's constructor to complete the remaining details. The RIP will construct one instance as a result of using either the setcustomcolorspace operator. These are commonly used in the RIP's configuration.

There will normally be at most one CCS instance active on each page. There may be more than one CCS instance active at a time if Harlequin Parallel Pages is in use. While discouraged, it is possible to call setcustomcolorspacecmm multiple times on the same page; this may result in several CCS instances active on the same page which will have unpredictable results depending on the job structure.

The instance structure may be subclassed to hold private data by defining a subclass structure containing this structure as its first member, and using the size of that structure as the implementation's instance size. Individual methods may then downcast their instance pointer parameters to subclass pointers, and use the private data. e.g.,

typedef struct my_instance {
sw_ccs_instance super ; // must be first entry
struct my_data *dynamic ;
int32 other_fields ;
} my_instance ;
static sw_ccs_result RIPCALL my_construct(sw_ccs_instance *inst)
{
my_instance *myinst = (my_instance *)inst ; // downcast to subclass
// allocate private data:
myinst->dynamic = cmmegMemAlloc(inst, sizeof(myinst->dynamic)) ;
return myinst->dynamic != NULL ? SW_CCS_SUCCESS : SW_CCS_ERROR_MEMORY ;
}
static void RIPCALL my_destruct(sw_ccs_instance *inst)
{
my_instance *myinst = (my_instance *)inst ; // downcast to subclass
// free allocated data, if necessary:
cmmegMemFree(inst, myinst->dynamic) ;
}
const static sw_ccs_api my_impl = {
{
(const uint8 *)"myname",
(const uint8 *)("A long description of my module implementation"
"Copyright (C) 2021 Global Graphics Software Ltd."),
sizeof(my_instance), // RIP will allocate this amount for the subclassed instance
},
// ...more of sw_ccs_api definition...
my_construct,
my_destruct,
// ...rest of sw_ccs_api definition...
} ;
// use the PostScript fragment:
// (myname) setcustomcolorspace
// in the config to create the CCS instance and call my_construct().
void cmmegMemFree(sw_memory_instance *instance, void *p)
Release CMM memory.
Definition: cmm_common.c:40
void * cmmegMemAlloc(sw_memory_instance *instance, size_t n)
Allocate CMM memory.
Definition: cmm_common.c:28
uint8_t uint8
8-bit unsigned integer
Definition: hqtypes.h:88
int32_t int32
32-bit signed integer
Definition: hqtypes.h:91
HqnResult sw_ccs_result
Type of return values from sw_ccs_api functions.
Definition: swccs.h:253
@ SW_CCS_ERROR_MEMORY
Unused, for compatibility with SW_CMM_RESULT.
Definition: swccs.h:236
@ SW_CCS_SUCCESS
Success return value for sw_ccs_api methods.
Definition: swccs.h:229
@ SW_CCS_API_VERSION_20251001
Current version. Must be > SW_CMM_API_VERSION_20200117.
Definition: swccs.h:221
#define NULL
Definition of NULL pointer.
Definition: hqtypes.h:37
#define RIPCALL
The normal calling convention for RIP-exported APIs.
Definition: ripcall.h:27
The definition of an implementation of the custom color space interface.
Definition: swccs.h:433
An instance structure for the CCS API implementation.
Definition: swccs.h:369

The RIP will not touch memory beyond the size of the instance structure for the implementation version registered.

◆ sw_ccs_result

Type of return values from sw_ccs_api functions.

This is a subclass of HqnResult that also supports some specific extra error codes generated by sw_ccs_api functions (declared as the SW_CCS_RESULT enumeration). Before assigning to values of HqnResult type or any of its other subclasses, sw_ccs_result values must be converted to change the API specific values to HQN_RESULT_SUCCESS or a monitor UID error code greater than MON_CLASS_ERROR. This can be done by calling the function swccs_result_translate().

Enumeration Type Documentation

◆ anonymous enum

anonymous enum

Version numbers defined for the CCS API.

Enumerator
SW_CCS_API_VERSION_20251001 

Current version. Must be > SW_CMM_API_VERSION_20200117.

◆ SW_CCS_RESULT

Return values for sw_ccs_api functions.

Enumerator
SW_CCS_SUCCESS 

Success return value for sw_ccs_api methods.

SW_CCS_ERROR 

Non-specific error, also minimum error value. Please avoid using this if possible.

SW_CCS_ERROR_MEMORY 

Unused, for compatibility with SW_CMM_RESULT.

SW_CCS_ERROR_INVALID 

Memory allocation failed.

SW_CCS_ERROR_UNSUPPORTED 

Invalid custom color space or transform.

SW_CCS_ERROR_VERSION 

Unsupported configuration.

Function Documentation

◆ swccs_result_translate()

HqnResult swccs_result_translate ( sw_ccs_result  result)

Translate a CCS API-specific error code to a generic HqnResult error code.

Parameters
[in]resultOne of the SW_CCS_RESULT values, or an error value greater than MON_CLASS_ERROR.
Returns
Either HQN_RESULT_SUCCESS, or an error value greater than MON_CLASS_ERROR.

◆ SwRegisterCCS()

sw_api_result SwRegisterCCS ( sw_ccs_api implementation)

This routine makes a custom color space implementation known to the rip.

It can be called any number of times with different implementations of the CustomColorSpace API. Within SwRegisterCCS(), sw_ccs_api::init() will be called for the implementation. After that, it will remain dormant until the sw_ccs_api::construct() is called as part of using the setcustomcolorspace operator. Both the sw_ccs_api::init() and sw_ccs_api::finish() callbacks are set to NULL in many implementations because the custom color space has nothing to do at this point.

This function may be called at any time after the RIP is initialized, and before the RIP is shut down.

Parameters
[in]implementationThe API implementation to register. This pointer will be returned through the sw_ccs_api::init() and sw_ccs_api::finish() calls, and also will be in the implementation member field of every instance created, so the pointer can be in dynamically allocated memory.
Returns
SW_API_REGISTERED if the invocation succeeded, one of the SWAPI_RESULT error codes otherwise.

Implementations may be subclassed to hold class-specific private data by defining a subclass structure containing the sw_ccs_api structure as its first member. Individual methods may then downcast their implementation pointers to subclass pointers, and use those to get at the class data. e.g.,

static HqBool RIPCALL my_init(sw_ccs_api *impl, const sw_ccs_init_params *params)
{
// as an example of what might be done in the init() callback -
// inform an external module that it should now get ready for work
return TRUE ;
}
static void RIPCALL my_finish(sw_ccs_api *impl)
{
// as an example of what might be done in the finish() callback -
// inform an external module that it is no longer needed
}
const static sw_ccs_api my_impl = {
{
(const uint8 *)"myname",
(const uint8 *)("A long description of my module implementation"
"Copyright (C) 2021 Global Graphics Software Ltd."),
sizeof(sw_ccs_instance), // RIP will allocate the size of the standard instance
},
my_init,
my_finish,
// ...rest of sw_ccs_api definition...
} ;
// Call SwRegisterCCS(&my_impl) after SwInit() to register the 'my_impl' CCS module.
int HqBool
Harlequin standard boolean type.
Definition: hqtypes.h:503
#define TRUE
HqBool boolean true value.
Definition: hqtypes.h:509
Collection structure for initialization parameters.
Definition: swccs.h:412