summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Plattner <aplattner@nvidia.com>2020-02-21 08:07:25 -0800
committerRichard Hughes <richard@hughsie.com>2020-03-23 19:52:27 +0000
commit9aba3df9895f58759f74d6b47f9434c2730d87f4 (patch)
tree993c4cef6a69d30451232363787d2510561c80ff
parent6d64e4cc8b6846bed6a242ff90403c0310208fdc (diff)
downloadcolord-9aba3df9895f58759f74d6b47f9434c2730d87f4.tar.gz
libcolord: Add cd_icc_utils_get_adaptation_matrix
Window systems such as gnome-shell can use this to calculate a color transform matrix (CTM) to plug into typical desktop display hardware.
-rw-r--r--lib/colord/cd-icc-utils.c123
-rw-r--r--lib/colord/cd-icc-utils.h6
2 files changed, 129 insertions, 0 deletions
diff --git a/lib/colord/cd-icc-utils.c b/lib/colord/cd-icc-utils.c
index ea6f65c..20db8e3 100644
--- a/lib/colord/cd-icc-utils.c
+++ b/lib/colord/cd-icc-utils.c
@@ -172,3 +172,126 @@ cd_icc_utils_get_coverage (CdIcc *icc,
*coverage = coverage_tmp;
return TRUE;
}
+
+/**
+ * cd_icc_utils_get_chroma_matrix:
+ * @icc: The profile to use.
+ * @mat: (out): The returned matrix containing the primaries from @icc.
+ *
+ * Fills a 3x3 matrix with the XYZ red, green, and blue primary values from an
+ * ICC profile as columns.
+ */
+static void
+cd_icc_utils_get_chroma_matrix (CdIcc *icc, CdMat3x3 *mat)
+{
+ const CdColorXYZ *red = cd_icc_get_red (icc);
+ const CdColorXYZ *green = cd_icc_get_green (icc);
+ const CdColorXYZ *blue = cd_icc_get_blue (icc);
+ CdMat3x3 matrix = {
+ red->X, green->X, blue->X,
+ red->Y, green->Y, blue->Y,
+ red->Z, green->Z, blue->Z };
+
+ *mat = matrix;
+}
+
+/**
+ * cd_bradford_transform:
+ * @reference: The white point to use as a reference.
+ * @measured: The white point measurement for the target device.
+ * @mat: (out): The returned Bradford color adaptation matrix.
+ */
+static void
+cd_bradford_transform (const CdColorXYZ *reference,
+ const CdColorXYZ *measured,
+ CdMat3x3 *mat)
+{
+ /* see https://onlinelibrary.wiley.com/doi/pdf/10.1002/9781119021780.app3 */
+ const CdMat3x3 bradford_response_matrix = {
+ 0.8951, 0.2664, -0.1614,
+ -0.7502, 1.7135, 0.0367,
+ 0.0389, -0.0685, 1.0296 };
+ CdMat3x3 bradford_inv;
+ CdMat3x3 ratio;
+ CdMat3x3 tmp;
+ CdVec3 ref_xyz = { reference->X / reference->Y,
+ 1.0,
+ reference->Z / reference->Y };
+ CdVec3 meas_xyz = { measured->X / measured->Y,
+ 1.0,
+ measured->Z / measured->Y };
+ CdVec3 ref_rgb;
+ CdVec3 meas_rgb;
+
+ /* convert XYZ white point values to RGB */
+ cd_mat33_vector_multiply (&bradford_response_matrix,
+ &ref_xyz,
+ &ref_rgb);
+ cd_mat33_vector_multiply (&bradford_response_matrix,
+ &meas_xyz,
+ &meas_rgb);
+
+ /* construct a diagonal matrix D of the ratios between the RGB values */
+ cd_mat33_clear (&ratio);
+ ratio.m00 = meas_rgb.v0 / ref_rgb.v0;
+ ratio.m11 = meas_rgb.v1 / ref_rgb.v1;
+ ratio.m22 = meas_rgb.v2 / ref_rgb.v2;
+
+ /* transform is inv(B) * D * B */
+ cd_mat33_reciprocal (&bradford_response_matrix, &bradford_inv);
+ cd_mat33_matrix_multiply (&bradford_inv, &ratio, &tmp);
+ cd_mat33_matrix_multiply (&tmp, &bradford_response_matrix, mat);
+}
+
+/**
+ * cd_icc_utils_get_adaptation_matrix:
+ * @icc: The measured ICC profile for the target device.
+ * @icc_reference: The ICC profile to use as a reference (typically sRGB).
+ * @mat: (out): The returned adaptation matrix.
+ * @error: (out): A #GError, or %NULL
+ *
+ * Computes a correction matrix suitable for adjusting colors in a reference
+ * color space @icc_reference (typically sRGB) to the color space of a target
+ * device described by @icc.
+ *
+ * This function is designed to be used by desktop window systems to program the
+ * color transform matrix (CTM) property of the display hardware.
+ *
+ * Return value: %TRUE for success
+ *
+ * Since: 1.4.5
+ */
+gboolean
+cd_icc_utils_get_adaptation_matrix (CdIcc *icc,
+ CdIcc *icc_reference,
+ CdMat3x3 *mat,
+ GError **error)
+{
+ CdMat3x3 reference;
+ CdMat3x3 measured_chroma;
+ CdMat3x3 measured;
+ CdMat3x3 measured_inv;
+ CdMat3x3 bradford;
+
+ cd_icc_utils_get_chroma_matrix (icc_reference, &reference);
+ cd_icc_utils_get_chroma_matrix (icc, &measured_chroma);
+
+ /* compute a Bradford color adaptation transform from the measured white
+ * point to the reference white point */
+ cd_bradford_transform (cd_icc_get_white (icc_reference),
+ cd_icc_get_white (icc),
+ &bradford);
+
+ /* use the Bradford transform to adjust the measured chroma values to
+ * match the reference luminance */
+ cd_mat33_matrix_multiply (&bradford, &measured_chroma, &measured);
+
+ /* invert the adjusted measured chroma matrix and multiply by the
+ * reference colors to compute the resulting CSC matrix */
+ cd_mat33_reciprocal (&measured, &measured_inv);
+ cd_mat33_matrix_multiply (&measured_inv,
+ &reference,
+ mat);
+
+ return cd_mat33_is_finite (mat, error);
+}
diff --git a/lib/colord/cd-icc-utils.h b/lib/colord/cd-icc-utils.h
index e46c0a6..49af3f6 100644
--- a/lib/colord/cd-icc-utils.h
+++ b/lib/colord/cd-icc-utils.h
@@ -29,6 +29,7 @@
#include <glib-object.h>
#include "cd-icc.h"
+#include "cd-math.h"
G_BEGIN_DECLS
@@ -37,6 +38,11 @@ gboolean cd_icc_utils_get_coverage (CdIcc *icc,
gdouble *coverage,
GError **error);
+gboolean cd_icc_utils_get_adaptation_matrix (CdIcc *icc,
+ CdIcc *icc_reference,
+ CdMat3x3 *out,
+ GError **error);
+
G_END_DECLS
#endif /* __CD_ICC_UTILS_H__ */