Example #1
0
// Adapts a color to a given illuminant. Original color is expected to have
// a SourceWhitePt white point.
cmsBool CMSEXPORT cmsAdaptToIlluminant(cmsCIEXYZ* Result,
                                       const cmsCIEXYZ* SourceWhitePt,
                                       const cmsCIEXYZ* Illuminant,
                                       const cmsCIEXYZ* Value)
{
    cmsMAT3 Bradford;
    cmsVEC3 In, Out;

    _cmsAssert(Result != NULL);
    _cmsAssert(SourceWhitePt != NULL);
    _cmsAssert(Illuminant != NULL);
    _cmsAssert(Value != NULL);

    if (!_cmsAdaptationMatrix(&Bradford, NULL, SourceWhitePt, Illuminant)) return FALSE;

    _cmsVEC3init(&In, Value -> X, Value -> Y, Value -> Z);
    _cmsMAT3eval(&Out, &Bradford, &In);

    Result -> X = Out.n[0];
    Result -> Y = Out.n[1];
    Result -> Z = Out.n[2];

    return TRUE;
}
Example #2
0
void CMSEXPORT cmsCIECAM02Forward(cmsHANDLE hModel, const cmsCIEXYZ* pIn, cmsJCh* pOut)
{
    CAM02COLOR clr;
    cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel;

    memset(&clr, 0, sizeof(clr));
    _cmsAssert(lpMod != NULL);
    _cmsAssert(pIn != NULL);
    _cmsAssert(pOut != NULL);

    clr.XYZ[0] = pIn ->X;
    clr.XYZ[1] = pIn ->Y;
    clr.XYZ[2] = pIn ->Z;

    clr = XYZtoCAT02(clr);
    clr = ChromaticAdaptation(clr, lpMod);
    clr = CAT02toHPE(clr);
    clr = NonlinearCompression(clr, lpMod);
    clr = ComputeCorrelates(clr, lpMod);

    pOut ->J = clr.J;
    pOut ->C = clr.C;
    pOut ->h = clr.h;
}
Example #3
0
void CMSEXPORT cmsCIECAM02Reverse(cmsHANDLE hModel, const cmsJCh* pIn, cmsCIEXYZ* pOut)
{
    CAM02COLOR clr;
    cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel;

    memset(&clr, 0, sizeof(clr));
    _cmsAssert(lpMod != NULL);
    _cmsAssert(pIn != NULL);
    _cmsAssert(pOut != NULL);

    clr.J = pIn -> J;
    clr.C = pIn -> C;
    clr.h = pIn -> h;

    clr = InverseCorrelates(clr, lpMod);
    clr = InverseNonlinearity(clr, lpMod);
    clr = HPEtoCAT02(clr);
    clr = InverseChromaticAdaptation(clr, lpMod);
    clr = CAT02toXYZ(clr);

    pOut ->X = clr.XYZ[0];
    pOut ->Y = clr.XYZ[1];
    pOut ->Z = clr.XYZ[2];
}
Example #4
0
void _cmsAllocMemPluginChunk(struct _cmsContext_struct* ctx, const struct _cmsContext_struct* src)
{
	_cmsAssert(ctx != NULL);

	if (src != NULL) {

		// Duplicate
		ctx ->chunks[MemPlugin] = _cmsSubAllocDup(ctx ->MemPool, src ->chunks[MemPlugin], sizeof(_cmsMemPluginChunkType));
	}
	else {

		// To reset it, we use the default allocators, which cannot be overriden
		ctx ->chunks[MemPlugin] = &ctx ->DefaultMemoryManager;
	}
}
Example #5
0
// Is a table linear? Do not use parametric since we cannot guarantee some weird parameters resulting
// in a linear table. This way assures it is linear in 12 bits, which should be enought in most cases.
cmsBool CMSEXPORT cmsIsToneCurveLinear(const cmsToneCurve* Curve)
{
    cmsUInt32Number i;
    int diff;

    _cmsAssert(Curve != NULL);

    for (i=0; i < Curve ->nEntries; i++) {

        diff = abs((int) Curve->Table16[i] - (int) _cmsQuantizeVal(i, Curve ->nEntries));
        if (diff > 0x0f)
            return FALSE;
    }

    return TRUE;
}
Example #6
0
// We need accuracy this time
cmsFloat32Number CMSEXPORT cmsEvalToneCurveFloat(const cmsToneCurve* Curve, cmsFloat32Number v)
{
    _cmsAssert(Curve != NULL);

    // Check for 16 bits table. If so, this is a limited-precision tone curve
    if (Curve ->nSegments == 0) {

        cmsUInt16Number In, Out;
        
        In = (cmsUInt16Number) _cmsQuickSaturateWord(v * 65535.0);
        Out = cmsEvalToneCurve16(Curve, In);
        
        return (cmsFloat32Number) (Out / 65535.0);
    }

    return (cmsFloat32Number) EvalSegmentedFn(Curve, v);
}
Example #7
0
// Obtains WhitePoint from Temperature
cmsBool  CMSEXPORT cmsWhitePointFromTemp(cmsCIExyY* WhitePoint, cmsFloat64Number TempK)
{
       cmsFloat64Number x, y;
       cmsFloat64Number T, T2, T3;
       // cmsFloat64Number M1, M2;

       _cmsAssert(WhitePoint != NULL);

       T = TempK;
       T2 = T*T;            // Square
       T3 = T2*T;           // Cube

       // For correlated color temperature (T) between 4000K and 7000K:

       if (T >= 4000. && T <= 7000.)
       {
              x = -4.6070*(1E9/T3) + 2.9678*(1E6/T2) + 0.09911*(1E3/T) + 0.244063;
       }
       else
              // or for correlated color temperature (T) between 7000K and 25000K:

       if (T > 7000.0 && T <= 25000.0)
       {
              x = -2.0064*(1E9/T3) + 1.9018*(1E6/T2) + 0.24748*(1E3/T) + 0.237040;
       }
       else {
              cmsSignalError(0, cmsERROR_RANGE, "cmsWhitePointFromTemp: invalid temp");
              return FALSE;
              }

       // Obtain y(x)

       y = -3.000*(x*x) + 2.870*x - 0.275;

       // wave factors (not used, but here for futures extensions)

       // M1 = (-1.3515 - 1.7703*x + 5.9114 *y)/(0.0241 + 0.2562*x - 0.7341*y);
       // M2 = (0.0300 - 31.4424*x + 30.0717*y)/(0.0241 + 0.2562*x - 0.7341*y);

       WhitePoint -> x = x;
       WhitePoint -> y = y;
       WhitePoint -> Y = 1.0;

       return TRUE;
}
Example #8
0
// Same, but for monotonicity
cmsBool  CMSEXPORT cmsIsToneCurveMonotonic(const cmsToneCurve* t)
{
    int n;
    int i, last;
    cmsBool lDescending;

    _cmsAssert(t != NULL);
   
    // Degenerated curves are monotonic? Ok, let's pass them
    n = t ->nEntries;
    if (n < 2) return TRUE;

    // Curve direction
    lDescending = cmsIsToneCurveDescending(t);     
   
    if (lDescending) {

        last = t ->Table16[0];

        for (i = 1; i < n; i++) {

            if (t ->Table16[i] - last > 2) // We allow some ripple
                return FALSE;
            else
                last = t ->Table16[i];

        }
    }
    else {

        last = t ->Table16[n-1];

        for (i = n-2; i >= 0; --i) {
          
            if (t ->Table16[i] - last > 2)
                return FALSE;
            else
                last = t ->Table16[i];

        }
    }

    return TRUE;
}
Example #9
0
// Auxiliary, read colorants as a MAT3 structure. Used by any function that needs a matrix-shaper
static
cmsBool ReadICCMatrixRGB2XYZ(cmsMAT3* r, cmsHPROFILE hProfile)
{
    cmsCIEXYZ *PtrRed, *PtrGreen, *PtrBlue;

    _cmsAssert(r != NULL);

    PtrRed   = (cmsCIEXYZ *) cmsReadTag(hProfile, cmsSigRedColorantTag);
    PtrGreen = (cmsCIEXYZ *) cmsReadTag(hProfile, cmsSigGreenColorantTag);
    PtrBlue  = (cmsCIEXYZ *) cmsReadTag(hProfile, cmsSigBlueColorantTag);

    if (PtrRed == NULL || PtrGreen == NULL || PtrBlue == NULL)
        return FALSE;

    _cmsVEC3init(&r -> v[0], PtrRed -> X, PtrGreen -> X,  PtrBlue -> X);
    _cmsVEC3init(&r -> v[1], PtrRed -> Y, PtrGreen -> Y,  PtrBlue -> Y);
    _cmsVEC3init(&r -> v[2], PtrRed -> Z, PtrGreen -> Z,  PtrBlue -> Z);

    return TRUE;
}
Example #10
0
// Chromatic adaptation matrix. Fix some issues as well
cmsBool  _cmsReadCHAD(cmsMAT3* Dest, cmsHPROFILE hProfile)
{
    cmsMAT3* Tag;

    _cmsAssert(Dest != NULL);

    Tag = (cmsMAT3*) cmsReadTag(hProfile, cmsSigChromaticAdaptationTag);

    if (Tag != NULL) {

        *Dest = *Tag;
        return TRUE;
    }

    // No CHAD available, default it to identity
    _cmsMAT3identity(Dest);

    // V2 display profiles should give D50
    if (cmsGetEncodedICCversion(hProfile) < 0x4000000) {

        if (cmsGetDeviceClass(hProfile) == cmsSigDisplayClass) {

            cmsCIEXYZ* White = (cmsCIEXYZ*) cmsReadTag(hProfile, cmsSigMediaWhitePointTag);

            if (White == NULL) {

                _cmsMAT3identity(Dest);
                return TRUE;
            }

            return _cmsAdaptationMatrix(Dest, NULL, White, cmsD50_XYZ());
        }
    }

    return TRUE;
}
Example #11
0
cmsFloat64Number CMSEXPORT cmsEstimateGamma(const cmsToneCurve* t, cmsFloat64Number Precision)
{
    cmsFloat64Number gamma, sum, sum2;
    cmsFloat64Number n, x, y, Std;
    cmsUInt32Number i;

    _cmsAssert(t != NULL);

    sum = sum2 = n = 0;

    // Excluding endpoints   
    for (i=1; i < (MAX_NODES_IN_CURVE-1); i++) {

        x = (cmsFloat64Number) i / (MAX_NODES_IN_CURVE-1);
        y = (cmsFloat64Number) cmsEvalToneCurveFloat(t, (cmsFloat32Number) x);

        // Avoid 7% on lower part to prevent 
        // artifacts due to linear ramps

        if (y > 0. && y < 1. && x > 0.07) {

            gamma = log(y) / log(x);
            sum  += gamma;
            sum2 += gamma * gamma;
            n++;
        }
    }

    // Take a look on SD to see if gamma isn't exponential at all
    Std = sqrt((n * sum2 - sum * sum) / (n*(n-1)));

    if (Std > Precision)
        return -1.0;

    return (sum / n);   // The mean
}
Example #12
0
// 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;
}
Example #13
0
void CMSEXPORT _cmsGetTransformFormattersFloat(struct _cmstransform_struct *CMMcargo, cmsFormatterFloat* FromInput, cmsFormatterFloat* ToOutput)
{
     _cmsAssert(CMMcargo != NULL);
     if (FromInput) *FromInput = CMMcargo ->FromInputFloat;
     if (ToOutput)  *ToOutput  = CMMcargo ->ToOutputFloat;
}
Example #14
0
void CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number OldAlarm[cmsMAXCHANNELS])
{ 
    _cmsAssert(OldAlarm != NULL);
    cmsGetAlarmCodesTHR(NULL, OldAlarm);
}
Example #15
0
void CMSEXPORT _cmsSetTransformUserData(struct _cmstransform_struct *CMMcargo, void* ptr, _cmsFreeUserDataFn FreePrivateDataFn)
{
    _cmsAssert(CMMcargo != NULL);
    CMMcargo ->UserData = ptr;
    CMMcargo ->FreeUserData = FreePrivateDataFn;
}
Example #16
0
// Access to estimated low-res table
cmsUInt32Number CMSEXPORT cmsGetToneCurveEstimatedTableEntries(const cmsToneCurve* t)
{
    _cmsAssert(t != NULL);
    return t ->nEntries;
}
Example #17
0
void CMSEXPORT cmsSetAlarmCodes(const cmsUInt16Number NewAlarm[cmsMAXCHANNELS])
{
    _cmsAssert(NewAlarm != NULL);

    cmsSetAlarmCodesTHR(NULL, NewAlarm);
}
Example #18
0
const cmsUInt16Number* CMSEXPORT cmsGetToneCurveEstimatedTable(const cmsToneCurve* t)
{
    _cmsAssert(t != NULL);
    return t ->Table16;
}
Example #19
0
// Does convert a transform into a device link profile
cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat64Number Version, cmsUInt32Number dwFlags)
{
    cmsHPROFILE hProfile = NULL;
    cmsUInt32Number FrmIn, FrmOut, ChansIn, ChansOut;
    cmsUInt32Number ColorSpaceBitsIn, ColorSpaceBitsOut;
    _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
    cmsPipeline* LUT = NULL;
    cmsStage* mpe;
    cmsContext ContextID = cmsGetTransformContextID(hTransform);
    const cmsAllowedLUT* AllowedLUT;
    cmsTagSignature DestinationTag;
    cmsProfileClassSignature deviceClass; 

    _cmsAssert(hTransform != NULL);

    // Get the first mpe to check for named color
    mpe = cmsPipelineGetPtrToFirstStage(xform ->Lut);

    // Check if is a named color transform
    if (mpe != NULL) {

        if (cmsStageType(mpe) == cmsSigNamedColorElemType) {
            return CreateNamedColorDevicelink(hTransform);
        }
    }

    // First thing to do is to get a copy of the transformation
    LUT = cmsPipelineDup(xform ->Lut);
    if (LUT == NULL) return NULL;

    // Time to fix the Lab2/Lab4 issue.
    if ((xform ->EntryColorSpace == cmsSigLabData) && (Version < 4.0)) {

        if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocLabV2ToV4curves(ContextID)))
            goto Error;
    }

    // On the output side too
    if ((xform ->ExitColorSpace) == cmsSigLabData && (Version < 4.0)) {

        if (!cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocLabV4ToV2(ContextID)))
            goto Error;
    }


    hProfile = cmsCreateProfilePlaceholder(ContextID);
    if (!hProfile) goto Error;                    // can't allocate

    cmsSetProfileVersion(hProfile, Version);

    FixColorSpaces(hProfile, xform -> EntryColorSpace, xform -> ExitColorSpace, dwFlags);

    // Optimize the LUT and precalculate a devicelink

    ChansIn  = cmsChannelsOf(xform -> EntryColorSpace);
    ChansOut = cmsChannelsOf(xform -> ExitColorSpace);

    ColorSpaceBitsIn  = _cmsLCMScolorSpace(xform -> EntryColorSpace);
    ColorSpaceBitsOut = _cmsLCMScolorSpace(xform -> ExitColorSpace);

    FrmIn  = COLORSPACE_SH(ColorSpaceBitsIn) | CHANNELS_SH(ChansIn)|BYTES_SH(2);
    FrmOut = COLORSPACE_SH(ColorSpaceBitsOut) | CHANNELS_SH(ChansOut)|BYTES_SH(2);

    deviceClass = cmsGetDeviceClass(hProfile);

     if (deviceClass == cmsSigOutputClass)
         DestinationTag = cmsSigBToA0Tag;
     else
         DestinationTag = cmsSigAToB0Tag;

    // Check if the profile/version can store the result
    if (dwFlags & cmsFLAGS_FORCE_CLUT)
        AllowedLUT = NULL;
    else
        AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag);

    if (AllowedLUT == NULL) {

        // Try to optimize
        _cmsOptimizePipeline(ContextID, &LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags);
        AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag);

    }

    // If no way, then force CLUT that for sure can be written
    if (AllowedLUT == NULL) {

        dwFlags |= cmsFLAGS_FORCE_CLUT;
        _cmsOptimizePipeline(ContextID, &LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags);

        // Put identity curves if needed
        if (cmsPipelineGetPtrToFirstStage(LUT) ->Type != cmsSigCurveSetElemType)
             if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, ChansIn)))
                 goto Error;

        if (cmsPipelineGetPtrToLastStage(LUT) ->Type != cmsSigCurveSetElemType)
             if (!cmsPipelineInsertStage(LUT, cmsAT_END,   _cmsStageAllocIdentityCurves(ContextID, ChansOut)))
                 goto Error;

        AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag);
    }

    // Somethings is wrong...
    if (AllowedLUT == NULL) {
        goto Error;
    }


    if (dwFlags & cmsFLAGS_8BITS_DEVICELINK)
                     cmsPipelineSetSaveAs8bitsFlag(LUT, TRUE);

    // Tag profile with information
    if (!SetTextTags(hProfile, L"devicelink")) goto Error;

    // Store result
    if (!cmsWriteTag(hProfile, DestinationTag, LUT)) goto Error;


    if (xform -> InputColorant != NULL) {
           if (!cmsWriteTag(hProfile, cmsSigColorantTableTag, xform->InputColorant)) goto Error;
    }

    if (xform -> OutputColorant != NULL) {
           if (!cmsWriteTag(hProfile, cmsSigColorantTableOutTag, xform->OutputColorant)) goto Error;
    }

    if ((deviceClass == cmsSigLinkClass) && (xform ->Sequence != NULL)) {
        if (!_cmsWriteProfileSequence(hProfile, xform ->Sequence)) goto Error;
    }

    // Set the white point
    if (deviceClass == cmsSigInputClass) {
        if (!cmsWriteTag(hProfile, cmsSigMediaWhitePointTag, &xform ->EntryWhitePoint)) goto Error;
    }
    else {
         if (!cmsWriteTag(hProfile, cmsSigMediaWhitePointTag, &xform ->ExitWhitePoint)) goto Error;
    }

  
    // Per 7.2.15 in spec 4.3
    cmsSetHeaderRenderingIntent(hProfile, xform ->RenderingIntent);

    cmsPipelineFree(LUT);
    return hProfile;

Error:
    if (LUT != NULL) cmsPipelineFree(LUT);
    cmsCloseProfile(hProfile);
    return NULL;
}
Example #20
0
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;

}
Example #21
0
// Reverse a gamma table
cmsToneCurve* CMSEXPORT cmsReverseToneCurve(const cmsToneCurve* InGamma)
{
    _cmsAssert(InGamma != NULL);

    return cmsReverseToneCurveEx(4096, InGamma);
}
Example #22
0
// Reverse a gamma table
cmsToneCurve* CMSEXPORT cmsReverseToneCurveEx(cmsInt32Number nResultSamples, const cmsToneCurve* InCurve)
{
    cmsToneCurve *out;
    cmsFloat64Number a = 0, b = 0, y, x1, y1, x2, y2;
    int i, j;
    int Ascending;
    
    _cmsAssert(InCurve != NULL);

    // Try to reverse it analytically whatever possible
    if (InCurve ->nSegments == 1 && InCurve ->Segments[0].Type > 0 && InCurve -> Segments[0].Type <= 5) {

        return cmsBuildParametricToneCurve(InCurve ->InterpParams->ContextID, 
                                       -(InCurve -> Segments[0].Type), 
                                       InCurve -> Segments[0].Params);
    }

    // Nope, reverse the table. 
    out = cmsBuildTabulatedToneCurve16(InCurve ->InterpParams->ContextID, nResultSamples, NULL);
    if (out == NULL)
        return NULL;

    // We want to know if this is an ascending or descending table
    Ascending = !cmsIsToneCurveDescending(InCurve);

    // Iterate across Y axis
    for (i=0; i <  nResultSamples; i++) {

        y = (cmsFloat64Number) i * 65535.0 / (nResultSamples - 1);

        // Find interval in which y is within. 
        j = GetInterval(y, InCurve->Table16, InCurve->InterpParams);
        if (j >= 0) {


            // Get limits of interval
            x1 = InCurve ->Table16[j]; 
            x2 = InCurve ->Table16[j+1];

            y1 = (cmsFloat64Number) (j * 65535.0) / (InCurve ->nEntries - 1);
            y2 = (cmsFloat64Number) ((j+1) * 65535.0 ) / (InCurve ->nEntries - 1);
    
            // If collapsed, then use any
            if (x1 == x2) {

                out ->Table16[i] = _cmsQuickSaturateWord(Ascending ? y2 : y1);
                continue;

            } else {

                // Interpolate      
                a = (y2 - y1) / (x2 - x1);
                b = y2 - a * x2;
            }
        }
           
        out ->Table16[i] = _cmsQuickSaturateWord(a* y + b);
    }


    return out;
}
Example #23
0
// Same, but for descending tables
cmsBool  CMSEXPORT cmsIsToneCurveDescending(const cmsToneCurve* t)
{
    _cmsAssert(t != NULL);

    return t ->Table16[0] > t ->Table16[t ->nEntries-1];
}
Example #24
0
// Another info fn: is out gamma table multisegment?
cmsBool  CMSEXPORT cmsIsToneCurveMultisegment(const cmsToneCurve* t)
{
    _cmsAssert(t != NULL);

    return t -> nSegments > 1;
}