diff options
author | Richard Hughes <richard@hughsie.com> | 2013-03-27 08:50:04 +0000 |
---|---|---|
committer | Richard Hughes <richard@hughsie.com> | 2013-03-27 09:03:44 +0000 |
commit | 75657ab2099354228985561c50ab94382101fcd9 (patch) | |
tree | c57d7a18e296f8e946cf8710c34c19c03845bb14 | |
parent | b6fb6cf82418353e9d52a2015a8ef9190fd9bae8 (diff) | |
download | colord-75657ab2099354228985561c50ab94382101fcd9.tar.gz |
libcolord: Add functionality to get the primaries and whitepoint from the profile
-rw-r--r-- | lib/colord/cd-icc.c | 317 | ||||
-rw-r--r-- | lib/colord/cd-icc.h | 7 | ||||
-rw-r--r-- | lib/colord/cd-self-test.c | 13 |
3 files changed, 333 insertions, 4 deletions
diff --git a/lib/colord/cd-icc.c b/lib/colord/cd-icc.c index 7899fef..8f0cb4a 100644 --- a/lib/colord/cd-icc.c +++ b/lib/colord/cd-icc.c @@ -70,6 +70,11 @@ struct _CdIccPrivate GHashTable *metadata; guint32 size; GPtrArray *named_colors; + guint temperature; + CdColorXYZ white; + CdColorXYZ red; + CdColorXYZ green; + CdColorXYZ blue; }; G_DEFINE_TYPE (CdIcc, cd_icc, G_TYPE_OBJECT) @@ -83,6 +88,11 @@ enum { PROP_COLORSPACE, PROP_CAN_DELETE, PROP_CHECKSUM, + PROP_RED, + PROP_GREEN, + PROP_BLUE, + PROP_WHITE, + PROP_TEMPERATURE, PROP_LAST }; @@ -517,15 +527,146 @@ out: } /** + * cd_icc_calc_whitepoint: + **/ +static gboolean +cd_icc_calc_whitepoint (CdIcc *icc, GError **error) +{ + CdIccPrivate *priv = icc->priv; + cmsBool bpc[2] = { FALSE, FALSE }; + cmsCIExyY tmp; + cmsCIEXYZ whitepoint; + cmsFloat64Number adaption[2] = { 0, 0 }; + cmsHPROFILE profiles[2]; + cmsHTRANSFORM transform; + cmsUInt32Number intents[2] = { INTENT_ABSOLUTE_COLORIMETRIC, + INTENT_ABSOLUTE_COLORIMETRIC }; + gboolean got_temperature; + gboolean ret = TRUE; + gdouble temp_float; + guint8 data[3] = { 255, 255, 255 }; + + /* do Lab to RGB transform to get primaries */ + profiles[0] = priv->lcms_profile; + profiles[1] = cmsCreateXYZProfile (); + transform = cmsCreateExtendedTransform (NULL, + 2, + profiles, + bpc, + intents, + adaption, + NULL, 0, /* gamut ICC */ + TYPE_RGB_8, + TYPE_XYZ_DBL, + cmsFLAGS_NOOPTIMIZE); + if (transform == NULL) { + ret = FALSE; + g_set_error_literal (error, + CD_ICC_ERROR, + CD_ICC_ERROR_FAILED_TO_PARSE, + "failed to setup RGB -> XYZ transform"); + goto out; + } + + /* run white through the transform */ + cmsDoTransform (transform, data, &whitepoint, 1); + cd_color_xyz_set (&priv->white, + whitepoint.X, + whitepoint.Y, + whitepoint.Z); + + /* get temperature rounded to nearest 100K */ + cmsXYZ2xyY (&tmp, &whitepoint); + got_temperature = cmsTempFromWhitePoint (&temp_float, &tmp); + if (got_temperature) + priv->temperature = (((guint) temp_float) / 100) * 100; +out: + if (profiles[1] != NULL) + cmsCloseProfile (profiles[1]); + if (transform != NULL) + cmsDeleteTransform (transform); + return ret; +} + +/** + * cd_icc_load_primaries: + **/ +static gboolean +cd_icc_load_primaries (CdIcc *icc, GError **error) +{ + CdIccPrivate *priv = icc->priv; + cmsCIEXYZ *cie_xyz; + cmsHPROFILE xyz_profile = NULL; + cmsHTRANSFORM transform = NULL; + gboolean ret = TRUE; + gdouble rgb_values[3]; + + /* get white point */ + ret = cd_icc_calc_whitepoint (icc, error); + if (!ret) + goto out; + + /* get the illuminants from the primaries */ + cie_xyz = cmsReadTag (priv->lcms_profile, cmsSigRedMatrixColumnTag); + if (cie_xyz != NULL) { + cd_color_xyz_copy ((CdColorXYZ *) cie_xyz, &priv->red); + cie_xyz = cmsReadTag (priv->lcms_profile, cmsSigGreenMatrixColumnTag); + cd_color_xyz_copy ((CdColorXYZ *) cie_xyz, &priv->green); + cie_xyz = cmsReadTag (priv->lcms_profile, cmsSigBlueMatrixColumnTag); + cd_color_xyz_copy ((CdColorXYZ *) cie_xyz, &priv->blue); + goto out; + } + + /* get the illuminants by running it through the profile */ + xyz_profile = cmsCreateXYZProfile (); + transform = cmsCreateTransform (priv->lcms_profile, TYPE_RGB_DBL, + xyz_profile, TYPE_XYZ_DBL, + INTENT_PERCEPTUAL, 0); + if (transform == NULL) { + ret = FALSE; + g_set_error_literal (error, + CD_ICC_ERROR, + CD_ICC_ERROR_FAILED_TO_PARSE, + "failed to setup RGB -> XYZ transform"); + goto out; + } + + /* red */ + rgb_values[0] = 1.0; + rgb_values[1] = 0.0; + rgb_values[2] = 0.0; + cmsDoTransform (transform, rgb_values, &priv->red, 1); + + /* green */ + rgb_values[0] = 0.0; + rgb_values[1] = 1.0; + rgb_values[2] = 0.0; + cmsDoTransform (transform, rgb_values, &priv->green, 1); + + /* blue */ + rgb_values[0] = 0.0; + rgb_values[1] = 0.0; + rgb_values[2] = 1.0; + cmsDoTransform (transform, rgb_values, &priv->blue, 1); +out: + if (transform != NULL) + cmsDeleteTransform (transform); + if (xyz_profile != NULL) + cmsCloseProfile (xyz_profile); + return ret; +} + +/** * cd_icc_load: **/ -static void -cd_icc_load (CdIcc *icc, CdIccLoadFlags flags) +static gboolean +cd_icc_load (CdIcc *icc, CdIccLoadFlags flags, GError **error) { CdIccPrivate *priv = icc->priv; cmsColorSpaceSignature colorspace; cmsHANDLE dict; cmsProfileClassSignature profile_class; + gboolean ret = TRUE; guint i; /* get version */ @@ -587,6 +728,16 @@ cd_icc_load (CdIcc *icc, CdIccLoadFlags flags) /* read named colors if the client cares */ if ((flags & CD_ICC_LOAD_FLAGS_NAMED_COLORS) > 0) cd_icc_load_named_colors (icc); + + /* read primaries if the client cares */ + if ((flags & CD_ICC_LOAD_FLAGS_PRIMARIES) > 0 && + priv->colorspace == CD_COLORSPACE_RGB) { + ret = cd_icc_load_primaries (icc, error); + if (!ret) + goto out; + } +out: + return ret; } /** @@ -641,7 +792,9 @@ cd_icc_load_data (CdIcc *icc, priv->size = data_len; /* load cached data */ - cd_icc_load (icc, flags); + ret = cd_icc_load (icc, flags, error); + if (!ret) + goto out; /* calculate the data MD5 if there was no embedded profile */ if (priv->checksum == NULL && @@ -1157,7 +1310,9 @@ cd_icc_load_fd (CdIcc *icc, } /* load cached data */ - cd_icc_load (icc, flags); + ret = cd_icc_load (icc, flags, error); + if (!ret) + goto out; out: return ret; } @@ -1995,6 +2150,101 @@ cd_icc_set_model_items (CdIcc *icc, GHashTable *values) } /** + * cd_icc_get_temperature: + * @icc: A valid #CdIcc + * + * Gets the ICC color temperature, rounded to the nearest 100K. + * This function will only return results if the profile was loaded with the + * %CD_ICC_LOAD_FLAGS_PRIMARIES flag. + * + * Return value: The color temperature in Kelvin, or 0 for error. + * + * Since: 0.1.32 + **/ +guint +cd_icc_get_temperature (CdIcc *icc) +{ + g_return_val_if_fail (CD_IS_ICC (icc), 0); + return icc->priv->temperature; +} + +/** + * cd_icc_get_red: + * @icc: a valid #CdIcc instance + * + * Gets the profile red chromaticity value. + * This function will only return results if the profile was loaded with the + * %CD_ICC_LOAD_FLAGS_PRIMARIES flag. + * + * Return value: the #CdColorXYZ value + * + * Since: 0.1.32 + **/ +const CdColorXYZ * +cd_icc_get_red (CdIcc *icc) +{ + g_return_val_if_fail (CD_IS_ICC (icc), NULL); + return &icc->priv->red; +} + +/** + * cd_icc_get_green: + * @icc: a valid #CdIcc instance + * + * Gets the profile green chromaticity value. + * This function will only return results if the profile was loaded with the + * %CD_ICC_LOAD_FLAGS_PRIMARIES flag. + * + * Return value: the #CdColorXYZ value + * + * Since: 0.1.32 + **/ +const CdColorXYZ * +cd_icc_get_green (CdIcc *icc) +{ + g_return_val_if_fail (CD_IS_ICC (icc), NULL); + return &icc->priv->green; +} + +/** + * cd_icc_get_blue: + * @icc: a valid #CdIcc instance + * + * Gets the profile red chromaticity value. + * This function will only return results if the profile was loaded with the + * %CD_ICC_LOAD_FLAGS_PRIMARIES flag. + * + * Return value: the #CdColorXYZ value + * + * Since: 0.1.32 + **/ +const CdColorXYZ * +cd_icc_get_blue (CdIcc *icc) +{ + g_return_val_if_fail (CD_IS_ICC (icc), NULL); + return &icc->priv->blue; +} + +/** + * cd_icc_get_white: + * @icc: a valid #CdIcc instance + * + * Gets the profile white point. + * This function will only return results if the profile was loaded with the + * %CD_ICC_LOAD_FLAGS_PRIMARIES flag. + * + * Return value: the #CdColorXYZ value + * + * Since: 0.1.32 + **/ +const CdColorXYZ * +cd_icc_get_white (CdIcc *icc) +{ + g_return_val_if_fail (CD_IS_ICC (icc), NULL); + return &icc->priv->white; +} + +/** * cd_icc_create_from_edid: * @icc: A valid #CdIcc * @gamma_value: approximate device gamma @@ -2112,6 +2362,21 @@ cd_icc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec * case PROP_CHECKSUM: g_value_set_string (value, priv->checksum); break; + case PROP_WHITE: + g_value_set_boxed (value, g_boxed_copy (CD_TYPE_COLOR_XYZ, &priv->white)); + break; + case PROP_RED: + g_value_set_boxed (value, g_boxed_copy (CD_TYPE_COLOR_XYZ, &priv->red)); + break; + case PROP_GREEN: + g_value_set_boxed (value, g_boxed_copy (CD_TYPE_COLOR_XYZ, &priv->green)); + break; + case PROP_BLUE: + g_value_set_boxed (value, g_boxed_copy (CD_TYPE_COLOR_XYZ, &priv->blue)); + break; + case PROP_TEMPERATURE: + g_value_set_uint (value, priv->temperature); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -2210,6 +2475,46 @@ cd_icc_class_init (CdIccClass *klass) G_PARAM_READABLE); g_object_class_install_property (object_class, PROP_CHECKSUM, pspec); + /** + * CdIcc:white: + */ + pspec = g_param_spec_boxed ("white", NULL, NULL, + CD_TYPE_COLOR_XYZ, + G_PARAM_READABLE); + g_object_class_install_property (object_class, PROP_WHITE, pspec); + + /** + * CdIcc:red: + */ + pspec = g_param_spec_boxed ("red", NULL, NULL, + CD_TYPE_COLOR_XYZ, + G_PARAM_READABLE); + g_object_class_install_property (object_class, PROP_RED, pspec); + + /** + * CdIcc:green: + */ + pspec = g_param_spec_boxed ("green", NULL, NULL, + CD_TYPE_COLOR_XYZ, + G_PARAM_READABLE); + g_object_class_install_property (object_class, PROP_GREEN, pspec); + + /** + * CdIcc:blue: + */ + pspec = g_param_spec_boxed ("blue", NULL, NULL, + CD_TYPE_COLOR_XYZ, + G_PARAM_READABLE); + g_object_class_install_property (object_class, PROP_BLUE, pspec); + + /** + * CdIcc:temperature: + */ + pspec = g_param_spec_uint ("temperature", NULL, NULL, + 0, G_MAXUINT, 0, + G_PARAM_READABLE); + g_object_class_install_property (object_class, PROP_TEMPERATURE, pspec); + g_type_class_add_private (klass, sizeof (CdIccPrivate)); } @@ -2235,6 +2540,10 @@ cd_icc_init (CdIcc *icc) g_free, g_free); } + cd_color_xyz_clear (&icc->priv->white); + cd_color_xyz_clear (&icc->priv->red); + cd_color_xyz_clear (&icc->priv->green); + cd_color_xyz_clear (&icc->priv->blue); } /** diff --git a/lib/colord/cd-icc.h b/lib/colord/cd-icc.h index 71483d4..0d06d15 100644 --- a/lib/colord/cd-icc.h +++ b/lib/colord/cd-icc.h @@ -97,6 +97,7 @@ typedef struct * @CD_ICC_LOAD_FLAGS_METADATA: Parse the metadata in the profile. * @CD_ICC_LOAD_FLAGS_FALLBACK_MD5: Calculate the profile MD5 if a profile * ID was not supplied in the profile. + * @CD_ICC_LOAD_FLAGS_PRIMARIES: Parse the primaries in the profile. * * Flags used when loading an ICC profile. * @@ -108,6 +109,7 @@ typedef enum { CD_ICC_LOAD_FLAGS_TRANSLATIONS = (1 << 1), CD_ICC_LOAD_FLAGS_METADATA = (1 << 2), CD_ICC_LOAD_FLAGS_FALLBACK_MD5 = (1 << 3), + CD_ICC_LOAD_FLAGS_PRIMARIES = (1 << 4), /* new entries go here: */ CD_ICC_LOAD_FLAGS_ALL = 0xff, CD_ICC_LOAD_FLAGS_LAST @@ -208,6 +210,11 @@ void cd_icc_set_model (CdIcc *icc, const gchar *value); void cd_icc_set_model_items (CdIcc *icc, GHashTable *values); +const CdColorXYZ *cd_icc_get_red (CdIcc *icc); +const CdColorXYZ *cd_icc_get_green (CdIcc *icc); +const CdColorXYZ *cd_icc_get_blue (CdIcc *icc); +const CdColorXYZ *cd_icc_get_white (CdIcc *icc); +guint cd_icc_get_temperature (CdIcc *icc); gboolean cd_icc_create_from_edid (CdIcc *icc, gdouble gamma_value, const CdColorYxy *red, diff --git a/lib/colord/cd-self-test.c b/lib/colord/cd-self-test.c index 206924d..19a7616 100644 --- a/lib/colord/cd-self-test.c +++ b/lib/colord/cd-self-test.c @@ -3277,6 +3277,7 @@ static void colord_icc_func (void) { CdIcc *icc; + const CdColorXYZ *xyz_tmp; const gchar *str; gboolean ret; gchar *created_str; @@ -3309,6 +3310,7 @@ colord_icc_func (void) file, CD_ICC_LOAD_FLAGS_METADATA | CD_ICC_LOAD_FLAGS_NAMED_COLORS | + CD_ICC_LOAD_FLAGS_PRIMARIES | CD_ICC_LOAD_FLAGS_TRANSLATIONS, NULL, &error); @@ -3333,6 +3335,17 @@ colord_icc_func (void) g_assert_cmpint (array->len, ==, 0); g_ptr_array_unref (array); + /* check profile primaries */ + xyz_tmp = cd_icc_get_red (icc); + g_assert_cmpfloat (ABS (xyz_tmp->X - 0.405), <, 0.01); + g_assert_cmpfloat (ABS (xyz_tmp->Y - 0.230), <, 0.01); + g_assert_cmpfloat (ABS (xyz_tmp->Z - 0.031), <, 0.01); + xyz_tmp = cd_icc_get_white (icc); + g_assert_cmpfloat (ABS (xyz_tmp->X - 0.969), <, 0.01); + g_assert_cmpfloat (ABS (xyz_tmp->Y - 1.000), <, 0.01); + g_assert_cmpfloat (ABS (xyz_tmp->Z - 0.854), <, 0.01); + g_assert_cmpint (cd_icc_get_temperature (icc), ==, 5000); + /* check metadata */ metadata = cd_icc_get_metadata (icc); g_assert_cmpint (g_hash_table_size (metadata), ==, 1); |