cmsHANDLE CMSEXPORT cmsCIECAM02Init(cmsContext ContextID, const cmsViewingConditions* pVC) { cmsCIECAM02* lpMod; _cmsAssert(pVC != NULL); if((lpMod = (cmsCIECAM02*) _cmsMallocZero(ContextID, sizeof(cmsCIECAM02))) == NULL) { return NULL; } lpMod ->ContextID = ContextID; lpMod ->adoptedWhite.XYZ[0] = pVC ->whitePoint.X; lpMod ->adoptedWhite.XYZ[1] = pVC ->whitePoint.Y; lpMod ->adoptedWhite.XYZ[2] = pVC ->whitePoint.Z; lpMod -> LA = pVC ->La; lpMod -> Yb = pVC ->Yb; lpMod -> D = pVC ->D_value; lpMod -> surround = pVC ->surround; switch (lpMod -> surround) { case CUTSHEET_SURROUND: lpMod->F = 0.8; lpMod->c = 0.41; lpMod->Nc = 0.8; break; case DARK_SURROUND: lpMod -> F = 0.8; lpMod -> c = 0.525; lpMod -> Nc = 0.8; break; case DIM_SURROUND: lpMod -> F = 0.9; lpMod -> c = 0.59; lpMod -> Nc = 0.95; break; default: // Average surround lpMod -> F = 1.0; lpMod -> c = 0.69; lpMod -> Nc = 1.0; } lpMod -> n = compute_n(lpMod); lpMod -> z = compute_z(lpMod); lpMod -> Nbb = computeNbb(lpMod); lpMod -> FL = computeFL(lpMod); if (lpMod -> D == D_CALCULATE) { lpMod -> D = computeD(lpMod); } lpMod -> Ncb = lpMod -> Nbb; lpMod -> adoptedWhite = XYZtoCAT02(lpMod -> adoptedWhite); lpMod -> adoptedWhite = ChromaticAdaptation(lpMod -> adoptedWhite, lpMod); lpMod -> adoptedWhite = CAT02toHPE(lpMod -> adoptedWhite); lpMod -> adoptedWhite = NonlinearCompression(lpMod -> adoptedWhite, lpMod); return (cmsHANDLE) lpMod; }
// Low level allocate, which takes care of memory details. nEntries may be zero, and in this case // no optimation curve is computed. nSegments may also be zero in the inverse case, where only the // optimization curve is given. Both features simultaneously is an error static cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsInt32Number nEntries, cmsInt32Number nSegments, const cmsCurveSegment* Segments, const cmsUInt16Number* Values) { cmsToneCurve* p; int i; // We allow huge tables, which are then restricted for smoothing operations if (nEntries > 65530 || nEntries < 0) { cmsSignalError(ContextID, cmsERROR_RANGE, "Couldn't create tone curve of more than 65530 entries"); return NULL; } if (nEntries <= 0 && nSegments <= 0) { cmsSignalError(ContextID, cmsERROR_RANGE, "Couldn't create tone curve with zero segments and no table"); return NULL; } // Allocate all required pointers, etc. p = (cmsToneCurve*) _cmsMallocZero(ContextID, sizeof(cmsToneCurve)); if (!p) return NULL; // In this case, there are no segments if (nSegments <= 0) { p ->Segments = NULL; p ->Evals = NULL; } else { p ->Segments = (cmsCurveSegment*) _cmsCalloc(ContextID, nSegments, sizeof(cmsCurveSegment)); if (p ->Segments == NULL) goto Error; p ->Evals = (cmsParametricCurveEvaluator*) _cmsCalloc(ContextID, nSegments, sizeof(cmsParametricCurveEvaluator)); if (p ->Evals == NULL) goto Error; } p -> nSegments = nSegments; // This 16-bit table contains a limited precision representation of the whole curve and is kept for // increasing xput on certain operations. if (nEntries <= 0) { p ->Table16 = NULL; } else { p ->Table16 = (cmsUInt16Number*) _cmsCalloc(ContextID, nEntries, sizeof(cmsUInt16Number)); if (p ->Table16 == NULL) goto Error; } p -> nEntries = nEntries; // Initialize members if requested if (Values != NULL && (nEntries > 0)) { for (i=0; i < nEntries; i++) p ->Table16[i] = Values[i]; } // Initialize the segments stuff. The evaluator for each segment is located and a pointer to it // is placed in advance to maximize performance. if (Segments != NULL && (nSegments > 0)) { _cmsParametricCurvesCollection *c; p ->SegInterp = (cmsInterpParams**) _cmsCalloc(ContextID, nSegments, sizeof(cmsInterpParams*)); if (p ->SegInterp == NULL) goto Error; for (i=0; i< nSegments; i++) { // Type 0 is a special marker for table-based curves if (Segments[i].Type == 0) p ->SegInterp[i] = _cmsComputeInterpParams(ContextID, Segments[i].nGridPoints, 1, 1, NULL, CMS_LERP_FLAGS_FLOAT); memmove(&p ->Segments[i], &Segments[i], sizeof(cmsCurveSegment)); if (Segments[i].Type == 0 && Segments[i].SampledPoints != NULL) p ->Segments[i].SampledPoints = (cmsFloat32Number*) _cmsDupMem(ContextID, Segments[i].SampledPoints, sizeof(cmsFloat32Number) * Segments[i].nGridPoints); else p ->Segments[i].SampledPoints = NULL; c = GetParametricCurveByType(Segments[i].Type, NULL); if (c != NULL) p ->Evals[i] = c ->Evaluator; } } p ->InterpParams = _cmsComputeInterpParams(ContextID, p ->nEntries, 1, 1, p->Table16, CMS_LERP_FLAGS_16BITS); return p; Error: if (p -> Segments) _cmsFree(ContextID, p ->Segments); if (p -> Evals) _cmsFree(ContextID, p -> Evals); if (p ->Table16) _cmsFree(ContextID, p ->Table16); _cmsFree(ContextID, p); return NULL; }
// 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, cmsPipeline* lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) { _cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID, TransformPlugin); _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 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)) { // 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(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; // Save the day? if (Plugin->OldXform) { p->OldXform = (_cmsTransformFn) p->xform; p->xform = _cmsTransform2toTransformAdaptor; } return p; } } // Not suitable for the transform plug-in, let's check the pipeline plug-in _cmsOptimizePipeline(ContextID, &p->Lut, Intent, InputFormat, OutputFormat, dwFlags); } // Check whatever this is a true floating point transform 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(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 { // Float transforms don't use caché, always are non-NULL 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; // Gamut check, no caché else p ->xform = PrecalculatedXFORM; // No caché, no gamut check } else { 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 ->ContextID = ContextID; p ->UserData = NULL; return p; }