// Little Color Management System
// Copyright (c) 1998-2011 Marti Maria Saguer
//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the "Software"),
-// to deal in the Software without restriction, including without limitation
-// the rights to use, copy, modify, merge, publish, distribute, sublicense,
-// and/or sell copies of the Software, and to permit persons to whom the Software
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following conditions:
//
-// The above copyright notice and this permission notice shall be included in
+// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
-// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//---------------------------------------------------------------------------------
{
cmsFloat64Number OldVal = GlobalAdaptationState;
- if (d >= 0)
+ if (d >= 0)
GlobalAdaptationState = d;
- return OldVal;
+ return OldVal;
}
// Alarm codes are always global
_cmsAssert(NewAlarm != NULL);
- for (i=0; i < cmsMAXCHANNELS; i++)
+ for (i=0; i < cmsMAXCHANNELS; i++)
Alarm[i] = NewAlarm[i];
}
_cmsAssert(OldAlarm != NULL);
- for (i=0; i < cmsMAXCHANNELS; i++)
+ for (i=0; i < cmsMAXCHANNELS; i++)
OldAlarm[i] = Alarm[i];
}
if (p ->Sequence)
cmsFreeProfileSequenceDescription(p ->Sequence);
+ if (p ->UserData)
+ p ->FreeUserData(p ->ContextID, p ->UserData);
+
_cmsFree(p ->ContextID, (void *) p);
}
-// Apply transform.
+// Apply transform.
void CMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform,
const void* InputBuffer,
- void* OutputBuffer,
+ void* OutputBuffer,
cmsUInt32Number Size)
{
_cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform;
-
- p -> xform(p, InputBuffer, OutputBuffer, Size);
+
+ p -> xform(p, InputBuffer, OutputBuffer, Size, Size);
+}
+
+
+// Apply transform.
+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);
}
// Float xform converts floats. Since there are no performance issues, one routine does all job, including gamut check.
// Note that because extended range, we can use a -1.0 value for out of gamut in this case.
static
-void FloatXFORM(_cmsTRANSFORM* p,
+void FloatXFORM(_cmsTRANSFORM* p,
const void* in,
- void* out, cmsUInt32Number Size)
+ void* out, cmsUInt32Number Size, cmsUInt32Number Stride)
{
cmsUInt8Number* accum;
cmsUInt8Number* output;
for (i=0; i < Size; i++) {
- accum = p -> FromInputFloat(p, fIn, accum, Size);
+ accum = p -> FromInputFloat(p, fIn, accum, Stride);
// Any gamut chack to do?
if (p ->GamutCheck != NULL) {
}
else {
// No, proceed normally
- cmsPipelineEvalFloat(fIn, fOut, p -> Lut);
+ cmsPipelineEvalFloat(fIn, fOut, p -> Lut);
}
}
else {
// No gamut check at all
- cmsPipelineEvalFloat(fIn, fOut, p -> Lut);
+ cmsPipelineEvalFloat(fIn, fOut, p -> Lut);
}
// Back to asked representation
- output = p -> ToOutputFloat(p, fOut, output, Size);
+ output = p -> ToOutputFloat(p, fOut, output, Stride);
}
}
static
void NullXFORM(_cmsTRANSFORM* p,
const void* in,
- void* out, cmsUInt32Number Size)
+ void* out, cmsUInt32Number Size,
+ cmsUInt32Number Stride)
{
cmsUInt8Number* accum;
cmsUInt8Number* output;
for (i=0; i < n; i++) {
- accum = p -> FromInput(p, wIn, accum, Size);
- output = p -> ToOutput(p, wIn, output, Size);
+ 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)
+ void* out, cmsUInt32Number Size, cmsUInt32Number Stride)
{
register cmsUInt8Number* accum;
register cmsUInt8Number* output;
accum = (cmsUInt8Number*) in;
output = (cmsUInt8Number*) out;
- n = Size;
+ n = Size;
for (i=0; i < n; i++) {
- accum = p -> FromInput(p, wIn, accum, Size);
- p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
- output = p -> ToOutput(p, wOut, output, Size);
+ accum = p -> FromInput(p, wIn, accum, Stride);
+ p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
+ output = p -> ToOutput(p, wOut, output, Stride);
}
}
// Auxiliar: Handle precalculated gamut check
static
-void TransformOnePixelWithGamutCheck(_cmsTRANSFORM* p,
- const cmsUInt16Number wIn[],
+void TransformOnePixelWithGamutCheck(_cmsTRANSFORM* p,
+ const cmsUInt16Number wIn[],
cmsUInt16Number wOut[])
{
cmsUInt16Number wOutOfGamut;
- p ->GamutCheck ->Eval16Fn(wIn, &wOutOfGamut, p ->GamutCheck ->Data);
+ p ->GamutCheck ->Eval16Fn(wIn, &wOutOfGamut, p ->GamutCheck ->Data);
if (wOutOfGamut >= 1) {
cmsUInt16Number i;
for (i=0; i < p ->Lut->OutputChannels; i++)
- wOut[i] = Alarm[i];
+ wOut[i] = Alarm[i];
}
else
- p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
+ p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
}
// Gamut check, No caché, 16 bits.
static
void PrecalculatedXFORMGamutCheck(_cmsTRANSFORM* p,
const void* in,
- void* out, cmsUInt32Number Size)
+ void* out, cmsUInt32Number Size, cmsUInt32Number Stride)
{
cmsUInt8Number* accum;
cmsUInt8Number* output;
for (i=0; i < n; i++) {
- accum = p -> FromInput(p, wIn, accum, Size);
+ accum = p -> FromInput(p, wIn, accum, Stride);
TransformOnePixelWithGamutCheck(p, wIn, wOut);
- output = p -> ToOutput(p, wOut, output, Size);
+ output = p -> ToOutput(p, wOut, output, Stride);
}
}
-// No gamut check, Caché, 16 bits,
+// No gamut check, Caché, 16 bits,
static
void CachedXFORM(_cmsTRANSFORM* p,
const void* in,
- void* out, cmsUInt32Number Size)
+ void* out, cmsUInt32Number Size, cmsUInt32Number Stride)
{
cmsUInt8Number* accum;
cmsUInt8Number* output;
for (i=0; i < n; i++) {
- accum = p -> FromInput(p, wIn, accum, Size);
+ accum = p -> FromInput(p, wIn, accum, Stride);
if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) {
memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut));
}
- else {
+ else {
- p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
+ 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, Size);
+ output = p -> ToOutput(p, wOut, output, Stride);
}
-
+
}
static
void CachedXFORMGamutCheck(_cmsTRANSFORM* p,
const void* in,
- void* out, cmsUInt32Number Size)
+ void* out, cmsUInt32Number Size, cmsUInt32Number Stride)
{
cmsUInt8Number* accum;
cmsUInt8Number* output;
for (i=0; i < n; i++) {
- accum = p -> FromInput(p, wIn, accum, Size);
-
+ accum = p -> FromInput(p, wIn, accum, Stride);
+
if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) {
memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut));
}
- else {
+ 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, Size);
+ output = p -> ToOutput(p, wOut, output, Stride);
}
-
+
+}
+
+// -------------------------------------------------------------------------------------------------------------
+
+// List of used-defined transform factories
+typedef struct _cmsTransformCollection_st {
+
+ _cmsTransformFactory Factory;
+ struct _cmsTransformCollection_st *Next;
+
+} _cmsTransformCollection;
+
+// The linked list head
+static _cmsTransformCollection* TransformCollection = NULL;
+
+// Register new ways to transform
+cmsBool _cmsRegisterTransformPlugin(cmsPluginBase* Data)
+{
+ cmsPluginTransform* Plugin = (cmsPluginTransform*) Data;
+ _cmsTransformCollection* fl;
+
+ if (Data == NULL) {
+
+ // Free the chain. Memory is safely freed at exit
+ TransformCollection = NULL;
+ return TRUE;
+ }
+
+ // Factory callback is required
+ if (Plugin ->Factory == NULL) return FALSE;
+
+
+ fl = (_cmsTransformCollection*) _cmsPluginMalloc(sizeof(_cmsTransformCollection));
+ if (fl == NULL) return FALSE;
+
+ // Copy the parameters
+ fl ->Factory = Plugin ->Factory;
+
+ // Keep linked list
+ fl ->Next = TransformCollection;
+ TransformCollection = fl;
+
+ // All is ok
+ return TRUE;
}
+void CMSEXPORT _cmsSetTransformUserData(struct _cmstransform_struct *CMMcargo, void* ptr, _cmsFreeUserDataFn FreePrivateDataFn)
+{
+ _cmsAssert(CMMcargo != NULL);
+ CMMcargo ->UserData = ptr;
+ CMMcargo ->FreeUserData = FreePrivateDataFn;
+}
+// returns the pointer defined by the plug-in to store private data
+void * CMSEXPORT _cmsGetTransformUserData(struct _cmstransform_struct *CMMcargo)
+{
+ _cmsAssert(CMMcargo != NULL);
+ return CMMcargo ->UserData;
+}
-// Allocate transform struct and set it to defaults
+// returns the current formatters
+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;
+}
+
+
+// Allocate transform struct and set it to defaults. Ask the optimization plug-in about if those formats are proper
+// for separated transforms. If this is the case,
static
-_cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsUInt32Number InputFormat, cmsUInt32Number OutputFormat, cmsUInt32Number dwFlags)
+_cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,
+ cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags)
{
+ _cmsTransformCollection* Plugin;
+
// Allocate needed memory
_cmsTRANSFORM* p = (_cmsTRANSFORM*) _cmsMallocZero(ContextID, sizeof(_cmsTRANSFORM));
if (!p) return NULL;
+ // Store the proposed pipeline
+ p ->Lut = lut;
+
+ // Let's see if any plug-in want to do the transform by itself
+ for (Plugin = TransformCollection;
+ Plugin != NULL;
+ Plugin = Plugin ->Next) {
+
+ if (Plugin ->Factory(&p->xform, &p->UserData, &p ->FreeUserData, &p ->Lut, InputFormat, OutputFormat, dwFlags)) {
+
+ // Last plugin in the declaration order takes control. We just keep
+ // the original parameters as a logging.
+ // Note that cmsFLAGS_CAN_CHANGE_FORMATTER is not set, so by default
+ // an optimized transform is not reusable. The plug-in can, however, change
+ // the flags and make it suitable.
+
+ p ->ContextID = ContextID;
+ p ->InputFormat = *InputFormat;
+ p ->OutputFormat = *OutputFormat;
+ p ->dwOriginalFlags = *dwFlags;
+
+ // Fill the formatters just in case the optimized routine is interested.
+ // No error is thrown if the formatter doesn't exist. It is up to the optimization
+ // factory to decide what to do in those cases.
+ p ->FromInput = _cmsGetFormatter(*InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
+ p ->ToOutput = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
+ p ->FromInputFloat = _cmsGetFormatter(*InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
+ p ->ToOutputFloat = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
+
+ return p;
+ }
+ }
+
+ // Not suitable for the transform plug-in, let's check the pipeline plug-in
+ if (p ->Lut != NULL)
+ _cmsOptimizePipeline(&p->Lut, Intent, InputFormat, OutputFormat, dwFlags);
+
// Check whatever this is a true floating point transform
- if (_cmsFormatterIsFloat(InputFormat) && _cmsFormatterIsFloat(OutputFormat)) {
+ if (_cmsFormatterIsFloat(*InputFormat) && _cmsFormatterIsFloat(*OutputFormat)) {
// Get formatter function always return a valid union, but the contents of this union may be NULL.
- p ->FromInputFloat = _cmsGetFormatter(InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
- p ->ToOutputFloat = _cmsGetFormatter(OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
- dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
+ p ->FromInputFloat = _cmsGetFormatter(*InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
+ p ->ToOutputFloat = _cmsGetFormatter(*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;
}
else {
- if (InputFormat == 0 && OutputFormat == 0) {
+ if (*InputFormat == 0 && *OutputFormat == 0) {
p ->FromInput = p ->ToOutput = NULL;
+ *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
}
else {
int BytesPerPixelInput;
- p ->FromInput = _cmsGetFormatter(InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
- p ->ToOutput = _cmsGetFormatter(OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
-
+ p ->FromInput = _cmsGetFormatter(*InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
+ p ->ToOutput = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
if (p ->FromInput == NULL || p ->ToOutput == NULL) {
}
BytesPerPixelInput = T_BYTES(p ->InputFormat);
- if (BytesPerPixelInput == 0 || BytesPerPixelInput >= 2)
- dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
+ if (BytesPerPixelInput == 0 || BytesPerPixelInput >= 2)
+ *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
}
- if (dwFlags & cmsFLAGS_NULLTRANSFORM) {
+ if (*dwFlags & cmsFLAGS_NULLTRANSFORM) {
p ->xform = NullXFORM;
}
else {
- if (dwFlags & cmsFLAGS_NOCACHE) {
+ if (*dwFlags & cmsFLAGS_NOCACHE) {
- if (dwFlags & cmsFLAGS_GAMUTCHECK)
+ if (*dwFlags & cmsFLAGS_GAMUTCHECK)
p ->xform = PrecalculatedXFORMGamutCheck; // Gamut check, no caché
else
p ->xform = PrecalculatedXFORM; // No caché, no gamut check
}
else {
- if (dwFlags & cmsFLAGS_GAMUTCHECK)
+ if (*dwFlags & cmsFLAGS_GAMUTCHECK)
p ->xform = CachedXFORMGamutCheck; // Gamut check, caché
else
p ->xform = CachedXFORM; // No gamut check, caché
}
}
-
- p ->InputFormat = InputFormat;
- p ->OutputFormat = OutputFormat;
- p ->dwOriginalFlags = dwFlags;
+ 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;
+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]);
- // Special handling for named color profiles as devicelinks
- if (nProfiles == 1 && cmsGetDeviceClass(hProfiles[0]) == cmsSigNamedColorClass) {
- *Input = cmsSig1colorData;
- *Output = PostColorSpace;
- return TRUE;
- }
-
for (i=0; i < nProfiles; i++) {
+ cmsProfileClassSignature cls;
cmsHPROFILE hProfile = hProfiles[i];
int lIsInput = (PostColorSpace != cmsSigXYZData) &&
(PostColorSpace != cmsSigLabData);
- int lIsDeviceLink;
-
if (hProfile == NULL) return FALSE;
- lIsDeviceLink = (cmsGetDeviceClass(hProfile) == cmsSigLinkClass);
+ cls = cmsGetDeviceClass(hProfile);
- if (lIsInput || lIsDeviceLink) {
+ if (cls == cmsSigNamedColorClass) {
+
+ ColorSpaceIn = cmsSig1colorData;
+ ColorSpaceOut = (nProfiles > 1) ? cmsGetPCS(hProfile) : cmsGetColorSpace(hProfile);
+ }
+ else
+ if (lIsInput || (cls == cmsSigLinkClass)) {
ColorSpaceIn = cmsGetColorSpace(hProfile);
ColorSpaceOut = cmsGetPCS(hProfile);
}
- else {
-
+ else
+ {
ColorSpaceIn = cmsGetPCS(hProfile);
ColorSpaceOut = cmsGetColorSpace(hProfile);
}
- PostColorSpace = ColorSpaceOut;
- }
+ if (i==0)
+ *Input = ColorSpaceIn;
+
+ PostColorSpace = ColorSpaceOut;
+ }
*Output = PostColorSpace;
// New to lcms 2.0 -- have all parameters available.
cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID,
- cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[],
- cmsBool BPC[],
- cmsUInt32Number Intents[],
+ cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[],
+ cmsBool BPC[],
+ cmsUInt32Number Intents[],
cmsFloat64Number AdaptationStates[],
cmsHPROFILE hGamutProfile,
- cmsUInt32Number nGamutPCSposition,
+ cmsUInt32Number nGamutPCSposition,
cmsUInt32Number InputFormat,
cmsUInt32Number OutputFormat,
cmsUInt32Number dwFlags)
cmsPipeline* Lut;
cmsUInt32Number LastIntent = Intents[nProfiles-1];
+ // If it is a fake transform
+ if (dwFlags & cmsFLAGS_NULLTRANSFORM)
+ {
+ return AllocEmptyTransform(ContextID, NULL, INTENT_PERCEPTUAL, &InputFormat, &OutputFormat, &dwFlags);
+ }
+
// If gamut check is requested, make sure we have a gamut profile
if (dwFlags & cmsFLAGS_GAMUTCHECK) {
if (hGamutProfile == NULL) dwFlags &= ~cmsFLAGS_GAMUTCHECK;
}
- // On floating point transforms, inhibit optimizations
+ // On floating point transforms, inhibit optimizations
FloatTransform = (_cmsFormatterIsFloat(InputFormat) && _cmsFormatterIsFloat(OutputFormat));
if (_cmsFormatterIsFloat(InputFormat) || _cmsFormatterIsFloat(OutputFormat))
// Mark entry/exit spaces
if (!GetXFormColorSpaces(nProfiles, hProfiles, &EntryColorSpace, &ExitColorSpace)) {
- cmsSignalError(ContextID, cmsERROR_NULL, "NULL input profiles on transform");
+ cmsSignalError(ContextID, cmsERROR_NULL, "NULL input profiles on transform");
return NULL;
}
// Check if proper colorspaces
- if (!IsProperColorSpace(EntryColorSpace, InputFormat)) {
- cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong input color space on transform");
+ 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");
+ cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong output color space on transform");
return NULL;
}
// Create a pipeline with all transformations
Lut = _cmsLinkProfiles(ContextID, nProfiles, Intents, hProfiles, BPC, AdaptationStates, dwFlags);
if (Lut == NULL) {
- cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Couldn't link the profiles");
+ cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Couldn't link the profiles");
return NULL;
}
- // Optimize the LUT if possible
- _cmsOptimizePipeline(&Lut, LastIntent, &InputFormat, &OutputFormat, &dwFlags);
+ // Check channel count
+ if ((cmsChannelsOf(EntryColorSpace) != cmsPipelineInputChannels(Lut)) ||
+ (cmsChannelsOf(ExitColorSpace) != cmsPipelineOutputChannels(Lut))) {
+ cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Channel count doesn't match. Profile is corrupted");
+ return NULL;
+ }
// All seems ok
- xform = AllocEmptyTransform(ContextID, InputFormat, OutputFormat, dwFlags);
+ xform = AllocEmptyTransform(ContextID, Lut, LastIntent, &InputFormat, &OutputFormat, &dwFlags);
if (xform == NULL) {
- cmsPipelineFree(Lut);
return NULL;
}
xform ->EntryColorSpace = EntryColorSpace;
xform ->ExitColorSpace = ExitColorSpace;
xform ->RenderingIntent = Intents[nProfiles-1];
- xform ->Lut = Lut;
-
+
+
// Create a gamut check LUT if requested
- if (hGamutProfile != NULL && (dwFlags & cmsFLAGS_GAMUTCHECK))
- xform ->GamutCheck = _cmsCreateGamutCheckPipeline(ContextID, hProfiles,
- BPC, Intents,
- AdaptationStates,
- nGamutPCSposition,
+ if (hGamutProfile != NULL && (dwFlags & cmsFLAGS_GAMUTCHECK))
+ xform ->GamutCheck = _cmsCreateGamutCheckPipeline(ContextID, hProfiles,
+ BPC, Intents,
+ AdaptationStates,
+ nGamutPCSposition,
hGamutProfile);
// Try to read input and output colorant table
if (cmsIsTag(hProfiles[0], cmsSigColorantTableTag)) {
- // Input table can only come in this way.
+ // Input table can only come in this way.
xform ->InputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[0], cmsSigColorantTableTag));
}
- // Output is a little bit more complex.
+ // Output is a little bit more complex.
if (cmsGetDeviceClass(hProfiles[nProfiles-1]) == cmsSigLinkClass) {
- // This tag may exist only on devicelink profiles.
+ // This tag may exist only on devicelink profiles.
if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableOutTag)) {
// It may be NULL if error
if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableTag)) {
xform -> OutputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[nProfiles-1], cmsSigColorantTableTag));
- }
+ }
}
// Store the sequence of profiles
if (dwFlags & cmsFLAGS_KEEP_SEQUENCE) {
xform ->Sequence = _cmsCompileProfileSequence(ContextID, nProfiles, hProfiles);
}
- else
+ else
xform ->Sequence = NULL;
// If this is a cached transform, init first value, which is zero (16 bits only)
}
else {
- xform ->Lut ->Eval16Fn(xform ->Cache.CacheIn, xform->Cache.CacheOut, xform -> Lut->Data);
+ xform ->Lut ->Eval16Fn(xform ->Cache.CacheIn, xform->Cache.CacheOut, xform -> Lut->Data);
}
}
- return (cmsHTRANSFORM) xform;
+ return (cmsHTRANSFORM) xform;
}
// Multiprofile transforms: Gamut check is not available here, as it is unclear from which profile the gamut comes.
{
cmsHPROFILE hArray[2];
-
+
hArray[0] = Input;
hArray[1] = Output;
cmsUInt32Number nIntent,
cmsUInt32Number ProofingIntent,
cmsUInt32Number dwFlags)
-{
+{
cmsHPROFILE hArray[4];
cmsUInt32Number Intents[4];
cmsBool BPC[4];
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] = GlobalAdaptationState;
- if (!(dwFlags & (cmsFLAGS_SOFTPROOFING|cmsFLAGS_GAMUTCHECK)))
+ if (!(dwFlags & (cmsFLAGS_SOFTPROOFING|cmsFLAGS_GAMUTCHECK)))
return cmsCreateTransformTHR(ContextID, InputProfile, InputFormat, OutputProfile, OutputFormat, nIntent, dwFlags);
-
- return cmsCreateExtendedTransform(ContextID, 4, hArray, BPC, Intents, Adaptation,
+
+ return cmsCreateExtendedTransform(ContextID, 4, hArray, BPC, Intents, Adaptation,
ProofingProfile, 1, InputFormat, OutputFormat, dwFlags);
}
cmsUInt32Number ProofingIntent,
cmsUInt32Number dwFlags)
{
- return cmsCreateProofingTransformTHR(cmsGetProfileContextID(InputProfile),
+ return cmsCreateProofingTransformTHR(cmsGetProfileContextID(InputProfile),
InputProfile,
InputFormat,
OutputProfile,
}
// For backwards compatibility
-cmsBool CMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform,
- cmsUInt32Number InputFormat,
+cmsBool CMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform,
+ cmsUInt32Number InputFormat,
cmsUInt32Number OutputFormat)
{
_cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
cmsFormatter16 FromInput, ToOutput;
- cmsUInt32Number BytesPerPixelInput;
+
// We only can afford to change formatters if previous transform is at least 16 bits
- BytesPerPixelInput = T_BYTES(xform ->InputFormat);
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");