cmsHPROFILE dt_colorspaces_create_xyzimatrix_profile(float mat[3][3]) { // mat: xyz -> cam float imat[3][3]; mat3inv ((float *)imat, (float *)mat); return dt_colorspaces_create_xyzmatrix_profile(imat); }
int matpl2( mat3typ tr, rvec3typ pl ) { if ( !mat3inv( tr ) ) return 0; return imatpl2( tr, pl ); }
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; }
int dt_colorspaces_get_darktable_matrix(const char *makermodel, float *matrix) { dt_profiled_colormatrix_t *preset = NULL; for(int k=0; k<dt_profiled_colormatrix_cnt; k++) { if(!strcasecmp(makermodel, dt_profiled_colormatrices[k].makermodel)) { preset = dt_profiled_colormatrices + k; break; } } if(!preset) return -1; const float wxyz = preset->white[0]+ preset->white[1]+ preset->white[2]; const float rxyz = preset->rXYZ[0] + preset->rXYZ[1] + preset->rXYZ[2]; const float gxyz = preset->gXYZ[0] + preset->gXYZ[1] + preset->gXYZ[2]; const float bxyz = preset->bXYZ[0] + preset->bXYZ[1] + preset->bXYZ[2]; const float xn = preset->white[0]/wxyz; const float yn = preset->white[1]/wxyz; const float xr = preset->rXYZ[0]/rxyz; const float yr = preset->rXYZ[1]/rxyz; const float xg = preset->gXYZ[0]/gxyz; const float yg = preset->gXYZ[1]/gxyz; const float xb = preset->bXYZ[0]/bxyz; const float yb = preset->bXYZ[1]/bxyz; const float primaries[9] = {xr, xg, xb, yr, yg, yb, 1.0f-xr-yr, 1.0f-xg-yg, 1.0f-xb-yb }; float result[9]; if(mat3inv(result, primaries)) return -1; const float whitepoint[3] = {xn/yn, 1.0f, (1.0f-xn-yn)/yn}; float coeff[3]; // get inverse primary whitepoint mat3mulv(coeff, result, whitepoint); float tmp[9] = { coeff[0]*xr, coeff[1]*xg, coeff[2]*xb, coeff[0]*yr, coeff[1]*yg, coeff[2]*yb, coeff[0]*(1.0f-xr-yr), coeff[1]*(1.0f-xg-yg), coeff[2]*(1.0f-xb-yb) }; // input whitepoint[] in XYZ with Y normalized to 1.0f const float dn[3] = { preset->white[0]/(float)preset->white[1], 1.0f, preset->white[2]/(float)preset->white[1]}; const float lam_rigg[9] = { 0.8951, 0.2664, -0.1614, -0.7502, 1.7135, 0.0367, 0.0389, -0.0685, 1.0296 }; const float d50[3] = { 0.9642, 1.0, 0.8249 }; // adapt to d50 float chad_inv[9]; if(mat3inv(chad_inv, lam_rigg)) return -1; float cone_src_rgb[3], cone_dst_rgb[3]; mat3mulv(cone_src_rgb, lam_rigg, dn); mat3mulv(cone_dst_rgb, lam_rigg, d50); const float cone[9] = { cone_dst_rgb[0]/cone_src_rgb[0], 0.0f, 0.0f, 0.0f, cone_dst_rgb[1]/cone_src_rgb[1], 0.0f, 0.0f, 0.0f, cone_dst_rgb[2]/cone_src_rgb[2] }; float tmp2[9]; float bradford[9]; mat3mul(tmp2, cone, lam_rigg); mat3mul(bradford, chad_inv, tmp2); mat3mul(matrix, bradford, tmp); return 0; }