// Create the ICC virtual profile for sRGB space cmsHPROFILE LCMSEXPORT cmsCreate_sRGBProfile(void) { cmsCIExyY D65; cmsCIExyYTRIPLE Rec709Primaries = { {0.6400, 0.3300, 1.0}, {0.3000, 0.6000, 1.0}, {0.1500, 0.0600, 1.0} }; LPGAMMATABLE Gamma22[3]; cmsHPROFILE hsRGB; cmsWhitePointFromTemp(6504, &D65); Gamma22[0] = Gamma22[1] = Gamma22[2] = Build_sRGBGamma(); hsRGB = cmsCreateRGBProfile(&D65, &Rec709Primaries, Gamma22); cmsFreeGamma(Gamma22[0]); if (hsRGB == NULL) return NULL; cmsAddTag(hsRGB, icSigDeviceMfgDescTag, (LPVOID) "(lcms internal)"); cmsAddTag(hsRGB, icSigDeviceModelDescTag, (LPVOID) "sRGB built-in"); cmsAddTag(hsRGB, icSigProfileDescriptionTag, (LPVOID) "sRGB built-in"); return hsRGB; }
// Create the ICC virtual profile for sRGB space cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfileTHR(cmsContext ContextID) { cmsCIExyY D65; cmsCIExyYTRIPLE Rec709Primaries = { {0.6400, 0.3300, 1.0}, {0.3000, 0.6000, 1.0}, {0.1500, 0.0600, 1.0} }; cmsToneCurve* Gamma22[3]; cmsHPROFILE hsRGB; cmsWhitePointFromTemp(&D65, 6504); Gamma22[0] = Gamma22[1] = Gamma22[2] = Build_sRGBGamma(ContextID); if (Gamma22[0] == NULL) return NULL; hsRGB = cmsCreateRGBProfileTHR(ContextID, &D65, &Rec709Primaries, Gamma22); cmsFreeToneCurve(Gamma22[0]); if (hsRGB == NULL) return NULL; if (!SetTextTags(hsRGB, L"sRGB built-in")) { cmsCloseProfile(hsRGB); return NULL; } return hsRGB; }
static cmsHPROFILE OpenProfile(const char* File) { if (!File) return cmsCreate_sRGBProfile(); if (stricmp(File, "*sRGB") == 0) return cmsCreate_sRGBProfile(NULL); if (stricmp(File, "*Lab") == 0) return cmsCreateLabProfile(NULL); if (stricmp(File, "*LabD65") == 0) { cmsCIExyY D65xyY; cmsWhitePointFromTemp(6504, &D65xyY); return cmsCreateLabProfile(&D65xyY); } if (stricmp(File, "*XYZ") == 0) return cmsCreateXYZProfile(); if (stricmp(File, "*Gray22") == 0) { LPGAMMATABLE Gamma = cmsBuildGamma(256, 2.2); cmsHPROFILE hProfile = cmsCreateGrayProfile(cmsD50_xyY(), Gamma); cmsFreeGamma(Gamma); return hProfile; } return cmsOpenProfileFromFile(File, "r"); }
// Compute a CHAD based on a given temperature static void Temp2CHAD(cmsMAT3* Chad, cmsFloat64Number Temp) { cmsCIEXYZ White; cmsCIExyY ChromaticityOfWhite; cmsWhitePointFromTemp(&ChromaticityOfWhite, Temp); cmsxyY2XYZ(&White, &ChromaticityOfWhite); _cmsAdaptationMatrix(Chad, NULL, &White, cmsD50_XYZ()); }
static int FromD40toD150(LPWHITEPOINTS pts) { int i, n; n = 0; for (i=40; i < 150; i ++) { sprintf(pts[n].Name, "D%d", i); cmsWhitePointFromTemp((int) (i*100.0), &pts[n].Val); n++; } return n; }
cmsHPROFILE dt_colorspaces_create_xyzmatrix_profile(float mat[3][3]) { // mat: cam -> xyz cmsCIExyY D65; float x[3], y[3]; for(int k=0; k<3; k++) { const float norm = mat[0][k] + mat[1][k] + mat[2][k]; x[k] = mat[0][k] / norm; y[k] = mat[1][k] / norm; } cmsCIExyYTRIPLE CameraPrimaries = { {x[0], y[0], 1.0}, {x[1], y[1], 1.0}, {x[2], y[2], 1.0} }; cmsHPROFILE cmat; cmsWhitePointFromTemp(&D65, 6504.0); cmsToneCurve *Gamma[3]; Gamma[0] = Gamma[1] = Gamma[2] = build_linear_gamma(); cmat = cmsCreateRGBProfile(&D65, &CameraPrimaries, Gamma); if (cmat == NULL) return NULL; cmsFreeToneCurve(Gamma[0]); cmsSetProfileVersion(cmat, 2.1); cmsMLU *mlu0 = cmsMLUalloc(NULL, 1); cmsMLUsetASCII(mlu0, "en", "US", "(dt internal)"); cmsMLU *mlu1 = cmsMLUalloc(NULL, 1); cmsMLUsetASCII(mlu1, "en", "US", "color matrix built-in"); cmsMLU *mlu2 = cmsMLUalloc(NULL, 1); cmsMLUsetASCII(mlu2, "en", "US", "color matrix built-in"); cmsWriteTag(cmat, cmsSigDeviceMfgDescTag, mlu0); cmsWriteTag(cmat, cmsSigDeviceModelDescTag, mlu1); // this will only be displayed when the embedded profile is read by for example GIMP cmsWriteTag(cmat, cmsSigProfileDescriptionTag, mlu2); cmsMLUfree(mlu0); cmsMLUfree(mlu1); cmsMLUfree(mlu2); return cmat; }
mng_cmsprof mnglcms_createsrgbprofile (void) { cmsCIExyY D65; cmsCIExyYTRIPLE Rec709Primaries = { {0.6400, 0.3300, 1.0}, {0.3000, 0.6000, 1.0}, {0.1500, 0.0600, 1.0} }; LPGAMMATABLE Gamma24[3]; mng_cmsprof hsRGB; cmsWhitePointFromTemp(6504, &D65); Gamma24[0] = Gamma24[1] = Gamma24[2] = cmsBuildGamma(256, 2.4); hsRGB = cmsCreateRGBProfile(&D65, &Rec709Primaries, Gamma24); cmsFreeGamma(Gamma24[0]); return hsRGB; }
static PyObject * createProfile(PyObject *self, PyObject *args) { char *sColorSpace; cmsHPROFILE hProfile; int iColorTemp = 0; LPcmsCIExyY whitePoint = NULL; LCMSBOOL result; if (!PyArg_ParseTuple(args, "s|i:createProfile", &sColorSpace, &iColorTemp)) return NULL; cmsErrorAction(LCMS_ERROR_IGNORE); if (strcmp(sColorSpace, "LAB") == 0) { if (iColorTemp > 0) { result = cmsWhitePointFromTemp(iColorTemp, whitePoint); if (!result) { PyErr_SetString(PyExc_ValueError,"ERROR: Could not calculate "\ "white point from color temperature provided, must be "\ "integer in degrees Kelvin"); return NULL; } hProfile = cmsCreateLabProfile(whitePoint); } else hProfile = cmsCreateLabProfile(NULL); } else if (strcmp(sColorSpace, "XYZ") == 0) hProfile = cmsCreateXYZProfile(); else if (strcmp(sColorSpace, "sRGB") == 0) hProfile = cmsCreate_sRGBProfile(); else hProfile = NULL; if (!hProfile) { PyErr_SetString(PyExc_ValueError, "failed to create requested color space"); return NULL; } return cms_profile_new(hProfile); }
static PyObject * createProfile(PyObject *self, PyObject *args) { char *sColorSpace; cmsHPROFILE hProfile; cmsFloat64Number dColorTemp = 0.0; cmsCIExyY whitePoint; cmsBool result; if (!PyArg_ParseTuple(args, "s|d:createProfile", &sColorSpace, &dColorTemp)) return NULL; if (strcmp(sColorSpace, "LAB") == 0) { if (dColorTemp > 0.0) { result = cmsWhitePointFromTemp(&whitePoint, dColorTemp); if (!result) { PyErr_SetString(PyExc_ValueError, "ERROR: Could not calculate white point from color temperature provided, must be float in degrees Kelvin"); return NULL; } hProfile = cmsCreateLab2Profile(&whitePoint); } else { hProfile = cmsCreateLab2Profile(NULL); } } else if (strcmp(sColorSpace, "XYZ") == 0) { hProfile = cmsCreateXYZProfile(); } else if (strcmp(sColorSpace, "sRGB") == 0) { hProfile = cmsCreate_sRGBProfile(); } else { hProfile = NULL; } if (!hProfile) { PyErr_SetString(PyExc_ValueError, "failed to create requested color space"); return NULL; } return cms_profile_new(hProfile); }
/* * Bruce Lindbloom, "Spectral Power Distribution of a CIE D-Illuminant" * http://www.brucelindbloom.com/Eqn_DIlluminant.html * and https://en.wikipedia.org/wiki/Standard_illuminant#Illuminant_series_D */ static double spd_daylight(unsigned long int wavelength, double TempK) { cmsCIExyY WhitePoint = { 0.3127, 0.3290, 1.0 }; /* * Bruce Lindbloom, "TempK to xy" * http://www.brucelindbloom.com/Eqn_T_to_xy.html */ cmsWhitePointFromTemp(&WhitePoint, TempK); const double M = (0.0241 + 0.2562 * WhitePoint.x - 0.7341 * WhitePoint.y), m1 = (-1.3515 - 1.7703 * WhitePoint.x + 5.9114 * WhitePoint.y) / M, m2 = (0.0300 - 31.4424 * WhitePoint.x + 30.0717 * WhitePoint.y) / M; const unsigned long int j = ((wavelength - cie_daylight_components[0].wavelength) / (cie_daylight_components[1].wavelength - cie_daylight_components[0].wavelength)); return (cie_daylight_components[j].S[0] + m1 * cie_daylight_components[j].S[1] + m2 * cie_daylight_components[j].S[2]); }
cmsHPROFILE dt_colorspaces_create_linear_infrared_profile(void) { // linear rgb with r and b swapped: cmsCIExyY D65; cmsCIExyYTRIPLE Rec709Primaries = { {0.1500, 0.0600, 1.0}, {0.3000, 0.6000, 1.0}, {0.6400, 0.3300, 1.0} }; cmsToneCurve *Gamma[3]; cmsHPROFILE hsRGB; cmsWhitePointFromTemp(&D65, 6504.0); Gamma[0] = Gamma[1] = Gamma[2] = build_linear_gamma(); hsRGB = cmsCreateRGBProfile(&D65, &Rec709Primaries, Gamma); cmsFreeToneCurve(Gamma[0]); if (hsRGB == NULL) return NULL; cmsSetProfileVersion(hsRGB, 2.1); cmsMLU *mlu0 = cmsMLUalloc(NULL, 1); cmsMLUsetASCII(mlu0, "en", "US", "(dt internal)"); cmsMLU *mlu1 = cmsMLUalloc(NULL, 1); cmsMLUsetASCII(mlu1, "en", "US", "linear infrared bgr"); cmsMLU *mlu2 = cmsMLUalloc(NULL, 1); cmsMLUsetASCII(mlu2, "en", "US", "Darktable Linear Infrared RGB"); cmsWriteTag(hsRGB, cmsSigDeviceMfgDescTag, mlu0); cmsWriteTag(hsRGB, cmsSigDeviceModelDescTag, mlu1); // this will only be displayed when the embedded profile is read by for example GIMP cmsWriteTag(hsRGB, cmsSigProfileDescriptionTag, mlu2); cmsMLUfree(mlu0); cmsMLUfree(mlu1); cmsMLUfree(mlu2); return hsRGB; }
// Create the ICC virtual profile for adobe rgb space cmsHPROFILE dt_colorspaces_create_adobergb_profile(void) { cmsCIExyY D65; cmsCIExyYTRIPLE AdobePrimaries = { {0.6400, 0.3300, 1.0}, {0.2100, 0.7100, 1.0}, {0.1500, 0.0600, 1.0} }; cmsToneCurve *Gamma22[3]; cmsHPROFILE hAdobeRGB; cmsWhitePointFromTemp(&D65, 6504.0); Gamma22[0] = Gamma22[1] = Gamma22[2] = build_adobergb_gamma(); hAdobeRGB = cmsCreateRGBProfile(&D65, &AdobePrimaries, Gamma22); cmsFreeToneCurve(Gamma22[0]); if (hAdobeRGB == NULL) return NULL; cmsSetProfileVersion(hAdobeRGB, 2.1); cmsMLU *mlu0 = cmsMLUalloc(NULL, 1); cmsMLUsetASCII(mlu0, "en", "US", "(dt internal)"); cmsMLU *mlu1 = cmsMLUalloc(NULL, 1); cmsMLUsetASCII(mlu1, "en", "US", "AdobeRGB"); cmsMLU *mlu2 = cmsMLUalloc(NULL, 1); cmsMLUsetASCII(mlu2, "en", "US", "Darktable AdobeRGB"); cmsWriteTag(hAdobeRGB, cmsSigDeviceMfgDescTag, mlu0); cmsWriteTag(hAdobeRGB, cmsSigDeviceModelDescTag, mlu1); // this will only be displayed when the embedded profile is read by for example GIMP cmsWriteTag(hAdobeRGB, cmsSigProfileDescriptionTag, mlu2); cmsMLUfree(mlu0); cmsMLUfree(mlu1); cmsMLUfree(mlu2); return hAdobeRGB; }
cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID, int nLUTPoints, cmsFloat64Number Bright, cmsFloat64Number Contrast, cmsFloat64Number Hue, cmsFloat64Number Saturation, int TempSrc, int TempDest) { cmsHPROFILE hICC; cmsPipeline* Pipeline; BCHSWADJUSTS bchsw; cmsCIExyY WhitePnt; cmsStage* CLUT; cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; int i; bchsw.Brightness = Bright; bchsw.Contrast = Contrast; bchsw.Hue = Hue; bchsw.Saturation = Saturation; cmsWhitePointFromTemp(&WhitePnt, TempSrc ); cmsxyY2XYZ(&bchsw.WPsrc, &WhitePnt); cmsWhitePointFromTemp(&WhitePnt, TempDest); cmsxyY2XYZ(&bchsw.WPdest, &WhitePnt); hICC = cmsCreateProfilePlaceholder(ContextID); if (!hICC) // can't allocate return NULL; cmsSetDeviceClass(hICC, cmsSigAbstractClass); cmsSetColorSpace(hICC, cmsSigLabData); cmsSetPCS(hICC, cmsSigLabData); cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); // Creates a Pipeline with 3D grid only Pipeline = cmsPipelineAlloc(ContextID, 3, 3); if (Pipeline == NULL) { cmsCloseProfile(hICC); return NULL; } for (i=0; i < MAX_INPUT_DIMENSIONS; i++) Dimensions[i] = nLUTPoints; CLUT = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, 3, 3, NULL); if (CLUT == NULL) return NULL; if (!cmsStageSampleCLut16bit(CLUT, bchswSampler, (void*) &bchsw, 0)) { // Shouldn't reach here goto Error; } if (!cmsPipelineInsertStage(Pipeline, cmsAT_END, CLUT)) { goto Error; } // Create tags if (!SetTextTags(hICC, L"BCHS built-in")) return NULL; cmsWriteTag(hICC, cmsSigMediaWhitePointTag, (void*) cmsD50_XYZ()); cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) Pipeline); // Pipeline is already on virtual profile cmsPipelineFree(Pipeline); // Ok, done return hICC; Error: cmsPipelineFree(Pipeline); cmsCloseProfile(hICC); return NULL; }
/** * cd_util_create_standard_space: **/ static gboolean cd_util_create_standard_space (CdUtilPrivate *priv, CdDom *dom, const GNode *root, GError **error) { CdColorYxy yxy; cmsCIExyYTRIPLE primaries; cmsCIExyY white; cmsToneCurve *transfer[3] = { NULL, NULL, NULL}; const gchar *data; const GNode *tmp; gboolean ret; gdouble curve_gamma; /* parse gamma */ tmp = cd_dom_get_node (dom, root, "gamma"); if (tmp == NULL) { ret = FALSE; g_set_error_literal (error, 1, 0, "XML error, expected gamma"); goto out; } data = cd_dom_get_node_data (tmp); if (g_strcmp0 (data, "sRGB") == 0) { transfer[0] = cd_util_build_srgb_gamma (); transfer[1] = transfer[0]; transfer[2] = transfer[0]; } else if (g_strcmp0 (data, "L*") == 0) { transfer[0] = cd_util_build_lstar_gamma (); transfer[1] = transfer[0]; transfer[2] = transfer[0]; } else if (g_strcmp0 (data, "Rec709") == 0) { transfer[0] = cd_util_build_rec709_gamma (); transfer[1] = transfer[0]; transfer[2] = transfer[0]; } else { curve_gamma = cd_dom_get_node_data_as_double (tmp); if (curve_gamma == G_MAXDOUBLE) { ret = FALSE; g_set_error (error, 1, 0, "failed to parse gamma: '%s'", data); goto out; } transfer[0] = cmsBuildGamma (NULL, curve_gamma); transfer[1] = transfer[0]; transfer[2] = transfer[0]; } /* values taken from https://en.wikipedia.org/wiki/Standard_illuminant */ tmp = cd_dom_get_node (dom, root, "whitepoint"); if (tmp == NULL) { ret = FALSE; g_set_error_literal (error, 1, 0, "XML error, expected whitepoint"); goto out; } data = cd_dom_get_node_data (tmp); white.Y = 1.0f; if (g_strcmp0 (data, "C") == 0) { white.x = 0.31006; white.y = 0.31616; } else if (g_strcmp0 (data, "E") == 0) { white.x = 0.33333; white.y = 0.33333; } else if (g_strcmp0 (data, "D50") == 0) { white.x = 0.345703; white.y = 0.358539; } else if (g_strcmp0 (data, "D65") == 0) { cmsWhitePointFromTemp (&white, 6504); } else { ret = FALSE; g_set_error_literal (error, 1, 0, "unknown illuminant, expected C, E, D50 or D65"); goto out; } /* get red primary */ tmp = cd_dom_get_node (dom, root, "primaries/red"); if (tmp == NULL) { ret = FALSE; g_set_error_literal (error, 1, 0, "XML error, expected primaries/red"); goto out; } ret = cd_dom_get_node_yxy (tmp, &yxy); if (!ret) { g_set_error_literal (error, 1, 0, "XML error, invalid primaries/red"); goto out; } primaries.Red.x = yxy.x; primaries.Red.y = yxy.y; primaries.Red.Y = yxy.Y; /* get green primary */ tmp = cd_dom_get_node (dom, root, "primaries/green"); if (tmp == NULL) { ret = FALSE; g_set_error_literal (error, 1, 0, "XML error, expected primaries/green"); goto out; } ret = cd_dom_get_node_yxy (tmp, &yxy); if (!ret) { g_set_error_literal (error, 1, 0, "XML error, invalid primaries/green"); goto out; } primaries.Green.x = yxy.x; primaries.Green.y = yxy.y; primaries.Green.Y = yxy.Y; /* get blue primary */ tmp = cd_dom_get_node (dom, root, "primaries/blue"); if (tmp == NULL) { ret = FALSE; g_set_error_literal (error, 1, 0, "XML error, expected primaries/blue"); goto out; } ret = cd_dom_get_node_yxy (tmp, &yxy); if (!ret) { g_set_error_literal (error, 1, 0, "XML error, invalid primaries/blue"); goto out; } primaries.Blue.x = yxy.x; primaries.Blue.y = yxy.y; primaries.Blue.Y = yxy.Y; /* create profile */ priv->lcms_profile = cmsCreateRGBProfileTHR (cd_icc_get_context (priv->icc), &white, &primaries, transfer); ret = TRUE; out: cmsFreeToneCurve (transfer[0]); return ret; }
// Virtual profiles are handled here. cmsHPROFILE OpenStockProfile(cmsContext ContextID, const char* File) { if (!File) return cmsCreate_sRGBProfileTHR(ContextID); if (cmsstrcasecmp(File, "*Lab2") == 0) return cmsCreateLab2ProfileTHR(ContextID, NULL); if (cmsstrcasecmp(File, "*Lab4") == 0) return cmsCreateLab4ProfileTHR(ContextID, NULL); if (cmsstrcasecmp(File, "*Lab") == 0) return cmsCreateLab4ProfileTHR(ContextID, NULL); if (cmsstrcasecmp(File, "*LabD65") == 0) { cmsCIExyY D65xyY; cmsWhitePointFromTemp( &D65xyY, 6504); return cmsCreateLab4ProfileTHR(ContextID, &D65xyY); } if (cmsstrcasecmp(File, "*XYZ") == 0) return cmsCreateXYZProfileTHR(ContextID); if (cmsstrcasecmp(File, "*Gray22") == 0) { cmsToneCurve* Curve = cmsBuildGamma(ContextID, 2.2); cmsHPROFILE hProfile = cmsCreateGrayProfileTHR(ContextID, cmsD50_xyY(), Curve); cmsFreeToneCurve(Curve); return hProfile; } if (cmsstrcasecmp(File, "*Gray30") == 0) { cmsToneCurve* Curve = cmsBuildGamma(ContextID, 3.0); cmsHPROFILE hProfile = cmsCreateGrayProfileTHR(ContextID, cmsD50_xyY(), Curve); cmsFreeToneCurve(Curve); return hProfile; } if (cmsstrcasecmp(File, "*srgb") == 0) return cmsCreate_sRGBProfileTHR(ContextID); if (cmsstrcasecmp(File, "*null") == 0) return cmsCreateNULLProfileTHR(ContextID); if (cmsstrcasecmp(File, "*Lin2222") == 0) { cmsToneCurve* Gamma = cmsBuildGamma(0, 2.2); cmsToneCurve* Gamma4[4]; cmsHPROFILE hProfile; Gamma4[0] = Gamma4[1] = Gamma4[2] = Gamma4[3] = Gamma; hProfile = cmsCreateLinearizationDeviceLink(cmsSigCmykData, Gamma4); cmsFreeToneCurve(Gamma); return hProfile; } return cmsOpenProfileFromFileTHR(ContextID, File, "r"); }
cmsHPROFILE LCMSEXPORT cmsCreateBCHSWabstractProfile(int nLUTPoints, double Bright, double Contrast, double Hue, double Saturation, int TempSrc, int TempDest) { cmsHPROFILE hICC; LPLUT Lut; BCHSWADJUSTS bchsw; cmsCIExyY WhitePnt; bchsw.Brightness = Bright; bchsw.Contrast = Contrast; bchsw.Hue = Hue; bchsw.Saturation = Saturation; cmsWhitePointFromTemp(TempSrc, &WhitePnt); cmsxyY2XYZ(&bchsw.WPsrc, &WhitePnt); cmsWhitePointFromTemp(TempDest, &WhitePnt); cmsxyY2XYZ(&bchsw.WPdest, &WhitePnt); hICC = _cmsCreateProfilePlaceholder(); if (!hICC) // can't allocate return NULL; cmsSetDeviceClass(hICC, icSigAbstractClass); cmsSetColorSpace(hICC, icSigLabData); cmsSetPCS(hICC, icSigLabData); cmsSetRenderingIntent(hICC, INTENT_PERCEPTUAL); // Creates a LUT with 3D grid only Lut = cmsAllocLUT(); if (Lut == NULL) { cmsCloseProfile(hICC); return NULL; } cmsAlloc3DGrid(Lut, nLUTPoints, 3, 3); if (!cmsSample3DGrid(Lut, bchswSampler, (LPVOID) &bchsw, 0)) { // Shouldn't reach here cmsFreeLUT(Lut); cmsCloseProfile(hICC); return NULL; } // Create tags cmsAddTag(hICC, icSigDeviceMfgDescTag, (LPVOID) "(lcms internal)"); cmsAddTag(hICC, icSigProfileDescriptionTag, (LPVOID) "lcms BCHSW abstract profile"); cmsAddTag(hICC, icSigDeviceModelDescTag, (LPVOID) "BCHSW built-in"); cmsAddTag(hICC, icSigMediaWhitePointTag, (LPVOID) cmsD50_XYZ()); cmsAddTag(hICC, icSigAToB0Tag, (LPVOID) Lut); // LUT is already on virtual profile cmsFreeLUT(Lut); // Ok, done return hICC; }