[gnome-color-manager: 2/3] Split out the lcms1 functionality into a derived class to allow us to add lcms2 at either compile ti
- From: Richard Hughes <rhughes src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gnome-color-manager: 2/3] Split out the lcms1 functionality into a derived class to allow us to add lcms2 at either compile ti
- Date: Wed, 23 Dec 2009 21:56:42 +0000 (UTC)
commit 57e3ca7feffab0c929b29d6971e336e6003eebcc
Author: Richard Hughes <richard hughsie com>
Date: Tue Dec 22 22:22:48 2009 +0000
Split out the lcms1 functionality into a derived class to allow us to add lcms2 at either compile time or at run time
src/Makefile.am | 3 +
src/gcm-cie-widget.c | 2 +-
src/gcm-dbus.c | 4 +-
src/gcm-dump-profile.c | 2 +-
src/gcm-import.c | 2 +-
src/gcm-inspect.c | 2 +-
src/gcm-prefs.c | 6 +-
src/gcm-profile-lcms1.c | 1010 ++++++++++++++++++++++++++++++++++++++++
src/gcm-profile-lcms1.h | 66 +++
src/gcm-profile.c | 1189 ++++++-----------------------------------------
src/gcm-profile.h | 12 +-
src/gcm-trc-widget.c | 2 +-
src/gcm-utils.c | 2 +-
13 files changed, 1245 insertions(+), 1057 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index b7ea6a7..554874d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -45,6 +45,8 @@ libgcmshared_a_SOURCES = \
gcm-trc-widget.h \
gcm-gamma-widget.c \
gcm-gamma-widget.h \
+ gcm-profile-lcms1.c \
+ gcm-profile-lcms1.h \
gcm-profile.c \
gcm-profile.h
@@ -204,6 +206,7 @@ gcm_self_test_SOURCES = \
gcm-utils.c \
gcm-device.c \
gcm-profile.c \
+ gcm-profile-lcms1.c \
gcm-brightness.c \
gcm-clut.c \
gcm-dmi.c \
diff --git a/src/gcm-cie-widget.c b/src/gcm-cie-widget.c
index 91a1589..2373a98 100644
--- a/src/gcm-cie-widget.c
+++ b/src/gcm-cie-widget.c
@@ -1215,7 +1215,7 @@ gcm_cie_widget_test (EggTest *test)
filename_profile = egg_test_get_data_file ("bluish.icc");
egg_test_assert (test, (filename_profile != NULL));
- profile = gcm_profile_new ();
+ profile = gcm_profile_default_new ();
gcm_profile_parse (profile, filename_profile, NULL);
g_object_get (profile,
"white-point", &white,
diff --git a/src/gcm-dbus.c b/src/gcm-dbus.c
index 04015de..3929c50 100644
--- a/src/gcm-dbus.c
+++ b/src/gcm-dbus.c
@@ -188,7 +188,7 @@ gcm_dbus_get_profiles_for_device_internal (GcmDbus *dbus, const gchar *sysfs_pat
NULL);
/* open and parse filename */
- profile = gcm_profile_new ();
+ profile = gcm_profile_default_new ();
ret = gcm_profile_parse (profile, filename, &error);
if (!ret) {
egg_warning ("failed to parse %s: %s", filename, error->message);
@@ -237,7 +237,7 @@ gcm_dbus_get_profiles_for_type_internal (GcmDbus *dbus, GcmDeviceType type)
filename = g_ptr_array_index (array_devices, i);
/* open and parse filename */
- profile = gcm_profile_new ();
+ profile = gcm_profile_default_new ();
ret = gcm_profile_parse (profile, filename, &error);
if (!ret) {
egg_warning ("failed to parse %s: %s", filename, error->message);
diff --git a/src/gcm-dump-profile.c b/src/gcm-dump-profile.c
index e6bf989..39bf4b2 100644
--- a/src/gcm-dump-profile.c
+++ b/src/gcm-dump-profile.c
@@ -48,7 +48,7 @@ gcm_dump_profile_filename (const gchar *filename)
gchar *datetime = NULL;
/* parse profile */
- profile = gcm_profile_new ();
+ profile = gcm_profile_default_new ();
ret = gcm_profile_parse (profile, filename, &error);
if (!ret) {
egg_warning ("failed to parse: %s", error->message);
diff --git a/src/gcm-import.c b/src/gcm-import.c
index 3ec9c2e..5bd469e 100644
--- a/src/gcm-import.c
+++ b/src/gcm-import.c
@@ -91,7 +91,7 @@ main (int argc, char **argv)
}
/* load profile */
- profile = gcm_profile_new ();
+ profile = gcm_profile_default_new ();
ret = gcm_profile_parse (profile, files[0], &error);
if (!ret) {
/* TRANSLATORS: could not read file */
diff --git a/src/gcm-inspect.c b/src/gcm-inspect.c
index 183ccbb..4619afc 100644
--- a/src/gcm-inspect.c
+++ b/src/gcm-inspect.c
@@ -46,7 +46,7 @@ gcm_inspect_print_data_info (const gchar *title, const guint8 *data, gsize lengt
gboolean ret;
/* parse the data */
- profile = gcm_profile_new ();
+ profile = gcm_profile_default_new ();
ret = gcm_profile_parse_data (profile, data, length, &error);
if (!ret) {
egg_warning ("failed to parse data: %s", error->message);
diff --git a/src/gcm-prefs.c b/src/gcm-prefs.c
index dbb047a..1b7fd9b 100644
--- a/src/gcm-prefs.c
+++ b/src/gcm-prefs.c
@@ -694,7 +694,7 @@ gcm_prefs_profile_import_cb (GtkWidget *widget, gpointer data)
}
/* add new profile */
- profile = gcm_profile_new ();
+ profile = gcm_profile_default_new ();
/* parse the new file */
ret = gcm_profile_parse (profile, destination, &error);
@@ -871,7 +871,7 @@ gcm_prefs_calibrate_cb (GtkWidget *widget, gpointer data)
}
/* create a new instance */
- profile = gcm_profile_new ();
+ profile = gcm_profile_default_new ();
/* parse the new file */
ret = gcm_profile_parse (profile, destination, &error);
@@ -1695,7 +1695,7 @@ gcm_prefs_add_profiles (GtkWidget *widget)
filename = g_ptr_array_index (filename_array, i);
/* parse the profile name */
- profile = gcm_profile_new ();
+ profile = gcm_profile_default_new ();
ret = gcm_profile_parse (profile, filename, &error);
if (!ret) {
egg_warning ("failed to add profile: %s", error->message);
diff --git a/src/gcm-profile-lcms1.c b/src/gcm-profile-lcms1.c
new file mode 100644
index 0000000..4f94794
--- /dev/null
+++ b/src/gcm-profile-lcms1.c
@@ -0,0 +1,1010 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 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 profile_lcms1.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:gcm-profile-lcms1
+ * @short_description: A parser object that understands the ICC profile data format.
+ *
+ * This object is a simple parser for the ICC binary profile data. If only understands
+ * a subset of the ICC profile_lcms1, just enought to get some metadata and the LUT.
+ */
+
+#include "config.h"
+
+#include <glib-object.h>
+#include <glib/gi18n.h>
+#include <math.h>
+#include <lcms.h>
+
+#include "egg-debug.h"
+
+#include "gcm-profile-lcms1.h"
+#include "gcm-utils.h"
+#include "gcm-xyz.h"
+
+static void gcm_profile_lcms1_finalize (GObject *object);
+
+#define GCM_PROFILE_LCMS1_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GCM_TYPE_PROFILE_LCMS1, GcmProfileLcms1Private))
+
+#define GCM_NUMTAGS 0x80
+#define GCM_BODY 0x84
+
+#define GCM_TAG_ID 0x00
+#define GCM_TAG_OFFSET 0x04
+#define GCM_TAG_SIZE 0x08
+#define GCM_TAG_WIDTH 0x0c
+
+#define icSigVideoCartGammaTableTag 0x76636774
+#define icSigMachineLookUpTableTag 0x6d4c5554
+
+#define GCM_MLUT_RED 0x000
+#define GCM_MLUT_GREEN 0x200
+#define GCM_MLUT_BLUE 0x400
+
+#define GCM_DESC_RECORD_SIZE 0x08
+#define GCM_DESC_RECORD_TEXT 0x0c
+#define GCM_TEXT_RECORD_TEXT 0x08
+
+#define GCM_VCGT_ID 0x00
+#define GCM_VCGT_DUMMY 0x04
+#define GCM_VCGT_GAMMA_TYPE 0x08
+#define GCM_VCGT_GAMMA_DATA 0x0c
+
+#define GCM_VCGT_FORMULA_GAMMA_RED 0x00
+#define GCM_VCGT_FORMULA_MIN_RED 0x04
+#define GCM_VCGT_FORMULA_MAX_RED 0x08
+#define GCM_VCGT_FORMULA_GAMMA_GREEN 0x0c
+#define GCM_VCGT_FORMULA_MIN_GREEN 0x10
+#define GCM_VCGT_FORMULA_MAX_GREEN 0x14
+#define GCM_VCGT_FORMULA_GAMMA_BLUE 0x18
+#define GCM_VCGT_FORMULA_MIN_BLUE 0x1c
+#define GCM_VCGT_FORMULA_MAX_BLUE 0x20
+
+#define GCM_VCGT_TABLE_NUM_CHANNELS 0x00
+#define GCM_VCGT_TABLE_NUM_ENTRIES 0x02
+#define GCM_VCGT_TABLE_NUM_SIZE 0x04
+#define GCM_VCGT_TABLE_NUM_DATA 0x06
+
+/**
+ * GcmProfileLcms1Private:
+ *
+ * Private #GcmProfileLcms1 data
+ **/
+struct _GcmProfileLcms1Private
+{
+ gboolean loaded;
+ gboolean has_mlut;
+ gboolean has_vcgt_formula;
+ gboolean has_vcgt_table;
+ cmsHPROFILE lcms_profile;
+ GcmClutData *vcgt_data;
+ guint vcgt_data_size;
+ GcmClutData *mlut_data;
+ guint mlut_data_size;
+ gboolean adobe_gamma_workaround;
+};
+
+G_DEFINE_TYPE (GcmProfileLcms1, gcm_profile_lcms1, GCM_TYPE_PROFILE)
+
+/**
+ * gcm_parser_decode_32:
+ **/
+static guint
+gcm_parser_decode_32 (const guint8 *data)
+{
+ guint retval;
+ retval = (*(data + 0) << 0) + (*(data + 1) << 8) + (*(data + 2) << 16) + (*(data + 3) << 24);
+ return GUINT32_FROM_BE (retval);
+}
+
+/**
+ * gcm_parser_decode_16:
+ **/
+static guint
+gcm_parser_decode_16 (const guint8 *data)
+{
+ guint retval;
+ retval = (*(data + 0) << 0) + (*(data + 1) << 8);
+ return GUINT16_FROM_BE (retval);
+}
+
+/**
+ * gcm_parser_decode_8:
+ **/
+static guint
+gcm_parser_decode_8 (const guint8 *data)
+{
+ guint retval;
+ retval = (*data << 0);
+ return GUINT16_FROM_BE (retval);
+}
+
+/**
+ * gcm_parser_load_icc_mlut:
+ **/
+static gboolean
+gcm_parser_load_icc_mlut (GcmProfileLcms1 *profile_lcms1, const guint8 *data, guint size)
+{
+ gboolean ret = TRUE;
+ guint i;
+ GcmClutData *mlut_data;
+
+ /* just load in data into a fixed size LUT */
+ profile_lcms1->priv->mlut_data = g_new0 (GcmClutData, 256);
+ mlut_data = profile_lcms1->priv->mlut_data;
+
+ for (i=0; i<256; i++)
+ mlut_data[i].red = gcm_parser_decode_16 (data + GCM_MLUT_RED + i*2);
+ for (i=0; i<256; i++)
+ mlut_data[i].green = gcm_parser_decode_16 (data + GCM_MLUT_GREEN + i*2);
+ for (i=0; i<256; i++)
+ mlut_data[i].blue = gcm_parser_decode_16 (data + GCM_MLUT_BLUE + i*2);
+
+ /* save datatype */
+ profile_lcms1->priv->has_mlut = TRUE;
+ return ret;
+}
+
+/**
+ * gcm_parser_load_icc_vcgt_formula:
+ **/
+static gboolean
+gcm_parser_load_icc_vcgt_formula (GcmProfileLcms1 *profile_lcms1, const guint8 *data, guint size)
+{
+ gboolean ret = FALSE;
+ GcmClutData *vcgt_data;
+
+ egg_debug ("loading a formula encoded gamma table");
+
+ /* just load in data into a temporary array */
+ profile_lcms1->priv->vcgt_data = g_new0 (GcmClutData, 4);
+ vcgt_data = profile_lcms1->priv->vcgt_data;
+
+ /* read in block of data */
+ vcgt_data[0].red = gcm_parser_decode_32 (data + GCM_VCGT_FORMULA_GAMMA_RED);
+ vcgt_data[0].green = gcm_parser_decode_32 (data + GCM_VCGT_FORMULA_GAMMA_GREEN);
+ vcgt_data[0].blue = gcm_parser_decode_32 (data + GCM_VCGT_FORMULA_GAMMA_BLUE);
+
+ vcgt_data[1].red = gcm_parser_decode_32 (data + GCM_VCGT_FORMULA_MIN_RED);
+ vcgt_data[1].green = gcm_parser_decode_32 (data + GCM_VCGT_FORMULA_MIN_GREEN);
+ vcgt_data[1].blue = gcm_parser_decode_32 (data + GCM_VCGT_FORMULA_MIN_BLUE);
+
+ vcgt_data[2].red = gcm_parser_decode_32 (data + GCM_VCGT_FORMULA_MAX_RED);
+ vcgt_data[2].green = gcm_parser_decode_32 (data + GCM_VCGT_FORMULA_MAX_GREEN);
+ vcgt_data[2].blue = gcm_parser_decode_32 (data + GCM_VCGT_FORMULA_MAX_BLUE);
+
+ /* check if valid */
+ if (vcgt_data[0].red / 65536.0 > 5.0 || vcgt_data[0].green / 65536.0 > 5.0 || vcgt_data[0].blue / 65536.0 > 5.0) {
+ egg_warning ("Gamma values out of range: [R:%u G:%u B:%u]", vcgt_data[0].red, vcgt_data[0].green, vcgt_data[0].blue);
+ goto out;
+ }
+ if (vcgt_data[1].red / 65536.0 >= 1.0 || vcgt_data[1].green / 65536.0 >= 1.0 || vcgt_data[1].blue / 65536.0 >= 1.0) {
+ egg_warning ("Gamma min limit out of range: [R:%u G:%u B:%u]", vcgt_data[1].red, vcgt_data[1].green, vcgt_data[1].blue);
+ goto out;
+ }
+ if (vcgt_data[2].red / 65536.0 > 1.0 || vcgt_data[2].green / 65536.0 > 1.0 || vcgt_data[2].blue / 65536.0 > 1.0) {
+ egg_warning ("Gamma max limit out of range: [R:%u G:%u B:%u]", vcgt_data[2].red, vcgt_data[2].green, vcgt_data[2].blue);
+ goto out;
+ }
+
+ /* save datatype */
+ profile_lcms1->priv->has_vcgt_formula = TRUE;
+ profile_lcms1->priv->vcgt_data_size = 3;
+ ret = TRUE;
+out:
+ return ret;
+}
+
+/**
+ * gcm_parser_load_icc_vcgt_table:
+ **/
+static gboolean
+gcm_parser_load_icc_vcgt_table (GcmProfileLcms1 *profile_lcms1, const guint8 *data, guint size)
+{
+ gboolean ret = TRUE;
+ guint num_channels = 0;
+ guint num_entries = 0;
+ guint entry_size = 0;
+ guint i;
+ GcmClutData *vcgt_data;
+
+ egg_debug ("loading a table encoded gamma table");
+
+ num_channels = gcm_parser_decode_16 (data + GCM_VCGT_TABLE_NUM_CHANNELS);
+ num_entries = gcm_parser_decode_16 (data + GCM_VCGT_TABLE_NUM_ENTRIES);
+ entry_size = gcm_parser_decode_16 (data + GCM_VCGT_TABLE_NUM_SIZE);
+
+ /* work-around for AdobeGamma-ProfileLcms1s (taken from xcalib) */
+ if (profile_lcms1->priv->adobe_gamma_workaround) {
+ egg_debug ("Working around AdobeGamma profile_lcms1");
+ entry_size = 2;
+ num_entries = 256;
+ num_channels = 3;
+ }
+
+ egg_debug ("channels: %u", num_channels);
+ egg_debug ("entry size: %ubits", entry_size * 8);
+ egg_debug ("entries/channel: %u", num_entries);
+
+ /* only able to parse RGB data */
+ if (num_channels != 3) {
+ egg_warning ("cannot parse non RGB entries");
+ ret = FALSE;
+ goto out;
+ }
+
+ /* bigger than will fit in 16 bits? */
+ if (entry_size > 2) {
+ egg_warning ("cannot parse large entries");
+ ret = FALSE;
+ goto out;
+ }
+
+ /* allocate ramp, plus one entry for extrapolation */
+ profile_lcms1->priv->vcgt_data = g_new0 (GcmClutData, num_entries + 1);
+ vcgt_data = profile_lcms1->priv->vcgt_data;
+
+ if (entry_size == 1) {
+ for (i=0; i<num_entries; i++)
+ vcgt_data[i].red = gcm_parser_decode_8 (data + GCM_VCGT_TABLE_NUM_DATA + (num_entries * 0) + i);
+ for (i=0; i<num_entries; i++)
+ vcgt_data[i].green = gcm_parser_decode_8 (data + GCM_VCGT_TABLE_NUM_DATA + (num_entries * 1) + i);
+ for (i=0; i<num_entries; i++)
+ vcgt_data[i].blue = gcm_parser_decode_8 (data + GCM_VCGT_TABLE_NUM_DATA + (num_entries * 2) + i);
+ } else {
+ for (i=0; i<num_entries; i++)
+ vcgt_data[i].red = gcm_parser_decode_16 (data + GCM_VCGT_TABLE_NUM_DATA + (num_entries * 0) + (i*2));
+ for (i=0; i<num_entries; i++)
+ vcgt_data[i].green = gcm_parser_decode_16 (data + GCM_VCGT_TABLE_NUM_DATA + (num_entries * 2) + (i*2));
+ for (i=0; i<num_entries; i++)
+ vcgt_data[i].blue = gcm_parser_decode_16 (data + GCM_VCGT_TABLE_NUM_DATA + (num_entries * 4) + (i*2));
+ }
+
+ /* save datatype */
+ profile_lcms1->priv->has_vcgt_table = TRUE;
+ profile_lcms1->priv->vcgt_data_size = num_entries;
+out:
+ return ret;
+}
+
+/**
+ * gcm_parser_load_icc_vcgt:
+ **/
+static gboolean
+gcm_parser_load_icc_vcgt (GcmProfileLcms1 *profile_lcms1, const guint8 *data, guint size)
+{
+ gboolean ret = FALSE;
+ guint tag_id;
+ guint gamma_type;
+
+ /* check we have a VCGT block */
+ tag_id = gcm_parser_decode_32 (data);
+ if (tag_id != icSigVideoCartGammaTableTag) {
+ egg_warning ("invalid content of table vcgt, starting with %x", tag_id);
+ goto out;
+ }
+
+ /* check what type of gamma encoding we have */
+ gamma_type = gcm_parser_decode_32 (data + GCM_VCGT_GAMMA_TYPE);
+ if (gamma_type == 0) {
+ ret = gcm_parser_load_icc_vcgt_table (profile_lcms1, data + GCM_VCGT_GAMMA_DATA, size);
+ goto out;
+ }
+ if (gamma_type == 1) {
+ ret = gcm_parser_load_icc_vcgt_formula (profile_lcms1, data + GCM_VCGT_GAMMA_DATA, size);
+ goto out;
+ }
+
+ /* we didn't understand the encoding */
+ egg_warning ("gamma type encoding not recognised");
+out:
+ return ret;
+}
+
+/**
+ * gcm_profile_lcms1_utf16be_to_locale:
+ *
+ * Convert ICC encoded UTF-16BE into a string the user can understand
+ **/
+static gchar *
+gcm_profile_lcms1_utf16be_to_locale (const guint8 *text, guint size)
+{
+ gsize items_written;
+ gchar *text_utf8 = NULL;
+ gchar *text_locale = NULL;
+ GError *error = NULL;
+
+ /* convert from ICC text encoding to UTF-8 */
+ text_utf8 = g_convert ((const gchar*)text, size, "UTF-8", "UTF-16BE", NULL, &items_written, &error);
+ if (text_utf8 == NULL) {
+ egg_warning ("failed to convert to UTF-8: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ /* convert from UTF-8 to the users locale*/
+ text_locale = g_locale_from_utf8 (text_utf8, items_written, NULL, NULL, &error);
+ if (text_locale == NULL) {
+ egg_warning ("failed to convert to locale: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+out:
+ g_free (text_utf8);
+ return text_locale;
+}
+
+/**
+ * gcm_profile_lcms1_parse_multi_localized_unicode:
+ **/
+static gchar *
+gcm_profile_lcms1_parse_multi_localized_unicode (GcmProfileLcms1 *profile_lcms1, const guint8 *data, guint size)
+{
+ guint i;
+ gchar *text = NULL;
+ guint record_size;
+ guint names_size;
+ guint len;
+ guint offset_name;
+ guint32 type;
+
+ /* get type */
+ type = gcm_parser_decode_32 (data);
+
+ /* check we are not a localized tag */
+ if (type == icSigTextDescriptionType) {
+ record_size = gcm_parser_decode_32 (data + GCM_DESC_RECORD_SIZE);
+ text = g_strndup ((const gchar*)&data[GCM_DESC_RECORD_TEXT], record_size);
+ goto out;
+ }
+
+ /* check we are not a localized tag */
+ if (type == icSigTextType) {
+ text = g_strdup ((const gchar*)&data[GCM_TEXT_RECORD_TEXT]);
+ goto out;
+ }
+
+ /* check we are not a localized tag */
+ if (type == icSigMultiLocalizedUnicodeType) {
+ names_size = gcm_parser_decode_32 (data + 8);
+ if (names_size != 1) {
+ /* there is more than one language encoded */
+ egg_warning ("more than one item of data in MLUC (names size: %i), using first one", names_size);
+ }
+ record_size = gcm_parser_decode_32 (data + 12);
+ len = gcm_parser_decode_32 (data + 20);
+ offset_name = gcm_parser_decode_32 (data + 24);
+ text = gcm_profile_lcms1_utf16be_to_locale (data + offset_name, len);
+ goto out;
+ }
+
+ /* an unrecognised tag */
+ for (i=0x0; i<0x1c; i++) {
+ egg_warning ("unrecognised text tag");
+ if (data[i] >= 'A' && data[i] <= 'z')
+ egg_debug ("%i\t%c (%i)", i, data[i], data[i]);
+ else
+ egg_debug ("%i\t (%i)", i, data[i]);
+ }
+out:
+ return text;
+}
+
+/**
+ * gcm_profile_lcms1_parse_data:
+ **/
+static gboolean
+gcm_profile_lcms1_parse_data (GcmProfile *profile, const guint8 *data, gsize length, GError **error)
+{
+ gboolean ret = FALSE;
+ guint num_tags;
+ guint i;
+ guint tag_id;
+ guint offset;
+ guint tag_size;
+ guint tag_offset;
+ icProfileClassSignature profile_class;
+ icColorSpaceSignature color_space;
+ GcmProfileColorspace colorspace;
+ GcmProfileType profile_type;
+ cmsCIEXYZ cie_xyz;
+ cmsCIEXYZTRIPLE cie_illum;
+ struct tm created;
+ cmsHPROFILE xyz_profile_lcms1;
+ cmsHTRANSFORM transform;
+ gchar *text;
+ GcmXyz *xyz;
+ GcmProfileLcms1 *profile_lcms1 = GCM_PROFILE_LCMS1 (profile);
+ GcmProfileLcms1Private *priv = profile_lcms1->priv;
+
+ g_return_val_if_fail (GCM_IS_PROFILE_LCMS1 (profile_lcms1), FALSE);
+ g_return_val_if_fail (data != NULL, FALSE);
+ g_return_val_if_fail (priv->loaded == FALSE, FALSE);
+
+ priv->loaded = TRUE;
+
+ /* load profile into lcms */
+ priv->lcms_profile = cmsOpenProfileFromMem ((LPVOID)data, length);
+ if (priv->lcms_profile == NULL) {
+ *error = g_error_new (1, 0, "failed to load: not an ICC profile_lcms1");
+ goto out;
+ }
+
+ /* get white point */
+ ret = cmsTakeMediaWhitePoint (&cie_xyz, priv->lcms_profile);
+ if (ret) {
+ xyz = gcm_xyz_new ();
+ g_object_set (xyz,
+ "cie-x", cie_xyz.X,
+ "cie-y", cie_xyz.Y,
+ "cie-z", cie_xyz.Z,
+ NULL);
+ g_object_set (profile,
+ "white-point", xyz,
+ NULL);
+ g_object_unref (xyz);
+ } else {
+ egg_warning ("failed to get white point");
+ }
+
+ /* get black point */
+ ret = cmsTakeMediaBlackPoint (&cie_xyz, priv->lcms_profile);
+ if (ret) {
+ xyz = gcm_xyz_new ();
+ g_object_set (xyz,
+ "cie-x", cie_xyz.X,
+ "cie-y", cie_xyz.Y,
+ "cie-z", cie_xyz.Z,
+ NULL);
+ g_object_set (profile,
+ "black-point", xyz,
+ NULL);
+ g_object_unref (xyz);
+ } else {
+ egg_warning ("failed to get black point");
+ }
+
+ /* get the profile_lcms1 type */
+ profile_class = cmsGetDeviceClass (priv->lcms_profile);
+ switch (profile_class) {
+ case icSigInputClass:
+ profile_type = GCM_PROFILE_TYPE_INPUT_DEVICE;
+ break;
+ case icSigDisplayClass:
+ profile_type = GCM_PROFILE_TYPE_DISPLAY_DEVICE;
+ break;
+ case icSigOutputClass:
+ profile_type = GCM_PROFILE_TYPE_OUTPUT_DEVICE;
+ break;
+ case icSigLinkClass:
+ profile_type = GCM_PROFILE_TYPE_DEVICELINK;
+ break;
+ case icSigColorSpaceClass:
+ profile_type = GCM_PROFILE_TYPE_COLORSPACE_CONVERSION;
+ break;
+ case icSigAbstractClass:
+ profile_type = GCM_PROFILE_TYPE_ABSTRACT;
+ break;
+ case icSigNamedColorClass:
+ profile_type = GCM_PROFILE_TYPE_NAMED_COLOR;
+ break;
+ default:
+ profile_type = GCM_PROFILE_TYPE_UNKNOWN;
+ }
+ g_object_set (profile,
+ "type", profile_type,
+ NULL);
+
+ /* get colorspace */
+ color_space = cmsGetColorSpace (priv->lcms_profile);
+ switch (color_space) {
+ case icSigXYZData:
+ colorspace = GCM_PROFILE_COLORSPACE_XYZ;
+ break;
+ case icSigLabData:
+ colorspace = GCM_PROFILE_COLORSPACE_LAB;
+ break;
+ case icSigLuvData:
+ colorspace = GCM_PROFILE_COLORSPACE_LUV;
+ break;
+ case icSigYCbCrData:
+ colorspace = GCM_PROFILE_COLORSPACE_YCBCR;
+ break;
+ case icSigYxyData:
+ colorspace = GCM_PROFILE_COLORSPACE_YXY;
+ break;
+ case icSigRgbData:
+ colorspace = GCM_PROFILE_COLORSPACE_RGB;
+ break;
+ case icSigGrayData:
+ colorspace = GCM_PROFILE_COLORSPACE_GRAY;
+ break;
+ case icSigHsvData:
+ colorspace = GCM_PROFILE_COLORSPACE_HSV;
+ break;
+ case icSigCmykData:
+ colorspace = GCM_PROFILE_COLORSPACE_CMYK;
+ break;
+ case icSigCmyData:
+ colorspace = GCM_PROFILE_COLORSPACE_CMY;
+ break;
+ default:
+ colorspace = GCM_PROFILE_COLORSPACE_UNKNOWN;
+ }
+ g_object_set (profile,
+ "colorspace", colorspace,
+ NULL);
+
+ /* get primary illuminants */
+ ret = cmsTakeColorants (&cie_illum, priv->lcms_profile);
+
+ /* geting the illuminants failed, try running it through the profile_lcms1 */
+ if (!ret && color_space == icSigRgbData) {
+ gdouble rgb_values[3];
+
+ /* create a transform from profile_lcms1 to XYZ */
+ xyz_profile_lcms1 = cmsCreateXYZProfile ();
+ transform = cmsCreateTransform (priv->lcms_profile, TYPE_RGB_DBL, xyz_profile_lcms1, TYPE_XYZ_DBL, INTENT_PERCEPTUAL, 0);
+ if (transform != NULL) {
+
+ /* red */
+ rgb_values[0] = 1.0;
+ rgb_values[1] = 0.0;
+ rgb_values[2] = 0.0;
+ cmsDoTransform (transform, rgb_values, &cie_illum.Red, 1);
+
+ /* green */
+ rgb_values[0] = 0.0;
+ rgb_values[1] = 1.0;
+ rgb_values[2] = 0.0;
+ cmsDoTransform (transform, rgb_values, &cie_illum.Green, 1);
+
+ /* blue */
+ rgb_values[0] = 0.0;
+ rgb_values[1] = 0.0;
+ rgb_values[2] = 1.0;
+ cmsDoTransform (transform, rgb_values, &cie_illum.Blue, 1);
+
+ /* we're done */
+ cmsDeleteTransform (transform);
+ ret = TRUE;
+ }
+
+ /* no more need for the output profile_lcms1 */
+ cmsCloseProfile (xyz_profile_lcms1);
+ }
+
+ /* we've got valid values */
+ if (ret) {
+ /* red */
+ xyz = gcm_xyz_new ();
+ g_object_set (xyz,
+ "cie-x", cie_illum.Red.X,
+ "cie-y", cie_illum.Red.Y,
+ "cie-z", cie_illum.Red.Z,
+ NULL);
+ g_object_set (profile,
+ "luminance_red", xyz,
+ NULL);
+ g_object_unref (xyz);
+
+ /* green */
+ xyz = gcm_xyz_new ();
+ g_object_set (xyz,
+ "cie-x", cie_illum.Green.X,
+ "cie-y", cie_illum.Green.Y,
+ "cie-z", cie_illum.Green.Z,
+ NULL);
+ g_object_set (profile,
+ "luminance-green", xyz,
+ NULL);
+ g_object_unref (xyz);
+
+ /* blue */
+ xyz = gcm_xyz_new ();
+ g_object_set (xyz,
+ "cie-x", cie_illum.Blue.X,
+ "cie-y", cie_illum.Blue.Y,
+ "cie-z", cie_illum.Blue.Z,
+ NULL);
+ g_object_set (profile,
+ "luminance-blue", xyz,
+ NULL);
+ g_object_unref (xyz);
+ } else {
+ egg_debug ("failed to get luminance values");
+ }
+
+ /* get the profile_lcms1 created time and date */
+ ret = cmsTakeCreationDateTime (&created, priv->lcms_profile);
+ if (ret) {
+ text = gcm_utils_format_date_time (&created);
+ g_object_set (profile,
+ "datetime", text,
+ NULL);
+ g_free (text);
+ }
+
+ /* get the number of tags in the file */
+ num_tags = gcm_parser_decode_32 (data + GCM_NUMTAGS);
+ egg_debug ("number of tags: %i", num_tags);
+
+ for (i=0; i<num_tags; i++) {
+ offset = GCM_TAG_WIDTH * i;
+ tag_id = gcm_parser_decode_32 (data + GCM_BODY + offset + GCM_TAG_ID);
+ tag_offset = gcm_parser_decode_32 (data + GCM_BODY + offset + GCM_TAG_OFFSET);
+ tag_size = gcm_parser_decode_32 (data + GCM_BODY + offset + GCM_TAG_SIZE);
+
+ /* print tag */
+ egg_debug ("tag %x is present at 0x%x with size %u", tag_id, tag_offset, tag_size);
+
+ if (tag_id == icSigProfileDescriptionTag) {
+ text = gcm_profile_lcms1_parse_multi_localized_unicode (profile_lcms1, data + tag_offset, tag_size);
+ g_object_set (profile, "description", text, NULL);
+ g_free (text);
+ }
+ if (tag_id == icSigCopyrightTag) {
+ text = gcm_profile_lcms1_parse_multi_localized_unicode (profile_lcms1, data + tag_offset, tag_size);
+ g_object_set (profile, "copyright", text, NULL);
+ g_free (text);
+ }
+ if (tag_id == icSigDeviceMfgDescTag) {
+ text = gcm_profile_lcms1_parse_multi_localized_unicode (profile_lcms1, data + tag_offset, tag_size);
+ g_object_set (profile, "manufacturer", text, NULL);
+ g_free (text);
+ }
+ if (tag_id == icSigDeviceModelDescTag) {
+ text = gcm_profile_lcms1_parse_multi_localized_unicode (profile_lcms1, data + tag_offset, tag_size);
+ g_object_set (profile, "model", text, NULL);
+ g_free (text);
+ }
+ if (tag_id == icSigMachineLookUpTableTag) {
+ egg_debug ("found MLUT which is a fixed size block");
+ ret = gcm_parser_load_icc_mlut (profile_lcms1, data + tag_offset, tag_size);
+ if (!ret) {
+ *error = g_error_new (1, 0, "failed to load mlut");
+ goto out;
+ }
+ }
+ if (tag_id == icSigVideoCartGammaTableTag) {
+ egg_debug ("found VCGT");
+ if (tag_size == 1584)
+ priv->adobe_gamma_workaround = TRUE;
+ ret = gcm_parser_load_icc_vcgt (profile_lcms1, data + tag_offset, tag_size);
+ if (!ret) {
+ *error = g_error_new (1, 0, "failed to load vcgt");
+ goto out;
+ }
+ }
+ }
+
+ /* success */
+ ret = TRUE;
+
+ egg_debug ("Has MLUT: %s", priv->has_mlut ? "YES" : "NO");
+ egg_debug ("Has VCGT formula: %s", priv->has_vcgt_formula ? "YES" : "NO");
+ egg_debug ("Has VCGT table: %s", priv->has_vcgt_table ? "YES" : "NO");
+out:
+ return ret;
+}
+
+/**
+ * gcm_profile_lcms1_generate_vcgt:
+ *
+ * Free with g_object_unref();
+ **/
+static GcmClut *
+gcm_profile_lcms1_generate_vcgt (GcmProfile *profile, guint size)
+{
+ guint i;
+ guint ratio;
+ GcmClutData *tmp;
+ GcmClutData *vcgt_data;
+ GcmClutData *mlut_data;
+ gfloat gamma_red, min_red, max_red;
+ gfloat gamma_green, min_green, max_green;
+ gfloat gamma_blue, min_blue, max_blue;
+ guint num_entries;
+ GcmClut *clut = NULL;
+ GPtrArray *array = NULL;
+ gfloat inverse_ratio;
+ guint idx;
+ gfloat frac;
+ GcmProfileLcms1 *profile_lcms1 = GCM_PROFILE_LCMS1 (profile);
+
+ g_return_val_if_fail (GCM_IS_PROFILE_LCMS1 (profile_lcms1), NULL);
+ g_return_val_if_fail (size != 0, FALSE);
+
+ /* reduce dereferences */
+ vcgt_data = profile_lcms1->priv->vcgt_data;
+ mlut_data = profile_lcms1->priv->mlut_data;
+
+ if (profile_lcms1->priv->has_vcgt_table) {
+
+ /* create array */
+ array = g_ptr_array_new_with_free_func (g_free);
+
+ /* simply subsample if the LUT is smaller than the number of entries in the file */
+ num_entries = profile_lcms1->priv->vcgt_data_size;
+ if (num_entries >= size) {
+ ratio = (guint) (num_entries / size);
+ for (i=0; i<size; i++) {
+ /* add a point */
+ tmp = g_new0 (GcmClutData, 1);
+ tmp->red = vcgt_data[ratio*i].red;
+ tmp->green = vcgt_data[ratio*i].green;
+ tmp->blue = vcgt_data[ratio*i].blue;
+ g_ptr_array_add (array, tmp);
+ }
+ goto out;
+ }
+
+ /* LUT is bigger than number of entries, so interpolate */
+ inverse_ratio = (gfloat) num_entries / size;
+ vcgt_data[num_entries].red = 0xffff;
+ vcgt_data[num_entries].green = 0xffff;
+ vcgt_data[num_entries].blue = 0xffff;
+
+ /* interpolate */
+ for (i=0; i<size; i++) {
+ idx = floor(i*inverse_ratio);
+ frac = (i*inverse_ratio) - idx;
+ tmp = g_new0 (GcmClutData, 1);
+ tmp->red = vcgt_data[idx].red * (1.0f-frac) + vcgt_data[idx + 1].red * frac;
+ tmp->green = vcgt_data[idx].green * (1.0f-frac) + vcgt_data[idx + 1].green * frac;
+ tmp->blue = vcgt_data[idx].blue * (1.0f-frac) + vcgt_data[idx + 1].blue * frac;
+ g_ptr_array_add (array, tmp);
+ }
+ goto out;
+ }
+
+ if (profile_lcms1->priv->has_vcgt_formula) {
+
+ /* create array */
+ array = g_ptr_array_new_with_free_func (g_free);
+
+ gamma_red = (gfloat) vcgt_data[0].red / 65536.0;
+ gamma_green = (gfloat) vcgt_data[0].green / 65536.0;
+ gamma_blue = (gfloat) vcgt_data[0].blue / 65536.0;
+ min_red = (gfloat) vcgt_data[1].red / 65536.0;
+ min_green = (gfloat) vcgt_data[1].green / 65536.0;
+ min_blue = (gfloat) vcgt_data[1].blue / 65536.0;
+ max_red = (gfloat) vcgt_data[2].red / 65536.0;
+ max_green = (gfloat) vcgt_data[2].green / 65536.0;
+ max_blue = (gfloat) vcgt_data[2].blue / 65536.0;
+
+ /* create mapping of desired size */
+ for (i=0; i<size; i++) {
+ /* add a point */
+ tmp = g_new0 (GcmClutData, 1);
+ tmp->red = 65536.0 * ((gdouble) pow ((gdouble) i / (gdouble) size, gamma_red) * (max_red - min_red) + min_red);
+ tmp->green = 65536.0 * ((gdouble) pow ((gdouble) i / (gdouble) size, gamma_green) * (max_green - min_green) + min_green);
+ tmp->blue = 65536.0 * ((gdouble) pow ((gdouble) i / (gdouble) size, gamma_blue) * (max_blue - min_blue) + min_blue);
+ g_ptr_array_add (array, tmp);
+ }
+ goto out;
+ }
+
+ if (profile_lcms1->priv->has_mlut) {
+
+ /* create array */
+ array = g_ptr_array_new_with_free_func (g_free);
+
+ /* roughly interpolate table */
+ ratio = (guint) (256 / (size));
+ for (i=0; i<size; i++) {
+ /* add a point */
+ tmp = g_new0 (GcmClutData, 1);
+ tmp->red = mlut_data[ratio*i].red;
+ tmp->green = mlut_data[ratio*i].green;
+ tmp->blue = mlut_data[ratio*i].blue;
+ g_ptr_array_add (array, tmp);
+ }
+ goto out;
+ }
+
+ /* bugger */
+ egg_debug ("no LUT to generate");
+out:
+ if (array != NULL) {
+ /* create new output array */
+ clut = gcm_clut_new ();
+ gcm_clut_set_source_array (clut, array);
+ g_ptr_array_unref (array);
+ }
+ return clut;
+}
+
+/**
+ * gcm_profile_lcms1_generate_curve:
+ *
+ * Free with g_object_unref();
+ **/
+static GcmClut *
+gcm_profile_lcms1_generate_curve (GcmProfile *profile, guint size)
+{
+ GcmClut *clut = NULL;
+ gdouble *values_in = NULL;
+ gdouble *values_out = NULL;
+ guint i;
+ GcmClutData *data;
+ GPtrArray *array = NULL;
+ gfloat divamount;
+ gfloat divadd;
+ guint component_width;
+ cmsHPROFILE srgb_profile_lcms1 = NULL;
+ cmsHTRANSFORM transform = NULL;
+ guint type;
+ GcmProfileColorspace colorspace;
+ GcmProfileLcms1 *profile_lcms1 = GCM_PROFILE_LCMS1 (profile);
+ GcmProfileLcms1Private *priv = profile_lcms1->priv;
+
+ /* get data */
+ g_object_get (profile,
+ "colorspace", &colorspace,
+ NULL);
+
+ /* run through the profile_lcms1 */
+ if (colorspace == GCM_PROFILE_COLORSPACE_RGB) {
+
+ /* RGB */
+ component_width = 3;
+ type = TYPE_RGB_DBL;
+
+ /* create input array */
+ values_in = g_new0 (gdouble, size * 3 * component_width);
+ divamount = 1.0f / (gfloat) (size - 1);
+ for (i=0; i<size; i++) {
+ divadd = divamount * (gfloat) i;
+
+ /* red component */
+ values_in[(i * 3 * component_width)+0] = divadd;
+ values_in[(i * 3 * component_width)+1] = 0.0f;
+ values_in[(i * 3 * component_width)+2] = 0.0f;
+
+ /* green component */
+ values_in[(i * 3 * component_width)+3] = 0.0f;
+ values_in[(i * 3 * component_width)+4] = divadd;
+ values_in[(i * 3 * component_width)+5] = 0.0f;
+
+ /* blue component */
+ values_in[(i * 3 * component_width)+6] = 0.0f;
+ values_in[(i * 3 * component_width)+7] = 0.0f;
+ values_in[(i * 3 * component_width)+8] = divadd;
+ }
+ }
+
+ /* do each transform */
+ if (values_in != NULL) {
+ /* create output array */
+ values_out = g_new0 (gdouble, size * 3 * component_width);
+
+ /* create a transform from profile_lcms1 to sRGB */
+ srgb_profile_lcms1 = cmsCreate_sRGBProfile ();
+ transform = cmsCreateTransform (priv->lcms_profile, type, srgb_profile_lcms1, TYPE_RGB_DBL, INTENT_PERCEPTUAL, 0);
+ if (transform == NULL)
+ goto out;
+
+ /* do transform */
+ cmsDoTransform (transform, values_in, values_out, size * 3);
+
+ /* create output array */
+ array = g_ptr_array_new_with_free_func (g_free);
+
+ for (i=0; i<size; i++) {
+ data = g_new0 (GcmClutData, 1);
+
+ data->red = values_out[(i * 3 * component_width)+0] * (gfloat) 0xffff;
+ data->green = values_out[(i * 3 * component_width)+4] * (gfloat) 0xffff;
+ data->blue = values_out[(i * 3 * component_width)+8] * (gfloat) 0xffff;
+ g_ptr_array_add (array, data);
+ }
+ clut = gcm_clut_new ();
+ gcm_clut_set_source_array (clut, array);
+ }
+
+out:
+ g_free (values_in);
+ g_free (values_out);
+ if (array != NULL)
+ g_ptr_array_unref (array);
+ if (transform != NULL)
+ cmsDeleteTransform (transform);
+ if (srgb_profile_lcms1 != NULL)
+ cmsCloseProfile (srgb_profile_lcms1);
+ return clut;
+}
+
+/**
+ * gcm_profile_lcms1_lcms_error_cb:
+ **/
+static int
+gcm_profile_lcms1_lcms_error_cb (int ErrorCode, const char *ErrorText)
+{
+ egg_warning ("LCMS error %i: %s", ErrorCode, ErrorText);
+ return LCMS_ERRC_WARNING;
+}
+
+/**
+ * gcm_profile_lcms1_class_init:
+ **/
+static void
+gcm_profile_lcms1_class_init (GcmProfileLcms1Class *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GcmProfileClass *parent_class = GCM_PROFILE_CLASS (klass);
+ object_class->finalize = gcm_profile_lcms1_finalize;
+
+ parent_class->parse_data = gcm_profile_lcms1_parse_data;
+ parent_class->generate_vcgt = gcm_profile_lcms1_generate_vcgt;
+ parent_class->generate_curve = gcm_profile_lcms1_generate_curve;
+
+ g_type_class_add_private (klass, sizeof (GcmProfileLcms1Private));
+}
+
+/**
+ * gcm_profile_lcms1_init:
+ **/
+static void
+gcm_profile_lcms1_init (GcmProfileLcms1 *profile_lcms1)
+{
+ profile_lcms1->priv = GCM_PROFILE_LCMS1_GET_PRIVATE (profile_lcms1);
+ profile_lcms1->priv->vcgt_data = NULL;
+ profile_lcms1->priv->mlut_data = NULL;
+ profile_lcms1->priv->adobe_gamma_workaround = FALSE;
+
+ /* setup LCMS */
+ cmsSetErrorHandler (gcm_profile_lcms1_lcms_error_cb);
+ cmsErrorAction (LCMS_ERROR_SHOW);
+ cmsSetLanguage ("en", "US");
+}
+
+/**
+ * gcm_profile_lcms1_finalize:
+ **/
+static void
+gcm_profile_lcms1_finalize (GObject *object)
+{
+ GcmProfileLcms1 *profile_lcms1 = GCM_PROFILE_LCMS1 (object);
+ GcmProfileLcms1Private *priv = profile_lcms1->priv;
+
+ if (priv->lcms_profile != NULL)
+ cmsCloseProfile (priv->lcms_profile);
+
+ g_free (priv->vcgt_data);
+ g_free (priv->mlut_data);
+
+ G_OBJECT_CLASS (gcm_profile_lcms1_parent_class)->finalize (object);
+}
+
+/**
+ * gcm_profile_lcms1_new:
+ *
+ * Return value: a new GcmProfileLcms1 object.
+ **/
+GcmProfileLcms1 *
+gcm_profile_lcms1_new (void)
+{
+ GcmProfileLcms1 *profile_lcms1;
+ profile_lcms1 = g_object_new (GCM_TYPE_PROFILE_LCMS1, NULL);
+ return GCM_PROFILE_LCMS1 (profile_lcms1);
+}
+
diff --git a/src/gcm-profile-lcms1.h b/src/gcm-profile-lcms1.h
new file mode 100644
index 0000000..78cefe9
--- /dev/null
+++ b/src/gcm-profile-lcms1.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GCM_PROFILE_LCMS1_H
+#define __GCM_PROFILE_LCMS1_H
+
+#include <glib-object.h>
+
+#include "gcm-clut.h"
+#include "gcm-profile.h"
+
+G_BEGIN_DECLS
+
+#define GCM_TYPE_PROFILE_LCMS1 (gcm_profile_lcms1_get_type ())
+#define GCM_PROFILE_LCMS1(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GCM_TYPE_PROFILE_LCMS1, GcmProfileLcms1))
+#define GCM_PROFILE_LCMS1_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GCM_TYPE_PROFILE_LCMS1, GcmProfileLcms1Class))
+#define GCM_IS_PROFILE_LCMS1(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GCM_TYPE_PROFILE_LCMS1))
+#define GCM_IS_PROFILE_LCMS1_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GCM_TYPE_PROFILE_LCMS1))
+#define GCM_PROFILE_LCMS1_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GCM_TYPE_PROFILE_LCMS1, GcmProfileLcms1Class))
+
+typedef struct _GcmProfileLcms1Private GcmProfileLcms1Private;
+typedef struct _GcmProfileLcms1 GcmProfileLcms1;
+typedef struct _GcmProfileLcms1Class GcmProfileLcms1Class;
+
+struct _GcmProfileLcms1
+{
+ GcmProfile parent;
+ GcmProfileLcms1Private *priv;
+};
+
+struct _GcmProfileLcms1Class
+{
+ GcmProfileClass parent_class;
+ /* padding for future expansion */
+ void (*_gcm_reserved1) (void);
+ void (*_gcm_reserved2) (void);
+ void (*_gcm_reserved3) (void);
+ void (*_gcm_reserved4) (void);
+ void (*_gcm_reserved5) (void);
+};
+
+GType gcm_profile_lcms1_get_type (void);
+GcmProfileLcms1 *gcm_profile_lcms1_new (void);
+
+G_END_DECLS
+
+#endif /* __GCM_PROFILE_LCMS1_H */
+
diff --git a/src/gcm-profile.c b/src/gcm-profile.c
index 87bb2ca..a1836d8 100644
--- a/src/gcm-profile.c
+++ b/src/gcm-profile.c
@@ -31,58 +31,18 @@
#include <glib-object.h>
#include <glib/gi18n.h>
-#include <math.h>
-#include <lcms.h>
#include "egg-debug.h"
#include "gcm-profile.h"
#include "gcm-utils.h"
#include "gcm-xyz.h"
+#include "gcm-profile-lcms1.h"
static void gcm_profile_finalize (GObject *object);
#define GCM_PROFILE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GCM_TYPE_PROFILE, GcmProfilePrivate))
-#define GCM_NUMTAGS 0x80
-#define GCM_BODY 0x84
-
-#define GCM_TAG_ID 0x00
-#define GCM_TAG_OFFSET 0x04
-#define GCM_TAG_SIZE 0x08
-#define GCM_TAG_WIDTH 0x0c
-
-#define icSigVideoCartGammaTableTag 0x76636774
-#define icSigMachineLookUpTableTag 0x6d4c5554
-
-#define GCM_MLUT_RED 0x000
-#define GCM_MLUT_GREEN 0x200
-#define GCM_MLUT_BLUE 0x400
-
-#define GCM_DESC_RECORD_SIZE 0x08
-#define GCM_DESC_RECORD_TEXT 0x0c
-#define GCM_TEXT_RECORD_TEXT 0x08
-
-#define GCM_VCGT_ID 0x00
-#define GCM_VCGT_DUMMY 0x04
-#define GCM_VCGT_GAMMA_TYPE 0x08
-#define GCM_VCGT_GAMMA_DATA 0x0c
-
-#define GCM_VCGT_FORMULA_GAMMA_RED 0x00
-#define GCM_VCGT_FORMULA_MIN_RED 0x04
-#define GCM_VCGT_FORMULA_MAX_RED 0x08
-#define GCM_VCGT_FORMULA_GAMMA_GREEN 0x0c
-#define GCM_VCGT_FORMULA_MIN_GREEN 0x10
-#define GCM_VCGT_FORMULA_MAX_GREEN 0x14
-#define GCM_VCGT_FORMULA_GAMMA_BLUE 0x18
-#define GCM_VCGT_FORMULA_MIN_BLUE 0x1c
-#define GCM_VCGT_FORMULA_MAX_BLUE 0x20
-
-#define GCM_VCGT_TABLE_NUM_CHANNELS 0x00
-#define GCM_VCGT_TABLE_NUM_ENTRIES 0x02
-#define GCM_VCGT_TABLE_NUM_SIZE 0x04
-#define GCM_VCGT_TABLE_NUM_DATA 0x06
-
/**
* GcmProfilePrivate:
*
@@ -90,7 +50,6 @@ static void gcm_profile_finalize (GObject *object);
**/
struct _GcmProfilePrivate
{
- gboolean loaded;
guint profile_type;
guint colorspace;
guint size;
@@ -100,15 +59,6 @@ struct _GcmProfilePrivate
gchar *manufacturer;
gchar *model;
gchar *datetime;
- gboolean has_mlut;
- gboolean has_vcgt_formula;
- gboolean has_vcgt_table;
- cmsHPROFILE lcms_profile;
- GcmClutData *vcgt_data;
- guint vcgt_data_size;
- GcmClutData *mlut_data;
- guint mlut_data_size;
- gboolean adobe_gamma_workaround;
GcmXyz *white_point;
GcmXyz *black_point;
GcmXyz *luminance_red;
@@ -128,6 +78,7 @@ enum {
PROP_COLORSPACE,
PROP_SIZE,
PROP_WHITE_POINT,
+ PROP_BLACK_POINT,
PROP_LUMINANCE_RED,
PROP_LUMINANCE_GREEN,
PROP_LUMINANCE_BLUE,
@@ -137,714 +88,27 @@ enum {
G_DEFINE_TYPE (GcmProfile, gcm_profile, G_TYPE_OBJECT)
/**
- * gcm_parser_decode_32:
- **/
-static guint
-gcm_parser_decode_32 (const guint8 *data)
-{
- guint retval;
- retval = (*(data + 0) << 0) + (*(data + 1) << 8) + (*(data + 2) << 16) + (*(data + 3) << 24);
- return GUINT32_FROM_BE (retval);
-}
-
-/**
- * gcm_parser_decode_16:
- **/
-static guint
-gcm_parser_decode_16 (const guint8 *data)
-{
- guint retval;
- retval = (*(data + 0) << 0) + (*(data + 1) << 8);
- return GUINT16_FROM_BE (retval);
-}
-
-/**
- * gcm_parser_decode_8:
- **/
-static guint
-gcm_parser_decode_8 (const guint8 *data)
-{
- guint retval;
- retval = (*data << 0);
- return GUINT16_FROM_BE (retval);
-}
-
-/**
- * gcm_prefs_get_tag_description:
- **/
-static const gchar *
-gcm_prefs_get_tag_description (guint tag)
-{
- if (tag == icSigProfileDescriptionTag)
- return "profileDescription";
- if (tag == icSigVideoCartGammaTableTag)
- return "videoCartGammaTable";
- if (tag == icSigMachineLookUpTableTag)
- return "massiveLookUpTable";
- if (tag == icSigDeviceMfgDescTag)
- return "deviceMfgDesc";
- if (tag == icSigDeviceModelDescTag)
- return "deviceModelDesc";
- if (tag == icSigViewingCondDescTag)
- return "viewingCondDesc";
- if (tag == icSigViewingConditionsTag)
- return "viewingConditions";
- if (tag == icSigLuminanceTag)
- return "luminance";
- if (tag == icSigMeasurementTag)
- return "measurement";
- if (tag == icSigRedColorantTag)
- return "redMatrixColumn";
- if (tag == icSigGreenColorantTag)
- return "greenMatrixColumn";
- if (tag == icSigBlueColorantTag)
- return "blueMatrixColumn";
- if (tag == icSigRedTRCTag)
- return "redTRC";
- if (tag == icSigGreenTRCTag)
- return "greenTRC";
- if (tag == icSigBlueTRCTag)
- return "blueTRC";
- if (tag == icSigMediaWhitePointTag)
- return "mediaWhitePoint";
- if (tag == icSigMediaBlackPointTag)
- return "mediaBlackPoint";
- if (tag == icSigTechnologyTag)
- return "technology";
- if (tag == icSigCopyrightTag)
- return "copyright";
- if (tag == icSigCalibrationDateTimeTag)
- return "calibrationDateTime";
- if (tag == icSigColorantTableTag)
- return "colorantTable";
- if (tag == icSigBToA0Tag)
- return "BToA0";
- if (tag == icSigBToA1Tag)
- return "BToA1";
- if (tag == icSigBToA2Tag)
- return "BToA2";
- if (tag == icSigAToB0Tag)
- return "AToB0";
- if (tag == icSigAToB1Tag)
- return "AToB1";
- if (tag == icSigAToB2Tag)
- return "AToB2";
- return NULL;
-}
-
-/**
- * gcm_parser_load_icc_mlut:
- **/
-static gboolean
-gcm_parser_load_icc_mlut (GcmProfile *profile, const guint8 *data, guint size)
-{
- gboolean ret = TRUE;
- guint i;
- GcmClutData *mlut_data;
-
- /* just load in data into a fixed size LUT */
- profile->priv->mlut_data = g_new0 (GcmClutData, 256);
- mlut_data = profile->priv->mlut_data;
-
- for (i=0; i<256; i++)
- mlut_data[i].red = gcm_parser_decode_16 (data + GCM_MLUT_RED + i*2);
- for (i=0; i<256; i++)
- mlut_data[i].green = gcm_parser_decode_16 (data + GCM_MLUT_GREEN + i*2);
- for (i=0; i<256; i++)
- mlut_data[i].blue = gcm_parser_decode_16 (data + GCM_MLUT_BLUE + i*2);
-
- /* save datatype */
- profile->priv->has_mlut = TRUE;
- return ret;
-}
-
-/**
- * gcm_parser_load_icc_vcgt_formula:
- **/
-static gboolean
-gcm_parser_load_icc_vcgt_formula (GcmProfile *profile, const guint8 *data, guint size)
-{
- gboolean ret = FALSE;
- GcmClutData *vcgt_data;
-
- egg_debug ("loading a formula encoded gamma table");
-
- /* just load in data into a temporary array */
- profile->priv->vcgt_data = g_new0 (GcmClutData, 4);
- vcgt_data = profile->priv->vcgt_data;
-
- /* read in block of data */
- vcgt_data[0].red = gcm_parser_decode_32 (data + GCM_VCGT_FORMULA_GAMMA_RED);
- vcgt_data[0].green = gcm_parser_decode_32 (data + GCM_VCGT_FORMULA_GAMMA_GREEN);
- vcgt_data[0].blue = gcm_parser_decode_32 (data + GCM_VCGT_FORMULA_GAMMA_BLUE);
-
- vcgt_data[1].red = gcm_parser_decode_32 (data + GCM_VCGT_FORMULA_MIN_RED);
- vcgt_data[1].green = gcm_parser_decode_32 (data + GCM_VCGT_FORMULA_MIN_GREEN);
- vcgt_data[1].blue = gcm_parser_decode_32 (data + GCM_VCGT_FORMULA_MIN_BLUE);
-
- vcgt_data[2].red = gcm_parser_decode_32 (data + GCM_VCGT_FORMULA_MAX_RED);
- vcgt_data[2].green = gcm_parser_decode_32 (data + GCM_VCGT_FORMULA_MAX_GREEN);
- vcgt_data[2].blue = gcm_parser_decode_32 (data + GCM_VCGT_FORMULA_MAX_BLUE);
-
- /* check if valid */
- if (vcgt_data[0].red / 65536.0 > 5.0 || vcgt_data[0].green / 65536.0 > 5.0 || vcgt_data[0].blue / 65536.0 > 5.0) {
- egg_warning ("Gamma values out of range: [R:%u G:%u B:%u]", vcgt_data[0].red, vcgt_data[0].green, vcgt_data[0].blue);
- goto out;
- }
- if (vcgt_data[1].red / 65536.0 >= 1.0 || vcgt_data[1].green / 65536.0 >= 1.0 || vcgt_data[1].blue / 65536.0 >= 1.0) {
- egg_warning ("Gamma min limit out of range: [R:%u G:%u B:%u]", vcgt_data[1].red, vcgt_data[1].green, vcgt_data[1].blue);
- goto out;
- }
- if (vcgt_data[2].red / 65536.0 > 1.0 || vcgt_data[2].green / 65536.0 > 1.0 || vcgt_data[2].blue / 65536.0 > 1.0) {
- egg_warning ("Gamma max limit out of range: [R:%u G:%u B:%u]", vcgt_data[2].red, vcgt_data[2].green, vcgt_data[2].blue);
- goto out;
- }
-
- /* save datatype */
- profile->priv->has_vcgt_formula = TRUE;
- profile->priv->vcgt_data_size = 3;
- ret = TRUE;
-out:
- return ret;
-}
-
-/**
- * gcm_parser_load_icc_vcgt_table:
- **/
-static gboolean
-gcm_parser_load_icc_vcgt_table (GcmProfile *profile, const guint8 *data, guint size)
-{
- gboolean ret = TRUE;
- guint num_channels = 0;
- guint num_entries = 0;
- guint entry_size = 0;
- guint i;
- GcmClutData *vcgt_data;
-
- egg_debug ("loading a table encoded gamma table");
-
- num_channels = gcm_parser_decode_16 (data + GCM_VCGT_TABLE_NUM_CHANNELS);
- num_entries = gcm_parser_decode_16 (data + GCM_VCGT_TABLE_NUM_ENTRIES);
- entry_size = gcm_parser_decode_16 (data + GCM_VCGT_TABLE_NUM_SIZE);
-
- /* work-around for AdobeGamma-Profiles (taken from xcalib) */
- if (profile->priv->adobe_gamma_workaround) {
- egg_debug ("Working around AdobeGamma profile");
- entry_size = 2;
- num_entries = 256;
- num_channels = 3;
- }
-
- egg_debug ("channels: %u", num_channels);
- egg_debug ("entry size: %ubits", entry_size * 8);
- egg_debug ("entries/channel: %u", num_entries);
-
- /* only able to parse RGB data */
- if (num_channels != 3) {
- egg_warning ("cannot parse non RGB entries");
- ret = FALSE;
- goto out;
- }
-
- /* bigger than will fit in 16 bits? */
- if (entry_size > 2) {
- egg_warning ("cannot parse large entries");
- ret = FALSE;
- goto out;
- }
-
- /* allocate ramp, plus one entry for extrapolation */
- profile->priv->vcgt_data = g_new0 (GcmClutData, num_entries + 1);
- vcgt_data = profile->priv->vcgt_data;
-
- if (entry_size == 1) {
- for (i=0; i<num_entries; i++)
- vcgt_data[i].red = gcm_parser_decode_8 (data + GCM_VCGT_TABLE_NUM_DATA + (num_entries * 0) + i);
- for (i=0; i<num_entries; i++)
- vcgt_data[i].green = gcm_parser_decode_8 (data + GCM_VCGT_TABLE_NUM_DATA + (num_entries * 1) + i);
- for (i=0; i<num_entries; i++)
- vcgt_data[i].blue = gcm_parser_decode_8 (data + GCM_VCGT_TABLE_NUM_DATA + (num_entries * 2) + i);
- } else {
- for (i=0; i<num_entries; i++)
- vcgt_data[i].red = gcm_parser_decode_16 (data + GCM_VCGT_TABLE_NUM_DATA + (num_entries * 0) + (i*2));
- for (i=0; i<num_entries; i++)
- vcgt_data[i].green = gcm_parser_decode_16 (data + GCM_VCGT_TABLE_NUM_DATA + (num_entries * 2) + (i*2));
- for (i=0; i<num_entries; i++)
- vcgt_data[i].blue = gcm_parser_decode_16 (data + GCM_VCGT_TABLE_NUM_DATA + (num_entries * 4) + (i*2));
- }
-
- /* save datatype */
- profile->priv->has_vcgt_table = TRUE;
- profile->priv->vcgt_data_size = num_entries;
-out:
- return ret;
-}
-
-/**
- * gcm_parser_load_icc_vcgt:
- **/
-static gboolean
-gcm_parser_load_icc_vcgt (GcmProfile *profile, const guint8 *data, guint size)
-{
- gboolean ret = FALSE;
- guint tag_id;
- guint gamma_type;
-
- /* check we have a VCGT block */
- tag_id = gcm_parser_decode_32 (data);
- if (tag_id != icSigVideoCartGammaTableTag) {
- egg_warning ("invalid content of table vcgt, starting with %x", tag_id);
- goto out;
- }
-
- /* check what type of gamma encoding we have */
- gamma_type = gcm_parser_decode_32 (data + GCM_VCGT_GAMMA_TYPE);
- if (gamma_type == 0) {
- ret = gcm_parser_load_icc_vcgt_table (profile, data + GCM_VCGT_GAMMA_DATA, size);
- goto out;
- }
- if (gamma_type == 1) {
- ret = gcm_parser_load_icc_vcgt_formula (profile, data + GCM_VCGT_GAMMA_DATA, size);
- goto out;
- }
-
- /* we didn't understand the encoding */
- egg_warning ("gamma type encoding not recognised");
-out:
- return ret;
-}
-
-/**
- * gcm_profile_ensure_printable:
- **/
-static void
-gcm_profile_ensure_printable (gchar *data)
-{
- guint i;
- guint idx = 0;
-
- g_return_if_fail (data != NULL);
-
- for (i=0; data[i] != '\0'; i++) {
- if (g_ascii_isalnum (data[i]) ||
- g_ascii_ispunct (data[i]) ||
- data[i] == ' ')
- data[idx++] = data[i];
- }
- data[idx] = '\0';
-
- /* broken profiles have _ instead of spaces */
- g_strdelimit (data, "_", ' ');
-}
-
-/**
- * gcm_profile_utf16be_to_locale:
- *
- * Convert ICC encoded UTF-16BE into a string the user can understand
- **/
-static gchar *
-gcm_profile_utf16be_to_locale (const guint8 *text, guint size)
-{
- gsize items_written;
- gchar *text_utf8 = NULL;
- gchar *text_locale = NULL;
- GError *error = NULL;
-
- /* convert from ICC text encoding to UTF-8 */
- text_utf8 = g_convert ((const gchar*)text, size, "UTF-8", "UTF-16BE", NULL, &items_written, &error);
- if (text_utf8 == NULL) {
- egg_warning ("failed to convert to UTF-8: %s", error->message);
- g_error_free (error);
- goto out;
- }
-
- /* convert from UTF-8 to the users locale*/
- text_locale = g_locale_from_utf8 (text_utf8, items_written, NULL, NULL, &error);
- if (text_locale == NULL) {
- egg_warning ("failed to convert to locale: %s", error->message);
- g_error_free (error);
- goto out;
- }
-out:
- g_free (text_utf8);
- return text_locale;
-}
-
-/**
- * gcm_profile_parse_multi_localized_unicode:
- **/
-static gchar *
-gcm_profile_parse_multi_localized_unicode (GcmProfile *profile, const guint8 *data, guint size)
-{
- guint i;
- gchar *text = NULL;
- guint record_size;
- guint names_size;
- guint len;
- guint offset_name;
- guint32 type;
-
- /* get type */
- type = gcm_parser_decode_32 (data);
-
- /* check we are not a localized tag */
- if (type == icSigTextDescriptionType) {
- record_size = gcm_parser_decode_32 (data + GCM_DESC_RECORD_SIZE);
- text = g_strndup ((const gchar*)&data[GCM_DESC_RECORD_TEXT], record_size);
- goto out;
- }
-
- /* check we are not a localized tag */
- if (type == icSigTextType) {
- text = g_strdup ((const gchar*)&data[GCM_TEXT_RECORD_TEXT]);
- goto out;
- }
-
- /* check we are not a localized tag */
- if (type == icSigMultiLocalizedUnicodeType) {
- names_size = gcm_parser_decode_32 (data + 8);
- if (names_size != 1) {
- /* there is more than one language encoded */
- egg_warning ("more than one item of data in MLUC (names size: %i), using first one", names_size);
- }
- record_size = gcm_parser_decode_32 (data + 12);
- len = gcm_parser_decode_32 (data + 20);
- offset_name = gcm_parser_decode_32 (data + 24);
- text = gcm_profile_utf16be_to_locale (data + offset_name, len);
- goto out;
- }
-
- /* an unrecognised tag */
- for (i=0x0; i<0x1c; i++) {
- egg_warning ("unrecognised text tag");
- if (data[i] >= 'A' && data[i] <= 'z')
- egg_debug ("%i\t%c (%i)", i, data[i], data[i]);
- else
- egg_debug ("%i\t (%i)", i, data[i]);
- }
-out:
- return text;
-}
-
-/**
- * gcm_profile_ensure_sane_length:
- **/
-static void
-gcm_profile_ensure_sane_length (gchar *text, guint max_length)
-{
- guint i;
- guint len;
-
- /* get length */
- len = strlen (text);
-
- /* check we have room for ellipsis */
- if (len <= max_length - 4)
- return;
-
- /* already correct len */
- if (len == max_length)
- return;
-
- /* truncate, finding prior word break */
- for (i=max_length-1; i>0; i--) {
- if (text[i] == ' ')
- break;
- }
-
- /* one long string with no spaces */
- if (i == 0)
- i = max_length - 3;
-
- /* ellipsis */
- text[i+0] = '.';
- text[i+1] = '.';
- text[i+2] = '.';
- text[i+3] = '\0';
-}
-
-/**
* gcm_profile_parse_data:
**/
gboolean
gcm_profile_parse_data (GcmProfile *profile, const guint8 *data, gsize length, GError **error)
{
gboolean ret = FALSE;
- guint num_tags;
- guint i;
- guint tag_id;
- guint offset;
- guint tag_size;
- guint tag_offset;
- icProfileClassSignature profile_class;
- icColorSpaceSignature color_space;
GcmProfilePrivate *priv = profile->priv;
- cmsCIEXYZ cie_xyz;
- cmsCIEXYZTRIPLE cie_illum;
- struct tm created;
- cmsHPROFILE xyz_profile;
- cmsHTRANSFORM transform;
-
- g_return_val_if_fail (GCM_IS_PROFILE (profile), FALSE);
- g_return_val_if_fail (data != NULL, FALSE);
- g_return_val_if_fail (priv->loaded == FALSE, FALSE);
-
- priv->loaded = TRUE;
-
- /* load profile into lcms */
- priv->lcms_profile = cmsOpenProfileFromMem ((LPVOID)data, length);
- if (priv->lcms_profile == NULL) {
- *error = g_error_new (1, 0, "failed to load: not an ICC profile");
- goto out;
- }
-
- /* get white point */
- ret = cmsTakeMediaWhitePoint (&cie_xyz, priv->lcms_profile);
- if (ret) {
- g_object_set (priv->white_point,
- "cie-x", cie_xyz.X,
- "cie-y", cie_xyz.Y,
- "cie-z", cie_xyz.Z,
- NULL);
- } else {
- gcm_xyz_clear (priv->white_point);
- egg_warning ("failed to get white point");
- }
-
- /* get black point */
- ret = cmsTakeMediaBlackPoint (&cie_xyz, priv->lcms_profile);
- if (ret) {
- g_object_set (priv->black_point,
- "cie-x", cie_xyz.X,
- "cie-y", cie_xyz.Y,
- "cie-z", cie_xyz.Z,
- NULL);
- } else {
- gcm_xyz_clear (priv->black_point);
- egg_warning ("failed to get black point");
- }
-
- /* get the profile type */
- profile_class = cmsGetDeviceClass (priv->lcms_profile);
- switch (profile_class) {
- case icSigInputClass:
- priv->profile_type = GCM_PROFILE_TYPE_INPUT_DEVICE;
- break;
- case icSigDisplayClass:
- priv->profile_type = GCM_PROFILE_TYPE_DISPLAY_DEVICE;
- break;
- case icSigOutputClass:
- priv->profile_type = GCM_PROFILE_TYPE_OUTPUT_DEVICE;
- break;
- case icSigLinkClass:
- priv->profile_type = GCM_PROFILE_TYPE_DEVICELINK;
- break;
- case icSigColorSpaceClass:
- priv->profile_type = GCM_PROFILE_TYPE_COLORSPACE_CONVERSION;
- break;
- case icSigAbstractClass:
- priv->profile_type = GCM_PROFILE_TYPE_ABSTRACT;
- break;
- case icSigNamedColorClass:
- priv->profile_type = GCM_PROFILE_TYPE_NAMED_COLOR;
- break;
- default:
- priv->profile_type = GCM_PROFILE_TYPE_UNKNOWN;
- }
-
- /* get colorspace */
- color_space = cmsGetColorSpace (priv->lcms_profile);
- switch (color_space) {
- case icSigXYZData:
- priv->colorspace = GCM_PROFILE_COLORSPACE_XYZ;
- break;
- case icSigLabData:
- priv->colorspace = GCM_PROFILE_COLORSPACE_LAB;
- break;
- case icSigLuvData:
- priv->colorspace = GCM_PROFILE_COLORSPACE_LUV;
- break;
- case icSigYCbCrData:
- priv->colorspace = GCM_PROFILE_COLORSPACE_YCBCR;
- break;
- case icSigYxyData:
- priv->colorspace = GCM_PROFILE_COLORSPACE_YXY;
- break;
- case icSigRgbData:
- priv->colorspace = GCM_PROFILE_COLORSPACE_RGB;
- break;
- case icSigGrayData:
- priv->colorspace = GCM_PROFILE_COLORSPACE_GRAY;
- break;
- case icSigHsvData:
- priv->colorspace = GCM_PROFILE_COLORSPACE_HSV;
- break;
- case icSigCmykData:
- priv->colorspace = GCM_PROFILE_COLORSPACE_CMYK;
- break;
- case icSigCmyData:
- priv->colorspace = GCM_PROFILE_COLORSPACE_CMY;
- break;
- default:
- priv->colorspace = GCM_PROFILE_COLORSPACE_UNKNOWN;
- }
-
- /* get primary illuminants */
- ret = cmsTakeColorants (&cie_illum, priv->lcms_profile);
-
- /* geting the illuminants failed, try running it through the profile */
- if (!ret && color_space == icSigRgbData) {
- gdouble rgb_values[3];
-
- /* create a transform from profile to XYZ */
- xyz_profile = cmsCreateXYZProfile ();
- transform = cmsCreateTransform (priv->lcms_profile, TYPE_RGB_DBL, xyz_profile, TYPE_XYZ_DBL, INTENT_PERCEPTUAL, 0);
- if (transform != NULL) {
-
- /* red */
- rgb_values[0] = 1.0;
- rgb_values[1] = 0.0;
- rgb_values[2] = 0.0;
- cmsDoTransform (transform, rgb_values, &cie_illum.Red, 1);
-
- /* green */
- rgb_values[0] = 0.0;
- rgb_values[1] = 1.0;
- rgb_values[2] = 0.0;
- cmsDoTransform (transform, rgb_values, &cie_illum.Green, 1);
-
- /* blue */
- rgb_values[0] = 0.0;
- rgb_values[1] = 0.0;
- rgb_values[2] = 1.0;
- cmsDoTransform (transform, rgb_values, &cie_illum.Blue, 1);
-
- /* we're done */
- cmsDeleteTransform (transform);
- ret = TRUE;
- }
-
- /* no more need for the output profile */
- cmsCloseProfile (xyz_profile);
- }
-
- /* we've got valid values */
- if (ret) {
- g_object_set (priv->luminance_red,
- "cie-x", cie_illum.Red.X,
- "cie-y", cie_illum.Red.Y,
- "cie-z", cie_illum.Red.Z,
- NULL);
- g_object_set (priv->luminance_green,
- "cie-x", cie_illum.Green.X,
- "cie-y", cie_illum.Green.Y,
- "cie-z", cie_illum.Green.Z,
- NULL);
- g_object_set (priv->luminance_blue,
- "cie-x", cie_illum.Blue.X,
- "cie-y", cie_illum.Blue.Y,
- "cie-z", cie_illum.Blue.Z,
- NULL);
- } else {
- gcm_xyz_clear (priv->luminance_red);
- gcm_xyz_clear (priv->luminance_green);
- gcm_xyz_clear (priv->luminance_blue);
- egg_debug ("failed to get luminance values");
- }
-
- /* get the profile created time and date */
- ret = cmsTakeCreationDateTime (&created, priv->lcms_profile);
- if (ret)
- priv->datetime = gcm_utils_format_date_time (&created);
-
- /* get the number of tags in the file */
- num_tags = gcm_parser_decode_32 (data + GCM_NUMTAGS);
- egg_debug ("number of tags: %i", num_tags);
-
- for (i=0; i<num_tags; i++) {
- const gchar *tag_description;
- offset = GCM_TAG_WIDTH * i;
- tag_id = gcm_parser_decode_32 (data + GCM_BODY + offset + GCM_TAG_ID);
- tag_offset = gcm_parser_decode_32 (data + GCM_BODY + offset + GCM_TAG_OFFSET);
- tag_size = gcm_parser_decode_32 (data + GCM_BODY + offset + GCM_TAG_SIZE);
-
- /* print description */
- tag_description = gcm_prefs_get_tag_description (tag_id);
- if (tag_description == NULL)
- egg_debug ("unknown tag %x is present at 0x%x with size %u", tag_id, tag_offset, tag_size);
- else
- egg_debug ("named tag %x [%s] is present at 0x%x with size %u", tag_id, tag_description, tag_offset, tag_size);
-
- if (tag_id == icSigProfileDescriptionTag) {
- priv->description = gcm_profile_parse_multi_localized_unicode (profile, data + tag_offset, tag_size);
- egg_debug ("found DESC: %s", priv->description);
- }
- if (tag_id == icSigCopyrightTag) {
- priv->copyright = gcm_profile_parse_multi_localized_unicode (profile, data + tag_offset, tag_size);
- egg_debug ("found COPYRIGHT: %s", priv->copyright);
- }
- if (tag_id == icSigDeviceMfgDescTag) {
- priv->manufacturer = gcm_profile_parse_multi_localized_unicode (profile, data + tag_offset, tag_size);
- egg_debug ("found MANUFACTURER: %s", priv->manufacturer);
- }
- if (tag_id == icSigDeviceModelDescTag) {
- priv->model = gcm_profile_parse_multi_localized_unicode (profile, data + tag_offset, tag_size);
- egg_debug ("found MODEL: %s", priv->model);
- }
- if (tag_id == icSigMachineLookUpTableTag) {
- egg_debug ("found MLUT which is a fixed size block");
- ret = gcm_parser_load_icc_mlut (profile, data + tag_offset, tag_size);
- if (!ret) {
- *error = g_error_new (1, 0, "failed to load mlut");
- goto out;
- }
- }
- if (tag_id == icSigVideoCartGammaTableTag) {
- egg_debug ("found VCGT");
- if (tag_size == 1584)
- priv->adobe_gamma_workaround = TRUE;
- ret = gcm_parser_load_icc_vcgt (profile, data + tag_offset, tag_size);
- if (!ret) {
- *error = g_error_new (1, 0, "failed to load vcgt");
- goto out;
- }
- }
- }
-
- /* there's nothing sensible to display */
- if (priv->description == NULL || priv->description[0] == '\0') {
- g_free (priv->description);
- if (priv->filename != NULL) {
- priv->description = g_path_get_basename (priv->filename);
- } else {
- /* TRANSLATORS: this is where the ICC profile has no description */
- priv->description = _("Missing description");
- }
- }
-
- /* Ensure this is displayable */
- if (priv->description != NULL)
- gcm_profile_ensure_printable (priv->description);
- if (priv->copyright != NULL)
- gcm_profile_ensure_printable (priv->copyright);
- if (priv->manufacturer != NULL)
- gcm_profile_ensure_printable (priv->manufacturer);
- if (priv->model != NULL)
- gcm_profile_ensure_printable (priv->model);
-
- /* some profiles have _really_ long titles - Microsoft, I'm looking at you... */
- if (priv->description != NULL)
- gcm_profile_ensure_sane_length (priv->description, 80);
+ GcmProfileClass *klass = GCM_PROFILE_GET_CLASS (profile);
/* save the length */
priv->size = length;
- /* success */
- ret = TRUE;
+ /* do we have support */
+ if (klass->parse_data == NULL) {
+ if (error != NULL)
+ *error = g_error_new (1, 0, "no support");
+ goto out;
+ }
- egg_debug ("Has MLUT: %s", priv->has_mlut ? "YES" : "NO");
- egg_debug ("Has VCGT formula: %s", priv->has_vcgt_formula ? "YES" : "NO");
- egg_debug ("Has VCGT table: %s", priv->has_vcgt_table ? "YES" : "NO");
+ /* proxy */
+ ret = klass->parse_data (profile, data, length, error);
out:
return ret;
}
@@ -863,7 +127,6 @@ gcm_profile_parse (GcmProfile *profile, const gchar *filename, GError **error)
g_return_val_if_fail (GCM_IS_PROFILE (profile), FALSE);
g_return_val_if_fail (filename != NULL, FALSE);
- g_return_val_if_fail (priv->loaded == FALSE, FALSE);
egg_debug ("loading '%s'", filename);
@@ -897,121 +160,16 @@ out:
GcmClut *
gcm_profile_generate_vcgt (GcmProfile *profile, guint size)
{
- guint i;
- guint ratio;
- GcmClutData *tmp;
- GcmClutData *vcgt_data;
- GcmClutData *mlut_data;
- gfloat gamma_red, min_red, max_red;
- gfloat gamma_green, min_green, max_green;
- gfloat gamma_blue, min_blue, max_blue;
- guint num_entries;
GcmClut *clut = NULL;
- GPtrArray *array = NULL;
- gfloat inverse_ratio;
- guint idx;
- gfloat frac;
-
- g_return_val_if_fail (GCM_IS_PROFILE (profile), NULL);
- g_return_val_if_fail (size != 0, FALSE);
-
- /* reduce dereferences */
- vcgt_data = profile->priv->vcgt_data;
- mlut_data = profile->priv->mlut_data;
-
- if (profile->priv->has_vcgt_table) {
-
- /* create array */
- array = g_ptr_array_new_with_free_func (g_free);
-
- /* simply subsample if the LUT is smaller than the number of entries in the file */
- num_entries = profile->priv->vcgt_data_size;
- if (num_entries >= size) {
- ratio = (guint) (num_entries / size);
- for (i=0; i<size; i++) {
- /* add a point */
- tmp = g_new0 (GcmClutData, 1);
- tmp->red = vcgt_data[ratio*i].red;
- tmp->green = vcgt_data[ratio*i].green;
- tmp->blue = vcgt_data[ratio*i].blue;
- g_ptr_array_add (array, tmp);
- }
- goto out;
- }
+ GcmProfileClass *klass = GCM_PROFILE_GET_CLASS (profile);
- /* LUT is bigger than number of entries, so interpolate */
- inverse_ratio = (gfloat) num_entries / size;
- vcgt_data[num_entries].red = 0xffff;
- vcgt_data[num_entries].green = 0xffff;
- vcgt_data[num_entries].blue = 0xffff;
-
- /* interpolate */
- for (i=0; i<size; i++) {
- idx = floor(i*inverse_ratio);
- frac = (i*inverse_ratio) - idx;
- tmp = g_new0 (GcmClutData, 1);
- tmp->red = vcgt_data[idx].red * (1.0f-frac) + vcgt_data[idx + 1].red * frac;
- tmp->green = vcgt_data[idx].green * (1.0f-frac) + vcgt_data[idx + 1].green * frac;
- tmp->blue = vcgt_data[idx].blue * (1.0f-frac) + vcgt_data[idx + 1].blue * frac;
- g_ptr_array_add (array, tmp);
- }
- goto out;
- }
-
- if (profile->priv->has_vcgt_formula) {
-
- /* create array */
- array = g_ptr_array_new_with_free_func (g_free);
-
- gamma_red = (gfloat) vcgt_data[0].red / 65536.0;
- gamma_green = (gfloat) vcgt_data[0].green / 65536.0;
- gamma_blue = (gfloat) vcgt_data[0].blue / 65536.0;
- min_red = (gfloat) vcgt_data[1].red / 65536.0;
- min_green = (gfloat) vcgt_data[1].green / 65536.0;
- min_blue = (gfloat) vcgt_data[1].blue / 65536.0;
- max_red = (gfloat) vcgt_data[2].red / 65536.0;
- max_green = (gfloat) vcgt_data[2].green / 65536.0;
- max_blue = (gfloat) vcgt_data[2].blue / 65536.0;
-
- /* create mapping of desired size */
- for (i=0; i<size; i++) {
- /* add a point */
- tmp = g_new0 (GcmClutData, 1);
- tmp->red = 65536.0 * ((gdouble) pow ((gdouble) i / (gdouble) size, gamma_red) * (max_red - min_red) + min_red);
- tmp->green = 65536.0 * ((gdouble) pow ((gdouble) i / (gdouble) size, gamma_green) * (max_green - min_green) + min_green);
- tmp->blue = 65536.0 * ((gdouble) pow ((gdouble) i / (gdouble) size, gamma_blue) * (max_blue - min_blue) + min_blue);
- g_ptr_array_add (array, tmp);
- }
- goto out;
- }
-
- if (profile->priv->has_mlut) {
-
- /* create array */
- array = g_ptr_array_new_with_free_func (g_free);
-
- /* roughly interpolate table */
- ratio = (guint) (256 / (size));
- for (i=0; i<size; i++) {
- /* add a point */
- tmp = g_new0 (GcmClutData, 1);
- tmp->red = mlut_data[ratio*i].red;
- tmp->green = mlut_data[ratio*i].green;
- tmp->blue = mlut_data[ratio*i].blue;
- g_ptr_array_add (array, tmp);
- }
+ /* do we have support */
+ if (klass->generate_vcgt == NULL)
goto out;
- }
- /* bugger */
- egg_debug ("no LUT to generate");
+ /* proxy */
+ clut = klass->generate_vcgt (profile, size);
out:
- if (array != NULL) {
- /* create new output array */
- clut = gcm_clut_new ();
- gcm_clut_set_source_array (clut, array);
- g_ptr_array_unref (array);
- }
return clut;
}
@@ -1024,87 +182,15 @@ GcmClut *
gcm_profile_generate_curve (GcmProfile *profile, guint size)
{
GcmClut *clut = NULL;
- gdouble *values_in = NULL;
- gdouble *values_out = NULL;
- guint i;
- GcmClutData *data;
- GPtrArray *array = NULL;
- gfloat divamount;
- gfloat divadd;
- guint component_width;
- cmsHPROFILE srgb_profile = NULL;
- cmsHTRANSFORM transform = NULL;
- GcmProfilePrivate *priv = profile->priv;
- guint type;
-
- /* run through the profile */
- if (priv->colorspace == GCM_PROFILE_COLORSPACE_RGB) {
-
- /* RGB */
- component_width = 3;
- type = TYPE_RGB_DBL;
-
- /* create input array */
- values_in = g_new0 (gdouble, size * 3 * component_width);
- divamount = 1.0f / (gfloat) (size - 1);
- for (i=0; i<size; i++) {
- divadd = divamount * (gfloat) i;
-
- /* red component */
- values_in[(i * 3 * component_width)+0] = divadd;
- values_in[(i * 3 * component_width)+1] = 0.0f;
- values_in[(i * 3 * component_width)+2] = 0.0f;
-
- /* green component */
- values_in[(i * 3 * component_width)+3] = 0.0f;
- values_in[(i * 3 * component_width)+4] = divadd;
- values_in[(i * 3 * component_width)+5] = 0.0f;
-
- /* blue component */
- values_in[(i * 3 * component_width)+6] = 0.0f;
- values_in[(i * 3 * component_width)+7] = 0.0f;
- values_in[(i * 3 * component_width)+8] = divadd;
- }
- }
-
- /* do each transform */
- if (values_in != NULL) {
- /* create output array */
- values_out = g_new0 (gdouble, size * 3 * component_width);
-
- /* create a transform from profile to sRGB */
- srgb_profile = cmsCreate_sRGBProfile ();
- transform = cmsCreateTransform (priv->lcms_profile, type, srgb_profile, TYPE_RGB_DBL, INTENT_PERCEPTUAL, 0);
- if (transform == NULL)
- goto out;
-
- /* do transform */
- cmsDoTransform (transform, values_in, values_out, size * 3);
+ GcmProfileClass *klass = GCM_PROFILE_GET_CLASS (profile);
- /* create output array */
- array = g_ptr_array_new_with_free_func (g_free);
-
- for (i=0; i<size; i++) {
- data = g_new0 (GcmClutData, 1);
-
- data->red = values_out[(i * 3 * component_width)+0] * (gfloat) 0xffff;
- data->green = values_out[(i * 3 * component_width)+4] * (gfloat) 0xffff;
- data->blue = values_out[(i * 3 * component_width)+8] * (gfloat) 0xffff;
- g_ptr_array_add (array, data);
- }
- clut = gcm_clut_new ();
- gcm_clut_set_source_array (clut, array);
- }
+ /* do we have support */
+ if (klass->generate_curve == NULL)
+ goto out;
+ /* proxy */
+ clut = klass->generate_curve (profile, size);
out:
- g_free (values_in);
- g_free (values_out);
- if (array != NULL)
- g_ptr_array_unref (array);
- if (transform != NULL)
- cmsDeleteTransform (transform);
- if (srgb_profile != NULL)
- cmsCloseProfile (srgb_profile);
return clut;
}
@@ -1161,16 +247,6 @@ gcm_profile_colorspace_to_text (GcmProfileColorspace type)
}
/**
- * gcm_profile_lcms_error_cb:
- **/
-static int
-gcm_profile_lcms_error_cb (int ErrorCode, const char *ErrorText)
-{
- egg_warning ("LCMS error %i: %s", ErrorCode, ErrorText);
- return LCMS_ERRC_WARNING;
-}
-
-/**
* gcm_profile_get_property:
**/
static void
@@ -1210,6 +286,9 @@ gcm_profile_get_property (GObject *object, guint prop_id, GValue *value, GParamS
case PROP_WHITE_POINT:
g_value_set_object (value, priv->white_point);
break;
+ case PROP_BLACK_POINT:
+ g_value_set_object (value, priv->black_point);
+ break;
case PROP_LUMINANCE_RED:
g_value_set_object (value, priv->luminance_red);
break;
@@ -1231,7 +310,81 @@ gcm_profile_get_property (GObject *object, guint prop_id, GValue *value, GParamS
static void
gcm_profile_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
+ GcmProfile *profile = GCM_PROFILE (object);
+ GcmProfilePrivate *priv = profile->priv;
+
switch (prop_id) {
+ case PROP_COPYRIGHT:
+ g_free (priv->copyright);
+ priv->copyright = g_strdup (g_value_get_string (value));
+ if (priv->copyright != NULL)
+ gcm_utils_ensure_printable (priv->copyright);
+ break;
+ case PROP_MANUFACTURER:
+ g_free (priv->manufacturer);
+ priv->manufacturer = g_strdup (g_value_get_string (value));
+ if (priv->manufacturer != NULL)
+ gcm_utils_ensure_printable (priv->manufacturer);
+ break;
+ case PROP_MODEL:
+ g_free (priv->model);
+ priv->model = g_strdup (g_value_get_string (value));
+ if (priv->model != NULL)
+ gcm_utils_ensure_printable (priv->model);
+ break;
+ case PROP_DATETIME:
+ g_free (priv->datetime);
+ priv->datetime = g_strdup (g_value_get_string (value));
+ break;
+ case PROP_DESCRIPTION:
+ g_free (priv->description);
+ priv->description = g_strdup (g_value_get_string (value));
+ if (priv->description != NULL)
+ gcm_utils_ensure_printable (priv->description);
+
+ /* some profile_lcms1s have _really_ long titles - Microsoft, I'm looking at you... */
+ if (priv->description != NULL)
+ gcm_utils_ensure_sane_length (priv->description, 80);
+
+ /* there's nothing sensible to display */
+ if (priv->description == NULL || priv->description[0] == '\0') {
+ g_free (priv->description);
+ if (priv->filename != NULL) {
+ priv->description = g_path_get_basename (priv->filename);
+ } else {
+ /* TRANSLATORS: this is where the ICC profile_lcms1 has no description */
+ priv->description = _("Missing description");
+ }
+ }
+ break;
+ case PROP_FILENAME:
+ g_free (priv->filename);
+ priv->filename = g_strdup (g_value_get_string (value));
+ break;
+ case PROP_TYPE:
+ priv->profile_type = g_value_get_uint (value);
+ break;
+ case PROP_COLORSPACE:
+ priv->colorspace = g_value_get_uint (value);
+ break;
+ case PROP_SIZE:
+ priv->size = g_value_get_uint (value);
+ break;
+ case PROP_WHITE_POINT:
+ priv->white_point = g_value_dup_object (value);
+ break;
+ case PROP_BLACK_POINT:
+ priv->black_point = g_value_dup_object (value);
+ break;
+ case PROP_LUMINANCE_RED:
+ priv->luminance_red = g_value_dup_object (value);
+ break;
+ case PROP_LUMINANCE_GREEN:
+ priv->luminance_green = g_value_dup_object (value);
+ break;
+ case PROP_LUMINANCE_BLUE:
+ priv->luminance_blue = g_value_dup_object (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1255,7 +408,7 @@ gcm_profile_class_init (GcmProfileClass *klass)
*/
pspec = g_param_spec_string ("copyright", NULL, NULL,
NULL,
- G_PARAM_READABLE);
+ G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_COPYRIGHT, pspec);
/**
@@ -1263,7 +416,7 @@ gcm_profile_class_init (GcmProfileClass *klass)
*/
pspec = g_param_spec_string ("manufacturer", NULL, NULL,
NULL,
- G_PARAM_READABLE);
+ G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_MANUFACTURER, pspec);
/**
@@ -1271,7 +424,7 @@ gcm_profile_class_init (GcmProfileClass *klass)
*/
pspec = g_param_spec_string ("model", NULL, NULL,
NULL,
- G_PARAM_READABLE);
+ G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_MODEL, pspec);
/**
@@ -1279,7 +432,7 @@ gcm_profile_class_init (GcmProfileClass *klass)
*/
pspec = g_param_spec_string ("datetime", NULL, NULL,
NULL,
- G_PARAM_READABLE);
+ G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_DATETIME, pspec);
/**
@@ -1287,7 +440,7 @@ gcm_profile_class_init (GcmProfileClass *klass)
*/
pspec = g_param_spec_string ("description", NULL, NULL,
NULL,
- G_PARAM_READABLE);
+ G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_DESCRIPTION, pspec);
/**
@@ -1295,7 +448,7 @@ gcm_profile_class_init (GcmProfileClass *klass)
*/
pspec = g_param_spec_string ("filename", NULL, NULL,
NULL,
- G_PARAM_READABLE);
+ G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_FILENAME, pspec);
/**
@@ -1303,7 +456,7 @@ gcm_profile_class_init (GcmProfileClass *klass)
*/
pspec = g_param_spec_uint ("type", NULL, NULL,
0, G_MAXUINT, 0,
- G_PARAM_READABLE);
+ G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_TYPE, pspec);
/**
@@ -1311,7 +464,7 @@ gcm_profile_class_init (GcmProfileClass *klass)
*/
pspec = g_param_spec_uint ("colorspace", NULL, NULL,
0, G_MAXUINT, 0,
- G_PARAM_READABLE);
+ G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_COLORSPACE, pspec);
/**
@@ -1319,7 +472,7 @@ gcm_profile_class_init (GcmProfileClass *klass)
*/
pspec = g_param_spec_uint ("size", NULL, NULL,
0, G_MAXUINT, 0,
- G_PARAM_READABLE);
+ G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_SIZE, pspec);
/**
@@ -1327,15 +480,23 @@ gcm_profile_class_init (GcmProfileClass *klass)
*/
pspec = g_param_spec_object ("white-point", NULL, NULL,
GCM_TYPE_XYZ,
- G_PARAM_READABLE);
+ G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_WHITE_POINT, pspec);
/**
+ * GcmProfile:black-point:
+ */
+ pspec = g_param_spec_object ("black-point", NULL, NULL,
+ GCM_TYPE_XYZ,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (object_class, PROP_BLACK_POINT, pspec);
+
+ /**
* GcmProfile:luminance-red:
*/
pspec = g_param_spec_object ("luminance-red", NULL, NULL,
GCM_TYPE_XYZ,
- G_PARAM_READABLE);
+ G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_LUMINANCE_RED, pspec);
/**
@@ -1343,7 +504,7 @@ gcm_profile_class_init (GcmProfileClass *klass)
*/
pspec = g_param_spec_object ("luminance-green", NULL, NULL,
GCM_TYPE_XYZ,
- G_PARAM_READABLE);
+ G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_LUMINANCE_GREEN, pspec);
/**
@@ -1351,7 +512,7 @@ gcm_profile_class_init (GcmProfileClass *klass)
*/
pspec = g_param_spec_object ("luminance-blue", NULL, NULL,
GCM_TYPE_XYZ,
- G_PARAM_READABLE);
+ G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_LUMINANCE_BLUE, pspec);
g_type_class_add_private (klass, sizeof (GcmProfilePrivate));
@@ -1364,9 +525,6 @@ static void
gcm_profile_init (GcmProfile *profile)
{
profile->priv = GCM_PROFILE_GET_PRIVATE (profile);
- profile->priv->vcgt_data = NULL;
- profile->priv->mlut_data = NULL;
- profile->priv->adobe_gamma_workaround = FALSE;
profile->priv->profile_type = GCM_PROFILE_TYPE_UNKNOWN;
profile->priv->colorspace = GCM_PROFILE_COLORSPACE_UNKNOWN;
profile->priv->white_point = gcm_xyz_new ();
@@ -1374,11 +532,6 @@ gcm_profile_init (GcmProfile *profile)
profile->priv->luminance_red = gcm_xyz_new ();
profile->priv->luminance_green = gcm_xyz_new ();
profile->priv->luminance_blue = gcm_xyz_new ();
-
- /* setup LCMS */
- cmsSetErrorHandler (gcm_profile_lcms_error_cb);
- cmsErrorAction (LCMS_ERROR_SHOW);
- cmsSetLanguage ("en", "US");
}
/**
@@ -1390,17 +543,12 @@ gcm_profile_finalize (GObject *object)
GcmProfile *profile = GCM_PROFILE (object);
GcmProfilePrivate *priv = profile->priv;
- if (priv->lcms_profile != NULL)
- cmsCloseProfile (priv->lcms_profile);
-
g_free (priv->copyright);
g_free (priv->description);
g_free (priv->filename);
g_free (priv->manufacturer);
g_free (priv->model);
g_free (priv->datetime);
- g_free (priv->vcgt_data);
- g_free (priv->mlut_data);
g_object_unref (priv->white_point);
g_object_unref (priv->black_point);
g_object_unref (priv->luminance_red);
@@ -1423,10 +571,26 @@ gcm_profile_new (void)
return GCM_PROFILE (profile);
}
+/**
+ * gcm_profile_default_new:
+ *
+ * Return value: a new GcmProfile object.
+ **/
+GcmProfile *
+gcm_profile_default_new (void)
+{
+ GcmProfile *profile = NULL;
+#if 1
+ profile = GCM_PROFILE (gcm_profile_lcms1_new ());
+#endif
+ return profile;
+}
+
/***************************************************************************
*** MAKE CHECK TESTS ***
***************************************************************************/
#ifdef EGG_TEST
+#include <math.h>
#include "egg-test.h"
typedef struct {
@@ -1459,14 +623,14 @@ gcm_profile_test_parse_file (EggTest *test, const guint8 *datafile, GcmProfileTe
gfloat gamma;
gboolean ret;
GError *error = NULL;
- GcmProfile *profile;
+ GcmProfile *profile_lcms1;
GcmXyz *xyz;
gfloat luminance;
/************************************************************/
- egg_test_title (test, "get a profile object");
- profile = gcm_profile_new ();
- egg_test_assert (test, profile != NULL);
+ egg_test_title (test, "get a profile_lcms1 object");
+ profile_lcms1 = GCM_PROFILE(gcm_profile_lcms1_new ());
+ egg_test_assert (test, profile_lcms1 != NULL);
/************************************************************/
egg_test_title (test, "get filename of data file");
@@ -1475,14 +639,14 @@ gcm_profile_test_parse_file (EggTest *test, const guint8 *datafile, GcmProfileTe
/************************************************************/
egg_test_title (test, "load ICC file");
- ret = gcm_profile_parse (profile, filename, &error);
+ ret = gcm_profile_parse (profile_lcms1, filename, &error);
if (ret)
egg_test_success (test, NULL);
else
egg_test_failed (test, "failed to parse: %s", error->message);
/* get some properties */
- g_object_get (profile,
+ g_object_get (profile_lcms1,
"copyright", ©right,
"manufacturer", &manufacturer,
"model", &model,
@@ -1551,7 +715,7 @@ gcm_profile_test_parse_file (EggTest *test, const guint8 *datafile, GcmProfileTe
/************************************************************/
egg_test_title (test, "check luminance red %s", datafile);
- g_object_get (profile,
+ g_object_get (profile_lcms1,
"luminance-red", &xyz,
NULL);
luminance = gcm_xyz_get_x (xyz);
@@ -1561,7 +725,7 @@ gcm_profile_test_parse_file (EggTest *test, const guint8 *datafile, GcmProfileTe
egg_test_failed (test, "invalid value: %f, expecting: %f", luminance, test_data->luminance);
g_object_unref (xyz);
- g_object_unref (profile);
+ g_object_unref (profile_lcms1);
g_free (copyright);
g_free (manufacturer);
g_free (model);
@@ -1576,75 +740,10 @@ void
gcm_profile_test (EggTest *test)
{
GcmProfileTestData test_data;
- gfloat fp;
- gfloat expected;
- gboolean ret;
- const gchar temp[5] = {0x6d, 0x42, 0x41, 0x20, 0x00};
- gchar *text;
if (!egg_test_start (test, "GcmProfile"))
return;
- /************************************************************/
- egg_test_title (test, "check strip printable");
- text = g_strdup ("1\r34 67_90");
- gcm_profile_ensure_printable (text);
- if (g_strcmp0 (text, "134 67 90") == 0)
- egg_test_success (test, NULL);
- else
- egg_test_failed (test, "invalid value: %s", text);
- g_free (text);
-
- /************************************************************/
- egg_test_title (test, "check sane length high");
- text = g_strdup ("1234 67890");
- gcm_profile_ensure_sane_length (text, 1024);
- if (g_strcmp0 (text, "1234 67890") == 0)
- egg_test_success (test, NULL);
- else
- egg_test_failed (test, "invalid value: %s", text);
- g_free (text);
-
- /************************************************************/
- egg_test_title (test, "check sane length limit");
- text = g_strdup ("1234 67890");
- gcm_profile_ensure_sane_length (text, 10);
- if (g_strcmp0 (text, "1234 67890") == 0)
- egg_test_success (test, NULL);
- else
- egg_test_failed (test, "invalid value: %s", text);
- g_free (text);
-
- /************************************************************/
- egg_test_title (test, "check sane length truncate");
- text = g_strdup ("1234 67890");
- gcm_profile_ensure_sane_length (text, 8);
- if (g_strcmp0 (text, "1234...") == 0)
- egg_test_success (test, NULL);
- else
- egg_test_failed (test, "invalid value: %s", text);
- g_free (text);
-
- /************************************************************/
- egg_test_title (test, "check sane length no spaces");
- text = g_strdup ("1234 67890");
- gcm_profile_ensure_sane_length (text, 4);
- if (g_strcmp0 (text, "1...") == 0)
- egg_test_success (test, NULL);
- else
- egg_test_failed (test, "invalid value: %s", text);
- g_free (text);
-
- /************************************************************/
- egg_test_title (test, "check sane length no data");
- text = g_strdup ("");
- gcm_profile_ensure_sane_length (text, 4);
- if (g_strcmp0 (text, "") == 0)
- egg_test_success (test, NULL);
- else
- egg_test_failed (test, "invalid value: %s", text);
- g_free (text);
-
/* bluish test */
test_data.copyright = "Copyright (c) 1998 Hewlett-Packard Company";
test_data.manufacturer = "IEC http://www.iec.ch";
diff --git a/src/gcm-profile.h b/src/gcm-profile.h
index 3c17b5f..2e1716e 100644
--- a/src/gcm-profile.h
+++ b/src/gcm-profile.h
@@ -46,7 +46,16 @@ struct _GcmProfile
struct _GcmProfileClass
{
- GObjectClass parent_class;
+ GObjectClass parent_class;
+ gboolean (*parse_data) (GcmProfile *profile,
+ const guint8 *data,
+ gsize length,
+ GError **error);
+ GcmClut *(*generate_vcgt) (GcmProfile *profile,
+ guint size);
+ GcmClut *(*generate_curve) (GcmProfile *profile,
+ guint size);
+
/* padding for future expansion */
void (*_gcm_reserved1) (void);
void (*_gcm_reserved2) (void);
@@ -82,6 +91,7 @@ typedef enum {
GType gcm_profile_get_type (void);
GcmProfile *gcm_profile_new (void);
+GcmProfile *gcm_profile_default_new (void);
gboolean gcm_profile_parse (GcmProfile *profile,
const gchar *filename,
GError **error);
diff --git a/src/gcm-trc-widget.c b/src/gcm-trc-widget.c
index 02a7c2e..66d54e0 100644
--- a/src/gcm-trc-widget.c
+++ b/src/gcm-trc-widget.c
@@ -432,7 +432,7 @@ gcm_trc_widget_test (EggTest *test)
filename_profile = egg_test_get_data_file ("AdobeGammaTest.icm");
egg_test_assert (test, (filename_profile != NULL));
- profile = gcm_profile_new ();
+ profile = gcm_profile_default_new ();
gcm_profile_parse (profile, filename_profile, NULL);
clut = gcm_profile_generate_vcgt (profile, 256);
g_object_set (widget,
diff --git a/src/gcm-utils.c b/src/gcm-utils.c
index de20a73..e03d699 100644
--- a/src/gcm-utils.c
+++ b/src/gcm-utils.c
@@ -404,7 +404,7 @@ gcm_utils_set_gamma_for_device (GcmDevice *device, GError **error)
use_global = gconf_client_get_bool (gconf_client, GCM_SETTINGS_GLOBAL_DISPLAY_CORRECTION, NULL);
if (use_global && filename != NULL) {
/* create dummy CLUT */
- profile = gcm_profile_new ();
+ profile = gcm_profile_default_new ();
ret = gcm_profile_parse (profile, filename, error);
if (!ret)
goto out;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]