QVector <double> LcmsColorProfileContainer::getEstimatedTRC() const
{
    QVector <double> TRCtriplet(3);
    if (d->hasColorants) {
        if (cmsIsToneCurveLinear(d->redTRC)) {
            TRCtriplet[0] = 1.0;
        } else {
            TRCtriplet[0] = cmsEstimateGamma(d->redTRC, 0.01);
        }
        if (cmsIsToneCurveLinear(d->greenTRC)) {
            TRCtriplet[1] = 1.0;
        } else {
            TRCtriplet[1] = cmsEstimateGamma(d->greenTRC, 0.01);
        }
        if (cmsIsToneCurveLinear(d->blueTRC)) {
            TRCtriplet[2] = 1.0;
        } else {
            TRCtriplet[2] = cmsEstimateGamma(d->blueTRC, 0.01);
        }

    } else {
        if (cmsIsTag(d->profile, cmsSigGrayTRCTag)) {
            if (cmsIsToneCurveLinear(d->grayTRC)) {
                TRCtriplet.fill(1.0);
            } else {
                TRCtriplet.fill(cmsEstimateGamma(d->grayTRC,  0.01));
            }
        } else {
            TRCtriplet.fill(1.0);
        }
    }
    return TRCtriplet;
}
void LcmsColorProfileContainer::DelinearizeFloatValueFast(QVector <double> & Value) const
{
    const qreal scale = 65535.0;
    const qreal invScale = 1.0 / scale;

    if (d->hasColorants) {
        //we can only reliably delinearise in the 0-1.0 range, outside of that leave the value alone.
        QVector <quint16> TRCtriplet(3);
        TRCtriplet[0] = Value[0] * scale;
        TRCtriplet[1] = Value[1] * scale;
        TRCtriplet[2] = Value[2] * scale;

        if (!cmsIsToneCurveLinear(d->redTRC) && Value[0]<1.0) {
            TRCtriplet[0] = cmsEvalToneCurve16(d->redTRCReverse, TRCtriplet[0]);
            Value[0] = TRCtriplet[0] * invScale;
        }
        if (!cmsIsToneCurveLinear(d->greenTRC) && Value[1]<1.0) {
            TRCtriplet[1] = cmsEvalToneCurve16(d->greenTRCReverse, TRCtriplet[1]);
            Value[1] = TRCtriplet[1] * invScale;
        }
        if (!cmsIsToneCurveLinear(d->blueTRC) && Value[2]<1.0) {
            TRCtriplet[2] = cmsEvalToneCurve16(d->blueTRCReverse, TRCtriplet[2]);
            Value[2] = TRCtriplet[2] * invScale;
        }
    } else {
        if (cmsIsTag(d->profile, cmsSigGrayTRCTag) && Value[0]<1.0) {
            quint16 newValue = cmsEvalToneCurve16(d->grayTRCReverse, Value[0] * scale);
            Value[0] = newValue * invScale;
        }
    }
}
void LcmsColorProfileContainer::LinearizeFloatValueFast(QVector <double> & Value) const
{
    //we can only reliably delinearise in the 0-1.0 range, outside of that leave the value alone.
    QVector <quint16> TRCtriplet(3);
    TRCtriplet[0] = Value[0]*65535;
    TRCtriplet[1] = Value[1]*65535;
    TRCtriplet[2] = Value[2]*65535;
    

    if (d->hasColorants) {
        if (!cmsIsToneCurveLinear(d->redTRC) && Value[0]<1.0) {
            TRCtriplet[0] = cmsEvalToneCurve16(d->redTRC, TRCtriplet[0]);
            Value[0] = TRCtriplet[0]/65535.0;
        }
        if (!cmsIsToneCurveLinear(d->greenTRC) && Value[1]<1.0) {
            TRCtriplet[1] = cmsEvalToneCurve16(d->greenTRC, TRCtriplet[1]);
            Value[1] = TRCtriplet[1]/65535.0;
        }
        if (!cmsIsToneCurveLinear(d->blueTRC) && Value[2]<1.0) {
            TRCtriplet[2] = cmsEvalToneCurve16(d->blueTRC, TRCtriplet[2]);
            Value[2] = TRCtriplet[2]/65535.0;
        }
            
    } else {
        if (cmsIsTag(d->profile, cmsSigGrayTRCTag) && Value[0]<1.0) {
            TRCtriplet[0] = (cmsEvalToneCurve16(d->grayTRC, Value[0]*65535));
            Value.fill(TRCtriplet[0]/65535.0);
        }
    }
}
void LcmsColorProfileContainer::DelinearizeFloatValue(QVector <double> & Value) const
{
    QVector <double> TRCtriplet(3);
    TRCtriplet[0] = Value[0];
    TRCtriplet[1] = Value[1];
    TRCtriplet[2] = Value[2];
    if (cmsIsTag(d->profile, cmsSigRedTRCTag)) {
        if (cmsIsToneCurveLinear(d->redTRC)) {
            TRCtriplet[0] = Value[0];
        } else {
            TRCtriplet[0] = cmsEvalToneCurveFloat(d->redTRCReverse, Value[0]);
        }
        if (cmsIsToneCurveLinear(d->greenTRC)) {
            TRCtriplet[1] = Value[1];
        } else {
            TRCtriplet[1] = cmsEvalToneCurveFloat(d->greenTRCReverse, Value[1]);
        }
        if (cmsIsToneCurveLinear(d->blueTRC)) {
            TRCtriplet[2] = Value[2];
        } else {
            TRCtriplet[2] = cmsEvalToneCurveFloat(d->blueTRCReverse, Value[2]);
        }
            
    } else {
        if (cmsIsTag(d->profile, cmsSigGrayTRCTag)) {
            TRCtriplet.fill(cmsEvalToneCurveFloat(d->grayTRCReverse, Value[0]));
        }
    }

    Value = TRCtriplet;
}
Beispiel #5
0
/**
 * gimp_color_profile_is_linear:
 * @profile: a #GimpColorProfile
 *
 * This function determines is the ICC profile represented by a GimpColorProfile
 * is a linear RGB profile or not, some profiles that are LUTs though linear
 * will also return FALSE;
 *
 * Return value: %TRUE if the profile is a matrix shaping profile with linear
 * TRCs, %FALSE otherwise.
 *
 * Since: 2.10
 **/
gboolean
gimp_color_profile_is_linear (GimpColorProfile *profile)
{
  cmsHPROFILE prof;
  cmsToneCurve *curve;

  g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), FALSE);

  prof = profile->priv->lcms_profile;

  if (! cmsIsMatrixShaper (prof))
    return FALSE;

  if (cmsIsCLUT (prof, INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT))
    return FALSE;

  if (cmsIsCLUT (prof, INTENT_PERCEPTUAL, LCMS_USED_AS_OUTPUT))
    return FALSE;

  curve = cmsReadTag(prof, cmsSigRedTRCTag);
  if (curve == NULL || ! cmsIsToneCurveLinear (curve))
    return FALSE;

  curve = cmsReadTag (prof, cmsSigGreenTRCTag);
  if (curve == NULL || ! cmsIsToneCurveLinear (curve))
    return FALSE;

  curve = cmsReadTag (prof, cmsSigBlueTRCTag);
  if (curve == NULL || ! cmsIsToneCurveLinear (curve))
    return FALSE;

  return TRUE;
}
void LcmsColorProfileContainer::DelinearizeFloatValue(QVector <double> & Value) const
{
    if (d->hasColorants) {
        if (!cmsIsToneCurveLinear(d->redTRC)) {
            Value[0] = cmsEvalToneCurveFloat(d->redTRCReverse, Value[0]);
        }
        if (!cmsIsToneCurveLinear(d->greenTRC)) {
            Value[1] = cmsEvalToneCurveFloat(d->greenTRCReverse, Value[1]);
        }
        if (!cmsIsToneCurveLinear(d->blueTRC)) {
            Value[2] = cmsEvalToneCurveFloat(d->blueTRCReverse, Value[2]);
        }

    } else {
        if (cmsIsTag(d->profile, cmsSigGrayTRCTag)) {
            Value[0] = cmsEvalToneCurveFloat(d->grayTRCReverse, Value[0]);
        }
    }
}
Beispiel #7
0
// Smooths a curve sampled at regular intervals. 
cmsBool  CMSEXPORT cmsSmoothToneCurve(cmsToneCurve* Tab, cmsFloat64Number lambda)
{
    cmsFloat32Number w[MAX_NODES_IN_CURVE], y[MAX_NODES_IN_CURVE], z[MAX_NODES_IN_CURVE];
    int i, nItems, Zeros, Poles;

    if (Tab == NULL) return FALSE;

    if (cmsIsToneCurveLinear(Tab)) return FALSE; // Nothing to do

    nItems = Tab -> nEntries;

    if (nItems >= MAX_NODES_IN_CURVE) {
        cmsSignalError(Tab ->InterpParams->ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: too many points.");
        return FALSE;
    }

    memset(w, 0, nItems * sizeof(cmsFloat32Number));
    memset(y, 0, nItems * sizeof(cmsFloat32Number));
    memset(z, 0, nItems * sizeof(cmsFloat32Number));

    for (i=0; i < nItems; i++)
    {
        y[i+1] = (cmsFloat32Number) Tab -> Table16[i];
        w[i+1] = 1.0;
    }

    if (!smooth2(Tab ->InterpParams->ContextID, w, y, z, (cmsFloat32Number) lambda, nItems)) return FALSE;

    // Do some reality - checking...
    Zeros = Poles = 0;
    for (i=nItems; i > 1; --i) {

        if (z[i] == 0.) Zeros++;
        if (z[i] >= 65535.) Poles++;
        if (z[i] < z[i-1]) return FALSE; // Non-Monotonic
    }

    if (Zeros > (nItems / 3)) return FALSE;  // Degenerated, mostly zeros
    if (Poles > (nItems / 3)) return FALSE;  // Degenerated, mostly poles

    // Seems ok
    for (i=0; i < nItems; i++) {

        // Clamp to cmsUInt16Number
        Tab -> Table16[i] = _cmsQuickSaturateWord(z[i+1]);
    }

    return TRUE;
}
Beispiel #8
0
static
void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table)
{
    cmsUInt32Number i;
    cmsFloat64Number gamma;


    if (Table ->nEntries <= 0) return;  // Empty table

    // Suppress whole if identity
    if (cmsIsToneCurveLinear(Table)) return;

    // Check if is really an exponential. If so, emit "exp"
	gamma = cmsEstimateGamma(Table, 0.001);
     if (gamma > 0) {
            _cmsIOPrintf(m, "{ %g exp } bind ", gamma);
            return;
     }

    _cmsIOPrintf(m, "{ ");

    // Bounds check
    EmitRangeCheck(m);
    
    // Emit intepolation code

    // PostScript code                      Stack
    // ===============                      ========================
                                            // v
    _cmsIOPrintf(m, " [");

    for (i=0; i < Table->nEntries; i++) {
		_cmsIOPrintf(m, "%d ", Table->Table16[i]);
    }

    _cmsIOPrintf(m, "] ");                        // v tab

    _cmsIOPrintf(m, "dup ");                      // v tab tab        
    _cmsIOPrintf(m, "length 1 sub ");             // v tab dom
    _cmsIOPrintf(m, "3 -1 roll ");                // tab dom v
    _cmsIOPrintf(m, "mul ");                      // tab val2
    _cmsIOPrintf(m, "dup ");                      // tab val2 val2
    _cmsIOPrintf(m, "dup ");                      // tab val2 val2 val2
    _cmsIOPrintf(m, "floor cvi ");                // tab val2 val2 cell0
    _cmsIOPrintf(m, "exch ");                     // tab val2 cell0 val2
    _cmsIOPrintf(m, "ceiling cvi ");              // tab val2 cell0 cell1
    _cmsIOPrintf(m, "3 index ");                  // tab val2 cell0 cell1 tab 
    _cmsIOPrintf(m, "exch ");                     // tab val2 cell0 tab cell1
    _cmsIOPrintf(m, "get ");                      // tab val2 cell0 y1
    _cmsIOPrintf(m, "4 -1 roll ");                // val2 cell0 y1 tab
    _cmsIOPrintf(m, "3 -1 roll ");                // val2 y1 tab cell0 
    _cmsIOPrintf(m, "get ");                      // val2 y1 y0 
    _cmsIOPrintf(m, "dup ");                      // val2 y1 y0 y0
    _cmsIOPrintf(m, "3 1 roll ");                 // val2 y0 y1 y0 
    _cmsIOPrintf(m, "sub ");                      // val2 y0 (y1-y0)
    _cmsIOPrintf(m, "3 -1 roll ");                // y0 (y1-y0) val2
    _cmsIOPrintf(m, "dup ");                      // y0 (y1-y0) val2 val2
    _cmsIOPrintf(m, "floor cvi ");                // y0 (y1-y0) val2 floor(val2) 
    _cmsIOPrintf(m, "sub ");                      // y0 (y1-y0) rest
    _cmsIOPrintf(m, "mul ");                      // y0 t1
    _cmsIOPrintf(m, "add ");                      // y
    _cmsIOPrintf(m, "65535 div ");                // result

    _cmsIOPrintf(m, " } bind ");
}
Beispiel #9
0
static int
dt_colorspaces_get_matrix_from_profile (cmsHPROFILE prof, float *matrix, float *lutr, float *lutg, float* lutb, const int lutsize, const int input)
{
  // create an OpenCL processable matrix + tone curves from an cmsHPROFILE:

  // check this first:
  if(!cmsIsMatrixShaper(prof)) return 1;

  cmsToneCurve* red_curve   = cmsReadTag(prof, cmsSigRedTRCTag);
  cmsToneCurve* green_curve = cmsReadTag(prof, cmsSigGreenTRCTag);
  cmsToneCurve* blue_curve  = cmsReadTag(prof, cmsSigBlueTRCTag);

  cmsCIEXYZ *red_color   = cmsReadTag(prof, cmsSigRedColorantTag);
  cmsCIEXYZ *green_color = cmsReadTag(prof, cmsSigGreenColorantTag);
  cmsCIEXYZ *blue_color  = cmsReadTag(prof, cmsSigBlueColorantTag);

  if(!red_curve || !green_curve || !blue_curve || !red_color || !green_color || !blue_color) return 2;

  matrix[0] = red_color->X;
  matrix[1] = green_color->X;
  matrix[2] = blue_color->X;
  matrix[3] = red_color->Y;
  matrix[4] = green_color->Y;
  matrix[5] = blue_color->Y;
  matrix[6] = red_color->Z;
  matrix[7] = green_color->Z;
  matrix[8] = blue_color->Z;

  // some camera ICC profiles claim to have color locations for red, green and blue base colors defined, 
  // but in fact these are all set to zero. we catch this case here.
  float sum = 0.0f;
  for(int k=0; k<9; k++) sum += matrix[k];
  if(sum == 0.0f) return 3;

  if(input)
  {
    // mark as linear, if they are:
    if(cmsIsToneCurveLinear(red_curve))   lutr[0] = -1.0f;
    else for(int k=0; k<lutsize; k++)     lutr[k] = cmsEvalToneCurveFloat(red_curve,   k/(lutsize-1.0f));
    if(cmsIsToneCurveLinear(green_curve)) lutg[0] = -1.0f;
    else for(int k=0; k<lutsize; k++)     lutg[k] = cmsEvalToneCurveFloat(green_curve, k/(lutsize-1.0f));
    if(cmsIsToneCurveLinear(blue_curve))  lutb[0] = -1.0f;
    else for(int k=0; k<lutsize; k++)     lutb[k] = cmsEvalToneCurveFloat(blue_curve,  k/(lutsize-1.0f));
  }
  else
  {
    // invert profile->XYZ matrix for output profiles
    float tmp[9];
    memcpy(tmp, matrix, sizeof(float)*9);
    if(mat3inv (matrix, tmp)) return 3;
    // also need to reverse gamma, to apply reverse before matrix multiplication:
    cmsToneCurve* rev_red   = cmsReverseToneCurveEx(0x8000, red_curve);
    cmsToneCurve* rev_green = cmsReverseToneCurveEx(0x8000, green_curve);
    cmsToneCurve* rev_blue  = cmsReverseToneCurveEx(0x8000, blue_curve);
    if(!rev_red || !rev_green || !rev_blue)
    {
      cmsFreeToneCurve(rev_red);
      cmsFreeToneCurve(rev_green);
      cmsFreeToneCurve(rev_blue);
      return 4;
    }
    // pass on tonecurves, in case lutsize > 0:
    if(cmsIsToneCurveLinear(red_curve))   lutr[0] = -1.0f;
    else for(int k=0; k<lutsize; k++)     lutr[k] = cmsEvalToneCurveFloat(rev_red,   k/(lutsize-1.0f));
    if(cmsIsToneCurveLinear(green_curve)) lutg[0] = -1.0f;
    else for(int k=0; k<lutsize; k++)     lutg[k] = cmsEvalToneCurveFloat(rev_green, k/(lutsize-1.0f));
    if(cmsIsToneCurveLinear(blue_curve))  lutb[0] = -1.0f;
    else for(int k=0; k<lutsize; k++)     lutb[k] = cmsEvalToneCurveFloat(rev_blue,  k/(lutsize-1.0f));
    cmsFreeToneCurve(rev_red);
    cmsFreeToneCurve(rev_green);
    cmsFreeToneCurve(rev_blue);
  }
  return 0;
}