/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions.
*/
// This file is available under and governed by the GNU General Public // License version 2 only, as published by the Free Software Foundation. // However, the following notice accompanied the original version of this // file: // //--------------------------------------------------------------------------------- // // Little Color Management System // Copyright (c) 1998-2022 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 // is furnished to do so, subject to the following conditions: // // 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 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- //
// 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;
}
// The adaptation state may be defaulted by this function. If you don't like it, use the extended transform routine
cmsFloat64Number CMSEXPORT cmsSetAdaptationState(cmsFloat64Number d)
{ return cmsSetAdaptationStateTHR(NULL, d);
}
// 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);
// Gets the current codes used to mark out-out-gamut on Proofing transforms for the given context. // Values are meant to be encoded in 16 bits. void CMSEXPORT cmsGetAlarmCodesTHR(cmsContext ContextID, cmsUInt16Number AlarmCodesP[cmsMAXCHANNELS])
{
_cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(ContextID, AlarmCodesContext);
{
_cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform;
cmsStride stride;
stride.BytesPerLineIn = 0; // Not used
stride.BytesPerLineOut = 0;
stride.BytesPerPlaneIn = Size * PixelSize(p->InputFormat);
stride.BytesPerPlaneOut = Size * PixelSize(p->OutputFormat);
p -> xform(p, InputBuffer, OutputBuffer, Size, 1, &stride);
}
// This is a legacy stride for planar void CMSEXPORT cmsDoTransformStride(cmsHTRANSFORM Transform, constvoid* InputBuffer, void* OutputBuffer,
cmsUInt32Number Size, cmsUInt32Number Stride)
{
_cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform;
cmsStride 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, constvoid* in, void* out,
cmsUInt32Number PixelsPerLine,
cmsUInt32Number LineCount, const cmsStride* Stride)
{
cmsUInt8Number* accum;
cmsUInt8Number* output;
cmsFloat32Number fIn[cmsMAXCHANNELS], fOut[cmsMAXCHANNELS];
cmsFloat32Number OutOfGamut;
cmsUInt32Number i, j, c, strideIn, strideOut;
_cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride);
// 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) {
// List of used-defined transform factories typedefstruct _cmsTransformCollection_st {
_cmsTransform2Factory Factory;
cmsBool OldXform; // Factory returns xform function in the old style
struct _cmsTransformCollection_st *Next;
} _cmsTransformCollection;
// The linked list head
_cmsTransformPluginChunkType _cmsTransformPluginChunk = { NULL };
// Duplicates the zone of memory used by the plug-in in the new context static void DupPluginTransformList(struct _cmsContext_struct* ctx, conststruct _cmsContext_struct* src)
{
_cmsTransformPluginChunkType newHead = { NULL };
_cmsTransformCollection* entry;
_cmsTransformCollection* Anterior = NULL;
_cmsTransformPluginChunkType* head = (_cmsTransformPluginChunkType*) src->chunks[TransformPlugin];
// Walk the list copying all nodes for (entry = head->TransformCollection;
entry != NULL;
entry = entry ->Next) {
// 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;
}
// 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;
}
// Returns the worker callback for parallelization plug-ins
_cmsTransform2Fn CMSEXPORT _cmsGetTransformWorker(struct _cmstransform_struct* CMMcargo)
{
_cmsAssert(CMMcargo != NULL); return CMMcargo->Worker;
}
// This field holds maximum number of workers or -1 to auto
cmsInt32Number CMSEXPORT _cmsGetTransformMaxWorkers(struct _cmstransform_struct* CMMcargo)
{
_cmsAssert(CMMcargo != NULL); return CMMcargo->MaxWorkers;
}
// This field is actually unused and reserved
cmsUInt32Number CMSEXPORT _cmsGetTransformWorkerFlags(struct _cmstransform_struct* CMMcargo)
{
_cmsAssert(CMMcargo != NULL); return CMMcargo->WorkerFlags;
}
// In the case there is a parallelization plug-in, let it to do its job static void ParalellizeIfSuitable(_cmsTRANSFORM* p)
{
_cmsParallelizationPluginChunkType* ctx = (_cmsParallelizationPluginChunkType*)_cmsContextGetClientChunk(p->ContextID, ParallelizationPlugin);
// 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) {
if (!(*dwFlags & cmsFLAGS_NOOPTIMIZE))
{ 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.
// 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? (Ignore the warning) if (Plugin->OldXform) {
p->OldXform = (_cmsTransformFn)(void*)p->xform;
p->xform = _cmsTransform2toTransformAdaptor;
}
ParalellizeIfSuitable(p); 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(*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) {
p ->xform = NullFloatXFORM;
} else { // Float transforms don't use cache, always are non-NULL
p ->xform = FloatXFORM;
}
} else {
// Formats are intended to be changed before use if (*InputFormat == 0 && *OutputFormat == 0) {
p->FromInput = UnrollNothing;
p->ToOutput = PackNothing;
*dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
} else {
cmsUInt32Number 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) {
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;
ParalellizeIfSuitable(p); return p;
}
// 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 cache if (_cmsFormatterIsFloat(InputFormat) || _cmsFormatterIsFloat(OutputFormat))
dwFlags |= cmsFLAGS_NOCACHE;
// Mark entry/exit spaces if (!GetXFormColorSpaces(nProfiles, hProfiles, &EntryColorSpace, &ExitColorSpace)) {
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"); return NULL;
}
if (!IsProperColorSpace(ExitColorSpace, OutputFormat)) {
cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong output color space on transform"); return NULL;
}
// Check whatever the transform is 16 bits and involves linear RGB in first profile. If so, disable optimizations if (EntryColorSpace == cmsSigRgbData && T_BYTES(InputFormat) == 2 && !(dwFlags & cmsFLAGS_NOOPTIMIZE))
{
cmsFloat64Number gamma = cmsDetectRGBProfileGamma(hProfiles[0], 0.1);
// 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"); return NULL;
}
// Take white points
SetWhitePoint(&xform->EntryWhitePoint, (cmsCIEXYZ*) cmsReadTag(hProfiles[0], cmsSigMediaWhitePointTag));
SetWhitePoint(&xform->ExitWhitePoint, (cmsCIEXYZ*) cmsReadTag(hProfiles[nProfiles-1], cmsSigMediaWhitePointTag));
// Create a gamut check LUT if requested 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.
xform ->InputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[0], cmsSigColorantTableTag));
}
// Output is a little bit more complex. if (cmsGetDeviceClass(hProfiles[nProfiles-1]) == cmsSigLinkClass) {
// This tag may exist only on devicelink profiles. if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableOutTag)) {
// It may be NULL if error
xform ->OutputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[nProfiles-1], cmsSigColorantTableOutTag));
}
} else {
if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableTag)) {
// Multiprofile transforms: Gamut check is not available here, as it is unclear from which profile the gamut comes.
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;
}
// Grab the ContextID from an open transform. Returns NULL if a NULL transform is passed
cmsContext CMSEXPORT cmsGetTransformContextID(cmsHTRANSFORM hTransform)
{
_cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
// We only can afford to change formatters if previous transform is at least 16 bits 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"); returnFALSE;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.