// Register new ways to transform cmsBool _cmsRegisterTransformPlugin(cmsContext ContextID, cmsPluginBase* Data) { cmsPluginTransform* Plugin = (cmsPluginTransform*) Data; _cmsTransformCollection* fl; _cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID,TransformPlugin); if (Data == NULL) { // Free the chain. Memory is safely freed at exit ctx->TransformCollection = NULL; return TRUE; } // Factory callback is required if (Plugin ->Factory == NULL) return FALSE; fl = (_cmsTransformCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsTransformCollection)); if (fl == NULL) return FALSE; // Copy the parameters fl ->Factory = Plugin ->Factory; // Keep linked list fl ->Next = ctx->TransformCollection; ctx->TransformCollection = fl; // All is ok return TRUE; }
// Get information about available intents. nMax is the maximum space for the supplied "Codes" // and "Descriptions" the function returns the total number of intents, which may be greater // than nMax, although the matrices are not populated beyond this level. cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions) { _cmsIntentsPluginChunkType* ctx = ( _cmsIntentsPluginChunkType*) _cmsContextGetClientChunk(ContextID, IntentPlugin); cmsIntentsList* pt; cmsUInt32Number nIntents; for (nIntents=0, pt = ctx->Intents; pt != NULL; pt = pt -> Next) { if (nIntents < nMax) { if (Codes != NULL) Codes[nIntents] = pt ->Intent; if (Descriptions != NULL) Descriptions[nIntents] = pt ->Description; } nIntents++; } for (nIntents=0, pt = DefaultIntents; pt != NULL; pt = pt -> Next) { if (nIntents < nMax) { if (Codes != NULL) Codes[nIntents] = pt ->Intent; if (Descriptions != NULL) Descriptions[nIntents] = pt ->Description; } nIntents++; } return nIntents; }
// Generic free memory void CMSEXPORT _cmsFree(cmsContext ContextID, void* Ptr) { if (Ptr != NULL) { _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); ptr ->FreePtr(ContextID, Ptr); } }
// The plug-in registration. User can add new intents or override default routines cmsBool _cmsRegisterRenderingIntentPlugin(cmsContext id, cmsPluginBase* Data) { _cmsIntentsPluginChunkType* ctx = ( _cmsIntentsPluginChunkType*) _cmsContextGetClientChunk(id, IntentPlugin); cmsPluginRenderingIntent* Plugin = (cmsPluginRenderingIntent*) Data; cmsIntentsList* fl; // Do we have to reset the custom intents? if (Data == NULL) { ctx->Intents = NULL; return TRUE; } fl = (cmsIntentsList*) _cmsPluginMalloc(id, sizeof(cmsIntentsList)); if (fl == NULL) return FALSE; fl ->Intent = Plugin ->Intent; strncpy(fl ->Description, Plugin ->Description, sizeof(fl ->Description)-1); fl ->Description[sizeof(fl ->Description)-1] = 0; fl ->Link = Plugin ->Link; fl ->Next = ctx ->Intents; ctx ->Intents = fl; return TRUE; }
// Register new ways to transform cmsBool _cmsRegisterMutexPlugin(cmsContext ContextID, cmsPluginBase* Data) { cmsPluginMutex* Plugin = (cmsPluginMutex*) Data; _cmsMutexPluginChunkType* ctx = ( _cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); if (Data == NULL) { // No lock routines ctx->CreateMutexPtr = NULL; ctx->DestroyMutexPtr = NULL; ctx->LockMutexPtr = NULL; ctx ->UnlockMutexPtr = NULL; return TRUE; } // Factory callback is required if (Plugin ->CreateMutexPtr == NULL || Plugin ->DestroyMutexPtr == NULL || Plugin ->LockMutexPtr == NULL || Plugin ->UnlockMutexPtr == NULL) return FALSE; ctx->CreateMutexPtr = Plugin->CreateMutexPtr; ctx->DestroyMutexPtr = Plugin ->DestroyMutexPtr; ctx ->LockMutexPtr = Plugin ->LockMutexPtr; ctx ->UnlockMutexPtr = Plugin ->UnlockMutexPtr; // All is ok return TRUE; }
// Plug-in replacement entry cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase *Data) { cmsPluginMemHandler* Plugin = (cmsPluginMemHandler*) Data; _cmsMemPluginChunkType* ptr; // NULL forces to reset to defaults. In this special case, the defaults are stored in the context structure. // Remaining plug-ins does NOT have any copy in the context structure, but this is somehow special as the // context internal data should be malloce'd by using those functions. if (Data == NULL) { struct _cmsContext_struct* ctx = ( struct _cmsContext_struct*) ContextID; // Return to the default allocators if (ContextID != NULL) { ctx->chunks[MemPlugin] = (void*) &ctx->DefaultMemoryManager; } return TRUE; } // Check for required callbacks if (Plugin -> MallocPtr == NULL || Plugin -> FreePtr == NULL || Plugin -> ReallocPtr == NULL) return FALSE; // Set replacement functions ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); if (ptr == NULL) return FALSE; _cmsInstallAllocFunctions(Plugin, ptr); return TRUE; }
// Sets the codes used to mark out-out-gamut on Proofing transforms for a given context. Values are meant to be // encoded in 16 bits. void CMSEXPORT cmsSetAlarmCodesTHR(cmsContext ContextID, const cmsUInt16Number AlarmCodesP[cmsMAXCHANNELS]) { _cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(ContextID, AlarmCodesContext); _cmsAssert(ContextAlarmCodes != NULL); // Can't happen memcpy(ContextAlarmCodes->AlarmCodes, AlarmCodesP, sizeof(ContextAlarmCodes->AlarmCodes)); }
cmsBool CMSEXPORT _cmsLockMutex(cmsContext ContextID, void* mtx) { _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); if (ptr ->LockMutexPtr == NULL) return TRUE; return ptr ->LockMutexPtr(ContextID, mtx); }
// Generic Mutex fns void* CMSEXPORT _cmsCreateMutex(cmsContext ContextID) { _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); if (ptr ->CreateMutexPtr == NULL) return NULL; return ptr ->CreateMutexPtr(ContextID); }
void CMSEXPORT _cmsUnlockMutex(cmsContext ContextID, void* mtx) { _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); if (ptr ->UnlockMutexPtr != NULL) { ptr ->UnlockMutexPtr(ContextID, mtx); } }
// Change log error, context based void CMSEXPORT cmsSetLogErrorHandlerTHR(cmsContext ContextID, cmsLogErrorHandlerFunction Fn) { _cmsLogErrorChunkType* lhg = (_cmsLogErrorChunkType*) _cmsContextGetClientChunk(ContextID, Logger); if (lhg != NULL) { if (Fn == NULL) lhg -> LogErrorHandler = DefaultLogErrorHandlerFunction; else lhg -> LogErrorHandler = Fn; } }
// Search the list for a suitable intent. Returns NULL if not found static cmsIntentsList* SearchIntent(cmsContext ContextID, cmsUInt32Number Intent) { _cmsIntentsPluginChunkType* ctx = ( _cmsIntentsPluginChunkType*) _cmsContextGetClientChunk(ContextID, IntentPlugin); cmsIntentsList* pt; for (pt = ctx -> Intents; pt != NULL; pt = pt -> Next) if (pt ->Intent == Intent) return pt; for (pt = DefaultIntents; pt != NULL; pt = pt -> Next) if (pt ->Intent == Intent) return pt; return NULL; }
// Sets adaptation state for absolute colorimetric intent in the given context. Adaptation state applies on all // but cmsCreateExtendedTransformTHR(). Little CMS can handle incomplete adaptation states. cmsFloat64Number CMSEXPORT cmsSetAdaptationStateTHR(cmsContext ContextID, cmsFloat64Number d) { cmsFloat64Number prev; _cmsAdaptationStateChunkType* ptr = (_cmsAdaptationStateChunkType*) _cmsContextGetClientChunk(ContextID, AdaptationStateContext); // Get previous value for return prev = ptr ->AdaptationState; // Set the value if d is positive or zero if (d >= 0.0) { ptr ->AdaptationState = d; } // Always return previous value return prev; }
// Log an error // ErrorText is a text holding an english description of error. void CMSEXPORT cmsSignalError(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *ErrorText, ...) { va_list args; char Buffer[MAX_ERROR_MESSAGE_LEN]; _cmsLogErrorChunkType* lhg; va_start(args, ErrorText); vsnprintf(Buffer, MAX_ERROR_MESSAGE_LEN-1, ErrorText, args); va_end(args); // Check for the context, if specified go there. If not, go for the global lhg = (_cmsLogErrorChunkType*) _cmsContextGetClientChunk(ContextID, Logger); if (lhg ->LogErrorHandler) { lhg ->LogErrorHandler(ContextID, ErrorCode, Buffer); } }
// Auxiliary: Handle precalculated gamut check. The retrieval of context may be alittle bit slow, but this function is not critical. 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); }
// Register new ways to transform cmsBool _cmsRegisterTransformPlugin(cmsContext ContextID, cmsPluginBase* Data) { cmsPluginTransform* Plugin = (cmsPluginTransform*) Data; _cmsTransformCollection* fl; _cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID,TransformPlugin); if (Data == NULL) { // Free the chain. Memory is safely freed at exit ctx->TransformCollection = NULL; return TRUE; } // Factory callback is required if (Plugin->factories.xform == NULL) return FALSE; fl = (_cmsTransformCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsTransformCollection)); if (fl == NULL) return FALSE; // Check for full xform plug-ins previous to 2.8, we would need an adapter in that case if (Plugin->base.ExpectedVersion < 2080) { fl->OldXform = TRUE; } else fl->OldXform = FALSE; // Copy the parameters fl->Factory = Plugin->factories.xform; // Keep linked list fl ->Next = ctx->TransformCollection; ctx->TransformCollection = fl; // All is ok return TRUE; }
// 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) { cmsPipelineFree(lut); 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"); cmsDeleteTransform(p); return NULL; } if (*dwFlags & cmsFLAGS_NULLTRANSFORM) { p ->xform = NullFloatXFORM; } else { // Float transforms don't use cache, 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"); cmsDeleteTransform(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 cache else p ->xform = PrecalculatedXFORM; // No cache, no gamut check } else { if (*dwFlags & cmsFLAGS_GAMUTCHECK) p ->xform = CachedXFORMGamutCheck; // Gamut check, cache else p ->xform = CachedXFORM; // No gamut check, cache } } } p ->InputFormat = *InputFormat; p ->OutputFormat = *OutputFormat; p ->dwOriginalFlags = *dwFlags; p ->ContextID = ContextID; p ->UserData = NULL; return p; }
// Generic reallocate void* CMSEXPORT _cmsRealloc(cmsContext ContextID, void* Ptr, cmsUInt32Number size) { _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); return ptr->ReallocPtr(ContextID, Ptr, size); }
// Generic block duplication void* CMSEXPORT _cmsDupMem(cmsContext ContextID, const void* Org, cmsUInt32Number size) { _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); return ptr ->DupPtr(ContextID, Org, size); }
// Generic allocate & zero void* CMSEXPORT _cmsMallocZero(cmsContext ContextID, cmsUInt32Number size) { _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); return ptr->MallocZeroPtr(ContextID, size); }