LittleCMS2.16 Plugin API
LittleCMS2.16 Plugin API
16
https://www.littlecms.com
Contents
Introduction ........................................................................................................................ 4
Using plug-ins from the core engine................................................................................... 5
Plug-in packages ............................................................................................................ 7
Example: ........................................................................................................................ 8
Multiple plug-ins with same entry point ........................................................................... 9
Placing plug-ins in a separate DLL (Windows® only) ...................................................... 9
Requirements .................................................................................................................. 10
Plugin structure ................................................................................................................ 10
Memory management plugin............................................................................................ 12
Interpolation plug-in ......................................................................................................... 15
16 bits interpolation. ..................................................................................................... 17
Floating point interpolation. .......................................................................................... 17
Interpolation parameters .............................................................................................. 18
Parametric curves plug-in ................................................................................................ 20
Formatters Plug-in ........................................................................................................... 23
Tag plug-in....................................................................................................................... 26
Tag type handler plug-in .................................................................................................. 28
Intent plug-in .................................................................................................................... 31
Support functions for intent plug-ins ............................................................................. 32
Stages ............................................................................................................................. 34
Creating new stage types ............................................................................................. 34
Stages plug-in. ............................................................................................................. 36
Optimization plug-in. ........................................................................................................ 38
Full transform plug-in [2.04], [2.08]................................................................................... 42
Mutex plug-in [2.06] ......................................................................................................... 46
Parallelization plug-in [2.14] ............................................................................................. 48
Support functions ............................................................................................................. 49
Plug-in support API .......................................................................................................... 51
I/O handlers.................................................................................................................. 51
Read/Write functions .................................................................................................... 52
Type base helper functions. ......................................................................................... 53
Introduction 3
Introduction
In computing, a plug-in consists of a computer program that interacts with a host to provide
a certain, usually very specific, function "on demand". One of the main improvements in
Little CMS 2.x is the ability to use such plug-in architecture. By using plug-ins you can use
the normal API to access customized functionality. Licensing is another compelling reason;
you can move all your intellectual property into plug-ins and be able to upgrade the core
Little CMS library, keeping it in the open source side.
• Memory management
• Interpolation
• Tone curve types
• Formatters
• Tag types
• Tags
• Rendering intents
• Multi processing elements
• Optimizations
• Full transform replacement
• Mutex
This manual details how to write any of those 11 types of plug-ins. It does not discuss how
to use them, as plug-ins are basically extensions of the base system and as such, works in
the same way.
2.6
Creates a new context with optional associated plug-ins. Caller may specify an optional
pointer to user-defined data that will be forwarded to plug-ins and logger.
Parameters:
Plugin: Pointer to plug-in collection. Set to NULL for no plug-ins.
UserData: optional pointer to user-defined data that will be forwarded to plug-ins
and logger. Set to NULL for none.
Returns:
A valid cmsContext on success, or NULL on error.
Note: All memory used by this context is allocated by using the memory plugin, if present,
This includes the block for the context itself.
2.6
The user can install additional plug-ins to a yet existing context by using this function.
2.0
This one installs plug-ins in the default context. Only useful when using Little CMS as a
static library. This function is deprecated, and the recommended way is by using contexts.
Using plug-ins from the core engine 6
2.0
void cmsUnregisterPlugins(void);
This function returns Little CMS default context to its pristine default state, as no plug-ins
were declared. There is no way to unregister a single plug-in, as a single call to
cmsPlugin() function may register many different plug-ins simultaneously, so there is no
way to identify which plug-in to unregister.
2.6
Plug-in packages
Despite it is declared as a void pointer, cmsPlugIn needs some structured data to deal
with. Let’s take a look on the internals of the structure accepted by cmsPlugin()
cmsUInt32Number Magic;
cmsUInt32Number ExpectedVersion;
cmsUInt32Number Type;
struct _cmsPluginBaseStruct* Next;
} cmsPluginBase;
Your package has to export a pointer to such structure. On depending on the plug-in type,
there may be some extra fields after this base.
typedef struct {
cmsPluginBase base;
cmsTagSignature Signature;
cmsTagDescriptor Descriptor;
} cmsPluginTag;
As you can see, the cmsPluginBase struct always begin the definition block.
Using plug-ins from the core engine 8
Example:
Imagine you are a printer vendor and want to include in your profiles a private tag for
storing the ink consumption. So, you register a private tag with the ICC, and you get the
private signature "inkc". Ok, now you want to store this tag as a Lut16Type, so it will be
driven by PCS and will return one channel giving the relative ink consumption by color.
Writing a plug-in in Little CMS 2 will allow cmsReadTag and cmsWriteTag to deal with
you new data exactly as any other standard tag.
To do so, you have to fill a cmsPluginTag structure to declare the plug-in. This structure
includes the base, which is common to all plug-ins:
cmsPluginTag plugin;
plugin.base.Magic = cmsPluginMagicNumber;
plugin.base.ExpectedVersion = 2000;
plugin.base.Type = cmsPluginTagSig;
plugin.base.Next = NULL;
That latter identifies your plug-in as "tag type". Now you have to set the additional fields
that only apply to “tag definition” plug-ins. This can be done with following code:
plugin.Signature = inkc_constant;
plugin.Descriptor.ElemCount = 1;
plugin.Descriptor.nSupportedTypes = 1;
plugin.Descriptor.SupportedTypes[0] = cmsSigLut16Type;
This adds some additional info about the type used by your tag:
• How many elements of that type the tag is going to hold (usually one)
• In how many different types the tag may come (again, usually one)
• And then the needed type(s).
That is all. You can “plug” the new functionality to Little CMS by calling:
cmsPlugin(&plugin);
And that is. Now lcms2 understand about “inkc” tags and can read and write them.
Using plug-ins from the core engine 9
As a plug-in writer, you may want to encapsulate several plug-in in the same package.
This is easy with the way Little CMS deals with plug-ins. In the “Next” field of base plug-in,
you can place a pointer to the next plug-in you want to register:
cmsPluginTag plugin;
plugin.base.Magic = cmsPluginMagicNumber;
plugin.base.ExpectedVersion = 2000;
plugin.base.Type = cmsPluginTagSig;
plugin.base.Next = (cmsPluginBase*) &secondPlugin;
In this way, your package may have unlimited plug-ins, and all will be registered with a
single call to cmsPlugin. Last plug-in in the chain must have a NULL in the “Next” field.
The plug-in API is exported by the main lcms2.dll using PASCAL convention. This is the
normal way DLL does work. That means, you can place your plug-in packages in a
separate DLL and therefore you can keep the standard, non-customized Little CMS DLL
safe for future upgrades. Of course you can also put the plug-ins in a single DLL, but
keeping both systems isolated can be handy. In this way lcms2.dll can be upgraded to a
new revision and your plug-in DLL, if properly written, will keep working. All the details are
handled by the header files. All what you have to do is to compile your plug-in DLL using
the CMS_DLL toggle, as plug-in package is basically a client of the core engine. When
placing plug-ins in a separate DLL, make sure to handle memory with the provided Plug-in
memory management API. Failure to do so may yield unexpected results.
Requirements 10
Requirements
Little CMS requires C99 to compile, and to write plug-ins your compiler should support
following include files (they are very common)
#include <stdlib.h>
#include <math.h>
#include <stdarg.h>
#include <memory.h>
#include <string.h>
You have not to include any of those files, just the file lcms2_plugin.h, which will take care
of including all necessary requirements.
#include “lcms2_plugin.h”
Plugin structure
Any plug-in should be declared with at least these common fields. On depending on the
type, additional fields would be required.
cmsUInt32Number Magic;
cmsUInt32Number ExpectedVersion;
cmsUInt32Number Type;
struct _cmsPluginBaseStruct* Next;
} cmsPluginBase;
Magic:
Identifies the structure as a Little CMS 2 plug-in. It must contain following value:
ExpectedVersion:
The expected Little CMS version; 2040 in current release. Little CMS core will
accept plug-ins with expected version less or equal that the core version. If a plug-
in is marked for a version greater that the core, plug-in will be rejected. That means
downgrading core engine may disable certain plug-ins (as it should be).
Type:
Next:
Points to the next plug-in header in multi plug-in packages. Set it to NULL to mark
end of chain.
Memory management plugin 12
Type:
typedef struct {
cmsPluginBase base;
// Required
_cmsMallocFnPtrType MallocPtr;
_cmsFreeFnPtrType FreePtr;
_cmsReallocFnPtrType ReallocPtr;
// Optional
_cmsMalloZerocFnPtrType MallocZeroPtr;
_cmsCallocFnPtrType CallocPtr;
_cmsDupFnPtrType DupPtr;
} cmsPluginMemHandler;
Setting optional function pointers to NULL forces Little CMS to use MallocPtr, FreePtr
and ReallocPtr functions for all operation. If you provide all set of functions, Little CMS will
use the optional memory operations when possible. This works in such way to allow
optimizations when using advanced memory managers. All functions get called with a
ContextID that identifies the calling environment. It may be zero on certain special cases.
This ContextID is provided by the user when calling Little CMS API functions.
Memory management plugin 13
Plug-ins should NOT call those functions directly. They should manage memory by calling
the plug-in memory management API, described below. This API does call this plug-in to
do its functionality. Changing memory managers with ongoing operations may yield
unexpected results.
Example:
#include “lcms2_plugin.h”
cmsPluginMemHandler MemHandler = {{
cmsPluginMagicNumber,
2000,
cmsPluginMemHandlerSig,
NULL
},
my_malloc,
my_free,
my_realloc,
NULL,
NULL,
NULL };
This example changes the internal Little CMS memory management to use plain C
malloc(), free() and realloc() functions. This is indeed a bad idea, as the internal memory
manager does some extra checks to make sure no overflow exploits are being tried, but
you may want to use this capability to do other things, like use your own memory manager
or to access out of board memory in embedded systems. In the test bed application, a
Memory management plugin 14
customized memory manager which adds extra levels of check is being used. You can
refer to this program for a more sophisticated example of memory manager replacement.
Interpolation plug-in 15
Interpolation plug-in
By using this plug-in type, programmer may change or increase the interpolation done by
Little CMS. To fully understand what means this, it is necessary to clarify some concepts
now.
Little CMS internal operation is based on pipelines. Each pipeline may contain a number
of stages. Those stages may be of several kinds, and there are two kinds which need
interpolation. One is tone curves, where a 1D curve is applied to each channel. The
second kind is multidimensional lookup tables (CLUT) where a number of channels are
interpolated across a multidimensional grid. In each one of those cases, the final value is
interpolated across a number of nodes. By using the interpolation plug-in you can change
the algorithm that applies in such cases. Please note that does NOT apply to the whole
pipeline, only to the specific steps that are using interpolation. If you want to accelerate the
pipeline evaluation by using some sort of ASIC or GPU, that is certainly possible by using
the optimization or the applier plug-ins, but not changing the interpolation.
The structure is based on the idea of interpolator factory. That is, the programmer supplies
a call back function. When Little CMS needs to do some interpolation, it calls this function
specifying the number of input and output channels, the base type (16 bits or floating
point) and gives some hints about the use it want to do to the routine, like to use a trilinear-
like. The factory then should return a function pointer if the plug-in implements this
particular interpolation or NULL to regret. In this case, the default interpolator provided by
Little CMS will be used instead. Only one factory can be set at time. Further calls to
cmsPlugin with this type will replace the behavior of previous plug-in. Interpolators have
no states and no memory, and therefore cannot hold private data.
Type:
#define MAX_INPUT_DIMENSIONS 15
That is indeed necessary because tables of more than those dimensions are so huge that
grown out of control when node count increases.
Interpolation plug-in 16
typedef struct {
cmsPluginBase base;
cmsInterpFnFactory InterpolatorsFactory;
} cmsPluginInterpolation;
Since the interpolators may have different parameter types on float and 16 bits, the factory
returns a union of pointers, although at the end this behaves just a single pointer.
typedef union {
_cmsInterpFn16 Lerp16;
_cmsInterpFnFloat LerpFloat;
} cmsInterpFunction;
Interpolators for 16 bits and floating point are very alike. They have, however, some
differences due the fact 16 bits are primarily intended for performance (throughput)
Interpolation plug-in 17
16 bits interpolation.
The returned function has to perform full precision interpolation using floats. This is not a
time critical function. Reference Implementations are tetrahedral or trilinear, and plug-ins
may choose to implement any other interpolation algorithm.
Interpolation parameters
cmsContext ContextID;
cmsUInt32Number dwFlags;
cmsUInt32Number nInputs;
cmsUInt32Number nOutputs;
cmsUInt32Number nSamples[MAX_INPUT_DIMENSIONS];
cmsUInt32Number Domain[MAX_INPUT_DIMENSIONS];
cmsUInt32Number opta[MAX_INPUT_DIMENSIONS];
const void * Table;
cmsInterpFunction Interpolation;
} cmsInterpParams;
Example:
if (Value[0] == 1.0) {
Output[0] = LutTable[p -> Domain[0]]; return; }
cmsInterpFunction
my_Interpolators_Factory(cmsUInt32Number nInputChannels,
cmsUInt32Number nOutputChannels,
cmsUInt32Number dwFlags)
{
cmsInterpFunction Interpolation;
cmsBool IsFloat = (dwFlags & CMS_LERP_FLAGS_FLOAT);
memset(&Interpolation, 0, sizeof(Interpolation));
Interpolation.LerpFloat = LinLerp1Dfloat;
}
return Interpolation;
}
cmsPluginInterpolation Plugin = {
{ cmsPluginMagicNumber,
2000,
cmsPluginInterpolationSig,
NULL },
my_Interpolators_Factory };
Parametric curves plug-in 20
Type:
cmsPluginParametricCurveSig 0x70617248 'parH'
If you need more curves types, you can use two linked plug-ins, as described above.
Structure:
typedef struct {
cmsPluginBase base;
cmsUInt32Number nFunctions;
cmsUInt32Number FunctionTypes[MAX_TYPES_IN_LCMS_PLUGIN];
cmsUInt32Number ParameterCount[MAX_TYPES_IN_LCMS_PLUGIN];
cmsParametricCurveEvaluator Evaluator;
} cmsPluginParametricCurves;
Evaluator:
May implement more than one type, and have to implement evaluation of the curve in
both, forward and reverse directions.
cmsFloat64Number (* cmsParametricCurveEvaluator)
( cmsInt32Number Type,
const cmsFloat64Number Params[10],
cmsFloat64Number R);
Parametric curves plug-in 21
Note the Type parameter is described as signed. A negative type means same function
but analytically inverted. Max. number of params is 10. Each parametric curve plug-in may
implement an arbitrary number of curve types, up to 20:
Since Little CMS can work as unbounded CMM, the domain of R is effectively from minus
infinite to infinite. However, the normal, in-range domain is 0…1.0, so you have to
normalize your function to get values of R = [0...1.0] and deal with remaining cases if you
want your function to be able to work in unbounded mode.
FunctionTypes:
ParameterCount:
Example:
#include “lcms2_plugin.h”
static
cmsFloat64Number my_fns(cmsInt32Number Type,
const cmsFloat64Number Params[],
cmsFloat64Number R)
{
switch (Type) {
case TYPE_SINH:
Val = Params[0]* sinh(R);
break;
case -TYPE_SINH:
Val = asinh(R) / Params[0];
break;
}
return Val;
}
cmsPluginParametricCurves NewCurvePlugin = {
{
cmsPluginMagicNumber,
2000,
cmsPluginParametricCurveSig,
NULL
},
1,
{TYPE_SINH},
{1},
my_fns};
This example adds a new parametric curve under the ID number of 1000. This is a basic
hyperbolic function, the hyperbolic sine "sinh" multiplied by the first parameter. Math
expression of function is 𝑓(𝑥) = 𝑝0 sinh(𝑥) the implementation adds an analytical reversing
of the curve when parametric curve is requested with a negative id.
Formatters Plug-in 23
Formatters Plug-in
Little CMS can handle a lot of formats of image data. For describing such formats, Little
CMS does use a 32-bit value, referred below as format specifier. Each bit in those 32 bits
has specific meaning:
This plug-in adds new format handlers, replacing them if they already exist.
Type:
Structure:
typedef struct {
cmsPluginBase base;
cmsFormatterFactory FormattersFactory;
} cmsPluginFormatters;
Formatters Plug-in 24
Factory callback:
The factory have to return a cmsFormatter type. This type holds a pointer to a formatter
that can be either 16 bits or 32 bit float.
typedef union {
cmsFormatter16 Fmt16;
cmsFormatterFloat FmtFloat;
} cmsFormatter;
Formatters dealing with floats (bps = 4) or double (bps = 0) types are requested via
FormatterFloat callback. Others come across Formatter16 callback.
cmsUInt8Number* (* cmsFormatter16)
(register struct _cmstransform_struct* CMMcargo,
register cmsUInt16Number Values[],
register cmsUInt8Number* Buffer,
register cmsUInt32Number Stride);
cmsUInt8Number* (* cmsFormatterFloat)
(struct _cmstransform_struct* CMMcargo,
cmsFloat32Number Values[],
cmsUInt8Number* Buffer,
cmsUInt32Number Stride);
Formatters Plug-in 25
Example:
cmsUInt8Number* my_Unroll8(struct _cmstransform_struct* nfo,
register cmsUInt16Number wIn[],
register cmsUInt8Number* accum,
register cmsUInt32Number Stride)
{
wIn[0] = accum[0]) << 8;
wIn[1] = (accum[1] + 128) << 8;
wIn[2] = (accum[2] + 128) << 8;
return accum + 3;
}
This example implements decoding a new format of Lab values. The format comes as L
[0..FF] and a and b as signed chars.
Tag plug-in 26
Tag plug-in
This is the tag plugin, which identifies new tags with existing types. This plug-in has been
discussed as an example at the beginning of this document.
typedef struct {
cmsPluginBase base;
cmsTagSignature Signature;
cmsTagDescriptor Descriptor;
} cmsPluginTag;
This function should return the desired type for this tag, given the version of profile and the
data being serialized.
typedef struct {
// For reading.
cmsUInt32Number nSupportedTypes; // In how many types this tag can come
cmsTagTypeSignature SupportedTypes[MAX_TYPES_IN_LCMS_PLUGIN];
// For writting
cmsTagTypeSignature (* DecideType)(double ICCVersion, const void *Data);
} cmsTagDescriptor;
DecideType: Callback to select the type based on the version of the ICC profile. It got
called on writing operations. ‘data’ is a pointer to the tag contents, i.e., the data supplied by
the user to cmsWriteTag().
Tag plug-in 27
Example:
cmsPluginTag plugin = {
{cmsPluginMagicNumber,
2000,
cmsPluginTagSig, NULL},
{inkc_constant,
1, 1, {cmsSigLut16Type}, NULL}
};
Tag type handler plug-in 28
Type:
typedef struct {
cmsPluginBase base;
cmsTagTypeHandler Handler;
} cmsPluginTagType;
To add a new type, programmer has to implement several callbacks for reading, writing,
duplicating and setting free the in-memory representation of the type. When designing a
new type, the first step should be to create a structure to hold the representation of data.
This structure may be the same as used to serialize on disk, but usually that is not the
case. Once the programmer has written all callback functions, she has to fill the handler
structure with pointers to those routines.
There is a copy of ContextID in the tag type handler structure. This member is there for
simplicity sake, and the plug-in developer may read this value, but needs not to initialize it.
Little CMS will set this member to proper value when invoking the plug-in.
Tag type handler plug-in 29
// Writes n Items
cmsBool (* WritePtr)(struct _cms_typehandler_struct* self,
cmsIOHANDLER* io,
void* Ptr,
cmsUInt32Number nItems);
} cmsTagTypeHandler;
Example:
void *Type_int_Read(struct _cms_typehandler_struct* self,
cmsIOHANDLER* io,
cmsUInt32Number* nItems,
cmsUInt32Number SizeOfTag)
{
int* Ptr = (int*) _cmsMalloc(self ->ContextID, sizeof(int));
if (Ptr == NULL) return NULL;
if (!_cmsReadUInt32Number(io, Ptr)) return NULL;
*nItems = 1;
return Ptr;
}
Intent plug-in
This plug-in implements new rendering intents. To do so, the callback has to join all
profiles specified in the array in a single pipeline doing any necessary adjustments. Any
custom intent in the chain redirects to the custom callback. If more than one custom intent
is found, the one located first is invoked. Usually users should use only one custom intent,
so mixing custom intents in same multiprofile transform is not supported.
typedef struct {
cmsPluginBase base;
cmsUInt32Number Intent;
cmsIntentFn Link;
char Description[256];
} cmsPluginRenderingIntent;
Plug-in has to specify a linker callback that accepts a chain of profiles and return a pipeline
implementing the new intent. All significant modificators are passed as parameters.
2.0
This function implements the standard ICC intents perceptual, relative colorimetric,
saturation and absolute colorimetric. Can be used as a basis for custom intents.
Parameters:
ContextID: Pointer to a user-defined context cargo.
nProfiles: Number of profiles in the chain
Intents[]: Intent to apply on each profile to profile joint.
hProfiles[]: Handles to open profiles
BPC[]: Array of black point compensation states for each profile to profile joint
AdaptationStates[]: Array of observer adaptation states for each profile to profile
joint.
dwFlags: color transform flags (see Little CMS API for further details)
Returns:
A pointer to a newly created pipeline holding the color transform on success, NULL
on error.
Intent plug-in 33
Example:
if (cmsGetColorSpace(hProfiles[0]) != cmsSigGrayData ||
cmsGetColorSpace(hProfiles[nProfiles-1]) != cmsSigGrayData)
return _cmsDefaultICCintents(ContextID, nProfiles,
ICCIntents, hProfiles,
BPC, AdaptationStates,
dwFlags);
cmsPipelineInsertStage(Result, cmsAT_BEGIN,
cmsStageAllocIdentity(ContextID, 1));
return Result;
}
cmsPluginRenderingIntent RIPlugin =
{cmsPluginMagicNumber,
2000,
cmsPluginRenderingIntentSig,
NULL},
300,
MyNewIntent,
“bypass gray to gray rendering intent” };
This example creates a new rendering intent, at intent number 300, that is identical to
perceptual intent for all color spaces but gray to gray transforms, in this case it bypasses
the data. Note that it has to clear all occurrences of intent 300 in the intents array to avoid
infinite recursion.
Stages 34
Stages
When dealing with pipelines, there is the possibility for the programmer to create new,
customized stages that cannot be modeled by using any of the yet existing steps.
Additionally, there is a plug-in type that allows saving such user defined stages as multi
profile elements in DToB/BToD tags.
2.0
Parameters:
Returns:
A pointer to the newly created stage on success, NULL on error.
The Stage element can accept private data. If so, you need to supply callback functions to
duplicate and free private data.
Example:
This example creates a stage that reverses the input (negative). It works on 3 → 3
channels.
Stages 36
Stages plug-in.
This plug-in type allows programmer to add new multi-process elements in the MPE tag,
and in this way extend the types documented in “Floating-Point Device Encoding Range”
addendum to ICC spec 4.2.
Type:
Plug-in structure:
typedef struct {
cmsPluginBase base;
cmsTagTypeHandler Handler;
} cmsPluginMultiProcessElement;
To describe the serialization, the same structure as tag type handler is being used,
although there are some differences:
- DupPtr and FreePtr of cmsTagTypeHandler are not used and have to be set to
NULL.
- ReadPtr must call cmsStageAllocPlaceholder to create the stage
- WritePtr can access the stage internals by using all cmsStage functions.
o cmsStageInputChannels
o cmsStageOutputChannels
o cmsStageType
o cmsStageData
Stages 37
*nItems = 1;
return StageAllocNegate(self -> ContextID);
}
cmsPluginMultiProcessElement Plugin = {
{cmsPluginMagicNumber,
2000,
cmsPluginMultiProcessElementSig,
NULL},
{ SigNegateType
Type_negate_Read,
Type_negate_Write,
NULL,
NULL,
NULL
}};
This example creates a new multi-processing element that saves our “negate” stage on
DToB/BToD tags. To do so, cmsWriteTag() should be called with a pipeline containing
“negate” stages.
Optimization plug-in. 38
Optimization plug-in.
Using this plug-in, additional optimization strategies may be implemented.
To implement transforms, Little CMS does create chains of operators by using pipelines.
Once created, those pipelines are passed to the optimization engine to remove
redundancies and perform any optimizations that would increase the
performance/throughput of the pipeline. The optimization engine consist on series of
algorithms that are applied to the pipeline chain, if suitable. By using optimization plug-in, a
programmer can add new optimization algorithms to the existing list. Formats suitable for
optimization are 8 and 16 bits. No optimization is possible on floating-point data.
The optimization algorith can decide to implement the evaluation of resulting pipeline in
any way it wants. To do so, it has to register a specialized callback that would be
responsible of evaluating the optimized version of LUT. This callback has this form:
cmsOPTeval16Fn:
It is also posible to allocate and maintain an amount of user-supplied data, used only by
the optimization callback. The plug-in writer, then, have to supply two additional callbacks.
One for duplicating this data and another to free any resource associated with this data.
Those last functions are optional, and only required if the optimization callback is using
private data. It is the optimization algorithm which have to setup the optimized callbacack
and possible user defined data. For that purpose, there is a specialized function:
Optimization plug-in. 39
2.0
Set the optimization parameters for a given pipeline. Private data may be NULL, and that
means the optimized callback needs no additional data. If not NULL, the Free and Dup
callbacks must be specified as well.
Parameters:
Returns:
*None*
The optimization plug-in exports the optimizer algorith as a function callback. That function
have to return TRUE if any optimization is done on the LUT, this terminates the
optimization search. Or FALSE if it is unable to optimize and want to give a chanceto the
rest of optimization algorithms.
Type:
Structure:
typedef struct {
cmsPluginBase base;
_cmsOPToptimizeFn OptimizePtr; // Optimization algorithm entry point
} cmsPluginOptimization;
Optimization plug-in. 40
This function may be used to set the optional evaluator and a block of private data. If
private data is being used, an optional duplicator and free functions should also be
specified in order to duplicate the pipeline construct. Use NULL to inhibit such functionality.
Optimization plug-in. 41
Example:
*dwFlags |= cmsFLAGS_NOCACHE;
_cmsPipelineSetOptimizationParameters(*Lut,
FastEvaluateCurves, NULL, NULL, NULL);
return TRUE;
}
cmsPluginOptimization Plugin = {
{cmsPluginMagicNumber,
2000,
cmsPluginOptimizationSig,
NULL},
MyOptimize};
This example detects whatever the pipeline contains only curves and in this case provides
a hypothetical fast evaluator (not listed). Note that the plug-in also inhibits the 1-pixel
cache, because the “FastEvaluateCurves” function is supposed to be faster than caching.
Full transform plug-in [2.04], [2.08] 42
Type:
Structure:
typedef struct {
cmsPluginBase base;
} cmsPluginTransform;
It is also posible to allocate and maintain an amount of data, used only by the transform
callback supplied by the plug-in. The plug-in writer, then, have to provide an additional
callback to free any resource associated with this data. This callback type is used in other
plug-ins as well.
Such data is optional. Use NULL when the plug-in callback does not need private data.
Full transform plug-in [2.04], [2.08] 43
Callbacks:
2.4
The function is invoked for each new color transform cretead after plug-in registration. The
factory can accept to provide transform entry points if the actual transform parameters
meets its requeriments. The factory can also change the actual transform parameters after
it has accepted the task.
2.8
2.8
typedef struct {
cmsUInt32Number BytesPerLineIn;
cmsUInt32Number BytesPerLineOut;
cmsUInt32Number BytesPerPlaneIn;
cmsUInt32Number BytesPerPlaneOut;
} cmsStride;
Full transform plug-in [2.04], [2.08] 44
Previous to 2.8, the generic transform function was slightly different. lcms2.8 regognizes te
veersion stamp for 2.4 to 2.7 and provides a conversion stage. The old generic transform
is now deprecated.
2.4
Parameters:
CMM: pointer to current transform. Equivalent to cmsHTRANSFORM object. May
be converted by a static cast.
Full transform plug-in [2.04], [2.08] 45
Example
// The factory
cmsBool Dispatch(_cmsTransformFn* xformPtr, void** UserData,
_cmsFreeUserDataFn* FreePrivateDataFn,
cmsPipeline** Lut,
cmsUInt32Number* InputFormat,
cmsUInt32Number* OutputFormat,
cmsUInt32Number* dwFlags)
{
if (*InputFormat == MY_TYPE_RGB_8) {
xformPtr = my_fn;
return TRUE;
}
Return FALSE;
}
Dispatch
};
Mutex plug-in [2.06] 46
Type:
Structure:
typedef struct {
cmsPluginBase base;
_cmsCreateMutexFnPtrType CreateMutexPtr;
_cmsDestroyMutexFnPtrType DestroyMutexPtr;
_cmsLockMutexFnPtrType LockMutexPtr;
_cmsUnlockMutexFnPtrType UnlockMutexPtr;
} cmsPluginMutex;
Example (Windows)
static
void* MyMtxCreate(cmsContext id)
{
return (void*) CreateMutex( NULL, FALSE, NULL);
}
static
void MyMtxDestroy(cmsContext id, void* mtx)
{
CloseHandle((HANDLE) mtx);
}
static
cmsBool MyMtxLock(cmsContext id, void* mtx)
{
WaitForSingleObject((HANDLE) mtx, INFINITE);
return TRUE;
}
static
void MyMtxUnlock(cmsContext id, void* mtx)
{
ReleaseMutex((HANDLE) mtx);
}
Type:
Structure:
typedef struct {
cmsPluginBase base;
} cmsPluginParalellization;
User has to provide a scheduler function that splits the buffers, launches threads or
processes and waits for completion.
Example
static
void Scheduler(struct _cmstransform_struct* CMMcargo,
const void* InputBuffer,
void* OutputBuffer,
cmsUInt32Number PixelsPerLine,
cmsUInt32Number LineCount,
const cmsStride* Stride)
{
[…]
}
Support functions
2.4
Returns a pointer to the user data associated with current color transform
Parameters:
CMM: pointer to current transform. Equivalent to cmsHTRANSFORM object. May
be converted by a static cast.
Returns:
2.12
Returns the original flags as declared when creating the color transform.
Parameters:
CMM: pointer to current transform. Equivalent to cmsHTRANSFORM object. May
be converted by a static cast.
Returns:
2.14
Parameters:
CMM: pointer to current transform. Equivalent to cmsHTRANSFORM object. May
be converted by a static cast.
Returns:
2.14
Returns the maximum number of thread workers or -1 if auto detect has been selected
Parameters:
CMM: pointer to current transform. Equivalent to cmsHTRANSFORM object. May
be converted by a static cast.
Returns:
IO handlers are abstractions used to deal with files or streams. All reading/writing of ICC
profiles, PostScript resources and CGATS are done across IO handlers. IO handlers do
support random access. The IO handler API allows you to access the low level functions,
as well as to write new handlers for specialized devices.
IO handler structure.
struct _cms_io_handler {
void* stream;
cmsContext ContextID;
cmsUInt32Number UsedSpace;
cmsUInt32Number ReportedSize;
char PhysicalFile[cmsMAX_PATH];
Read/Write functions
2.0
Parameters:
Parameters:
Io: pointer to the cmsIOHANDLER object.
Param: Object to write.
Returns:
TRUE on success, FALSE on error.
Plug-in support API 53
Parameters:
Io: pointer to an cmsIOHANDLER object.
Returns:
cmsTagTypeSignature or 0 on error.
2.0
Parameters:
Io: pointer to an cmsIOHANDLER object.
Sig: cmsTagTypeSignature to be written.
Returns:
TRUE on success, FALSE on error.
Plug-in support API 54
Parameters:
Io: pointer to a cmsIOHANDLER object.
Returns:
TRUE on success, FALSE on error.
2.0
Parameters:
Io: pointer to cmsIOHANDLER object.
Returns:
TRUE on success, FALSE on error.
2.0
Outputs printf-like strings to the given IOHANDLER. To deal with text streams. 2K at most
Parameters:
Io: pointer to cmsIOHANDLER object.
Frm: format string (printf-like)
…: optional parameters (printf-like)
Returns:
TRUE on success, FALSE on error.
Plug-in support API 55
Parameters:
fixed8: 8.8 encoded fixed point value.
Returns:
2.0
Parameters:
Val: cmsFloat64Number holding the value.
Returns:
Parameters:
Fix32: 15.16 (signed) fixed point encoded fixed point value.
Returns:
2.0
Parameters:
V: cmsFloat64Number holding the value.
Returns:
Decodes from the standard “C” struct tm to ICC date and time format.
Parameters:
Dest: a pointer to a cmsDateTimeNumber structure.
Source: a pointer to a struct tm structure.
Returns:
*None*
2.0
Decodes from ICC date and time format to the standard “C” struct tm.
Parameters:
Source: a pointer to a cmsDateTimeNumber structure.
Dest: a pointer to a struct tm structure.
Returns:
*None*
Plug-in support API 58
For debugging purposes, it may be handy to know what is making a function to fail. This
function add traces to let developer what is going on.
cmsERROR_UNDEFINED 0
cmsERROR_FILE 1
cmsERROR_RANGE 2
cmsERROR_INTERNAL 3
cmsERROR_NULL 4
cmsERROR_READ 5
cmsERROR_SEEK 6
cmsERROR_WRITE 7
cmsERROR_UNKNOWN_EXTENSION 8
cmsERROR_COLORSPACE_CHECK 9
cmsERROR_ALREADY_DEFINED 10
cmsERROR_BAD_SIGNATURE 11
cmsERROR_CORRUPTION_DETECTED 12
cmsERROR_NOT_SUITABLE 13
Table 1
2.0
Parameters:
ContextID: Pointer to a user-defined context cargo.
ErrorCode: Error family, as stated in Table 1
ErrorText: Error description, printf-like
…: additional printf-like parameters.
Returns:
*None*
Those are the memory management primitives as used by the core engine. It uses the
memory management plug-in if defined.
2.0
Parameters:
ContextID: Pointer to a user-defined context cargo.
Size: amount of memory to allocate in bytes
Returns:
Pointer to newly allocated block, or NULL on error.
2.0
Cause the space pointed to by Ptr to be deallocated; that is, made available for further
allocation. If ptr is a null pointer, no action will occur.
Parameters:
Returns:
*None*
Plug-in support API 60
2.0
Parameters:
ContextID: Pointer to a user-defined context cargo.
Size: amount of memory to allocate in bytes
Returns:
Pointer to newly allocated block, or NULL on error.
2.0
Allocate space for an array of num elements each of whose size in bytes is size. The
space shall be initialized to all bits 0.
Parameters:
ContextID: Pointer to a user-defined context cargo.
Num: number of array elements
Size: Array element size in bytes
Returns:
Pointer to newly allocated block, or NULL on error.
2.0
The size of the memory block pointed to by the Ptr parameter is changed to the NewSize
bytes, expanding or reducing the amount of memory available in the block.
Parameters:
ContextID: Pointer to a user-defined context cargo.
Ptr: pointer to memory block.
NewSize: number of bytes.
Returns:
Pointer to newly allocated block, or NULL on error.
Plug-in support API 61
2.0
Parameters:
Returns:
Pointer to newly allocated copy, or NULL on error.
Plug-in support API 62
Those are low-level primitives to opearate with 3-component vectors and 3x3 matrices.
Please note this is an internal module, those types and functions are not shared with any
other part of the API. Use at your discretion.
VEC3 vectors
typedef struct {
cmsFloat64Number n[3];
} cmsVEC3;
2.0
void _cmsVEC3init(cmsVEC3* r,
cmsFloat64Number x,
cmsFloat64Number y,
cmsFloat64Number z);
Populates a vector.
Parameters:
Returns:
*None*
2.0
Vector subtraction.
Parameters:
Returns:
Plug-in support API 63
*None*
2.0
Parameters:
Returns:
*None*
2.0
Parameters:
Returns:
Dot product 𝑢 ∙ 𝑣
2.0
Parameters:
Returns:
Euclidean length √x 2 + y 2 + z 2
Plug-in support API 64
2.0
Parameters:
Returns:
Euclidean distance ||a-b||
Plug-in support API 65
MAT3 matrices
3x3 Matrices are formed by 3 VEC3 vectors. The Plugin API provides several low-level
primitives for 3x3 Matrix math.
typedef struct {
cmsVEC3 v[3];
} cmsMAT3;
2.0
Parameters:
Returns:
*None*
2.0
Return true if “a” is close enough to be interpreted as identity. Else return false
Parameters:
Returns:
TRUE on identity, FALSE on non-identity.
Plug-in support API 66
2.0
Parameters:
Returns:
*None*
2.0
Parameters:
2.0
Parameters:
Returns:
TRUE on success, FALSE on error.
Plug-in support API 67
2.0
Parameters:
Returns:
*None*
Plug-in support API 68
Those functions are provided to expose the internal MD5 algorithms. This is a very basic
implementation, for reuse sake. All are accessible across lcm2_plugin.h header.
2.10
Parameters:
ContextID: Pointer to a user-defined context.
Returns:
Handle to an MD5 object
2.10
Adds to the digest the contents of memory pointed by buffer. Up to len bytes.
Parameters:
handle: Handle to an MD5 object
uf: pointer to memory holding the values to compute the digest
len: length of buffer in bytes.
Returns:
*None*
2.10
Computes the digest number and destroys the MD5 object. In this case the digest number
is stored as profile ID.
Parameters:
id: Pointer to variable to get the digest.
Handle: Handle to an MD5 object
Returns:
*None*
Conclusion 69
Conclusion
Little CMS 2.x plug-in system is a convenient way to enhance the CMM functionality in
many aspects, but there are chances you don’t need to use plug-in to add new
functionality at all. If you can stay in the standard Little CMS API, I would recommend
avoiding writing plug-ins. Avoiding plug-ins is convenient because backwards compatibility,
clarity and maintainability. The normal API has been designed with easy-to-use goals; on
the other hand, on plug-in API functionality is the most desirable attribute.
If you decide to write extensions, please note there are many ways to do that. One
example would be to write functions using the plug-in API, but without exporting any plug-
in. This is ok if you need to use low-level functions that are not present in the normal API.