This source file includes following definitions.
- _cmsAllocAdaptationStateChunk
- cmsSetAdaptationStateTHR
- cmsSetAdaptationState
- cmsSetAlarmCodesTHR
- cmsGetAlarmCodesTHR
- cmsSetAlarmCodes
- cmsGetAlarmCodes
- _cmsAllocAlarmCodesChunk
- cmsDeleteTransform
- cmsDoTransform
- cmsDoTransformStride
- FloatXFORM
- NullFloatXFORM
- NullXFORM
- PrecalculatedXFORM
- TransformOnePixelWithGamutCheck
- PrecalculatedXFORMGamutCheck
- CachedXFORM
- CachedXFORMGamutCheck
- DupPluginTransformList
- _cmsAllocTransformPluginChunk
- _cmsRegisterTransformPlugin
- _cmsSetTransformUserData
- _cmsGetTransformUserData
- _cmsGetTransformFormatters16
- _cmsGetTransformFormattersFloat
- AllocEmptyTransform
- GetXFormColorSpaces
- IsProperColorSpace
- SetWhitePoint
- cmsCreateExtendedTransform
- cmsCreateMultiprofileTransformTHR
- cmsCreateMultiprofileTransform
- cmsCreateTransformTHR
- cmsCreateTransform
- cmsCreateProofingTransformTHR
- cmsCreateProofingTransform
- cmsGetTransformContextID
- cmsGetTransformInputFormat
- cmsGetTransformOutputFormat
- cmsChangeBuffersFormat
#include "lcms2_internal.h"
#define DEFAULT_OBSERVER_ADAPTATION_STATE 1.0
_cmsAdaptationStateChunkType _cmsAdaptationStateChunk = { DEFAULT_OBSERVER_ADAPTATION_STATE };
void _cmsAllocAdaptationStateChunk(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src)
{
static _cmsAdaptationStateChunkType AdaptationStateChunk = { DEFAULT_OBSERVER_ADAPTATION_STATE };
void* from;
if (src != NULL) {
from = src ->chunks[AdaptationStateContext];
}
else {
from = &AdaptationStateChunk;
}
ctx ->chunks[AdaptationStateContext] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsAdaptationStateChunkType));
}
cmsFloat64Number CMSEXPORT cmsSetAdaptationStateTHR(cmsContext ContextID, cmsFloat64Number d)
{
cmsFloat64Number prev;
_cmsAdaptationStateChunkType* ptr = (_cmsAdaptationStateChunkType*) _cmsContextGetClientChunk(ContextID, AdaptationStateContext);
prev = ptr ->AdaptationState;
if (d >= 0.0) {
ptr ->AdaptationState = d;
}
return prev;
}
cmsFloat64Number CMSEXPORT cmsSetAdaptationState(cmsFloat64Number d)
{
return cmsSetAdaptationStateTHR(NULL, d);
}
#define DEFAULT_ALARM_CODES_VALUE {0x7F00, 0x7F00, 0x7F00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
_cmsAlarmCodesChunkType _cmsAlarmCodesChunk = { DEFAULT_ALARM_CODES_VALUE };
void CMSEXPORT cmsSetAlarmCodesTHR(cmsContext ContextID, const cmsUInt16Number AlarmCodesP[cmsMAXCHANNELS])
{
_cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(ContextID, AlarmCodesContext);
_cmsAssert(ContextAlarmCodes != NULL);
memcpy(ContextAlarmCodes->AlarmCodes, AlarmCodesP, sizeof(ContextAlarmCodes->AlarmCodes));
}
void CMSEXPORT cmsGetAlarmCodesTHR(cmsContext ContextID, cmsUInt16Number AlarmCodesP[cmsMAXCHANNELS])
{
_cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(ContextID, AlarmCodesContext);
_cmsAssert(ContextAlarmCodes != NULL);
memcpy(AlarmCodesP, ContextAlarmCodes->AlarmCodes, sizeof(ContextAlarmCodes->AlarmCodes));
}
void CMSEXPORT cmsSetAlarmCodes(const cmsUInt16Number NewAlarm[cmsMAXCHANNELS])
{
_cmsAssert(NewAlarm != NULL);
cmsSetAlarmCodesTHR(NULL, NewAlarm);
}
void CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number OldAlarm[cmsMAXCHANNELS])
{
_cmsAssert(OldAlarm != NULL);
cmsGetAlarmCodesTHR(NULL, OldAlarm);
}
void _cmsAllocAlarmCodesChunk(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src)
{
static _cmsAlarmCodesChunkType AlarmCodesChunk = { DEFAULT_ALARM_CODES_VALUE };
void* from;
if (src != NULL) {
from = src ->chunks[AlarmCodesContext];
}
else {
from = &AlarmCodesChunk;
}
ctx ->chunks[AlarmCodesContext] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsAlarmCodesChunkType));
}
void CMSEXPORT cmsDeleteTransform(cmsHTRANSFORM hTransform)
{
_cmsTRANSFORM* p = (_cmsTRANSFORM*) hTransform;
_cmsAssert(p != NULL);
if (p -> GamutCheck)
cmsPipelineFree(p -> GamutCheck);
if (p -> Lut)
cmsPipelineFree(p -> Lut);
if (p ->InputColorant)
cmsFreeNamedColorList(p ->InputColorant);
if (p -> OutputColorant)
cmsFreeNamedColorList(p ->OutputColorant);
if (p ->Sequence)
cmsFreeProfileSequenceDescription(p ->Sequence);
if (p ->UserData)
p ->FreeUserData(p ->ContextID, p ->UserData);
_cmsFree(p ->ContextID, (void *) p);
}
void CMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform,
const void* InputBuffer,
void* OutputBuffer,
cmsUInt32Number Size)
{
_cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform;
p -> xform(p, InputBuffer, OutputBuffer, Size, Size);
}
void CMSEXPORT cmsDoTransformStride(cmsHTRANSFORM Transform,
const void* InputBuffer,
void* OutputBuffer,
cmsUInt32Number Size, cmsUInt32Number Stride)
{
_cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform;
p -> xform(p, InputBuffer, OutputBuffer, Size, Stride);
}
static
void FloatXFORM(_cmsTRANSFORM* p,
const void* in,
void* out, cmsUInt32Number Size, cmsUInt32Number Stride)
{
cmsUInt8Number* accum;
cmsUInt8Number* output;
cmsFloat32Number fIn[cmsMAXCHANNELS], fOut[cmsMAXCHANNELS];
cmsFloat32Number OutOfGamut;
cmsUInt32Number i, j;
accum = (cmsUInt8Number*) in;
output = (cmsUInt8Number*) out;
for (i=0; i < Size; i++) {
accum = p -> FromInputFloat(p, fIn, accum, Stride);
if (p ->GamutCheck != NULL) {
cmsPipelineEvalFloat( fIn, &OutOfGamut, p ->GamutCheck);
if (OutOfGamut > 0.0) {
for (j=0; j < cmsMAXCHANNELS; j++)
fOut[j] = -1.0;
}
else {
cmsPipelineEvalFloat(fIn, fOut, p -> Lut);
}
}
else {
cmsPipelineEvalFloat(fIn, fOut, p -> Lut);
}
output = p -> ToOutputFloat(p, fOut, output, Stride);
}
}
static
void NullFloatXFORM(_cmsTRANSFORM* p,
const void* in,
void* out,
cmsUInt32Number Size,
cmsUInt32Number Stride)
{
cmsUInt8Number* accum;
cmsUInt8Number* output;
cmsFloat32Number fIn[cmsMAXCHANNELS];
cmsUInt32Number i, n;
accum = (cmsUInt8Number*) in;
output = (cmsUInt8Number*) out;
n = Size;
for (i=0; i < n; i++) {
accum = p -> FromInputFloat(p, fIn, accum, Stride);
output = p -> ToOutputFloat(p, fIn, output, Stride);
}
}
static
void NullXFORM(_cmsTRANSFORM* p,
const void* in,
void* out, cmsUInt32Number Size,
cmsUInt32Number Stride)
{
cmsUInt8Number* accum;
cmsUInt8Number* output;
cmsUInt16Number wIn[cmsMAXCHANNELS];
cmsUInt32Number i, n;
accum = (cmsUInt8Number*) in;
output = (cmsUInt8Number*) out;
n = Size;
for (i=0; i < n; i++) {
accum = p -> FromInput(p, wIn, accum, Stride);
output = p -> ToOutput(p, wIn, output, Stride);
}
}
static
void PrecalculatedXFORM(_cmsTRANSFORM* p,
const void* in,
void* out, cmsUInt32Number Size, cmsUInt32Number Stride)
{
register cmsUInt8Number* accum;
register cmsUInt8Number* output;
cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
cmsUInt32Number i, n;
accum = (cmsUInt8Number*) in;
output = (cmsUInt8Number*) out;
n = Size;
for (i=0; i < n; i++) {
accum = p -> FromInput(p, wIn, accum, Stride);
p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
output = p -> ToOutput(p, wOut, output, Stride);
}
}
static
void TransformOnePixelWithGamutCheck(_cmsTRANSFORM* p,
const cmsUInt16Number wIn[],
cmsUInt16Number wOut[])
{
cmsUInt16Number wOutOfGamut;
p ->GamutCheck ->Eval16Fn(wIn, &wOutOfGamut, p ->GamutCheck ->Data);
if (wOutOfGamut >= 1) {
cmsUInt16Number i;
_cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(p->ContextID, AlarmCodesContext);
for (i=0; i < p ->Lut->OutputChannels; i++) {
wOut[i] = ContextAlarmCodes ->AlarmCodes[i];
}
}
else
p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
}
static
void PrecalculatedXFORMGamutCheck(_cmsTRANSFORM* p,
const void* in,
void* out, cmsUInt32Number Size, cmsUInt32Number Stride)
{
cmsUInt8Number* accum;
cmsUInt8Number* output;
cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
cmsUInt32Number i, n;
accum = (cmsUInt8Number*) in;
output = (cmsUInt8Number*) out;
n = Size;
for (i=0; i < n; i++) {
accum = p -> FromInput(p, wIn, accum, Stride);
TransformOnePixelWithGamutCheck(p, wIn, wOut);
output = p -> ToOutput(p, wOut, output, Stride);
}
}
static
void CachedXFORM(_cmsTRANSFORM* p,
const void* in,
void* out, cmsUInt32Number Size, cmsUInt32Number Stride)
{
cmsUInt8Number* accum;
cmsUInt8Number* output;
cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
cmsUInt32Number i, n;
_cmsCACHE Cache;
accum = (cmsUInt8Number*) in;
output = (cmsUInt8Number*) out;
n = Size;
memset(wIn, 0, sizeof(wIn));
memset(wOut, 0, sizeof(wOut));
memcpy(&Cache, &p ->Cache, sizeof(Cache));
for (i=0; i < n; i++) {
accum = p -> FromInput(p, wIn, accum, Stride);
if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) {
memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut));
}
else {
p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
memcpy(Cache.CacheIn, wIn, sizeof(Cache.CacheIn));
memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut));
}
output = p -> ToOutput(p, wOut, output, Stride);
}
}
static
void CachedXFORMGamutCheck(_cmsTRANSFORM* p,
const void* in,
void* out, cmsUInt32Number Size, cmsUInt32Number Stride)
{
cmsUInt8Number* accum;
cmsUInt8Number* output;
cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
cmsUInt32Number i, n;
_cmsCACHE Cache;
accum = (cmsUInt8Number*) in;
output = (cmsUInt8Number*) out;
n = Size;
memset(wIn, 0, sizeof(cmsUInt16Number) * cmsMAXCHANNELS);
memset(wOut, 0, sizeof(cmsUInt16Number) * cmsMAXCHANNELS);
memcpy(&Cache, &p ->Cache, sizeof(Cache));
for (i=0; i < n; i++) {
accum = p -> FromInput(p, wIn, accum, Stride);
if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) {
memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut));
}
else {
TransformOnePixelWithGamutCheck(p, wIn, wOut);
memcpy(Cache.CacheIn, wIn, sizeof(Cache.CacheIn));
memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut));
}
output = p -> ToOutput(p, wOut, output, Stride);
}
}
typedef struct _cmsTransformCollection_st {
_cmsTransformFactory Factory;
struct _cmsTransformCollection_st *Next;
} _cmsTransformCollection;
_cmsTransformPluginChunkType _cmsTransformPluginChunk = { NULL };
static
void DupPluginTransformList(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src)
{
_cmsTransformPluginChunkType newHead = { NULL };
_cmsTransformCollection* entry;
_cmsTransformCollection* Anterior = NULL;
_cmsTransformPluginChunkType* head = (_cmsTransformPluginChunkType*) src->chunks[TransformPlugin];
for (entry = head->TransformCollection;
entry != NULL;
entry = entry ->Next) {
_cmsTransformCollection *newEntry = ( _cmsTransformCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTransformCollection));
if (newEntry == NULL)
return;
newEntry -> Next = NULL;
if (Anterior)
Anterior -> Next = newEntry;
Anterior = newEntry;
if (newHead.TransformCollection == NULL)
newHead.TransformCollection = newEntry;
}
ctx ->chunks[TransformPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTransformPluginChunkType));
}
void _cmsAllocTransformPluginChunk(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src)
{
if (src != NULL) {
DupPluginTransformList(ctx, src);
}
else {
static _cmsTransformPluginChunkType TransformPluginChunkType = { NULL };
ctx ->chunks[TransformPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TransformPluginChunkType, sizeof(_cmsTransformPluginChunkType));
}
}
cmsBool _cmsRegisterTransformPlugin(cmsContext ContextID, cmsPluginBase* Data)
{
cmsPluginTransform* Plugin = (cmsPluginTransform*) Data;
_cmsTransformCollection* fl;
_cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID,TransformPlugin);
if (Data == NULL) {
ctx->TransformCollection = NULL;
return TRUE;
}
if (Plugin ->Factory == NULL) return FALSE;
fl = (_cmsTransformCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsTransformCollection));
if (fl == NULL) return FALSE;
fl ->Factory = Plugin ->Factory;
fl ->Next = ctx->TransformCollection;
ctx->TransformCollection = fl;
return TRUE;
}
void CMSEXPORT _cmsSetTransformUserData(struct _cmstransform_struct *CMMcargo, void* ptr, _cmsFreeUserDataFn FreePrivateDataFn)
{
_cmsAssert(CMMcargo != NULL);
CMMcargo ->UserData = ptr;
CMMcargo ->FreeUserData = FreePrivateDataFn;
}
void * CMSEXPORT _cmsGetTransformUserData(struct _cmstransform_struct *CMMcargo)
{
_cmsAssert(CMMcargo != NULL);
return CMMcargo ->UserData;
}
void CMSEXPORT _cmsGetTransformFormatters16(struct _cmstransform_struct *CMMcargo, cmsFormatter16* FromInput, cmsFormatter16* ToOutput)
{
_cmsAssert(CMMcargo != NULL);
if (FromInput) *FromInput = CMMcargo ->FromInput;
if (ToOutput) *ToOutput = CMMcargo ->ToOutput;
}
void CMSEXPORT _cmsGetTransformFormattersFloat(struct _cmstransform_struct *CMMcargo, cmsFormatterFloat* FromInput, cmsFormatterFloat* ToOutput)
{
_cmsAssert(CMMcargo != NULL);
if (FromInput) *FromInput = CMMcargo ->FromInputFloat;
if (ToOutput) *ToOutput = CMMcargo ->ToOutputFloat;
}
static
_cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,
cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags)
{
_cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID, TransformPlugin);
_cmsTransformCollection* Plugin;
_cmsTRANSFORM* p = (_cmsTRANSFORM*)_cmsMallocZero(ContextID, sizeof(_cmsTRANSFORM));
if (!p) return NULL;
p->Lut = lut;
if (p->Lut != NULL) {
for (Plugin = ctx->TransformCollection;
Plugin != NULL;
Plugin = Plugin->Next) {
if (Plugin->Factory(&p->xform, &p->UserData, &p->FreeUserData, &p->Lut, InputFormat, OutputFormat, dwFlags)) {
p->ContextID = ContextID;
p->InputFormat = *InputFormat;
p->OutputFormat = *OutputFormat;
p->dwOriginalFlags = *dwFlags;
p->FromInput = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
p->ToOutput = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
p->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
p->ToOutputFloat = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
return p;
}
}
_cmsOptimizePipeline(ContextID, &p->Lut, Intent, InputFormat, OutputFormat, dwFlags);
}
if (_cmsFormatterIsFloat(*InputFormat) && _cmsFormatterIsFloat(*OutputFormat)) {
p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
p ->ToOutputFloat = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
*dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
if (p ->FromInputFloat == NULL || p ->ToOutputFloat == NULL) {
cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
_cmsFree(ContextID, p);
return NULL;
}
if (*dwFlags & cmsFLAGS_NULLTRANSFORM) {
p ->xform = NullFloatXFORM;
}
else {
p ->xform = FloatXFORM;
}
}
else {
if (*InputFormat == 0 && *OutputFormat == 0) {
p ->FromInput = p ->ToOutput = NULL;
*dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
}
else {
int BytesPerPixelInput;
p ->FromInput = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
p ->ToOutput = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
if (p ->FromInput == NULL || p ->ToOutput == NULL) {
cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
_cmsFree(ContextID, p);
return NULL;
}
BytesPerPixelInput = T_BYTES(p ->InputFormat);
if (BytesPerPixelInput == 0 || BytesPerPixelInput >= 2)
*dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
}
if (*dwFlags & cmsFLAGS_NULLTRANSFORM) {
p ->xform = NullXFORM;
}
else {
if (*dwFlags & cmsFLAGS_NOCACHE) {
if (*dwFlags & cmsFLAGS_GAMUTCHECK)
p ->xform = PrecalculatedXFORMGamutCheck;
else
p ->xform = PrecalculatedXFORM;
}
else {
if (*dwFlags & cmsFLAGS_GAMUTCHECK)
p ->xform = CachedXFORMGamutCheck;
else
p ->xform = CachedXFORM;
}
}
}
p ->InputFormat = *InputFormat;
p ->OutputFormat = *OutputFormat;
p ->dwOriginalFlags = *dwFlags;
p ->ContextID = ContextID;
p ->UserData = NULL;
return p;
}
static
cmsBool GetXFormColorSpaces(int nProfiles, cmsHPROFILE hProfiles[], cmsColorSpaceSignature* Input, cmsColorSpaceSignature* Output)
{
cmsColorSpaceSignature ColorSpaceIn, ColorSpaceOut;
cmsColorSpaceSignature PostColorSpace;
int i;
if (nProfiles <= 0) return FALSE;
if (hProfiles[0] == NULL) return FALSE;
*Input = PostColorSpace = cmsGetColorSpace(hProfiles[0]);
for (i=0; i < nProfiles; i++) {
cmsProfileClassSignature cls;
cmsHPROFILE hProfile = hProfiles[i];
int lIsInput = (PostColorSpace != cmsSigXYZData) &&
(PostColorSpace != cmsSigLabData);
if (hProfile == NULL) return FALSE;
cls = cmsGetDeviceClass(hProfile);
if (cls == cmsSigNamedColorClass) {
ColorSpaceIn = cmsSig1colorData;
ColorSpaceOut = (nProfiles > 1) ? cmsGetPCS(hProfile) : cmsGetColorSpace(hProfile);
}
else
if (lIsInput || (cls == cmsSigLinkClass)) {
ColorSpaceIn = cmsGetColorSpace(hProfile);
ColorSpaceOut = cmsGetPCS(hProfile);
}
else
{
ColorSpaceIn = cmsGetPCS(hProfile);
ColorSpaceOut = cmsGetColorSpace(hProfile);
}
if (i==0)
*Input = ColorSpaceIn;
PostColorSpace = ColorSpaceOut;
}
*Output = PostColorSpace;
return TRUE;
}
static
cmsBool IsProperColorSpace(cmsColorSpaceSignature Check, cmsUInt32Number dwFormat)
{
int Space1 = T_COLORSPACE(dwFormat);
int Space2 = _cmsLCMScolorSpace(Check);
if (Space1 == PT_ANY) return TRUE;
if (Space1 == Space2) return TRUE;
if (Space1 == PT_LabV2 && Space2 == PT_Lab) return TRUE;
if (Space1 == PT_Lab && Space2 == PT_LabV2) return TRUE;
return FALSE;
}
static
void SetWhitePoint(cmsCIEXYZ* wtPt, const cmsCIEXYZ* src)
{
if (src == NULL) {
wtPt ->X = cmsD50X;
wtPt ->Y = cmsD50Y;
wtPt ->Z = cmsD50Z;
}
else {
wtPt ->X = src->X;
wtPt ->Y = src->Y;
wtPt ->Z = src->Z;
}
}
cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID,
cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[],
cmsBool BPC[],
cmsUInt32Number Intents[],
cmsFloat64Number AdaptationStates[],
cmsHPROFILE hGamutProfile,
cmsUInt32Number nGamutPCSposition,
cmsUInt32Number InputFormat,
cmsUInt32Number OutputFormat,
cmsUInt32Number dwFlags)
{
_cmsTRANSFORM* xform;
cmsColorSpaceSignature EntryColorSpace;
cmsColorSpaceSignature ExitColorSpace;
cmsPipeline* Lut;
cmsUInt32Number LastIntent = Intents[nProfiles-1];
if (dwFlags & cmsFLAGS_NULLTRANSFORM)
{
return AllocEmptyTransform(ContextID, NULL, INTENT_PERCEPTUAL, &InputFormat, &OutputFormat, &dwFlags);
}
if (dwFlags & cmsFLAGS_GAMUTCHECK) {
if (hGamutProfile == NULL) dwFlags &= ~cmsFLAGS_GAMUTCHECK;
}
if (_cmsFormatterIsFloat(InputFormat) || _cmsFormatterIsFloat(OutputFormat))
dwFlags |= cmsFLAGS_NOCACHE;
if (!GetXFormColorSpaces(nProfiles, hProfiles, &EntryColorSpace, &ExitColorSpace)) {
cmsSignalError(ContextID, cmsERROR_NULL, "NULL input profiles on transform");
return NULL;
}
if (!IsProperColorSpace(EntryColorSpace, InputFormat)) {
cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong input color space on transform");
return NULL;
}
if (!IsProperColorSpace(ExitColorSpace, OutputFormat)) {
cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong output color space on transform");
return NULL;
}
Lut = _cmsLinkProfiles(ContextID, nProfiles, Intents, hProfiles, BPC, AdaptationStates, dwFlags);
if (Lut == NULL) {
cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Couldn't link the profiles");
return NULL;
}
if ((cmsChannelsOf(EntryColorSpace) != cmsPipelineInputChannels(Lut)) ||
(cmsChannelsOf(ExitColorSpace) != cmsPipelineOutputChannels(Lut))) {
cmsPipelineFree(Lut);
cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Channel count doesn't match. Profile is corrupted");
return NULL;
}
xform = AllocEmptyTransform(ContextID, Lut, LastIntent, &InputFormat, &OutputFormat, &dwFlags);
if (xform == NULL) {
return NULL;
}
xform ->EntryColorSpace = EntryColorSpace;
xform ->ExitColorSpace = ExitColorSpace;
xform ->RenderingIntent = Intents[nProfiles-1];
SetWhitePoint(&xform->EntryWhitePoint, (cmsCIEXYZ*) cmsReadTag(hProfiles[0], cmsSigMediaWhitePointTag));
SetWhitePoint(&xform->ExitWhitePoint, (cmsCIEXYZ*) cmsReadTag(hProfiles[nProfiles-1], cmsSigMediaWhitePointTag));
if (hGamutProfile != NULL && (dwFlags & cmsFLAGS_GAMUTCHECK))
xform ->GamutCheck = _cmsCreateGamutCheckPipeline(ContextID, hProfiles,
BPC, Intents,
AdaptationStates,
nGamutPCSposition,
hGamutProfile);
if (cmsIsTag(hProfiles[0], cmsSigColorantTableTag)) {
xform ->InputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[0], cmsSigColorantTableTag));
}
if (cmsGetDeviceClass(hProfiles[nProfiles-1]) == cmsSigLinkClass) {
if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableOutTag)) {
xform ->OutputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[nProfiles-1], cmsSigColorantTableOutTag));
}
} else {
if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableTag)) {
xform -> OutputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[nProfiles-1], cmsSigColorantTableTag));
}
}
if (dwFlags & cmsFLAGS_KEEP_SEQUENCE) {
xform ->Sequence = _cmsCompileProfileSequence(ContextID, nProfiles, hProfiles);
}
else
xform ->Sequence = NULL;
if (!(dwFlags & cmsFLAGS_NOCACHE)) {
memset(&xform ->Cache.CacheIn, 0, sizeof(xform ->Cache.CacheIn));
if (xform ->GamutCheck != NULL) {
TransformOnePixelWithGamutCheck(xform, xform ->Cache.CacheIn, xform->Cache.CacheOut);
}
else {
xform ->Lut ->Eval16Fn(xform ->Cache.CacheIn, xform->Cache.CacheOut, xform -> Lut->Data);
}
}
return (cmsHTRANSFORM) xform;
}
cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransformTHR(cmsContext ContextID,
cmsHPROFILE hProfiles[],
cmsUInt32Number nProfiles,
cmsUInt32Number InputFormat,
cmsUInt32Number OutputFormat,
cmsUInt32Number Intent,
cmsUInt32Number dwFlags)
{
cmsUInt32Number i;
cmsBool BPC[256];
cmsUInt32Number Intents[256];
cmsFloat64Number AdaptationStates[256];
if (nProfiles <= 0 || nProfiles > 255) {
cmsSignalError(ContextID, cmsERROR_RANGE, "Wrong number of profiles. 1..255 expected, %d found.", nProfiles);
return NULL;
}
for (i=0; i < nProfiles; i++) {
BPC[i] = dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION ? TRUE : FALSE;
Intents[i] = Intent;
AdaptationStates[i] = cmsSetAdaptationStateTHR(ContextID, -1);
}
return cmsCreateExtendedTransform(ContextID, nProfiles, hProfiles, BPC, Intents, AdaptationStates, NULL, 0, InputFormat, OutputFormat, dwFlags);
}
cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransform(cmsHPROFILE hProfiles[],
cmsUInt32Number nProfiles,
cmsUInt32Number InputFormat,
cmsUInt32Number OutputFormat,
cmsUInt32Number Intent,
cmsUInt32Number dwFlags)
{
if (nProfiles <= 0 || nProfiles > 255) {
cmsSignalError(NULL, cmsERROR_RANGE, "Wrong number of profiles. 1..255 expected, %d found.", nProfiles);
return NULL;
}
return cmsCreateMultiprofileTransformTHR(cmsGetProfileContextID(hProfiles[0]),
hProfiles,
nProfiles,
InputFormat,
OutputFormat,
Intent,
dwFlags);
}
cmsHTRANSFORM CMSEXPORT cmsCreateTransformTHR(cmsContext ContextID,
cmsHPROFILE Input,
cmsUInt32Number InputFormat,
cmsHPROFILE Output,
cmsUInt32Number OutputFormat,
cmsUInt32Number Intent,
cmsUInt32Number dwFlags)
{
cmsHPROFILE hArray[2];
hArray[0] = Input;
hArray[1] = Output;
return cmsCreateMultiprofileTransformTHR(ContextID, hArray, Output == NULL ? 1 : 2, InputFormat, OutputFormat, Intent, dwFlags);
}
CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateTransform(cmsHPROFILE Input,
cmsUInt32Number InputFormat,
cmsHPROFILE Output,
cmsUInt32Number OutputFormat,
cmsUInt32Number Intent,
cmsUInt32Number dwFlags)
{
return cmsCreateTransformTHR(cmsGetProfileContextID(Input), Input, InputFormat, Output, OutputFormat, Intent, dwFlags);
}
cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransformTHR(cmsContext ContextID,
cmsHPROFILE InputProfile,
cmsUInt32Number InputFormat,
cmsHPROFILE OutputProfile,
cmsUInt32Number OutputFormat,
cmsHPROFILE ProofingProfile,
cmsUInt32Number nIntent,
cmsUInt32Number ProofingIntent,
cmsUInt32Number dwFlags)
{
cmsHPROFILE hArray[4];
cmsUInt32Number Intents[4];
cmsBool BPC[4];
cmsFloat64Number Adaptation[4];
cmsBool DoBPC = (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION) ? TRUE : FALSE;
hArray[0] = InputProfile; hArray[1] = ProofingProfile; hArray[2] = ProofingProfile; hArray[3] = OutputProfile;
Intents[0] = nIntent; Intents[1] = nIntent; Intents[2] = INTENT_RELATIVE_COLORIMETRIC; Intents[3] = ProofingIntent;
BPC[0] = DoBPC; BPC[1] = DoBPC; BPC[2] = 0; BPC[3] = 0;
Adaptation[0] = Adaptation[1] = Adaptation[2] = Adaptation[3] = cmsSetAdaptationStateTHR(ContextID, -1);
if (!(dwFlags & (cmsFLAGS_SOFTPROOFING|cmsFLAGS_GAMUTCHECK)))
return cmsCreateTransformTHR(ContextID, InputProfile, InputFormat, OutputProfile, OutputFormat, nIntent, dwFlags);
return cmsCreateExtendedTransform(ContextID, 4, hArray, BPC, Intents, Adaptation,
ProofingProfile, 1, InputFormat, OutputFormat, dwFlags);
}
cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile,
cmsUInt32Number InputFormat,
cmsHPROFILE OutputProfile,
cmsUInt32Number OutputFormat,
cmsHPROFILE ProofingProfile,
cmsUInt32Number nIntent,
cmsUInt32Number ProofingIntent,
cmsUInt32Number dwFlags)
{
return cmsCreateProofingTransformTHR(cmsGetProfileContextID(InputProfile),
InputProfile,
InputFormat,
OutputProfile,
OutputFormat,
ProofingProfile,
nIntent,
ProofingIntent,
dwFlags);
}
cmsContext CMSEXPORT cmsGetTransformContextID(cmsHTRANSFORM hTransform)
{
_cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
if (xform == NULL) return NULL;
return xform -> ContextID;
}
cmsUInt32Number CMSEXPORT cmsGetTransformInputFormat(cmsHTRANSFORM hTransform)
{
_cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
if (xform == NULL) return 0;
return xform->InputFormat;
}
cmsUInt32Number CMSEXPORT cmsGetTransformOutputFormat(cmsHTRANSFORM hTransform)
{
_cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
if (xform == NULL) return 0;
return xform->OutputFormat;
}
cmsBool CMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform,
cmsUInt32Number InputFormat,
cmsUInt32Number OutputFormat)
{
_cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
cmsFormatter16 FromInput, ToOutput;
if (!(xform ->dwOriginalFlags & cmsFLAGS_CAN_CHANGE_FORMATTER)) {
cmsSignalError(xform ->ContextID, cmsERROR_NOT_SUITABLE, "cmsChangeBuffersFormat works only on transforms created originally with at least 16 bits of precision");
return FALSE;
}
FromInput = _cmsGetFormatter(xform->ContextID, InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
ToOutput = _cmsGetFormatter(xform->ContextID, OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
if (FromInput == NULL || ToOutput == NULL) {
cmsSignalError(xform -> ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
return FALSE;
}
xform ->InputFormat = InputFormat;
xform ->OutputFormat = OutputFormat;
xform ->FromInput = FromInput;
xform ->ToOutput = ToOutput;
return TRUE;
}