78#include "colord-gtk.h"
83#include <gdk/gdkwin32.h>
88#include <glib/gi18n.h>
91#include <ApplicationServices/ApplicationServices.h>
92#include <Carbon/Carbon.h>
93#include <CoreServices/CoreServices.h>
103static const cmsCIEXYZ
d65 = {0.95045471, 1.00000000, 1.08905029};
106static const cmsCIExyY
D65xyY = {0.312700492, 0.329000939, 1.0};
112static const cmsCIExyY
D50xyY = {0.3457, 0.3585, 1.0};
116 {0.6400, 0.3300, 1.0},
117 {0.3000, 0.6000, 1.0},
118 {0.1500, 0.0600, 1.0}
123 {0.7080, 0.2920, 1.0},
124 {0.1700, 0.7970, 1.0},
125 {0.1310, 0.0460, 1.0}
130 {0.6400, 0.3300, 1.0},
131 {0.3000, 0.6000, 1.0},
132 {0.1500, 0.0600, 1.0}
137 {0.6400, 0.3300, 1.0},
138 {0.2100, 0.7100, 1.0},
139 {0.1500, 0.0600, 1.0}
153 { 0.734699, 0.265301, 1.0000 },
154 { 0.159597, 0.840403, 1.0000 },
155 { 0.036598, 0.000105, 1.0000 },
193#define generate_mat3inv_body(c_type, A, B) \
194 int mat3inv_##c_type(c_type *const dst, const c_type *const src) \
197 const c_type det = A(1, 1) * (A(3, 3) * A(2, 2) - A(3, 2) * A(2, 3)) \
198 - A(2, 1) * (A(3, 3) * A(1, 2) - A(3, 2) * A(1, 3)) \
199 + A(3, 1) * (A(2, 3) * A(1, 2) - A(2, 2) * A(1, 3)); \
201 const c_type epsilon = 1e-7f; \
202 if(fabs(det) < epsilon) return 1; \
204 const c_type invDet = 1.0 / det; \
206 B(1, 1) = invDet * (A(3, 3) * A(2, 2) - A(3, 2) * A(2, 3)); \
207 B(1, 2) = -invDet * (A(3, 3) * A(1, 2) - A(3, 2) * A(1, 3)); \
208 B(1, 3) = invDet * (A(2, 3) * A(1, 2) - A(2, 2) * A(1, 3)); \
210 B(2, 1) = -invDet * (A(3, 3) * A(2, 1) - A(3, 1) * A(2, 3)); \
211 B(2, 2) = invDet * (A(3, 3) * A(1, 1) - A(3, 1) * A(1, 3)); \
212 B(2, 3) = -invDet * (A(2, 3) * A(1, 1) - A(2, 1) * A(1, 3)); \
214 B(3, 1) = invDet * (A(3, 2) * A(2, 1) - A(3, 1) * A(2, 2)); \
215 B(3, 2) = -invDet * (A(3, 2) * A(1, 1) - A(3, 1) * A(1, 2)); \
216 B(3, 3) = invDet * (A(2, 2) * A(1, 1) - A(2, 1) * A(1, 2)); \
220#define A(y, x) src[(y - 1) * 3 + (x - 1)]
221#define B(y, x) dst[(y - 1) * 3 + (x - 1)]
225 int
mat3inv(
float *const dst, const
float *const src)
233#undef generate_mat3inv_body
243 float *lutb,
const int lutsize,
const int input)
250 if(
IS_NULL_PTR(prof) || !cmsIsMatrixShaper(prof))
return 1;
258 const int UsedDirection = input ? LCMS_USED_AS_INPUT : LCMS_USED_AS_OUTPUT;
260 if(cmsIsCLUT(prof, INTENT_PERCEPTUAL, UsedDirection)
261 || cmsIsCLUT(prof, INTENT_RELATIVE_COLORIMETRIC, UsedDirection)
262 || cmsIsCLUT(prof, INTENT_ABSOLUTE_COLORIMETRIC, UsedDirection)
263 || cmsIsCLUT(prof, INTENT_SATURATION, UsedDirection))
266 cmsToneCurve *red_curve = cmsReadTag(prof, cmsSigRedTRCTag);
267 cmsToneCurve *green_curve = cmsReadTag(prof, cmsSigGreenTRCTag);
268 cmsToneCurve *blue_curve = cmsReadTag(prof, cmsSigBlueTRCTag);
270 cmsCIEXYZ *red_color = cmsReadTag(prof, cmsSigRedColorantTag);
271 cmsCIEXYZ *green_color = cmsReadTag(prof, cmsSigGreenColorantTag);
272 cmsCIEXYZ *blue_color = cmsReadTag(prof, cmsSigBlueColorantTag);
276 dt_colormatrix_t matrix_tmp = { { red_color->X, green_color->X, blue_color->X },
277 { red_color->Y, green_color->Y, blue_color->Y },
278 { red_color->Z, green_color->Z, blue_color->Z } };
283 for(
int k1 = 0; k1 < 3; k1++)
284 for(
int k2 = 0; k2 < 3; k2++)
285 sum += matrix_tmp[k1][k2];
286 if(sum == 0.0f)
return 3;
291 if(lutr && lutg && lutb)
293 if(cmsIsToneCurveLinear(red_curve))
296 for(
int k = 0;
k <
lutsize;
k++) lutr[
k] = cmsEvalToneCurveFloat(red_curve,
k / (
lutsize - 1.0f));
297 if(cmsIsToneCurveLinear(green_curve))
300 for(
int k = 0;
k <
lutsize;
k++) lutg[
k] = cmsEvalToneCurveFloat(green_curve,
k / (
lutsize - 1.0f));
301 if(cmsIsToneCurveLinear(blue_curve))
304 for(
int k = 0;
k <
lutsize;
k++) lutb[
k] = cmsEvalToneCurveFloat(blue_curve,
k / (
lutsize - 1.0f));
315 cmsToneCurve *rev_red = cmsReverseToneCurveEx(0x8000, red_curve);
316 cmsToneCurve *rev_green = cmsReverseToneCurveEx(0x8000, green_curve);
317 cmsToneCurve *rev_blue = cmsReverseToneCurveEx(0x8000, blue_curve);
320 cmsFreeToneCurve(rev_red);
321 cmsFreeToneCurve(rev_green);
322 cmsFreeToneCurve(rev_blue);
326 if(lutr && lutg && lutb)
329 if(cmsIsToneCurveLinear(red_curve))
332 for(
int k = 0;
k <
lutsize;
k++) lutr[
k] = cmsEvalToneCurveFloat(rev_red,
k / (
lutsize - 1.0f));
333 if(cmsIsToneCurveLinear(green_curve))
336 for(
int k = 0;
k <
lutsize;
k++) lutg[
k] = cmsEvalToneCurveFloat(rev_green,
k / (
lutsize - 1.0f));
337 if(cmsIsToneCurveLinear(blue_curve))
340 for(
int k = 0;
k <
lutsize;
k++) lutb[
k] = cmsEvalToneCurveFloat(rev_blue,
k / (
lutsize - 1.0f));
343 cmsFreeToneCurve(rev_red);
344 cmsFreeToneCurve(rev_green);
345 cmsFreeToneCurve(rev_blue);
355 float *lutb,
const int lutsize)
361 float *lutb,
const int lutsize)
368 return cmsCreateLab4Profile(cmsD50_xyY());
372 const cmsCIExyYTRIPLE* primaries,
373 cmsCIEXYZTRIPLE *primaries_prequantized)
375 cmsHPROFILE
profile = cmsCreateRGBProfile(whitepoint, primaries, NULL);
377 cmsCIEXYZ *
R = cmsReadTag(
profile, cmsSigRedColorantTag);
378 cmsCIEXYZ *G = cmsReadTag(
profile, cmsSigGreenColorantTag);
379 cmsCIEXYZ *
B = cmsReadTag(
profile, cmsSigBlueColorantTag);
381 primaries_prequantized->Red.X = (
double)
R->X;
382 primaries_prequantized->Red.Y = (
double)
R->Y;
383 primaries_prequantized->Red.Z = (
double)
R->Z;
385 primaries_prequantized->Green.X = (
double)G->X;
386 primaries_prequantized->Green.Y = (
double)G->Y;
387 primaries_prequantized->Green.Z = (
double)G->Z;
389 primaries_prequantized->Blue.X = (
double)
B->X;
390 primaries_prequantized->Blue.Y = (
double)
B->Y;
391 primaries_prequantized->Blue.Z = (
double)
B->Z;
397 const cmsCIExyY *whitepoint,
const cmsCIExyYTRIPLE *primaries, cmsToneCurve *trc,
400 cmsMLU *mlu1 = cmsMLUalloc(NULL, 1);
401 cmsMLU *mlu2 = cmsMLUalloc(NULL, 1);
402 cmsMLU *mlu3 = cmsMLUalloc(NULL, 1);
403 cmsMLU *mlu4 = cmsMLUalloc(NULL, 1);
405 cmsToneCurve *out_curves[3] = { trc, trc, trc };
406 cmsHPROFILE
profile = cmsCreateRGBProfile(whitepoint, primaries, out_curves);
408 if(v2) cmsSetProfileVersion(
profile, 2.4);
410 cmsSetHeaderFlags(
profile, cmsEmbeddedProfileTrue);
412 cmsMLUsetASCII(mlu1,
"en",
"US",
"Public Domain");
413 cmsWriteTag(
profile, cmsSigCopyrightTag, mlu1);
415 cmsMLUsetASCII(mlu2,
"en",
"US", desc);
416 cmsWriteTag(
profile, cmsSigProfileDescriptionTag, mlu2);
418 cmsMLUsetASCII(mlu3,
"en",
"US", dmdd);
419 cmsWriteTag(
profile, cmsSigDeviceModelDescTag, mlu3);
421 cmsMLUsetASCII(mlu4,
"en",
"US",
"darktable");
422 cmsWriteTag(
profile, cmsSigDeviceMfgDescTag, mlu4);
436 static const double M1 = 2610.0 / 16384.0;
437 static const double M2 = (2523.0 / 4096.0) * 128.0;
438 static const double C1 = 3424.0 / 4096.0;
439 static const double C2 = (2413.0 / 4096.0) * 32.0;
440 static const double C3 = (2392.0 / 4096.0) * 32.0;
442 if (
x == 0.0)
return 0.0;
443 const double sign =
x;
446 const double xpo = pow(
x, 1.0 / M2);
447 const double num =
MAX(xpo - C1, 0.0);
448 const double den = C2 - C3 * xpo;
449 const double res = pow(num / den, 1.0 / M1);
458 static const double A = 0.17883277;
459 static const double B = 0.28466892;
460 static const double C = 0.55991073;
468 const double sign =
x;
469 const double e = fabs(
x);
472 return copysign((e * e) / 3.0,
sign);
474 return copysign((exp((e -
C) /
A) +
B) / 12.0,
sign);
479 float *values = g_malloc(
sizeof(
float) *
size);
481 for (int32_t
i = 0;
i <
size; ++
i)
483 const double x = (float)
i / (
size - 1);
484 const double y =
MIN(fct(
x), 1.0f);
485 values[
i] = (float)y;
488 cmsToneCurve* result = cmsBuildTabulatedToneCurveFloat(NULL,
size, values);
495 cmsFloat64Number srgb_parameters[5] = { 2.4, 1.0 / 1.055, 0.055 / 1.055, 1.0 / 12.92, 0.04045 };
496 cmsToneCurve *transferFunction = cmsBuildParametricToneCurve(NULL, 4, srgb_parameters);
501 cmsFreeToneCurve(transferFunction);
518 cmsFloat64Number srgb_parameters[5] = { 2.4, 1.0 / 1.055, 0.055 / 1.055, 1.0 / 12.92, 0.04045 };
519 cmsToneCurve *transferFunction = cmsBuildParametricToneCurve(NULL, 4, srgb_parameters);
524 &
D65xyY, &BRG_Primaries, transferFunction,
TRUE);
526 cmsFreeToneCurve(transferFunction);
533 cmsFloat64Number srgb_parameters[5] = { 1/0.45, 1.0 / 1.099, 0.099 / 1.099, 1.0 / 4.5, 0.081 };
534 cmsToneCurve *transferFunction = cmsBuildParametricToneCurve(NULL, 4, srgb_parameters);
539 cmsFreeToneCurve(transferFunction);
547 cmsToneCurve *transferFunction = cmsBuildGamma(NULL, 2.19921875);
552 cmsFreeToneCurve(transferFunction);
562 cmsToneCurve *transferFunction = cmsBuildGamma(NULL, 2.19921875);
567 cmsFreeToneCurve(transferFunction);
590 cmsCIExyY WP = {
preset->white[0] / wxyz,
preset->white[1] / wxyz, 1.0 };
591 cmsCIExyYTRIPLE XYZPrimaries = { {
preset->rXYZ[0] / rxyz,
preset->rXYZ[1] / rxyz, 1.0 },
592 {
preset->gXYZ[0] / gxyz,
preset->gXYZ[1] / gxyz, 1.0 },
593 {
preset->bXYZ[0] / bxyz,
preset->bXYZ[1] / bxyz, 1.0 } };
594 cmsToneCurve *Gamma[3];
597 Gamma[0] = Gamma[1] = Gamma[2] = cmsBuildGamma(NULL, 1.0);
599 hp = cmsCreateRGBProfile(&WP, &XYZPrimaries, Gamma);
600 cmsFreeToneCurve(Gamma[0]);
604 snprintf(
name,
sizeof(
name),
"darktable alternate %s", makermodel);
605 cmsSetProfileVersion(hp, 2.1);
606 cmsMLU *mlu0 = cmsMLUalloc(NULL, 1);
607 cmsMLUsetASCII(mlu0,
"en",
"US",
"(dt internal)");
608 cmsMLU *mlu1 = cmsMLUalloc(NULL, 1);
609 cmsMLUsetASCII(mlu1,
"en",
"US",
name);
610 cmsMLU *mlu2 = cmsMLUalloc(NULL, 1);
611 cmsMLUsetASCII(mlu2,
"en",
"US",
name);
612 cmsWriteTag(hp, cmsSigDeviceMfgDescTag, mlu0);
613 cmsWriteTag(hp, cmsSigDeviceModelDescTag, mlu1);
615 cmsWriteTag(hp, cmsSigProfileDescriptionTag, mlu2);
640 cmsCIExyY WP = {
preset->white[0] / wxyz,
preset->white[1] / wxyz, 1.0 };
641 cmsCIExyYTRIPLE XYZPrimaries = { {
preset->rXYZ[0] / rxyz,
preset->rXYZ[1] / rxyz, 1.0 },
642 {
preset->gXYZ[0] / gxyz,
preset->gXYZ[1] / gxyz, 1.0 },
643 {
preset->bXYZ[0] / bxyz,
preset->bXYZ[1] / bxyz, 1.0 } };
644 cmsToneCurve *Gamma[3];
647 Gamma[0] = Gamma[1] = Gamma[2] = cmsBuildGamma(NULL, 1.0);
649 hp = cmsCreateRGBProfile(&WP, &XYZPrimaries, Gamma);
650 cmsFreeToneCurve(Gamma[0]);
654 snprintf(
name,
sizeof(
name),
"darktable vendor %s", makermodel);
655 cmsSetProfileVersion(hp, 2.1);
656 cmsMLU *mlu0 = cmsMLUalloc(NULL, 1);
657 cmsMLUsetASCII(mlu0,
"en",
"US",
"(dt internal)");
658 cmsMLU *mlu1 = cmsMLUalloc(NULL, 1);
659 cmsMLUsetASCII(mlu1,
"en",
"US",
name);
660 cmsMLU *mlu2 = cmsMLUalloc(NULL, 1);
661 cmsMLUsetASCII(mlu2,
"en",
"US",
name);
662 cmsWriteTag(hp, cmsSigDeviceMfgDescTag, mlu0);
663 cmsWriteTag(hp, cmsSigDeviceModelDescTag, mlu1);
665 cmsWriteTag(hp, cmsSigProfileDescriptionTag, mlu2);
690 cmsCIExyY WP = {
preset->white[0] / wxyz,
preset->white[1] / wxyz, 1.0 };
691 cmsCIExyYTRIPLE XYZPrimaries = { {
preset->rXYZ[0] / rxyz,
preset->rXYZ[1] / rxyz, 1.0 },
692 {
preset->gXYZ[0] / gxyz,
preset->gXYZ[1] / gxyz, 1.0 },
693 {
preset->bXYZ[0] / bxyz,
preset->bXYZ[1] / bxyz, 1.0 } };
694 cmsToneCurve *Gamma[3];
697 Gamma[0] = Gamma[1] = Gamma[2] = cmsBuildGamma(NULL, 1.0);
699 hp = cmsCreateRGBProfile(&WP, &XYZPrimaries, Gamma);
700 cmsFreeToneCurve(Gamma[0]);
704 snprintf(
name,
sizeof(
name),
"darktable profiled %s", makermodel);
705 cmsSetProfileVersion(hp, 2.1);
706 cmsMLU *mlu0 = cmsMLUalloc(NULL, 1);
707 cmsMLUsetASCII(mlu0,
"en",
"US",
"(dt internal)");
708 cmsMLU *mlu1 = cmsMLUalloc(NULL, 1);
709 cmsMLUsetASCII(mlu1,
"en",
"US",
name);
710 cmsMLU *mlu2 = cmsMLUalloc(NULL, 1);
711 cmsMLUsetASCII(mlu2,
"en",
"US",
name);
712 cmsWriteTag(hp, cmsSigDeviceMfgDescTag, mlu0);
713 cmsWriteTag(hp, cmsSigDeviceModelDescTag, mlu1);
715 cmsWriteTag(hp, cmsSigProfileDescriptionTag, mlu2);
725 cmsHPROFILE hXYZ = cmsCreateXYZProfile();
726 cmsSetPCS(hXYZ, cmsSigXYZData);
727 cmsSetHeaderRenderingIntent(hXYZ, INTENT_PERCEPTUAL);
731 cmsSetProfileVersion(hXYZ, 2.1);
732 cmsMLU *mlu0 = cmsMLUalloc(NULL, 1);
733 cmsMLUsetASCII(mlu0,
"en",
"US",
"(dt internal)");
734 cmsMLU *mlu1 = cmsMLUalloc(NULL, 1);
735 cmsMLUsetASCII(mlu1,
"en",
"US",
"linear XYZ");
736 cmsMLU *mlu2 = cmsMLUalloc(NULL, 1);
737 cmsMLUsetASCII(mlu2,
"en",
"US",
"darktable linear XYZ");
738 cmsWriteTag(hXYZ, cmsSigDeviceMfgDescTag, mlu0);
739 cmsWriteTag(hXYZ, cmsSigDeviceModelDescTag, mlu1);
741 cmsWriteTag(hXYZ, cmsSigProfileDescriptionTag, mlu2);
751 cmsToneCurve *transferFunction = cmsBuildGamma(NULL, 1.0);
756 cmsFreeToneCurve(transferFunction);
763 cmsToneCurve *transferFunction = cmsBuildGamma(NULL, 1.0);
768 cmsFreeToneCurve(transferFunction);
780 cmsFreeToneCurve(transferFunction);
792 cmsFreeToneCurve(transferFunction);
804 cmsFreeToneCurve(transferFunction);
816 cmsFreeToneCurve(transferFunction);
823 cmsFloat64Number srgb_parameters[5] = { 2.4, 1.0 / 1.055, 0.055 / 1.055, 1.0 / 12.92, 0.04045 };
824 cmsToneCurve *transferFunction = cmsBuildParametricToneCurve(NULL, 4, srgb_parameters);
829 cmsFreeToneCurve(transferFunction);
836 cmsToneCurve *transferFunction = cmsBuildGamma(NULL, 1.0);
841 cmsFreeToneCurve(transferFunction);
848 cmsToneCurve *transferFunction = cmsBuildGamma(NULL, 1.0);
856 cmsFreeToneCurve(transferFunction);
887static void dt_colorspaces_create_cmatrix(
float cmatrix[4][3],
float mat[3][3])
890 static const dt_colormatrix_t rgb_to_xyz = { { 0.4124564f, 0.3575761f, 0.1804375f, 0.0f },
891 { 0.2126729f, 0.7151522f, 0.0721750f, 0.0f },
892 { 0.0193339f, 0.1191920f, 0.9503041f, 0.0f } };
894 for(
int c = 0;
c < 3;
c++)
896 for(
int j = 0; j < 3; j++)
899 for(
int k = 0;
k < 3;
k++)
901 mat[
c][j] += rgb_to_xyz[
k][j] * cmatrix[
c][
k];
912 for(
int k = 0;
k < 3;
k++)
914 const float norm = mat[0][
k] + mat[1][
k] + mat[2][
k];
915 x[
k] = mat[0][
k] / norm;
916 y[
k] = mat[1][
k] / norm;
918 cmsCIExyYTRIPLE CameraPrimaries = { {
x[0], y[0], 1.0 }, {
x[1], y[1], 1.0 }, {
x[2], y[2], 1.0 } };
922 cmsXYZ2xyY(&D65, &
d65);
924 cmsToneCurve *Gamma[3];
925 Gamma[0] = Gamma[1] = Gamma[2] = cmsBuildGamma(NULL, 1.0);
926 profile = cmsCreateRGBProfile(&D65, &CameraPrimaries, Gamma);
927 cmsFreeToneCurve(Gamma[0]);
930 cmsSetProfileVersion(
profile, 2.1);
931 cmsMLU *mlu0 = cmsMLUalloc(NULL, 1);
932 cmsMLUsetASCII(mlu0,
"en",
"US",
"(dt internal)");
933 cmsMLU *mlu1 = cmsMLUalloc(NULL, 1);
934 cmsMLUsetASCII(mlu1,
"en",
"US",
"color matrix built-in");
935 cmsMLU *mlu2 = cmsMLUalloc(NULL, 1);
936 cmsMLUsetASCII(mlu2,
"en",
"US",
"color matrix built-in");
937 cmsWriteTag(
profile, cmsSigDeviceMfgDescTag, mlu0);
938 cmsWriteTag(
profile, cmsSigDeviceModelDescTag, mlu1);
940 cmsWriteTag(
profile, cmsSigProfileDescriptionTag, mlu2);
952 mat3inv((
float *)imat, (
float *)mat);
960 cmsToneCurve *trc = cmsReadTag(
profile, cmsSigGrayTRCTag);
961 cmsCIEXYZ *wtpt = cmsReadTag(
profile, cmsSigMediaWhitePointTag);
962 cmsCIEXYZ *bkpt = cmsReadTag(
profile, cmsSigMediaBlackPointTag);
963 cmsCIEXYZ *chad = cmsReadTag(
profile, cmsSigChromaticAdaptationTag);
965 cmsMLU *cprt = cmsReadTag(
profile, cmsSigCopyrightTag);
966 cmsMLU *desc = cmsReadTag(
profile, cmsSigProfileDescriptionTag);
967 cmsMLU *dmnd = cmsReadTag(
profile, cmsSigDeviceMfgDescTag);
968 cmsMLU *dmdd = cmsReadTag(
profile, cmsSigDeviceModelDescTag);
970 cmsHPROFILE rgb_profile = cmsCreateProfilePlaceholder(0);
972 cmsSetDeviceClass(rgb_profile, cmsSigDisplayClass);
973 cmsSetColorSpace(rgb_profile, cmsSigRgbData);
974 cmsSetPCS(rgb_profile, cmsSigXYZData);
976 cmsWriteTag(rgb_profile, cmsSigCopyrightTag, cprt);
977 cmsWriteTag(rgb_profile, cmsSigProfileDescriptionTag, desc);
978 cmsWriteTag(rgb_profile, cmsSigDeviceMfgDescTag, dmnd);
979 cmsWriteTag(rgb_profile, cmsSigDeviceModelDescTag, dmdd);
981 cmsWriteTag(rgb_profile, cmsSigMediaBlackPointTag, bkpt);
982 cmsWriteTag(rgb_profile, cmsSigMediaWhitePointTag, wtpt);
983 cmsWriteTag(rgb_profile, cmsSigChromaticAdaptationTag, chad);
984 cmsSetColorSpace(rgb_profile, cmsSigRgbData);
985 cmsSetPCS(rgb_profile, cmsSigXYZData);
993 cmsWriteTag(rgb_profile, cmsSigRedTRCTag, (
void *)trc);
994 cmsLinkTag(rgb_profile, cmsSigGreenTRCTag, cmsSigRedTRCTag);
995 cmsLinkTag(rgb_profile, cmsSigBlueTRCTag, cmsSigRedTRCTag);
1020 cmsUInt32Number
size;
1022 wchar_t *wbuf = NULL;
1025 size = cmsGetProfileInfoASCII(
p, cmsInfoDescription, language, country, NULL, 0);
1028 buf = (
char *)calloc(
size + 1,
sizeof(
char));
1029 size = cmsGetProfileInfoASCII(
p, cmsInfoDescription, language, country, buf,
size);
1033 if(
sizeof(
wchar_t) != 4 || g_utf8_validate(buf, -1, NULL))
1034 g_strlcpy(
name, buf, len);
1037 wbuf = (
wchar_t *)calloc(
size + 1,
sizeof(
wchar_t));
1038 size = cmsGetProfileInfo(
p, cmsInfoDescription, language, country, wbuf,
sizeof(
wchar_t) *
size);
1040 utf8 = g_ucs4_to_utf8((gunichar *)wbuf, -1, NULL, NULL, NULL);
1042 g_strlcpy(
name, utf8, len);
1052 g_strlcpy(
name, buf, len);
1063 const float pmax = fmaxf(
r, fmax(
g, b));
1064 const float pmin = fminf(
r, fmin(
g, b));
1065 const float delta = (pmax - pmin);
1067 float hv = 0, sv = 0, lv = (pmin + pmax) / 2.0;
1071 sv = lv < 0.5 ?
delta / fmaxf(pmax + pmin, 1.52587890625e-05f)
1072 :
delta / fmaxf(2.0 - pmax - pmin, 1.52587890625e-05f);
1077 hv = 2.0 + (b -
r) /
delta;
1092static inline __attribute__((always_inline))
float hue2rgb(
float m1,
float m2,
float hue)
1097 return (m1 + (m2 - m1) * hue);
1101 return hue < 4.0f ? (m1 + (m2 - m1) * (4.0f - hue)) : m1;
1112 m2 = l < 0.5 ? l * (1.0 + s) : l + s - l * s;
1113 m1 = (2.0 * l - m2);
1115 rgb[0] = hue2rgb(m1, m2, h < 4.0f ? h + 2.0f : h - 4.0f);
1116 rgb[1] = hue2rgb(m1, m2, h);
1117 rgb[2] = hue2rgb(m1, m2, h > 2.0f ? h - 2.0f : h + 4.0f);
1126 pthread_rwlock_init(&prof->
lock, NULL);
1164 cmsHPROFILE display_profile = display_dt_profile->
profile;
1310 const char *
const cur_filename,
1405 const gboolean changed = (self->
mode != mode);
1426 if(self->
mode != now)
1451 for(
int y = 0; y <
height; y++)
1453 const float *
const in = image_in + (size_t)y *
width * 4;
1454 float *
const out = image_out + (size_t)y *
width * 4;
1469 for(
int y = 0; y <
height; y++)
1474 const uint8_t *
const in = image_in + (size_t)y *
width * 4u;
1475 uint8_t *
const out = image_out + (size_t)y *
width * 4u;
1481 for(
int x = 0;
x <
width;
x++)
out[4 *
x + 3] = UINT8_MAX;
1491 const uint8_t
r = in[4 *
x + 0];
1492 const uint8_t
g = in[4 *
x + 1];
1493 const uint8_t b = in[4 *
x + 2];
1498 out[4 *
x + 3] = UINT8_MAX;
1540 gboolean owned =
FALSE;
1541 gboolean managed =
TRUE;
1570 INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE);
1593 gboolean owned =
FALSE;
1610 INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE);
1630 const int n_channels,
const gboolean has_alpha,
1631 uint8_t *
const row_in, uint8_t *
const row_out)
1635 const int s =
x * n_channels;
1636 const int d =
x * 4;
1637 row_in[
d + 0] = src[s + 0];
1638 row_in[
d + 1] = src[s + 1];
1639 row_in[
d + 2] = src[s + 2];
1640 row_in[
d + 3] = has_alpha ? src[s + 3] : UINT8_MAX;
1647 const int s =
x * 4;
1648 const int d =
x * n_channels;
1649 src[
d + 0] = row_out[s + 2];
1650 src[
d + 1] = row_out[s + 1];
1651 src[
d + 2] = row_out[s + 0];
1652 if(has_alpha) src[
d + 3] = row_out[s + 3];
1657 const int rowstride,
const int n_channels,
1658 const gboolean has_alpha)
1675 const size_t row_bytes = (size_t)
width * 4u;
1677 uint8_t *
const scratch = g_try_malloc((
size_t)nthreads * 2u * row_bytes);
1688 uint8_t *
const row_out = row_in + row_bytes;
1691 for(
int y = 0; y <
height; y++)
1711 cmsHPROFILE
profile = cmsOpenProfileFromMem(tmp_data,
size);
1714 for(GList *iter = color_profiles->
profiles; iter; iter = g_list_next(iter))
1726 pthread_rwlock_wrlock(&
p->lock);
1731 pthread_rwlock_unlock(&
p->lock);
1756 gchar *name_a = g_utf8_casefold(profile_a->
name, -1);
1757 gchar *name_b = g_utf8_casefold(profile_b->
name, -1);
1759 gint result = g_strcmp0(name_a, name_b);
1769 GList *temp_profiles = NULL;
1770 const gchar *d_name;
1775 char *lang = getenv(
"LANG");
1778 char *dirname = g_build_filename(confdir,
"color", subdir, NULL);
1779 if(!g_file_test(dirname, G_FILE_TEST_IS_DIR))
1782 dirname = g_build_filename(datadir,
"color", subdir, NULL);
1784 GDir *dir = g_dir_open(dirname, 0, NULL);
1787 while((d_name = g_dir_read_name(dir)))
1789 char *
filename = g_build_filename(dirname, d_name, NULL);
1791 for(; *cc !=
'.' && cc >
filename; cc--)
1793 if(!g_ascii_strcasecmp(cc,
".icc") || !g_ascii_strcasecmp(cc,
".icm"))
1797 if(
IS_NULL_PTR(icc_content))
goto icc_loading_done;
1800 cmsHPROFILE tmpprof =
_ensure_rgb_profile(cmsOpenProfileFromMem(icc_content,
sizeof(
char) * end));
1805 if(prof->
name[0] ==
'\0')
1806 g_strlcpy(prof->
name, _(
"(unknown name)"),
sizeof(prof->
name));
1813 temp_profiles = g_list_prepend(temp_profiles, prof);
1825 return temp_profiles;
1846 res->profiles = g_list_append(
1861 res->profiles = g_list_append(
res->profiles,
1865 res->profiles = g_list_append(
1875 res->profiles = g_list_append(
1879 res->profiles = g_list_append(
1883 res->profiles = g_list_append(
1887 res->profiles = g_list_append(
1891 res->profiles = g_list_append(
1895 res->profiles = g_list_append(
1899 res->profiles = g_list_append(
1903 res->profiles = g_list_append(
1908 res->profiles = g_list_append(
1912 res->profiles = g_list_append(
1924 g_strlcpy(
res->display_filename, tmp,
sizeof(
res->display_filename));
1926 g_strlcpy(
res->softproof_filename, tmp,
sizeof(
res->softproof_filename));
1935 && (!
res->display_filename[0] || !g_file_test(
res->display_filename, G_FILE_TEST_IS_REGULAR))))
1940 && (!
res->softproof_filename[0] || !g_file_test(
res->softproof_filename, G_FILE_TEST_IS_REGULAR))))
1944 GList *temp_profiles;
1948 for(GList *iter = temp_profiles; iter; iter = g_list_next(iter))
1953 res->profiles = g_list_concat(
res->profiles, temp_profiles);
1957 for(GList *iter = temp_profiles; iter; iter = g_list_next(iter))
1968 const gboolean is_valid_matrix_profile
1972 if(is_valid_matrix_profile)
1979 "output profile `%s' color space `%c%c%c%c' not supported for work or histogram profile\n",
1984 res->profiles = g_list_concat(
res->profiles, temp_profiles);
2017 for(GList *iter = self->
profiles; iter; iter = g_list_next(iter))
2023 pthread_rwlock_destroy(&
p->lock);
2047 return _(
"Adobe RGB (compatible)");
2049 return _(
"linear Rec709 RGB");
2051 return _(
"linear Rec2020 RGB");
2053 return _(
"linear XYZ");
2057 return _(
"linear infrared BGR");
2059 return _(
"System display profile (recommended)");
2061 return _(
"embedded ICC profile");
2063 return _(
"embedded matrix");
2065 return _(
"standard color matrix");
2067 return _(
"enhanced color matrix");
2069 return _(
"vendor color matrix");
2071 return _(
"alternate color matrix");
2073 return _(
"BRG (experimental)");
2075 return _(
"export profile");
2077 return _(
"softproof profile");
2079 return _(
"work profile");
2081 return _(
"Not used. Shouldn't be here.");
2083 return _(
"Rec709 RGB");
2085 return _(
"linear ProPhoto RGB");
2087 return _(
"PQ Rec2020");
2089 return _(
"HLG Rec2020");
2095 return _(
"Display P3");
2097 return _(
"ITU-R BT.1886");
2106static void dt_colorspaces_get_display_profile_colord_callback(GObject *source, GAsyncResult *
res, gpointer user_data)
2116 CdWindow *
window = CD_WINDOW(source);
2117 GError *
error = NULL;
2133 guchar *tmp_data = NULL;
2135 g_file_get_contents(
filename, (gchar **)&tmp_data, &
size, NULL);
2143 "[color profile] colord gave us a new screen profile: '%s' (size: %" G_GSIZE_FORMAT
")\n",
filename,
size);
2161#if defined GDK_WINDOWING_X11
2186 guint8 *buffer = NULL;
2187 gint buffer_size = 0;
2188 gchar *profile_source = NULL;
2190#if defined GDK_WINDOWING_X11
2193 gboolean use_xatom =
TRUE;
2194#if defined USE_COLORDGTK
2195 gboolean use_colord =
TRUE;
2198 if(display_profile_source)
2200 if(!strcmp(display_profile_source,
"xatom"))
2202 else if(!strcmp(display_profile_source,
"colord"))
2216 CdWindow *
window = cd_window_new();
2217 cd_window_get_profile(
window, widget, NULL, dt_colorspaces_get_display_profile_colord_callback,
2218 GINT_TO_POINTER(profile_type));
2227 || memcmp(color_profiles->
xprofile_data, buffer, buffer_size) != 0);
2231 char name[512] = { 0 };
2234 *
name ?
name :
"(unknown)", profile_source, buffer_size);
2250 if(*
f ==
'/' || *
f ==
'\\')
return FALSE;
2267 if(*
f ==
'/' || *
f ==
'\\')
2289 for(GList *iter = self->
profiles; iter; iter = g_list_next(iter))
2292 if((
p->roles & role)
2339 return (
p->roles & role) != 0;
2344 return role != 0 && (role & (role - 1)) == 0;
2349 out->type =
p->type;
2350 g_strlcpy(
out->filename,
p->filename,
sizeof(
out->filename));
2351 g_strlcpy(
out->name,
p->name,
sizeof(
out->name));
2374 pthread_rwlock_rdlock((pthread_rwlock_t *)&
profile->lock);
2380 pthread_rwlock_unlock((pthread_rwlock_t *)&
profile->lock);
2393 for(
const GList *l = self->
profiles; l; l = g_list_next(l))
2396 if(count == 0)
return 0;
2402 for(
const GList *l = self->
profiles; l; l = g_list_next(l))
2422 for(
const GList *l = self->
profiles; l; l = g_list_next(l))
2447 for(
const GList *l = self->
profiles; l; l = g_list_next(l))
2469 for(
const GList *l = self->
profiles; l; l = g_list_next(l))
2487 for(
int i = 0;
i < 3;
i++) {
2488 for(
int j = 0; j < 6; j++)
2489 work[
i][j] = j ==
i+3;
2490 for(
int j = 0; j < 3; j++)
2492 work[
i][j] += in[
k][
i] * in[
k][j];
2494 for(
int i = 0;
i < 3;
i++) {
2495 double num = work[
i][
i];
2496 for(
int j = 0; j < 6; j++)
2498 for(
int k = 0;
k < 3;
k++) {
2501 for(
int j = 0; j < 6; j++)
2502 work[
k][j] -= work[
i][j] * num;
2506 for(
int j = 0; j < 3; j++)
2509 for(
int k = 0;
k < 3;
k++)
2510 out[
i][j] += work[j][
k+3] * in[
i][
k];
2516 if(!isnan(in_XYZ_to_CAM[0]))
2518 for(
int i = 0;
i < 9;
i++)
2519 XYZ_to_CAM[
i/3][
i%3] = (
double) in_XYZ_to_CAM[
i];
2520 for(
int i = 0;
i < 3;
i++)
2521 XYZ_to_CAM[3][
i] = 0.0f;
2525 if(isnan(adobe_XYZ_to_CAM[0][0]))
2528 for(
int i = 0;
i < 4;
i++)
2529 for(
int j = 0; j < 3; j++)
2530 XYZ_to_CAM[
i][j] = (
double)adobe_XYZ_to_CAM[
i][j];
2534 double inverse[4][3];
2536 for(
int i = 0;
i < 3;
i++)
2537 for(
int j = 0; j < 4; j++)
2538 CAM_to_XYZ[
i][j] = inverse[j][
i];
2547 double (*out_RGB_to_CAM)[3],
double (*out_CAM_to_RGB)[4],
2548 const float *embedded_matrix,
2551 double RGB_to_CAM[4][3];
2553 float XYZ_to_CAM[4][3];
2554 XYZ_to_CAM[0][0] = NAN;
2556 if(
IS_NULL_PTR(embedded_matrix) || isnan(embedded_matrix[0]))
2558 for(
int k=0;
k<4;
k++)
2559 for(
int i=0;
i<3;
i++)
2560 XYZ_to_CAM[
k][
i] = adobe_XYZ_to_CAM[
k * 3 +
i];
2566 XYZ_to_CAM[0][0] = embedded_matrix[0];
2567 XYZ_to_CAM[0][1] = embedded_matrix[1];
2568 XYZ_to_CAM[0][2] = embedded_matrix[2];
2570 XYZ_to_CAM[1][0] = embedded_matrix[3];
2571 XYZ_to_CAM[1][1] = embedded_matrix[4];
2572 XYZ_to_CAM[1][2] = embedded_matrix[5];
2574 XYZ_to_CAM[2][0] = embedded_matrix[6];
2575 XYZ_to_CAM[2][1] = embedded_matrix[7];
2576 XYZ_to_CAM[2][2] = embedded_matrix[8];
2579 if(isnan(XYZ_to_CAM[0][0]))
2582 const double RGB_to_XYZ[3][3] = {
2584 { 0.412453, 0.357580, 0.180423 },
2585 { 0.212671, 0.715160, 0.072169 },
2586 { 0.019334, 0.119193, 0.950227 },
2590 for(
int i = 0;
i < 4;
i++)
2591 for(
int j = 0; j < 3; j++)
2593 RGB_to_CAM[
i][j] = 0.0f;
2594 for(
int k = 0;
k < 3;
k++)
2595 RGB_to_CAM[
i][j] += XYZ_to_CAM[
i][
k] * RGB_to_XYZ[
k][j];
2599 for(
int i = 0;
i < 4;
i++) {
2601 for(
int j = 0; j < 3; j++)
2602 num += RGB_to_CAM[
i][j];
2603 for(
int j = 0; j < 3; j++)
2604 RGB_to_CAM[
i][j] /= num;
2605 if(mul) mul[
i] = 1.0f / num;
2609 for(
int i = 0;
i < 4;
i++)
2610 for(
int j = 0; j < 3; j++)
2611 out_RGB_to_CAM[
i][j] = RGB_to_CAM[
i][j];
2616 double inverse[4][3];
2618 for(
int i = 0;
i < 3;
i++)
2619 for(
int j = 0; j < 4; j++)
2620 out_CAM_to_RGB[
i][j] = inverse[j][
i];
2630 double CAM_to_RGB_WB[3][4];
2631 for (
int a=0; a<3; a++)
2632 for (
int b=0; b<4; b++)
2633 CAM_to_RGB_WB[a][b] = CAM_to_RGB[a][b] * coeffs[b];
2636 double RGB_to_RGB_WB[3][3];
2637 for (
int a=0; a<3; a++)
2638 for (
int b=0; b<3; b++) {
2639 RGB_to_RGB_WB[a][b] = 0.0f;
2640 for (
int c=0; c<4; c++)
2641 RGB_to_RGB_WB[a][b] += CAM_to_RGB_WB[a][c] * RGB_to_CAM[c][b];
2644 for(
int i = 0;
i < num;
i++)
2646 const float *inpos = &in[
i*4];
2647 float *outpos = &
out[
i*4];
2648 outpos[0]=outpos[1]=outpos[2] = 0.0f;
2649 for (
int a=0; a<3; a++)
2650 for (
int b=0; b<3; b++)
2651 outpos[a] += RGB_to_RGB_WB[a][b] * inpos[b];
2659 for(
int i = 0;
i < num;
i++)
2661 float *in = &
out[
i*4];
2663 for(
int c = 0; c < 3; c++)
2664 for(
int k = 0;
k < 4;
k++)
2665 o[c] += CAM_to_RGB[c][
k] * in[
k];
2666 for(
int c = 0; c < 3; c++)
2674 for(
int i = 0;
i < num;
i++)
2676 float *in = &
out[
i*3];
2678 for(
int c = 0; c < 4; c++)
2679 for(
int k = 0;
k < 3;
k++)
2680 o[c] += RGB_to_CAM[c][
k] * in[
k];
2681 for(
int c = 0; c < 4; c++)
static void _update_display_profile(void)
static void error(char *msg)
uint32_t container(dt_lib_module_t *self)
static void transform(float *x, float *o, const float *m, const float t_h, const float t_v)
static void profile_changed(GtkWidget *widget, gpointer user_data)
static const dt_profiled_colormatrix_t dt_alternate_colormatrices[]
static const int dt_vendor_colormatrix_cnt
static const int dt_alternate_colormatrix_cnt
static const dt_profiled_colormatrix_t dt_vendor_colormatrices[]
static const dt_profiled_colormatrix_t dt_profiled_colormatrices[]
static const int dt_profiled_colormatrix_cnt
void dt_colorspaces_invalidate_display_profile_memo(void)
Drop the memoised DT_COLORSPACE_DISPLAY entry, whose source profile this module replaces on a monitor...
void dt_colorspaces_flush_profile_memo(void)
Drop every memoised entry. Called by dt_colorprofiles_cleanup().
The colour-profile struct and the maths over it: the derived matrix/LUT engine.
const float const int lutsize
static cmsHPROFILE dt_colorspaces_create_gamma_rec709_rgb_profile(void)
static const cmsCIExyYTRIPLE Rec2020_Primaries
void dt_colorspaces_unlock_profile(const dt_colorspaces_color_profile_t *const profile)
static const dt_colorspaces_color_profile_t * _get_profile(dt_colorspaces_t *self, dt_colorspaces_color_profile_type_t type, const char *filename, dt_colorspaces_profile_role_t role)
static void _colorspaces_destroy(dt_colorspaces_t *self)
static const char * _colorspaces_get_base_name(const char *profile)
cmsHPROFILE dt_colorspaces_create_xyzimatrix_profile(float mat[3][3])
Create a linear-gamma RGB profile from an XYZ->camera matrix.
void dt_colorspaces_free_image_profile(struct dt_colorspaces_color_profile_t *profile)
Release a profile container owned by an image, closing the LCMS2 handle inside it if and only if the ...
static cmsHPROFILE dt_colorspaces_create_linear_rec709_rgb_profile(void)
#define generate_mat3inv_body(c_type, A, B)
static uint64_t _settings_generation
static cmsHPROFILE dt_colorspaces_create_itur_bt1886_rgb_profile(void)
gboolean dt_colorprofiles_bgra8_to_adobergb_rgba8(const uint8_t *const in, uint8_t *const out, const int width, const int height, const dt_colorspaces_color_profile_type_t src_space)
The storage leg: convert an 8-bit plane from src_space (BGRA8) to AdobeRGB (RGBA8),...
void dt_colorspaces_rgb_to_cygm(float *out, int num, double RGB_to_CAM[4][3])
Convert an RGB buffer to 4-channel CYGM, in place.
gboolean dt_colorprofiles_set_display_profile_choice(const dt_colorspaces_color_profile_type_t type, const char *const filename)
Set the monitor profile identity and rebuild the four prepared transforms.
static const cmsCIExyYTRIPLE ProPhoto_Primaries
void rgb2hsl(const dt_aligned_pixel_t rgb, float *h, float *s, float *l)
Convert RGB to HSL. Common helper used by iop modules.
static cmsHPROFILE dt_colorspaces_create_lab_profile()
gboolean dt_colorprofiles_set_display_intent(const dt_iop_color_intent_t intent)
Set the rendering intent used towards the monitor, rebuilding the four prepared transforms.
static void _transform_rgba8_to_bgra8(const cmsHTRANSFORM transform, const uint8_t *image_in, uint8_t *image_out, const int width, const int height)
static dt_colorspaces_profile_changed_handler_t _profile_changed_handler
static cmsHPROFILE dt_colorspaces_create_pq_rec2020_rgb_profile(void)
static const cmsCIExyY D65xyY
void dt_colorprofiles_cleanup(void)
Persist the display/soft-proof settings to conf, flush the derived matrix/LUT memo,...
static cmsHPROFILE dt_colorspaces_create_xyzmatrix_profile(const float mat[3][3])
static const cmsCIExyYTRIPLE Rec709_Primaries
static dt_colorspaces_color_profile_t * _create_profile(dt_colorspaces_color_profile_type_t type, cmsHPROFILE profile, const char *name, dt_colorspaces_profile_role_t roles)
struct dt_colorspaces_color_profile_t * dt_colorspaces_new_image_profile(dt_colorspaces_color_profile_type_t type, cmsHPROFILE profile, gboolean owns_profile)
Build a container for a profile that belongs to ONE image rather than to the application.
void dt_colorprofiles_init(void)
Build the module's single instance: register every built-in profile, load the color/in and color/out ...
__DT_CLONE_TARGETS__ void dt_colorspaces_transform_rgba_float_image(const cmsHTRANSFORM transform, const float *image_in, float *image_out, const int width, const int height)
Run a caller-owned LCMS transform over a whole RGBA float image, one OpenMP task per row.
static void _notify_profile_changed(void)
const dt_colorspaces_color_profile_t * dt_colorspaces_get_profile(dt_colorspaces_color_profile_type_t type, const char *filename, dt_colorspaces_profile_role_t role)
Resolve a profile identity to its registered entry.
int dt_colorspaces_get_matrix_from_output_profile(cmsHPROFILE prof, dt_colormatrix_t matrix, float *lutr, float *lutg, float *lutb, const int lutsize)
Extract the XYZ->profile matrix and the inverse tone curves from an OUTPUT profile.
cmsCIEXYZTRIPLE Rec709_Primaries_Prequantized
void dt_colorspaces_update_display_transforms()
Delete and rebuild the four prepared display transforms from the current display profile and intent.
static cmsHPROFILE dt_colorspaces_create_linear_infrared_profile(void)
static cmsHPROFILE dt_colorspaces_create_hlg_p3_rgb_profile(void)
static cmsHPROFILE _create_lcms_profile(const char *desc, const char *dmdd, const cmsCIExyY *whitepoint, const cmsCIExyYTRIPLE *primaries, cmsToneCurve *trc, gboolean v2)
static cmsHPROFILE dt_colorspaces_create_srgb_profile()
static cmsHPROFILE dt_colorspaces_create_hlg_rec2020_rgb_profile(void)
static cmsHPROFILE dt_colorspaces_create_xyz_profile(void)
static dt_colorspaces_t * _colorspaces_build(void)
static cmsHPROFILE dt_colorspaces_create_display_p3_rgb_profile(void)
cmsHPROFILE dt_colorspaces_create_vendor_profile(const char *makermodel)
Create an ICC virtual profile from the shipped vendor matrices.
size_t dt_colorspaces_enumerate_profiles(const dt_colorspaces_profile_role_t role, dt_colorprofile_desc_t **out)
Ordered snapshot of every profile registered for one role.
static double _PQ_fct(double x)
gboolean dt_colorspaces_profile_exists(const dt_colorspaces_profile_role_t role, const dt_colorspaces_color_profile_type_t type, const char *const filename)
Is this identity registered for this direction?
int dt_colorspaces_get_matrix_from_input_profile(cmsHPROFILE prof, dt_colormatrix_t matrix, float *lutr, float *lutg, float *lutb, const int lutsize)
Extract the profile->XYZ matrix and the per-channel tone curves from an INPUT profile.
__DT_CLONE_TARGETS__ int dt_colorspaces_conversion_matrices_rgb(const float *adobe_XYZ_to_CAM, double(*out_RGB_to_CAM)[3], double(*out_CAM_to_RGB)[4], const float *embedded_matrix, double *mul)
Compute the sRGB->camera and camera->sRGB matrices, and the default white balance multipliers.
void dt_colorspaces_set_profile_changed_handler(dt_colorspaces_profile_changed_handler_t handler)
Register the one callback fired when the display profile changes.
static void cms_error_handler(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *text)
static cmsHPROFILE dt_colorspaces_create_linear_prophoto_rgb_profile(void)
static gboolean _colorspaces_is_base_name(const char *profile)
int mat3inv(float *const dst, const float *const src)
Thin alias of mat3inv_float(), same contract.
static __DT_CLONE_TARGETS__ void dt_colorspaces_pseudoinverse(double(*in)[3], double(*out)[3], int size)
static void _advance_settings_generation(void)
static dt_colorspaces_t * _colorprofiles
cmsHPROFILE dt_colorspaces_create_darktable_profile(const char *makermodel)
Create an ICC virtual profile from the shipped profiled colour matrices.
int dt_colorspaces_conversion_matrices_xyz(const float adobe_XYZ_to_CAM[4][3], float in_XYZ_to_CAM[9], double XYZ_to_CAM[4][3], double CAM_to_XYZ[3][4])
Compute the XYZ->camera and camera->XYZ matrices for an image.
__DT_CLONE_TARGETS__ void dt_colorspaces_cygm_to_rgb(float *out, int num, double CAM_to_RGB[3][4])
Convert a 4-channel CYGM buffer to RGB, in place.
static pthread_rwlock_t _transforms_lock
static gint _sort_profiles(gconstpointer a, gconstpointer b)
static const cmsCIExyY D50xyY
void dt_colorspaces_cleanup_profile(cmsHPROFILE p)
Close a profile created by any of the dt_colorspaces_create_* / dt_colorspaces_get_rgb_profile_from_m...
static pthread_rwlock_t _settings_lock
gboolean dt_colorprofiles_srgb_to_display_strided(uint8_t *const pixels, const int width, const int height, const int rowstride, const int n_channels, const gboolean has_alpha)
Convert a strided, packed-RGB(A) 8-bit buffer (GdkPixbuf shape) from sRGB to the display profile,...
void dt_colorspaces_set_display_profile(const dt_colorspaces_color_profile_type_t profile_type, GtkWidget *widget)
Refresh the cached display profile from the monitor showing widget (X atom, colord,...
static cmsHPROFILE dt_colorspaces_create_adobergb_profile(void)
static cmsHPROFILE dt_colorspaces_create_srgb_profile_v4()
static cmsToneCurve * _colorspaces_create_transfer(int32_t size, double(*fct)(double))
cmsHPROFILE dt_colorspaces_get_rgb_profile_from_mem(uint8_t *data, uint32_t size)
Open an lcms2 RGB profile from an in-memory ICC blob.
static void _fill_desc(const dt_colorspaces_color_profile_t *const p, dt_colorprofile_desc_t *const out)
static cmsHPROFILE dt_colorspaces_create_linear_rec2020_rgb_profile(void)
int dt_colorspaces_profile_index(const dt_colorspaces_profile_role_t role, const dt_colorspaces_color_profile_type_t type, const char *const filename)
Combo position of (type, filename) within direction.
static cmsHPROFILE dt_colorspaces_create_pq_p3_rgb_profile(void)
static gboolean _entry_serves(const dt_colorspaces_color_profile_t *const p, const dt_colorspaces_profile_role_t role)
void dt_colorprofiles_xyz_to_display(const dt_aligned_pixel_t XYZ, dt_aligned_pixel_t RGB)
Convert one D50 XYZ pixel to display RGB.
const char * dt_colorspaces_get_name(dt_colorspaces_color_profile_type_t type, const char *filename)
Printable name for a profile identity, without touching the profile list.
static GList * load_profile_from_dir(const char *subdir)
gboolean dt_colorprofiles_set_softproof_profile_choice(const dt_colorspaces_color_profile_type_t type, const char *const filename)
Set the soft-proofing target identity.
static void _update_display_transforms(dt_colorspaces_t *self)
static const cmsCIExyYTRIPLE P3_Primaries
static cmsHPROFILE _colorspaces_create_srgb_profile(gboolean v2)
void dt_colorspaces_get_profile_name(cmsHPROFILE p, const char *language, const char *country, char *name, size_t len)
Read a profile's description tag into name, handling character encodings.
static const cmsCIExyYTRIPLE sRGB_Primaries
static __DT_CLONE_TARGETS__ int dt_colorspaces_get_matrix_from_profile(cmsHPROFILE prof, dt_colormatrix_t matrix, float *lutr, float *lutg, float *lutb, const int lutsize, const int input)
cmsHPROFILE dt_colorspaces_create_alternate_profile(const char *makermodel)
Create an ICC virtual profile from the shipped alternate matrices.
static gboolean _is_single_role(const dt_colorspaces_profile_role_t role)
gboolean dt_colorprofiles_set_mode(const dt_colorspaces_color_mode_t mode)
Set the proofing mode outright.
static void _srgb_to_display_row(const cmsHTRANSFORM transform, uint8_t *const src, const int width, const int n_channels, const gboolean has_alpha, uint8_t *const row_in, uint8_t *const row_out)
gboolean dt_colorspaces_profile_at(const dt_colorspaces_profile_role_t role, const int index, dt_colorprofile_desc_t *const out)
Identity of the profile at index within direction.
gboolean dt_colorprofiles_set_softproof_intent(const dt_iop_color_intent_t intent)
Set the rendering intent used towards the soft-proofing target.
static const cmsCIExyYTRIPLE Adobe_Primaries
void hsl2rgb(dt_aligned_pixel_t rgb, float h, float s, float l)
Convert HSL back to RGB. Common helper used by iop modules.
static const cmsCIEXYZ d65
gboolean dt_colorspaces_is_profile_equal(const char *fullname, const char *filename)
Do these two names refer to the same profile file?
static cmsHPROFILE _ensure_rgb_profile(cmsHPROFILE profile)
void dt_colorspaces_lock_profile(const dt_colorspaces_color_profile_t *const profile)
dt_colorspaces_color_mode_t dt_colorprofiles_toggle_mode(const dt_colorspaces_color_mode_t mode)
Turn mode on, or back to DT_PROFILE_NORMAL if it is already the current mode, as one locked read-modi...
void dt_colorspaces_cygm_apply_coeffs_to_rgb(float *out, const float *in, int num, double RGB_to_CAM[4][3], double CAM_to_RGB[3][4], dt_aligned_pixel_t coeffs)
Apply CYGM white-balance coefficients to an image already converted to RGB by dt_colorspaces_cygm_to_...
int mat3inv_float(float *const dst, const float *const src)
Invert a 3x3 matrix stored row-major as 9 contiguous floats.
static gboolean _profile_choice_differs(const dt_colorspaces_color_profile_type_t cur_type, const char *const cur_filename, const dt_colorspaces_color_profile_type_t type, const char *const filename)
static dt_colorspaces_t * dt_colorspaces_get_global(void)
static double _HLG_fct(double x)
void dt_colorspaces_transform_rgba_float_row(const cmsHTRANSFORM transform, const float *in, float *out, const int width)
Run a caller-owned LCMS transform over one row of RGBA float pixels.
static cmsHPROFILE dt_colorspaces_create_brg_profile()
void dt_colorprofiles_get_settings(dt_colorprofiles_settings_t *const out)
Copy the current settings into caller-provided storage, under one lock.
gboolean dt_colorprofiles_rgba8_to_display_bgra8(const uint8_t *const in, uint8_t *const out, const int width, const int height, const dt_colorspaces_color_profile_type_t src_space)
Convert a whole 8-bit plane from src_space to the display profile: packed RGBA8 in,...
static void _compute_prequantized_primaries(const cmsCIExyY *whitepoint, const cmsCIExyYTRIPLE *primaries, cmsCIEXYZTRIPLE *primaries_prequantized)
The colour-profile module's API: which profiles exist, and how to apply one.
#define TYPE_XYZA_FLT
lcms2 pixel format for float XYZ + one extra channel.
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
void(* dt_colorspaces_profile_changed_handler_t)(void)
Callback invoked after the monitor profile actually changed.
static dt_aligned_pixel_t rgb
dt_XYZ_to_sRGB(XYZ, result)
static dt_aligned_pixel_t XYZ
const dt_colormatrix_t dt_aligned_pixel_t out
static const float const float C
static dt_aligned_pixel_t RGB
const dt_colormatrix_t matrix
int dt_conf_get_bool(const char *name)
void dt_conf_set_int(const char *name, int val)
int dt_conf_get_int(const char *name)
Integer for name, clamped to the bounds declared in the XML.
void dt_conf_set_string(const char *name, const char *val)
const char * dt_conf_get_string_const(const char *name)
Borrow the stored string for name without copying it.
int dt_get_num_openmp_threads(void)
Number of OpenMP threads the application decided to use.
void * dt_alloc_align(size_t size)
Allocate cacheline-aligned memory.
void dt_display_profile_read(GtkWidget *widget, guint8 **buffer, gint *buffer_size, gchar **source)
void dt_loc_get_datadir(char *datadir, size_t bufsize)
void dt_loc_get_user_config_dir(char *configdir, size_t bufsize)
struct dt_iop_tonecurve_params_t preset
_lib_location_type_t type
void dt_print(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
Print to stdout when thread is enabled, prefixed with seconds since startup.
float *const restrict const size_t k
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
float DT_ALIGNED_ARRAY dt_colormatrix_t[4][4]
static int mat3SSEinv(dt_colormatrix_t dst, const dt_colormatrix_t src)
static void dt_free_gpointer(gpointer ptr)
g_free() one pointer, with the signature GDestroyNotify wants.
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
dt_colorspaces_color_profile_type_t color_space
static int dt_get_thread_num()
Index of the calling thread within its parallel region, 0 outside one.
#define __OMP_PARALLEL__(...)
#define __OMP_PARALLEL_FOR__(...)
#define DT_PATH_MAX
Buffer size for a filesystem path anywhere in Ansel.
dt_iop_color_intent_t
ICC rendering intent, as stored in iop params and in conf.
@ DT_INTENT_ABSOLUTE_COLORIMETRIC
@ DT_INTENT_RELATIVE_COLORIMETRIC
dt_colorspaces_color_profile_type_t
@ DT_COLORSPACE_PROPHOTO_RGB
@ DT_COLORSPACE_EMBEDDED_MATRIX
@ DT_COLORSPACE_EMBEDDED_ICC
Image-derived profiles: enum 9..14, NOT registered in the list.
@ DT_COLORSPACE_FILE
A user ICC file on disk; the only type whose filename is meaningful.
@ DT_COLORSPACE_DISPLAY
The monitor profile – the one list entry that mutates after init.
@ DT_COLORSPACE_SRGB
sRGB – registered TWICE, and the two entries are not interchangeable.
@ DT_COLORSPACE_EXPORT
Category placeholders: "whatever the export/softproof/work setting currently says".
@ DT_COLORSPACE_PQ_REC2020
@ DT_COLORSPACE_DISPLAY2
Dead value, kept only because old params and conf keys contain it.
@ DT_COLORSPACE_NONE
No profile / "take it from the image settings". Never matches a list entry.
@ DT_COLORSPACE_HLG_REC2020
@ DT_COLORSPACE_LAST
Count, not a colour space. The last usable value is DT_COLORSPACE_LAST - 1.
@ DT_COLORSPACE_ENHANCED_MATRIX
@ DT_COLORSPACE_LIN_REC2020
@ DT_COLORSPACE_DISPLAY_P3
@ DT_COLORSPACE_STANDARD_MATRIX
@ DT_COLORSPACE_VENDOR_MATRIX
@ DT_COLORSPACE_SOFTPROOF
@ DT_COLORSPACE_ITUR_BT1886
@ DT_COLORSPACE_LIN_REC709
@ DT_COLORSPACE_ALTERNATE_MATRIX
dt_colorspaces_profile_role_t
Which use a profile is eligible for – the mandatory filter on every lookup and enumeration.
@ DT_PROFILE_ROLE_OUTPUT
Listed in the output/export-profile combo (colorout, export).
@ DT_PROFILE_ROLE_INPUT
Listed in the input-profile combo (colorin).
@ DT_PROFILE_ROLE_WORKING
Listed in the working-profile combo (colorin).
@ DT_PROFILE_ROLE_MONITOR
Eligible for the monitor-profile menu.
dt_colorspaces_color_mode_t
What the output transform is being asked to show: the picture, or a proof of it.
DT_ALIGNED_PIXEL float dt_aligned_pixel_t[4]
float dt_aligned_pixel_simd_t __attribute__((vector_size(16), aligned(16)))
Apply one channel's tone curve to each of the three colour channels, or pass the channel through unto...
static const dt_aligned_pixel_simd_t sign
unsigned __int64 uint64_t
A profile's public identity: what the GUI displays and stores, and nothing else.
Consistent snapshot of the display and soft-proofing settings.
One registered profile: its identity, its LCMS handle, and where it sits in each combo box.
cmsHPROFILE profile
the actual profile; NULL for the three category entries
char filename[DT_IOP_COLOR_ICC_LEN]
icc file name (absolute; compare with dt_colorspaces_is_profile_equal())
pthread_rwlock_t lock
Guards profile, and nothing else in this struct.
dt_colorspaces_color_profile_type_t type
filename is only used for type DT_COLORSPACE_FILE
char name[512]
product name, displayed in GUI (translated for built-ins)
dt_colorspaces_profile_role_t roles
Which menus this entry appears in, as a dt_colorspaces_profile_role_t mask.
The module's private state. Declared here for the module's own .c files only.
cmsHTRANSFORM transform_adobe_rgb_to_display
dt_colorspaces_color_profile_type_t softproof_type
gchar * colord_profile_file
cmsHTRANSFORM transform_display_to_adobe_rgb
cmsHTRANSFORM transform_srgb_to_display
cmsHTRANSFORM transform_xyz_to_display
dt_colorspaces_color_mode_t mode
char softproof_filename[512]
dt_colorspaces_color_profile_type_t display_type
char display_filename[512]
dt_iop_color_intent_t softproof_intent
dt_iop_color_intent_t display_intent
#define __DT_CLONE_TARGETS__
typedef double((*spd)(unsigned long int wavelength, double TempK))
char * dt_read_file(const char *const filename, size_t *filesize)