summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Hughes <richard@hughsie.com>2013-04-12 11:07:20 +0100
committerRichard Hughes <richard@hughsie.com>2013-04-12 11:07:24 +0100
commit714396bdf5fb81323d40f358c729f4854faaed1d (patch)
treef3df9aeb933c69593060fd61cbb5e6fe1dc7f807
parent650d78c1387bec59e2e13d82d260058faf0c498f (diff)
downloadcolord-714396bdf5fb81323d40f358c729f4854faaed1d.tar.gz
libcolord: Always write C-locale floating point values in IT8 files
LCMS uses 'sprintf(.10%g)' to convert floating point values to strings. If LC_NUMERIC is set to something like 'nl_BE' then values such as 1.234 are printed as '1,234'. This is against the CGATS standard and Argyll correctly refuses to parse the file. Wrap each call to get and set the floating point values with the safe GLib functions of g_ascii_strtod() and g_ascii_dtostr().
-rw-r--r--lib/colord/cd-it8.c175
-rw-r--r--lib/colord/cd-self-test.c44
2 files changed, 166 insertions, 53 deletions
diff --git a/lib/colord/cd-it8.c b/lib/colord/cd-it8.c
index 62a9f77..35b16e3 100644
--- a/lib/colord/cd-it8.c
+++ b/lib/colord/cd-it8.c
@@ -95,6 +95,62 @@ cd_it8_error_quark (void)
}
/**
+ * _cmsIT8GetPropertyDbl:
+ *
+ * This gets a property ensuring the decimal point is '.' rather than what is
+ * specified in LC_NUMERIC
+ **/
+static gdouble
+_cmsIT8GetPropertyDbl (cmsHANDLE it8_lcms, const gchar *key)
+{
+ const gchar *value;
+ value = cmsIT8GetProperty (it8_lcms, key);
+ return g_ascii_strtod (value, NULL);
+}
+
+/**
+ * _cmsIT8GetDataRowColDbl:
+ *
+ * This gets a data value ensuring the decimal point is '.' rather than what is
+ * specified in LC_NUMERIC
+ **/
+static gdouble
+_cmsIT8GetDataRowColDbl (cmsHANDLE it8_lcms, gint row, gint col)
+{
+ const char *value;
+ value = cmsIT8GetDataRowCol (it8_lcms, row, col);
+ return g_ascii_strtod (value, NULL);
+}
+
+/**
+ * _cmsIT8SetPropertyDbl:
+ *
+ * This sets a property ensuring the decimal point is '.' rather than what is
+ * specified in LC_NUMERIC
+ **/
+static void
+_cmsIT8SetPropertyDbl (cmsHANDLE it8_lcms, const gchar *key, gdouble value)
+{
+ gchar buffer[G_ASCII_DTOSTR_BUF_SIZE];
+ g_ascii_dtostr (buffer, G_ASCII_DTOSTR_BUF_SIZE, value);
+ cmsIT8SetPropertyUncooked (it8_lcms, key, buffer);
+}
+
+/**
+ * _cmsIT8SetDataRowColDbl:
+ *
+ * This sets a data value ensuring the decimal point is '.' rather than what is
+ * specified in LC_NUMERIC
+ **/
+static void
+_cmsIT8SetDataRowColDbl (cmsHANDLE it8_lcms, gint row, gint col, gdouble value)
+{
+ gchar buffer[G_ASCII_DTOSTR_BUF_SIZE];
+ g_ascii_dtostr (buffer, G_ASCII_DTOSTR_BUF_SIZE, value);
+ cmsIT8SetDataRowCol (it8_lcms, row, col, buffer);
+}
+
+/**
* cd_it8_set_matrix:
* @it8: a #CdIt8 instance.
* @matrix: a #CdMat3x3.
@@ -339,12 +395,12 @@ cd_it8_load_ti1_cal (CdIt8 *it8, cmsHANDLE it8_lcms, GError **error)
}
/* copy out data entries */
- number_of_sets = cmsIT8GetPropertyDbl (it8_lcms, "NUMBER_OF_SETS");
+ number_of_sets = _cmsIT8GetPropertyDbl (it8_lcms, "NUMBER_OF_SETS");
for (i = 0; i < number_of_sets; i++) {
rgb = cd_color_rgb_new ();
- rgb->R = cmsIT8GetDataRowColDbl(it8_lcms, i, 1);
- rgb->G = cmsIT8GetDataRowColDbl(it8_lcms, i, 2);
- rgb->B = cmsIT8GetDataRowColDbl(it8_lcms, i, 3);
+ rgb->R = _cmsIT8GetDataRowColDbl(it8_lcms, i, 1);
+ rgb->G = _cmsIT8GetDataRowColDbl(it8_lcms, i, 2);
+ rgb->B = _cmsIT8GetDataRowColDbl(it8_lcms, i, 3);
/* ti1 files don't have NORMALIZED_TO_Y_100 so guess on
* the asumption the first patch isn't black */
@@ -404,12 +460,12 @@ cd_it8_load_ti3 (CdIt8 *it8, cmsHANDLE it8_lcms, GError **error)
cd_it8_set_instrument (it8, cmsIT8GetProperty (it8_lcms, "TARGET_INSTRUMENT"));
/* copy out data entries */
- number_of_sets = cmsIT8GetPropertyDbl (it8_lcms, "NUMBER_OF_SETS");
+ number_of_sets = _cmsIT8GetPropertyDbl (it8_lcms, "NUMBER_OF_SETS");
for (i = 0; i < number_of_sets; i++) {
rgb = cd_color_rgb_new ();
- rgb->R = cmsIT8GetDataRowColDbl(it8_lcms, i, 1);
- rgb->G = cmsIT8GetDataRowColDbl(it8_lcms, i, 2);
- rgb->B = cmsIT8GetDataRowColDbl(it8_lcms, i, 3);
+ rgb->R = _cmsIT8GetDataRowColDbl(it8_lcms, i, 1);
+ rgb->G = _cmsIT8GetDataRowColDbl(it8_lcms, i, 2);
+ rgb->B = _cmsIT8GetDataRowColDbl(it8_lcms, i, 3);
if (scaled_to_y100) {
rgb->R /= 100.0f;
rgb->G /= 100.0f;
@@ -417,9 +473,9 @@ cd_it8_load_ti3 (CdIt8 *it8, cmsHANDLE it8_lcms, GError **error)
}
g_ptr_array_add (it8->priv->array_rgb, rgb);
xyz = cd_color_xyz_new ();
- xyz->X = cmsIT8GetDataRowColDbl(it8_lcms, i, 4);
- xyz->Y = cmsIT8GetDataRowColDbl(it8_lcms, i, 5);
- xyz->Z = cmsIT8GetDataRowColDbl(it8_lcms, i, 6);
+ xyz->X = _cmsIT8GetDataRowColDbl(it8_lcms, i, 4);
+ xyz->Y = _cmsIT8GetDataRowColDbl(it8_lcms, i, 5);
+ xyz->Z = _cmsIT8GetDataRowColDbl(it8_lcms, i, 6);
if (scaled_to_y100) {
xyz->X /= 100.0f;
xyz->Y /= 100.0f;
@@ -455,15 +511,15 @@ cd_it8_load_ccmx (CdIt8 *it8, cmsHANDLE it8_lcms, GError **error)
cd_it8_set_instrument (it8, cmsIT8GetProperty (it8_lcms, "INSTRUMENT"));
/* just load the matrix */
- it8->priv->matrix.m00 = cmsIT8GetDataRowColDbl(it8_lcms, 0, 0);
- it8->priv->matrix.m01 = cmsIT8GetDataRowColDbl(it8_lcms, 0, 1);
- it8->priv->matrix.m02 = cmsIT8GetDataRowColDbl(it8_lcms, 0, 2);
- it8->priv->matrix.m10 = cmsIT8GetDataRowColDbl(it8_lcms, 1, 0);
- it8->priv->matrix.m11 = cmsIT8GetDataRowColDbl(it8_lcms, 1, 1);
- it8->priv->matrix.m12 = cmsIT8GetDataRowColDbl(it8_lcms, 1, 2);
- it8->priv->matrix.m20 = cmsIT8GetDataRowColDbl(it8_lcms, 2, 0);
- it8->priv->matrix.m21 = cmsIT8GetDataRowColDbl(it8_lcms, 2, 1);
- it8->priv->matrix.m22 = cmsIT8GetDataRowColDbl(it8_lcms, 2, 2);
+ it8->priv->matrix.m00 = _cmsIT8GetDataRowColDbl(it8_lcms, 0, 0);
+ it8->priv->matrix.m01 = _cmsIT8GetDataRowColDbl(it8_lcms, 0, 1);
+ it8->priv->matrix.m02 = _cmsIT8GetDataRowColDbl(it8_lcms, 0, 2);
+ it8->priv->matrix.m10 = _cmsIT8GetDataRowColDbl(it8_lcms, 1, 0);
+ it8->priv->matrix.m11 = _cmsIT8GetDataRowColDbl(it8_lcms, 1, 1);
+ it8->priv->matrix.m12 = _cmsIT8GetDataRowColDbl(it8_lcms, 1, 2);
+ it8->priv->matrix.m20 = _cmsIT8GetDataRowColDbl(it8_lcms, 2, 0);
+ it8->priv->matrix.m21 = _cmsIT8GetDataRowColDbl(it8_lcms, 2, 1);
+ it8->priv->matrix.m22 = _cmsIT8GetDataRowColDbl(it8_lcms, 2, 2);
out:
return ret;
}
@@ -642,6 +698,19 @@ cd_it8_color_match (CdColorRGB *rgb, gdouble r, gdouble g, gdouble b)
}
/**
+ * cd_it8_convert_xyz_to_string:
+ **/
+static gchar *
+cd_it8_convert_xyz_to_string (CdColorXYZ *src)
+{
+ gchar buffer[3][G_ASCII_DTOSTR_BUF_SIZE];
+ g_ascii_dtostr (buffer[0], G_ASCII_DTOSTR_BUF_SIZE, src->X);
+ g_ascii_dtostr (buffer[1], G_ASCII_DTOSTR_BUF_SIZE, src->Y);
+ g_ascii_dtostr (buffer[2], G_ASCII_DTOSTR_BUF_SIZE, src->Z);
+ return g_strdup_printf ("%s %s %s", buffer[0], buffer[1], buffer[2]);
+}
+
+/**
* cd_it8_save_to_file_ti1_ti3:
**/
static gboolean
@@ -688,7 +757,7 @@ cd_it8_save_to_file_ti1_ti3 (CdIt8 *it8, cmsHANDLE it8_lcms, GError **error)
/* scale all the readings to 100 */
normalize = 100.0f / normalize;
}
- lumi_str = g_strdup_printf ("%f %f %f", lumi_xyz.X, lumi_xyz.Y, lumi_xyz.Z);
+ lumi_str = cd_it8_convert_xyz_to_string (&lumi_xyz);
/* write data */
if (it8->priv->kind == CD_IT8_KIND_TI1) {
@@ -717,8 +786,8 @@ cd_it8_save_to_file_ti1_ti3 (CdIt8 *it8, cmsHANDLE it8_lcms, GError **error)
} else {
cmsIT8SetPropertyStr (it8_lcms, "NORMALIZED_TO_Y_100", "NO");
}
- cmsIT8SetPropertyDbl (it8_lcms, "NUMBER_OF_FIELDS", 7);
- cmsIT8SetPropertyDbl (it8_lcms, "NUMBER_OF_SETS", it8->priv->array_rgb->len);
+ _cmsIT8SetPropertyDbl (it8_lcms, "NUMBER_OF_FIELDS", 7);
+ _cmsIT8SetPropertyDbl (it8_lcms, "NUMBER_OF_SETS", it8->priv->array_rgb->len);
cmsIT8SetDataFormat (it8_lcms, 0, "SAMPLE_ID");
cmsIT8SetDataFormat (it8_lcms, 1, "RGB_R");
cmsIT8SetDataFormat (it8_lcms, 2, "RGB_G");
@@ -732,21 +801,21 @@ cd_it8_save_to_file_ti1_ti3 (CdIt8 *it8, cmsHANDLE it8_lcms, GError **error)
rgb_tmp = g_ptr_array_index (it8->priv->array_rgb, i);
xyz_tmp = g_ptr_array_index (it8->priv->array_xyz, i);
- cmsIT8SetDataRowColDbl(it8_lcms, i, 0, i + 1);
+ _cmsIT8SetDataRowColDbl(it8_lcms, i, 0, i + 1);
if (it8->priv->normalized) {
- cmsIT8SetDataRowColDbl(it8_lcms, i, 1, rgb_tmp->R * 100.0f);
- cmsIT8SetDataRowColDbl(it8_lcms, i, 2, rgb_tmp->G * 100.0f);
- cmsIT8SetDataRowColDbl(it8_lcms, i, 3, rgb_tmp->B * 100.0f);
- cmsIT8SetDataRowColDbl(it8_lcms, i, 4, xyz_tmp->X * normalize);
- cmsIT8SetDataRowColDbl(it8_lcms, i, 5, xyz_tmp->Y * normalize);
- cmsIT8SetDataRowColDbl(it8_lcms, i, 6, xyz_tmp->Z * normalize);
+ _cmsIT8SetDataRowColDbl(it8_lcms, i, 1, rgb_tmp->R * 100.0f);
+ _cmsIT8SetDataRowColDbl(it8_lcms, i, 2, rgb_tmp->G * 100.0f);
+ _cmsIT8SetDataRowColDbl(it8_lcms, i, 3, rgb_tmp->B * 100.0f);
+ _cmsIT8SetDataRowColDbl(it8_lcms, i, 4, xyz_tmp->X * normalize);
+ _cmsIT8SetDataRowColDbl(it8_lcms, i, 5, xyz_tmp->Y * normalize);
+ _cmsIT8SetDataRowColDbl(it8_lcms, i, 6, xyz_tmp->Z * normalize);
} else {
- cmsIT8SetDataRowColDbl(it8_lcms, i, 1, rgb_tmp->R);
- cmsIT8SetDataRowColDbl(it8_lcms, i, 2, rgb_tmp->G);
- cmsIT8SetDataRowColDbl(it8_lcms, i, 3, rgb_tmp->B);
- cmsIT8SetDataRowColDbl(it8_lcms, i, 4, xyz_tmp->X);
- cmsIT8SetDataRowColDbl(it8_lcms, i, 5, xyz_tmp->Y);
- cmsIT8SetDataRowColDbl(it8_lcms, i, 6, xyz_tmp->Z);
+ _cmsIT8SetDataRowColDbl(it8_lcms, i, 1, rgb_tmp->R);
+ _cmsIT8SetDataRowColDbl(it8_lcms, i, 2, rgb_tmp->G);
+ _cmsIT8SetDataRowColDbl(it8_lcms, i, 3, rgb_tmp->B);
+ _cmsIT8SetDataRowColDbl(it8_lcms, i, 4, xyz_tmp->X);
+ _cmsIT8SetDataRowColDbl(it8_lcms, i, 5, xyz_tmp->Y);
+ _cmsIT8SetDataRowColDbl(it8_lcms, i, 6, xyz_tmp->Z);
}
}
out:
@@ -774,8 +843,8 @@ cd_it8_save_to_file_cal (CdIt8 *it8, cmsHANDLE it8_lcms, GError **error)
cmsIT8SetPropertyStr (it8_lcms, "TARGET_INSTRUMENT",
it8->priv->instrument);
}
- cmsIT8SetPropertyDbl (it8_lcms, "NUMBER_OF_FIELDS", 4);
- cmsIT8SetPropertyDbl (it8_lcms, "NUMBER_OF_SETS", it8->priv->array_rgb->len);
+ _cmsIT8SetPropertyDbl (it8_lcms, "NUMBER_OF_FIELDS", 4);
+ _cmsIT8SetPropertyDbl (it8_lcms, "NUMBER_OF_SETS", it8->priv->array_rgb->len);
cmsIT8SetDataFormat (it8_lcms, 0, "RGB_I");
cmsIT8SetDataFormat (it8_lcms, 1, "RGB_R");
cmsIT8SetDataFormat (it8_lcms, 2, "RGB_G");
@@ -784,10 +853,10 @@ cd_it8_save_to_file_cal (CdIt8 *it8, cmsHANDLE it8_lcms, GError **error)
/* write to the it8 file */
for (i = 0; i < it8->priv->array_rgb->len; i++) {
rgb_tmp = g_ptr_array_index (it8->priv->array_rgb, i);
- cmsIT8SetDataRowColDbl(it8_lcms, i, 0, 1.0f / (gdouble) (it8->priv->array_rgb->len - 1) * (gdouble) i);
- cmsIT8SetDataRowColDbl(it8_lcms, i, 1, rgb_tmp->R);
- cmsIT8SetDataRowColDbl(it8_lcms, i, 2, rgb_tmp->G);
- cmsIT8SetDataRowColDbl(it8_lcms, i, 3, rgb_tmp->B);
+ _cmsIT8SetDataRowColDbl(it8_lcms, i, 0, 1.0f / (gdouble) (it8->priv->array_rgb->len - 1) * (gdouble) i);
+ _cmsIT8SetDataRowColDbl(it8_lcms, i, 1, rgb_tmp->R);
+ _cmsIT8SetDataRowColDbl(it8_lcms, i, 2, rgb_tmp->G);
+ _cmsIT8SetDataRowColDbl(it8_lcms, i, 3, rgb_tmp->B);
}
return ret;
@@ -806,8 +875,8 @@ cd_it8_save_to_file_ccmx (CdIt8 *it8, cmsHANDLE it8_lcms, GError **error)
"Device Correction Matrix");
cmsIT8SetPropertyStr (it8_lcms, "COLOR_REP", "XYZ");
- cmsIT8SetPropertyDbl (it8_lcms, "NUMBER_OF_FIELDS", 3);
- cmsIT8SetPropertyDbl (it8_lcms, "NUMBER_OF_SETS", 3);
+ _cmsIT8SetPropertyDbl (it8_lcms, "NUMBER_OF_FIELDS", 3);
+ _cmsIT8SetPropertyDbl (it8_lcms, "NUMBER_OF_SETS", 3);
cmsIT8SetDataFormat (it8_lcms, 0, "XYZ_X");
cmsIT8SetDataFormat (it8_lcms, 1, "XYZ_Y");
cmsIT8SetDataFormat (it8_lcms, 2, "XYZ_Z");
@@ -819,15 +888,15 @@ cd_it8_save_to_file_ccmx (CdIt8 *it8, cmsHANDLE it8_lcms, GError **error)
}
/* just save the matrix */
- cmsIT8SetDataRowColDbl (it8_lcms, 0, 0, it8->priv->matrix.m00);
- cmsIT8SetDataRowColDbl (it8_lcms, 0, 1, it8->priv->matrix.m01);
- cmsIT8SetDataRowColDbl (it8_lcms, 0, 2, it8->priv->matrix.m02);
- cmsIT8SetDataRowColDbl (it8_lcms, 1, 0, it8->priv->matrix.m10);
- cmsIT8SetDataRowColDbl (it8_lcms, 1, 1, it8->priv->matrix.m11);
- cmsIT8SetDataRowColDbl (it8_lcms, 1, 2, it8->priv->matrix.m12);
- cmsIT8SetDataRowColDbl (it8_lcms, 2, 0, it8->priv->matrix.m20);
- cmsIT8SetDataRowColDbl (it8_lcms, 2, 1, it8->priv->matrix.m21);
- cmsIT8SetDataRowColDbl (it8_lcms, 2, 2, it8->priv->matrix.m22);
+ _cmsIT8SetDataRowColDbl (it8_lcms, 0, 0, it8->priv->matrix.m00);
+ _cmsIT8SetDataRowColDbl (it8_lcms, 0, 1, it8->priv->matrix.m01);
+ _cmsIT8SetDataRowColDbl (it8_lcms, 0, 2, it8->priv->matrix.m02);
+ _cmsIT8SetDataRowColDbl (it8_lcms, 1, 0, it8->priv->matrix.m10);
+ _cmsIT8SetDataRowColDbl (it8_lcms, 1, 1, it8->priv->matrix.m11);
+ _cmsIT8SetDataRowColDbl (it8_lcms, 1, 2, it8->priv->matrix.m12);
+ _cmsIT8SetDataRowColDbl (it8_lcms, 2, 0, it8->priv->matrix.m20);
+ _cmsIT8SetDataRowColDbl (it8_lcms, 2, 1, it8->priv->matrix.m21);
+ _cmsIT8SetDataRowColDbl (it8_lcms, 2, 2, it8->priv->matrix.m22);
return ret;
}
diff --git a/lib/colord/cd-self-test.c b/lib/colord/cd-self-test.c
index 42ff6be..4363310 100644
--- a/lib/colord/cd-self-test.c
+++ b/lib/colord/cd-self-test.c
@@ -24,6 +24,7 @@
#include <limits.h>
#include <stdlib.h>
#include <math.h>
+#include <locale.h>
#include <string.h>
#include <glib.h>
@@ -188,6 +189,48 @@ colord_it8_raw_func (void)
}
static void
+colord_it8_locale_func (void)
+{
+ CdIt8 *ccmx;
+ CdMat3x3 mat;
+ const gchar *orig_locale;
+ gboolean ret;
+ gchar *data;
+ GError *error = NULL;
+
+ /* set to a locale with ',' as the decimal point */
+ orig_locale = setlocale (LC_NUMERIC, NULL);
+ setlocale (LC_NUMERIC, "nl_BE.UTF-8");
+
+ ccmx = cd_it8_new_with_kind (CD_IT8_KIND_CCMX);
+ cd_mat33_clear (&mat);
+ mat.m00 = 1.234;
+ cd_it8_set_matrix (ccmx, &mat);
+ cd_it8_set_enable_created (ccmx, FALSE);
+ ret = cd_it8_save_to_data (ccmx, &data, NULL, &error);
+
+ g_assert_no_error (error);
+ g_assert (ret);
+ g_assert_cmpstr (data, ==, "CCMX \n"
+ "DESCRIPTOR \"Device Correction Matrix\"\n"
+ "COLOR_REP \"XYZ\"\n"
+ "NUMBER_OF_FIELDS 3\n"
+ "NUMBER_OF_SETS 3\n"
+ "BEGIN_DATA_FORMAT\n"
+ " XYZ_X XYZ_Y XYZ_Z\n"
+ "END_DATA_FORMAT\n"
+ "BEGIN_DATA\n"
+ " 1.234 0 0\n"
+ " 0 0 0\n"
+ " 0 0 0\n"
+ "END_DATA\n");
+ setlocale (LC_NUMERIC, orig_locale);
+
+ g_free (data);
+ g_object_unref (ccmx);
+}
+
+static void
colord_it8_normalized_func (void)
{
CdColorRGB rgb;
@@ -3605,6 +3648,7 @@ main (int argc, char **argv)
g_test_add_func ("/colord/color{interpolate}", colord_color_interpolate_func);
g_test_add_func ("/colord/math", cd_test_math_func);
g_test_add_func ("/colord/it8{raw}", colord_it8_raw_func);
+ g_test_add_func ("/colord/it8{locale}", colord_it8_locale_func);
g_test_add_func ("/colord/it8{normalized}", colord_it8_normalized_func);
g_test_add_func ("/colord/it8{ccmx}", colord_it8_ccmx_func);
g_test_add_func ("/colord/it8{ccmx-util", colord_it8_ccmx_util_func);