[gnome-color-manager] Split out the display characterization and add a helper program to test it
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-color-manager] Split out the display characterization and add a helper program to test it
- Date: Thu, 24 Nov 2011 21:31:16 +0000 (UTC)
commit b26510195b72684be1748f3a979d0c1b14e8521c
Author: Richard Hughes <richard hughsie com>
Date: Tue Nov 8 22:09:58 2011 +0000
Split out the display characterization and add a helper program to test it
Long term, this will allow us to do less interactive stuff with Argyll and just
use it for profile generation.
po/POTFILES.in | 1 +
src/Makefile.am | 30 +++++-
src/gcm-calibrate-helper.c | 157 ++++++++++++++++++++++++++++
src/gcm-calibrate.c | 246 +++++++++++++++++++++++++++++++++++++++++---
src/gcm-calibrate.h | 8 ++
5 files changed, 424 insertions(+), 18 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 1e741ee..6d4428c 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -5,6 +5,7 @@ data/gcm-viewer.desktop.in
[type: gettext/glade]data/gcm-viewer.ui
src/gcm-calibrate-argyll.c
src/gcm-calibrate.c
+src/gcm-calibrate-helper.c
src/gcm-calibrate-main.c
src/gcm-calibrate-native.c
src/gcm-cell-renderer-profile-text.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 0b15858..f1a1c51 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -63,8 +63,11 @@ bin_PROGRAMS = \
gcm-picker \
gcm-import
+libexec_PROGRAMS = \
+ gcm-calibrate-helper
+
if HAVE_EXIV
-libexec_PROGRAMS = gcm-helper-exiv
+libexec_PROGRAMS += gcm-helper-exiv
gcm_helper_exiv_SOURCES = gcm-helper-exiv.cpp
gcm_helper_exiv_LDADD = $(EXIV_LIBS) $(GLIB_LIBS)
gcm_helper_exiv_CXXFLAGS = -Wall
@@ -122,6 +125,31 @@ gcm_inspect_LDADD = \
gcm_inspect_CFLAGS = \
$(WARNINGFLAGS_C)
+gcm_calibrate_helper_SOURCES = \
+ gcm-debug.c \
+ gcm-debug.h \
+ gcm-utils.c \
+ gcm-utils.h \
+ gcm-exif.c \
+ gcm-exif.h \
+ gcm-calibrate.c \
+ gcm-calibrate.h \
+ gcm-sample-window.c \
+ gcm-sample-window.h \
+ gcm-calibrate-helper.c
+
+gcm_calibrate_helper_LDADD = \
+ $(GLIB_LIBS) \
+ $(GTK_LIBS) \
+ $(LCMS_LIBS) \
+ $(EXIF_LIBS) \
+ $(TIFF_LIBS) \
+ $(COLORD_LIBS) \
+ -lm
+
+gcm_calibrate_helper_CFLAGS = \
+ $(WARNINGFLAGS_C)
+
gcm_import_SOURCES = \
gcm-import.c
diff --git a/src/gcm-calibrate-helper.c b/src/gcm-calibrate-helper.c
new file mode 100644
index 0000000..63a8dc0
--- /dev/null
+++ b/src/gcm-calibrate-helper.c
@@ -0,0 +1,157 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2011 Richard Hughes <richard hughsie com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <locale.h>
+
+#include "gcm-debug.h"
+#include "gcm-calibrate.h"
+
+/**
+ * gcm_calibrate_helper_ti1_to_ti3:
+ **/
+static gboolean
+gcm_calibrate_helper_ti1_to_ti3 (const gchar *device_id,
+ const gchar *ti1_fn,
+ const gchar *ti3_fn,
+ GError **error)
+{
+ CdClient *client = NULL;
+ CdSensor *sensor_tmp;
+ gboolean ret;
+ GcmCalibrate *calibrate = NULL;
+ GPtrArray *sensors = NULL;
+
+ /* get sensor */
+ client = cd_client_new ();
+ ret = cd_client_connect_sync (client, NULL, error);
+ if (!ret)
+ goto out;
+
+ sensors = cd_client_get_sensors_sync (client, NULL, error);
+ if (sensors == NULL) {
+ ret = FALSE;
+ goto out;
+ }
+ if (sensors->len == 0) {
+ ret = FALSE;
+ g_set_error_literal (error, 1, 0,
+ "No sensors plugged in!");
+ goto out;
+ }
+ sensor_tmp = g_ptr_array_index (sensors, 0);
+ ret = cd_sensor_connect_sync (sensor_tmp, NULL, error);
+ if (!ret)
+ goto out;
+
+ /* set sensor */
+ calibrate = gcm_calibrate_new ();
+ gcm_calibrate_set_sensor (calibrate, sensor_tmp);
+
+ /* convert the ti1 file to a ti3 file */
+ ret = gcm_calibrate_display_characterize (calibrate,
+ ti1_fn,
+ ti3_fn,
+ NULL, /* device */
+ NULL, /* window */
+ error);
+ if (!ret)
+ goto out;
+
+ /* success */
+ g_print ("%s: %s\n", _("Wrote file"), ti3_fn);
+out:
+ if (sensors != NULL)
+ g_ptr_array_unref (sensors);
+ if (calibrate != NULL)
+ g_object_unref (calibrate);
+ return ret;
+}
+
+/**
+ * main:
+ **/
+int
+main (int argc, char **argv)
+{
+ gboolean ret;
+ gchar *device_id = NULL;
+ GError *error = NULL;
+ GOptionContext *context;
+ guint retval = 1;
+ guint xid = 0;
+
+ const GOptionEntry options[] = {
+ { "device", '\0', 0, G_OPTION_ARG_INT, &device_id,
+ /* TRANSLATORS: command line option */
+ _("Use this device for profiling"), NULL },
+ { "xid", '\0', 0, G_OPTION_ARG_INT, &xid,
+ /* TRANSLATORS: command line option */
+ _("Make the window modal to this XID"), NULL },
+ { NULL}
+ };
+
+ setlocale (LC_ALL, "");
+
+ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+
+ gtk_init (&argc, &argv);
+
+ /* TRANSLATORS: just dumps the EDID to disk */
+ context = g_option_context_new (_("gcm-dispread"));
+ g_option_context_add_main_entries (context, options, NULL);
+ g_option_context_add_group (context, gcm_debug_get_option_group ());
+ g_option_context_add_group (context, gtk_get_option_group (TRUE));
+ g_option_context_parse (context, &argc, &argv, NULL);
+ g_option_context_free (context);
+
+ /* correct arguments */
+ if (argc == 3 &&
+ g_str_has_suffix (argv[1], "ti1") &&
+ g_str_has_suffix (argv[2], "ti3")) {
+ ret = gcm_calibrate_helper_ti1_to_ti3 (device_id,
+ argv[1],
+ argv[2],
+ &error);
+ } else {
+ ret = FALSE;
+ g_print ("%s\n", _("Specify one of:"));
+ g_print ("file.ti1 file.ti3\n");
+ goto out;
+ }
+ if (!ret) {
+ g_print ("%s: %s\n",
+ _("Failed to calibrate"),
+ error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ retval = 0;
+out:
+ g_free (device_id);
+ return retval;
+}
diff --git a/src/gcm-calibrate.c b/src/gcm-calibrate.c
index cd5ccc7..12c909b 100644
--- a/src/gcm-calibrate.c
+++ b/src/gcm-calibrate.c
@@ -24,11 +24,13 @@
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <colord.h>
+#include <lcms2.h>
#include "gcm-calibrate.h"
#include "gcm-utils.h"
#include "gcm-brightness.h"
#include "gcm-exif.h"
+#include "gcm-sample-window.h"
static void gcm_calibrate_finalize (GObject *object);
@@ -61,6 +63,7 @@ struct _GcmCalibratePrivate
gchar *working_path;
guint target_whitepoint;
GtkWidget *content_widget;
+ GtkWindow *sample_window;
GPtrArray *old_message;
GPtrArray *old_title;
};
@@ -364,22 +367,214 @@ gcm_calibrate_copy_file (const gchar *src,
}
/**
+ * gcm_calibrate_lcms_error_cb:
+ **/
+static void
+gcm_calibrate_lcms_error_cb (cmsContext ContextID,
+ cmsUInt32Number error_code,
+ const char *text)
+{
+ g_warning ("LCMS: %s", text);
+}
+
+/**
+ * gcm_calibrate_display_characterize:
+ **/
+gboolean
+gcm_calibrate_display_characterize (GcmCalibrate *calibrate,
+ const gchar *ti1_fn,
+ const gchar *ti3_fn,
+ CdDevice *device,
+ GtkWindow *window,
+ GError **error)
+{
+ CdColorRGB rgb;
+ CdColorXYZ *xyz;
+ cmsHANDLE ti1 = NULL;
+ cmsHANDLE ti3 = NULL;
+ const gchar *sample_id;
+ const gchar *tmp;
+ gboolean is_spectral;
+ gboolean ret;
+ gchar *found_lcms2_bodge;
+ gchar *ti1_data = NULL;
+ gsize ti1_size;
+ guint col;
+ guint i;
+ guint number_of_sets = 0;
+ guint table_count;
+ GcmCalibratePrivate *priv = calibrate->priv;
+
+ /* open ti1 file as input */
+ g_debug ("loading %s", ti3_fn);
+ ret = g_file_get_contents (ti1_fn, &ti1_data, &ti1_size, error);
+ if (!ret)
+ goto out;
+
+ /* hack to fix lcms2 */
+ found_lcms2_bodge = g_strstr_len (ti1_data, ti1_size, "END_DATA\n");
+ if (found_lcms2_bodge != NULL)
+ found_lcms2_bodge[9] = '\0';
+
+ /* load the ti1 data */
+ cmsSetLogErrorHandler (gcm_calibrate_lcms_error_cb);
+ ti1 = cmsIT8LoadFromMem (NULL, ti1_data, ti1_size);
+ if (ti1 == NULL) {
+ ret = FALSE;
+ g_set_error (error, 1, 0, "Cannot open %s", ti1_fn);
+ goto out;
+ }
+
+ /* select correct sheet */
+ table_count = cmsIT8TableCount (ti1);
+ g_debug ("selecting sheet %i of %i (%s)",
+ 0, table_count,
+ cmsIT8GetSheetType (ti1));
+ cmsIT8SetTable (ti1, 0);
+
+ /* check color format */
+ tmp = cmsIT8GetProperty (ti1, "COLOR_REP");
+ if (g_strcmp0 (tmp, "RGB") != 0) {
+ ret = FALSE;
+ g_set_error (error, 1, 0, "Invalid format: %s", tmp);
+ goto out;
+ }
+ number_of_sets = cmsIT8GetPropertyDbl (ti1, "NUMBER_OF_SETS");
+
+ /* setup the measure window */
+ gcm_sample_window_set_color (GCM_SAMPLE_WINDOW (priv->sample_window), &rgb);
+ gcm_sample_window_set_percentage (GCM_SAMPLE_WINDOW (priv->sample_window), 0);
+ gtk_window_set_modal (priv->sample_window, TRUE);
+ gtk_window_stick (priv->sample_window);
+ gtk_window_present (priv->sample_window);
+
+ /* write to a ti3 file as output */
+ ti3 = cmsIT8Alloc (NULL);
+ cmsIT8SetSheetType (ti3, "CTI3");
+ cmsIT8SetPropertyStr (ti3, "DESCRIPTOR",
+ "Calibration Target chart information 3");
+ cmsIT8SetPropertyStr (ti3, "ORIGINATOR",
+ "GNOME Color Manager");
+ cmsIT8SetPropertyStr (ti3, "CREATED",
+ "now");//fixme
+ cmsIT8SetPropertyStr (ti3, "DEVICE_CLASS",
+ "DISPLAY");
+ cmsIT8SetPropertyStr (ti3, "COLOR_REP",
+ "RGB_XYZ");
+ cmsIT8SetPropertyStr (ti3, "TARGET_INSTRUMENT",
+ cd_sensor_get_model (priv->sensor));
+ is_spectral = cd_sensor_has_cap (priv->sensor,
+ CD_SENSOR_CAP_SPOT);
+ cmsIT8SetPropertyStr (ti3, "INSTRUMENT_TYPE_SPECTRAL",
+ is_spectral ? "YES" : "NO");
+ cmsIT8SetPropertyStr (ti3, "LUMINANCE_XYZ_CDM2",
+ "132.922451 129.524179 165.093861");
+ cmsIT8SetPropertyStr (ti3, "NORMALIZED_TO_Y_100", "NO");
+ cmsIT8SetPropertyDbl (ti3, "NUMBER_OF_FIELDS", 7);
+ cmsIT8SetPropertyDbl (ti3, "NUMBER_OF_SETS", number_of_sets);
+ cmsIT8SetDataFormat (ti3, 0, "SAMPLE_ID");
+ cmsIT8SetDataFormat (ti3, 1, "RGB_R");
+ cmsIT8SetDataFormat (ti3, 2, "RGB_G");
+ cmsIT8SetDataFormat (ti3, 3, "RGB_B");
+ cmsIT8SetDataFormat (ti3, 4, "XYZ_X");
+ cmsIT8SetDataFormat (ti3, 5, "XYZ_Y");
+ cmsIT8SetDataFormat (ti3, 6, "XYZ_Z");
+
+ /* lock the sensor */
+ ret = cd_sensor_lock_sync (calibrate->priv->sensor,
+ NULL,
+ error);
+ if (!ret)
+ goto out;
+
+ /* capture all the source colors */
+ for (i = 0; i < number_of_sets; i++) {
+
+ /* get the source color */
+ col = cmsIT8FindDataFormat(ti1, "SAMPLE_ID");
+ sample_id = cmsIT8GetDataRowCol(ti1, i, col);
+ col = cmsIT8FindDataFormat(ti1, "RGB_R");
+ rgb.R = cmsIT8GetDataRowColDbl(ti1, i, col);
+ col = cmsIT8FindDataFormat(ti1, "RGB_G");
+ rgb.G = cmsIT8GetDataRowColDbl(ti1, i, col);
+ col = cmsIT8FindDataFormat(ti1, "RGB_B");
+ rgb.B = cmsIT8GetDataRowColDbl(ti1, i, col);
+
+ /* set the window color */
+ gcm_sample_window_set_color (GCM_SAMPLE_WINDOW (priv->sample_window), &rgb);
+ gcm_sample_window_set_percentage (GCM_SAMPLE_WINDOW (priv->sample_window),
+ 100 * i / number_of_sets);
+
+ /* wait for the refresh to set the new color */
+ g_usleep (50000);
+
+ /* get the sample from the hardware */
+ xyz = cd_sensor_get_sample_sync (calibrate->priv->sensor,
+ CD_SENSOR_CAP_LCD,
+ NULL,
+ error);
+ if (xyz == NULL) {
+ ret = FALSE;
+ goto out;
+ }
+ g_debug ("sampled %f,%f,%f as %f,%f,%f",
+ rgb.R, rgb.G, rgb.B,
+ xyz->X, xyz->Y, xyz->Z);
+
+ /* write to the ti3 file */
+ cmsIT8SetDataRowCol(ti3, i, 0, sample_id);
+ cmsIT8SetDataRowColDbl(ti3, i, 1, rgb.R);
+ cmsIT8SetDataRowColDbl(ti3, i, 2, rgb.G);
+ cmsIT8SetDataRowColDbl(ti3, i, 3, rgb.B);
+ cmsIT8SetDataRowColDbl(ti3, i, 4, xyz->X);
+ cmsIT8SetDataRowColDbl(ti3, i, 5, xyz->Y);
+ cmsIT8SetDataRowColDbl(ti3, i, 6, xyz->Z);
+ cd_color_xyz_free (xyz);
+ }
+
+ /* write the file */
+ g_debug ("writing %s", ti3_fn);
+ cmsIT8SaveToFile (ti3, ti3_fn);
+
+ /* unlock the sensor */
+ ret = cd_sensor_unlock_sync (calibrate->priv->sensor,
+ NULL,
+ error);
+ if (!ret)
+ goto out;
+out:
+ /* hide the sample window */
+ gtk_widget_hide (GTK_WIDGET (priv->sample_window));
+
+ if (ti1 != NULL)
+ cmsIT8Free (ti1);
+ if (ti3 != NULL)
+ cmsIT8Free (ti3);
+ g_free (ti1_data);
+ return ret;
+}
+
+/**
* gcm_calibrate_display:
**/
static gboolean
-gcm_calibrate_display (GcmCalibrate *calibrate, CdDevice *device, GtkWindow *window, GError **error)
+gcm_calibrate_display (GcmCalibrate *calibrate,
+ CdDevice *device,
+ GtkWindow *window,
+ GError **error)
{
const gchar *filename_tmp;
gboolean ret = TRUE;
- gchar *dest_ti1;
- gchar *src_ti1;
+ gchar *ti1_dest_fn = NULL;
+ gchar *ti1_src_fn = NULL;
+ gchar *ti3_fn = NULL;
GcmCalibrateClass *klass = GCM_CALIBRATE_GET_CLASS (calibrate);
GcmCalibratePrivate *priv = calibrate->priv;
/* get a ti1 file suitable for the calibration */
- dest_ti1 = g_strdup_printf ("%s/%s.ti1",
- calibrate->priv->working_path,
- calibrate->priv->basename);
+ ti1_dest_fn = g_strdup_printf ("%s/%s.ti1",
+ calibrate->priv->working_path,
+ calibrate->priv->basename);
/* copy a pre-generated file into the working path */
switch (priv->precision) {
@@ -395,11 +590,25 @@ gcm_calibrate_display (GcmCalibrate *calibrate, CdDevice *device, GtkWindow *win
default:
g_assert_not_reached ();
}
- src_ti1 = g_build_filename (GCM_DATA, "ti1", filename_tmp, NULL);
- ret = gcm_calibrate_copy_file (src_ti1, dest_ti1, error);
+ ti1_src_fn = g_build_filename (GCM_DATA, "ti1", filename_tmp, NULL);
+ ret = gcm_calibrate_copy_file (ti1_src_fn, ti1_dest_fn, error);
if (!ret)
goto out;
+ /* if sensor is native, then take some measurements */
+ if (cd_sensor_get_native (calibrate->priv->sensor) &&
+ cd_sensor_get_kind (calibrate->priv->sensor) == CD_SENSOR_KIND_COLORHUG) {
+ ti3_fn = g_strdup_printf ("%s/%s.ti3",
+ priv->working_path,
+ priv->basename);
+ ret = gcm_calibrate_display_characterize (calibrate,
+ ti1_dest_fn,
+ ti3_fn,
+ device,
+ window,
+ error);
+ }
+
/* coldplug source */
if (klass->calibrate_display == NULL) {
ret = FALSE;
@@ -413,8 +622,9 @@ gcm_calibrate_display (GcmCalibrate *calibrate, CdDevice *device, GtkWindow *win
/* proxy */
ret = klass->calibrate_display (calibrate, device, priv->sensor, window, error);
out:
- g_free (src_ti1);
- g_free (dest_ti1);
+ g_free (ti1_src_fn);
+ g_free (ti1_dest_fn);
+ g_free (ti3_fn);
return ret;
}
@@ -602,13 +812,13 @@ gcm_calibrate_printer (GcmCalibrate *calibrate, CdDevice *device, GtkWindow *win
GtkWindow *window_tmp = NULL;
gchar *precision = NULL;
const gchar *filename_tmp;
- gchar *dest_ti1;
- gchar *src_ti1;
+ gchar *ti1_dest_fn = NULL;
+ gchar *ti1_src_fn = NULL;
GcmCalibrateClass *klass = GCM_CALIBRATE_GET_CLASS (calibrate);
GcmCalibratePrivate *priv = calibrate->priv;
/* get a ti1 file suitable for the calibration */
- dest_ti1 = g_strdup_printf ("%s/%s.ti1",
+ ti1_dest_fn = g_strdup_printf ("%s/%s.ti1",
calibrate->priv->working_path,
calibrate->priv->basename);
@@ -626,8 +836,8 @@ gcm_calibrate_printer (GcmCalibrate *calibrate, CdDevice *device, GtkWindow *win
default:
g_assert_not_reached ();
}
- src_ti1 = g_build_filename (GCM_DATA, "ti1", filename_tmp, NULL);
- ret = gcm_calibrate_copy_file (src_ti1, dest_ti1, error);
+ ti1_src_fn = g_build_filename (GCM_DATA, "ti1", filename_tmp, NULL);
+ ret = gcm_calibrate_copy_file (ti1_src_fn, ti1_dest_fn, error);
if (!ret)
goto out;
@@ -673,8 +883,8 @@ gcm_calibrate_printer (GcmCalibrate *calibrate, CdDevice *device, GtkWindow *win
/* proxy */
ret = klass->calibrate_printer (calibrate, device, priv->sensor, window, error);
out:
- g_free (src_ti1);
- g_free (dest_ti1);
+ g_free (ti1_src_fn);
+ g_free (ti1_dest_fn);
g_free (precision);
return ret;
}
@@ -1153,6 +1363,7 @@ gcm_calibrate_init (GcmCalibrate *calibrate)
calibrate->priv->print_kind = GCM_CALIBRATE_PRINT_KIND_UNKNOWN;
calibrate->priv->reference_kind = GCM_CALIBRATE_REFERENCE_KIND_UNKNOWN;
calibrate->priv->precision = GCM_CALIBRATE_PRECISION_UNKNOWN;
+ calibrate->priv->sample_window = gcm_sample_window_new ();
// FIXME: this has to be per-run specific
calibrate->priv->working_path = g_strdup ("/tmp");
@@ -1182,6 +1393,7 @@ gcm_calibrate_finalize (GObject *object)
g_free (priv->working_path);
g_ptr_array_unref (calibrate->priv->old_title);
g_ptr_array_unref (calibrate->priv->old_message);
+ gtk_widget_destroy (GTK_WIDGET (calibrate->priv->sample_window));
G_OBJECT_CLASS (gcm_calibrate_parent_class)->finalize (object);
}
diff --git a/src/gcm-calibrate.h b/src/gcm-calibrate.h
index a7783c5..48ae66b 100644
--- a/src/gcm-calibrate.h
+++ b/src/gcm-calibrate.h
@@ -162,6 +162,14 @@ const gchar *gcm_calibrate_get_filename_result (GcmCalibrate *calibrate);
const gchar *gcm_calibrate_get_working_path (GcmCalibrate *calibrate);
const gchar *gcm_calibrate_get_basename (GcmCalibrate *calibrate);
+/* for gcm-calibrate-helper */
+gboolean gcm_calibrate_display_characterize (GcmCalibrate *calibrate,
+ const gchar *ti1_fn,
+ const gchar *ti3_fn,
+ CdDevice *device,
+ GtkWindow *window,
+ GError **error);
+
G_END_DECLS
#endif /* __GCM_CALIBRATE_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]