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; }
/** * cd_util_extract_vcgt: **/ static gboolean cd_util_extract_vcgt (CdUtilPrivate *priv, gchar **values, GError **error) { cmsFloat32Number in; cmsHPROFILE lcms_profile; const cmsToneCurve **vcgt; guint i; guint size; /* check arguments */ if (g_strv_length (values) != 2) { g_set_error_literal (error, 1, 0, "invalid input, expect 'filename' size'"); return FALSE; } /* invalid size */ size = atoi (values[1]); if (size <= 1 || size > 1024) { g_set_error_literal (error, 1, 0, "invalid size,expected 2-1024"); return FALSE; } /* does profile have VCGT */ lcms_profile = cd_icc_get_handle (priv->icc); vcgt = cmsReadTag (lcms_profile, cmsSigVcgtTag); if (vcgt == NULL || vcgt[0] == NULL) { g_set_error_literal (error, 1, 0, "profile does not have any VCGT data"); return FALSE; } /* output data */ g_print ("idx,red,green,blue\n"); for (i = 0; i < size; i++) { in = (gdouble) i / (gdouble) (size - 1); g_print ("%u,", i); g_print ("%f,", cmsEvalToneCurveFloat(vcgt[0], in)); g_print ("%f,", cmsEvalToneCurveFloat(vcgt[1], in)); g_print ("%f\n", cmsEvalToneCurveFloat(vcgt[2], in)); } /* success */ priv->rewrite_file = 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]); } } }
void weston_cms_set_color_profile(struct weston_output *o, struct weston_color_profile *p) { #ifdef HAVE_LCMS cmsFloat32Number in; const cmsToneCurve **vcgt; int i; int size; uint16_t *red = NULL; uint16_t *green = NULL; uint16_t *blue = NULL; if (!o->set_gamma) return; if (!p) { weston_cms_gamma_clear(o); return; } weston_log("Using ICC profile %s\n", p->filename); vcgt = cmsReadTag (p->lcms_handle, cmsSigVcgtTag); if (vcgt == NULL || vcgt[0] == NULL) { weston_cms_gamma_clear(o); return; } size = o->gamma_size; red = calloc(size, sizeof(uint16_t)); green = calloc(size, sizeof(uint16_t)); blue = calloc(size, sizeof(uint16_t)); for (i = 0; i < size; i++) { in = (cmsFloat32Number) i / (cmsFloat32Number) (size - 1); red[i] = cmsEvalToneCurveFloat(vcgt[0], in) * (double) 0xffff; green[i] = cmsEvalToneCurveFloat(vcgt[1], in) * (double) 0xffff; blue[i] = cmsEvalToneCurveFloat(vcgt[2], in) * (double) 0xffff; } o->set_gamma(o, size, red, green, blue); free(red); free(green); free(blue); #endif }
// Joins two curves for X and Y. Curves should be monotonic. // We want to get // // y = Y^-1(X(t)) // cmsToneCurve* CMSEXPORT cmsJoinToneCurve(cmsContext ContextID, const cmsToneCurve* X, const cmsToneCurve* Y, cmsUInt32Number nResultingPoints) { cmsToneCurve* out = NULL; cmsToneCurve* Yreversed = NULL; cmsFloat32Number t, x; cmsFloat32Number* Res = NULL; cmsUInt32Number i; _cmsAssert(X != NULL); _cmsAssert(Y != NULL); Yreversed = cmsReverseToneCurveEx(nResultingPoints, Y); if (Yreversed == NULL) goto Error; Res = (cmsFloat32Number*) _cmsCalloc(ContextID, nResultingPoints, sizeof(cmsFloat32Number)); if (Res == NULL) goto Error; //Iterate for (i=0; i < nResultingPoints; i++) { t = (cmsFloat32Number) i / (nResultingPoints-1); x = cmsEvalToneCurveFloat(X, t); Res[i] = cmsEvalToneCurveFloat(Yreversed, x); } // Allocate space for output out = cmsBuildTabulatedToneCurveFloat(ContextID, nResultingPoints, Res); Error: if (Res != NULL) _cmsFree(ContextID, Res); if (Yreversed != NULL) cmsFreeToneCurve(Yreversed); return out; }
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 }
// The CLUT will be stored at 16 bits, but calculations are performed at cmsFloat32Number precision static int BlackPreservingSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo) { int i; cmsFloat32Number Inf[4], Outf[4]; cmsFloat32Number LabK[4]; cmsFloat64Number SumCMY, SumCMYK, Error, Ratio; cmsCIELab ColorimetricLab, BlackPreservingLab; PreserveKPlaneParams* bp = (PreserveKPlaneParams*) Cargo; // Convert from 16 bits to floating point for (i=0; i < 4; i++) Inf[i] = (cmsFloat32Number) (In[i] / 65535.0); // Get the K across Tone curve LabK[3] = cmsEvalToneCurveFloat(bp ->KTone, Inf[3]); // If going across black only, keep black only if (In[0] == 0 && In[1] == 0 && In[2] == 0) { Out[0] = Out[1] = Out[2] = 0; Out[3] = _cmsQuickSaturateWord(LabK[3] * 65535.0); return TRUE; } // Try the original transform, cmsPipelineEvalFloat( Inf, Outf, bp ->cmyk2cmyk); // Store a copy of the floating point result into 16-bit for (i=0; i < 4; i++) Out[i] = _cmsQuickSaturateWord(Outf[i] * 65535.0); // Maybe K is already ok (mostly on K=0) if ( fabs(Outf[3] - LabK[3]) < (3.0 / 65535.0) ) { return TRUE; } // K differ, mesure and keep Lab measurement for further usage // this is done in relative colorimetric intent cmsDoTransform(bp->hProofOutput, Out, &ColorimetricLab, 1); // Is not black only and the transform doesn't keep black. // Obtain the Lab of output CMYK. After that we have Lab + K cmsDoTransform(bp ->cmyk2Lab, Outf, LabK, 1); // Obtain the corresponding CMY using reverse interpolation // (K is fixed in LabK[3]) if (!cmsPipelineEvalReverseFloat(LabK, Outf, Outf, bp ->LabK2cmyk)) { // Cannot find a suitable value, so use colorimetric xform // which is already stored in Out[] return TRUE; } // Make sure to pass thru K (which now is fixed) Outf[3] = LabK[3]; // Apply TAC if needed SumCMY = Outf[0] + Outf[1] + Outf[2]; SumCMYK = SumCMY + Outf[3]; if (SumCMYK > bp ->MaxTAC) { Ratio = 1 - ((SumCMYK - bp->MaxTAC) / SumCMY); if (Ratio < 0) Ratio = 0; } else Ratio = 1.0; Out[0] = _cmsQuickSaturateWord(Outf[0] * Ratio * 65535.0); // C Out[1] = _cmsQuickSaturateWord(Outf[1] * Ratio * 65535.0); // M Out[2] = _cmsQuickSaturateWord(Outf[2] * Ratio * 65535.0); // Y Out[3] = _cmsQuickSaturateWord(Outf[3] * 65535.0); // Estimate the error (this goes 16 bits to Lab DBL) cmsDoTransform(bp->hProofOutput, Out, &BlackPreservingLab, 1); Error = cmsDeltaE(&ColorimetricLab, &BlackPreservingLab); if (Error > bp -> MaxError) bp->MaxError = Error; return TRUE; }
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; }