[gthumb] use colord to get the monitor color profile
- From: Paolo Bacchilega <paobac src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gthumb] use colord to get the monitor color profile
- Date: Wed, 28 Jun 2017 09:51:12 +0000 (UTC)
commit 6693627d8eb83e1715c4c41c144326d5b4a45632
Author: Paolo Bacchilega <paobac src gnome org>
Date: Sun Jun 25 19:30:19 2017 +0200
use colord to get the monitor color profile
this makes color profiles work on wayland as well.
configure.ac | 22 +
extensions/cairo_io/cairo-image-surface-jpeg.c | 7 +-
extensions/image_viewer/gth-image-viewer-page.c | 102 +++++-
extensions/slideshow/actions.c | 2 +-
gthumb/Makefile.am | 6 +
gthumb/gth-browser.c | 57 ++--
gthumb/gth-browser.h | 2 +-
gthumb/gth-color-manager.c | 500 +++++++++++++++++++++++
gthumb/gth-color-manager.h | 79 ++++
gthumb/gth-icc-profile.c | 179 ++++++++
gthumb/gth-icc-profile.h | 65 +++
gthumb/gth-image-loader.c | 11 +-
gthumb/gth-image-loader.h | 2 +-
gthumb/gth-image-preloader.c | 8 +-
gthumb/gth-image-preloader.h | 2 +-
gthumb/gth-image.c | 152 ++------
gthumb/gth-image.h | 13 +-
gthumb/gth-main.c | 12 +
gthumb/gth-main.h | 2 +
gthumb/gtk-utils.c | 19 +-
gthumb/gtk-utils.h | 3 +-
21 files changed, 1062 insertions(+), 183 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 06f0fcc..6807385 100644
--- a/configure.ac
+++ b/configure.ac
@@ -71,6 +71,7 @@ LIBWEBP_REQUIRED=0.2.0
JSON_GLIB_REQUIRED=0.15.0
WEBKIT2_REQUIRED=1.10.0
LCMS2_REQUIRED=2.6
+COLORD_REQUIRED=1.3
dnl ===========================================================================
@@ -290,6 +291,26 @@ AM_CONDITIONAL(ENABLE_LCMS2, test "x$enable_lcms2" = xyes)
dnl ===========================================================================
+AC_ARG_ENABLE([colord],
+ [AS_HELP_STRING([--disable-colord],[do not compile code that uses the colord library])],,
+ [enable_colord=yes])
+
+if test x$enable_colord = xyes ; then
+ PKG_CHECK_MODULES(COLORD,
+ colord >= $COLORD_REQUIRED,
+ [enable_colord=yes],
+ [enable_colord=no])
+fi
+if test x$enable_colord = xyes ; then
+ AC_DEFINE(HAVE_COLORD, 1, [Define to 1 if colord support is included])
+fi
+
+AC_SUBST(COLORD_LIBS)
+AC_SUBST(COLORD_CFLAGS)
+AM_CONDITIONAL(ENABLE_COLORD, test "x$enable_colord" = xyes)
+
+dnl ===========================================================================
+
IT_PROG_INTLTOOL([0.50.1])
GETTEXT_PACKAGE=gthumb
AC_SUBST([GETTEXT_PACKAGE])
@@ -808,4 +829,5 @@ Configuration:
SVG support : ${enable_librsvg}
WebP support : ${enable_libwebp}
LCMS2 support : ${enable_lcms2}
+ colord support : ${enable_colord}
"
diff --git a/extensions/cairo_io/cairo-image-surface-jpeg.c b/extensions/cairo_io/cairo-image-surface-jpeg.c
index 6ea9ef8..d54ff89 100644
--- a/extensions/cairo_io/cairo-image-surface-jpeg.c
+++ b/extensions/cairo_io/cairo-image-surface-jpeg.c
@@ -208,8 +208,11 @@ _cairo_image_surface_create_from_jpeg (GInputStream *istream,
else
orientation = GTH_TRANSFORM_NONE;
#if HAVE_LCMS2
- if (jpeg_info.valid & _JPEG_INFO_ICC_PROFILE)
- gth_image_set_icc_profile (image, cmsOpenProfileFromMem (jpeg_info.icc_data,
jpeg_info.icc_data_size));
+ if (jpeg_info.valid & _JPEG_INFO_ICC_PROFILE) {
+ GthICCData *profile = gth_icc_data_new (NULL, cmsOpenProfileFromMem (jpeg_info.icc_data,
jpeg_info.icc_data_size));
+ gth_image_set_icc_profile (image, profile);
+ g_object_unref (profile);
+ }
#endif
_jpeg_info_data_dispose (&jpeg_info);
diff --git a/extensions/image_viewer/gth-image-viewer-page.c b/extensions/image_viewer/gth-image-viewer-page.c
index 1ec6a6b..83ec2e9 100644
--- a/extensions/image_viewer/gth-image-viewer-page.c
+++ b/extensions/image_viewer/gth-image-viewer-page.c
@@ -203,20 +203,39 @@ _gth_image_preloader_get_requested_size_for_current_image (GthImageViewerPage *s
}
+/* -- _gth_image_viewer_page_load_with_preloader -- */
+
+
+typedef struct {
+ GthImageViewerPage *self;
+ GthFileData *file_data;
+ int requested_size;
+ GCancellable *cancellable;
+ GAsyncReadyCallback callback;
+ gpointer user_data;
+} ProfileData;
+
+
static void
-_gth_image_viewer_page_load_with_preloader (GthImageViewerPage *self,
- GthFileData *file_data,
- int requested_size,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+profile_data_free (ProfileData *profile_data)
{
- if (self->priv->apply_icc_profile)
- gth_image_preloader_set_out_profile (self->priv->preloader, gth_browser_get_screen_profile
(self->priv->browser));
- else
- gth_image_preloader_set_out_profile (self->priv->preloader, NULL);
+ _g_object_unref (profile_data->cancellable);
+ _g_object_unref (profile_data->file_data);
+ _g_object_unref (profile_data->self);
+ g_free (profile_data);
+}
+
+static void
+_gth_image_viewer_page_load_with_preloader_step2 (GthImageViewerPage *self,
+ GthFileData *file_data,
+ int requested_size,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
g_object_ref (self);
+
gth_image_preloader_load (self->priv->preloader,
file_data,
requested_size,
@@ -231,6 +250,69 @@ _gth_image_viewer_page_load_with_preloader (GthImageViewerPage *self,
}
+static void
+profile_ready_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ ProfileData *profile_data = user_data;
+ GthImageViewerPage *self = profile_data->self;
+ GthICCData *profile;
+
+ profile = gth_color_manager_get_profile_finish (GTH_COLOR_MANAGER (source_object), res, NULL);
+ if (profile == NULL)
+ profile = gth_browser_get_monitor_profile (self->priv->browser);
+ gth_image_preloader_set_out_profile (self->priv->preloader, profile);
+
+ _gth_image_viewer_page_load_with_preloader_step2 (profile_data->self,
+ profile_data->file_data,
+ profile_data->requested_size,
+ profile_data->cancellable,
+ profile_data->callback,
+ profile_data->user_data);
+
+ _g_object_unref (profile);
+ profile_data_free (profile_data);
+}
+
+
+static void
+_gth_image_viewer_page_load_with_preloader (GthImageViewerPage *self,
+ GthFileData *file_data,
+ int requested_size,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ if (self->priv->apply_icc_profile) {
+ char *monitor_name = NULL;
+
+ if (_gtk_window_get_monitor_info (GTK_WINDOW (self->priv->browser), NULL, NULL,
&monitor_name)) {
+ ProfileData *profile_data;
+
+ profile_data = g_new (ProfileData, 1);
+ profile_data->self = g_object_ref (self);
+ profile_data->file_data = g_object_ref (file_data);
+ profile_data->requested_size = requested_size;
+ profile_data->cancellable = _g_object_ref (cancellable);
+ profile_data->callback = callback;
+ profile_data->user_data = user_data;
+
+ gth_color_manager_get_profile_async (gth_main_get_default_color_manager(),
+ monitor_name,
+ cancellable,
+ profile_ready_cb,
+ profile_data);
+
+ return;
+ }
+ }
+
+ gth_image_preloader_set_out_profile (self->priv->preloader, NULL);
+ _gth_image_viewer_page_load_with_preloader_step2 (self, file_data, requested_size, cancellable,
callback, user_data);
+}
+
+
static gboolean
_gth_image_viewer_page_load_with_preloader_finish (GthImageViewerPage *self)
{
diff --git a/extensions/slideshow/actions.c b/extensions/slideshow/actions.c
index 573a9c9..c94b9b5 100644
--- a/extensions/slideshow/actions.c
+++ b/extensions/slideshow/actions.c
@@ -132,7 +132,7 @@ gth_browser_activate_slideshow (GSimpleAction *action,
GdkRectangle monitor_geometry;
int monitor_num;
- if (_gtk_window_get_monitor_info (GTK_WINDOW (browser), &monitor_geometry, &monitor_num)) {
+ if (_gtk_window_get_monitor_info (GTK_WINDOW (browser), &monitor_geometry, &monitor_num,
NULL)) {
gtk_window_set_default_size (GTK_WINDOW (slideshow), monitor_geometry.width,
monitor_geometry.height);
gtk_window_fullscreen_on_monitor (GTK_WINDOW (slideshow), gtk_window_get_screen
(GTK_WINDOW (browser)), monitor_num);
}
diff --git a/gthumb/Makefile.am b/gthumb/Makefile.am
index 9c3f087..4e1ca2a 100644
--- a/gthumb/Makefile.am
+++ b/gthumb/Makefile.am
@@ -35,6 +35,7 @@ PUBLIC_HEADER_FILES = \
gth-async-task.h \
gth-buffer-data.h \
gth-browser.h \
+ gth-color-manager.h \
gth-color-scale.h \
gth-delete-task.h \
gth-dumb-notebook.h \
@@ -62,6 +63,7 @@ PUBLIC_HEADER_FILES = \
gth-histogram.h \
gth-histogram-view.h \
gth-hook.h \
+ gth-icc-profile.h \
gth-icon-cache.h \
gth-image.h \
gth-image-dragger.h \
@@ -179,6 +181,7 @@ gthumb_SOURCES = \
gth-browser.c \
gth-browser-actions-callbacks.c \
gth-buffer-data.c \
+ gth-color-manager.c \
gth-color-scale.c \
gth-delete-task.c \
gth-dumb-notebook.c \
@@ -207,6 +210,7 @@ gthumb_SOURCES = \
gth-histogram.c \
gth-histogram-view.c \
gth-hook.c \
+ gth-icc-profile.c \
gth-icon-cache.c \
gth-image.c \
gth-image-dragger.c \
@@ -305,6 +309,7 @@ gthumb_LDADD = \
$(JSON_GLIB_LIBS) \
$(WEBKIT2_LIBS) \
$(LCMS2_LIBS) \
+ $(COLORD_LIBS) \
$(NULL)
if RUN_IN_PLACE
@@ -336,6 +341,7 @@ gthumb_CFLAGS = \
$(LIBCHAMPLAIN_CFLAGS) \
$(SMCLIENT_CFLAGS) \
$(LCMS2_CFLAGS) \
+ $(COLORD_CFLAGS) \
-DGTHUMB_LOCALEDIR=\"$(localedir)\" \
-DGTHUMB_UI_DIR=\"$(ui_dir)\" \
-DGTHUMB_ICON_DIR=\"$(icon_dir)\" \
diff --git a/gthumb/gth-browser.c b/gthumb/gth-browser.c
index 55d99e4..ee343a1 100644
--- a/gthumb/gth-browser.c
+++ b/gthumb/gth-browser.c
@@ -2599,7 +2599,7 @@ gth_browser_finalize (GObject *object)
g_free (browser->priv->list_attributes);
_g_object_unref (browser->priv->folder_popup_file_data);
_g_object_unref (browser->priv->history_menu);
- gth_icc_profile_free (browser->priv->screen_profile);
+ _g_object_unref (browser->priv->screen_profile);
gtk_tree_path_free (browser->priv->folder_tree_last_dest_row);
G_OBJECT_CLASS (gth_browser_parent_class)->finalize (object);
@@ -6951,36 +6951,45 @@ gth_browser_apply_editor_changes (GthBrowser *browser)
}
-GthICCProfile
-gth_browser_get_screen_profile (GthBrowser *browser)
+GthICCData *
+gth_browser_get_monitor_profile (GthBrowser *browser)
{
#if HAVE_LCMS2
if (browser->priv->screen_profile == NULL) {
- GdkScreen *screen;
- char *atom_name;
- GdkAtom type = GDK_NONE;
- int format = 0;
- int nitems = 0;
- guchar *data = NULL;
+ int monitor_num;
- screen = gtk_widget_get_screen (GTK_WIDGET (browser));
- if (gdk_screen_get_number (screen) > 0)
- atom_name = g_strdup_printf ("_ICC_PROFILE_%d", gdk_screen_get_number (screen));
- else
- atom_name = g_strdup ("_ICC_PROFILE");
+ if (_gtk_window_get_monitor_info (GTK_WINDOW (browser), NULL, &monitor_num, NULL)) {
+ char *atom_name;
+ GdkAtom type = GDK_NONE;
+ int format = 0;
+ int nitems = 0;
+ guchar *data = NULL;
- if (gdk_property_get (gdk_screen_get_root_window (screen),
- gdk_atom_intern (atom_name, FALSE),
- GDK_NONE,
- 0, 64 * 1024 * 1024, FALSE,
- &type, &format, &nitems, &data) && nitems > 0)
- {
- browser->priv->screen_profile = cmsOpenProfileFromMem (data, nitems);
- g_free (data);
- }
+ if (monitor_num > 0)
+ atom_name = g_strdup_printf ("_ICC_PROFILE_%d", monitor_num);
+ else
+ atom_name = g_strdup ("_ICC_PROFILE");
- g_free (atom_name);
+ if (gdk_property_get (gdk_screen_get_root_window (gtk_widget_get_screen (GTK_WIDGET
(browser))),
+ gdk_atom_intern (atom_name, FALSE),
+ GDK_NONE,
+ 0, 64 * 1024 * 1024, FALSE,
+ &type, &format, &nitems, &data) && nitems > 0)
+ {
+ GthICCProfile profile;
+
+ profile = cmsOpenProfileFromMem (data, nitems);
+ if (profile != NULL) {
+ char *filename = g_strdup_printf ("icc-profile://%d", monitor_num);
+ browser->priv->screen_profile = gth_icc_data_new (filename, profile);
+ g_free (filename);
+ }
+ g_free (data);
+ }
+
+ g_free (atom_name);
+ }
}
#endif
return browser->priv->screen_profile;
diff --git a/gthumb/gth-browser.h b/gthumb/gth-browser.h
index 9f76b1a..68d60cd 100644
--- a/gthumb/gth-browser.h
+++ b/gthumb/gth-browser.h
@@ -272,7 +272,7 @@ void gth_browser_ask_whether_to_save (GthBrowser *browser,
void gth_browser_save_state (GthBrowser *browser);
gboolean gth_browser_restore_state (GthBrowser *browser);
void gth_browser_apply_editor_changes (GthBrowser *browser);
-GthICCProfile gth_browser_get_screen_profile (GthBrowser *browser);
+GthICCData * gth_browser_get_monitor_profile (GthBrowser *browser);
GtkWidget * gth_browser_get_fullscreen_headerbar
(GthBrowser *browser);
void gth_browser_keep_mouse_visible (GthBrowser *browser,
diff --git a/gthumb/gth-color-manager.c b/gthumb/gth-color-manager.c
new file mode 100644
index 0000000..078aa77
--- /dev/null
+++ b/gthumb/gth-color-manager.c
@@ -0,0 +1,500 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2017 Free Software Foundation, Inc.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <glib.h>
+#ifdef HAVE_LCMS2
+#include <lcms2.h>
+#endif /* HAVE_LCMS2 */
+#ifdef HAVE_COLORD
+#include <colord.h>
+#endif /* HAVE_COLORD */
+#include "gio-utils.h"
+#include "glib-utils.h"
+#include "gth-color-manager.h"
+
+
+typedef struct {
+ GthICCData *in_profile;
+ GthICCData *out_profile;
+ GthICCTransform transform;
+} TransformData;
+
+
+static TransformData *
+transform_data_new (void)
+{
+ TransformData *data;
+
+ data = g_new (TransformData, 1);
+ data->in_profile = NULL;
+ data->out_profile = NULL;
+ data->transform = NULL;
+
+ return data;
+}
+
+
+static void
+transform_data_free (TransformData *data)
+{
+ _g_object_unref (data->in_profile);
+ _g_object_unref (data->out_profile);
+ gth_icc_transform_free (data->transform);
+ g_free (data);
+}
+
+
+/* Signals */
+enum {
+ CHANGED,
+ LAST_SIGNAL
+};
+
+
+struct _GthColorManagerPrivate {
+ GHashTable *profile_cache;
+ GHashTable *transform_cache;
+#if HAVE_COLORD
+ CdClient *cd_client;
+#else
+ GObject *cd_client;
+#endif
+};
+
+
+static guint gth_color_manager_signals[LAST_SIGNAL] = { 0 };
+
+
+G_DEFINE_TYPE (GthColorManager, gth_color_manager, G_TYPE_OBJECT)
+
+
+static void
+gth_color_manager_finalize (GObject *object)
+{
+ GthColorManager *self;
+
+ self = GTH_COLOR_MANAGER (object);
+
+ g_hash_table_unref (self->priv->profile_cache);
+ g_hash_table_unref (self->priv->transform_cache);
+ _g_object_unref (self->priv->cd_client);
+
+ G_OBJECT_CLASS (gth_color_manager_parent_class)->finalize (object);
+}
+
+
+static void
+gth_color_manager_class_init (GthColorManagerClass *klass)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (klass, sizeof (GthColorManagerPrivate));
+
+ object_class = (GObjectClass*) klass;
+ object_class->finalize = gth_color_manager_finalize;
+
+ /* signals */
+
+ gth_color_manager_signals[CHANGED] =
+ g_signal_new ("changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GthColorManagerClass, changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+}
+
+
+static void
+gth_color_manager_init (GthColorManager *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_COLOR_MANAGER, GthColorManagerPrivate);
+ self->priv->profile_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+ self->priv->transform_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
(GDestroyNotify) transform_data_free);
+ self->priv->cd_client = NULL;
+}
+
+
+GthColorManager *
+gth_color_manager_new (void)
+{
+ return (GthColorManager*) g_object_new (GTH_TYPE_COLOR_MANAGER, NULL);
+}
+
+
+#if HAVE_LCMS2 && HAVE_COLORD
+
+
+typedef struct {
+ GthColorManager *color_manager;
+ char *monitor_name;
+ char *cache_id;
+ GFile *icc_file;
+} ProfilesData;
+
+
+static void
+profiles_data_free (ProfilesData *data)
+{
+ _g_object_unref (data->color_manager);
+ _g_object_unref (data->icc_file);
+ g_free (data->monitor_name);
+ g_free (data->cache_id);
+ g_slice_free (ProfilesData, data);
+}
+
+
+static void
+profile_buffer_ready_cb (void **buffer,
+ gsize count,
+ GError *error,
+ gpointer user_data)
+{
+ GTask *task = user_data;
+
+ if (error != NULL) {
+ g_task_return_error (task, g_error_copy (error));
+ }
+ else {
+ ProfilesData *data = g_task_get_task_data (task);
+ char *filename;
+ GthICCData *icc_data;
+
+ filename = g_file_get_path (data->icc_file);
+ icc_data = gth_icc_data_new (filename, (GthICCProfile) cmsOpenProfileFromMem (*buffer,
count));
+ gth_color_manager_add_profile (data->color_manager, data->cache_id, icc_data);
+ g_task_return_pointer (task, g_object_ref (icc_data), g_object_unref);
+
+ g_object_unref (icc_data);
+ g_free (filename);
+ }
+
+ g_object_unref (task);
+}
+
+
+static void
+cd_profile_connected_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ CdProfile *profile = CD_PROFILE (source_object);
+ GTask *task = user_data;
+ ProfilesData *data = g_task_get_task_data (task);
+
+ if (! cd_profile_connect_finish (profile, res, NULL)) {
+ g_task_return_pointer (task, NULL, NULL);
+ g_object_unref (task);
+ }
+ else {
+ data->icc_file = g_file_new_for_path (cd_profile_get_filename (profile));
+ _g_file_load_async (data->icc_file,
+ G_PRIORITY_DEFAULT,
+ g_task_get_cancellable (task),
+ profile_buffer_ready_cb,
+ task);
+ }
+
+ g_object_unref (profile);
+}
+
+
+static void
+cd_device_connected_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ CdDevice *device = CD_DEVICE (source_object);
+ GTask *task = user_data;
+
+ if (! cd_device_connect_finish (device, res, NULL)) {
+ g_task_return_pointer (task, NULL, NULL);
+ g_object_unref (task);
+ }
+ else {
+ CdProfile *profile = cd_device_get_default_profile (device);
+ if (profile != NULL) {
+ cd_profile_connect (profile,
+ g_task_get_cancellable (task),
+ cd_profile_connected_cb,
+ task);
+ }
+ else {
+ g_task_return_pointer (task, NULL, NULL);
+ g_object_unref (task);
+ }
+ }
+
+ g_object_unref (device);
+}
+
+
+static void
+find_device_by_property_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GTask *task = user_data;
+ CdDevice *device;
+
+ device = cd_client_find_device_by_property_finish (CD_CLIENT (source_object), res, NULL);
+ if (device == NULL) {
+ g_task_return_pointer (task, NULL, NULL);
+ g_object_unref (task);
+ return;
+ }
+
+ cd_device_connect (device,
+ g_task_get_cancellable (task),
+ cd_device_connected_cb,
+ task);
+}
+
+
+static void
+_cd_client_find_device_for_task (CdClient *cd_client,
+ GTask *task)
+{
+ ProfilesData *data = g_task_get_task_data (task);
+
+ cd_client_find_device_by_property (cd_client,
+ CD_DEVICE_METADATA_XRANDR_NAME,
+ data->monitor_name,
+ g_task_get_cancellable (task),
+ find_device_by_property_cb,
+ task);
+}
+
+
+static void
+cd_client_connected_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ CdClient *cd_client = CD_CLIENT (source_object);
+ GTask *task = user_data;
+
+ if (! cd_client_connect_finish (cd_client, res, NULL)) {
+ g_task_return_pointer (task, NULL, NULL);
+ g_object_unref (task);
+ return;
+ }
+
+ _cd_client_find_device_for_task (cd_client, task);
+}
+
+
+#endif /* HAVE_LCMS2 && HAVE_COLORD */
+
+
+void
+gth_color_manager_get_profile_async (GthColorManager *self,
+ char *monitor_name,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+
+ task = g_task_new (self, cancellable, callback, user_data);
+
+#if HAVE_LCMS2
+
+ {
+ char *id;
+ GthICCData *profile;
+ ProfilesData *data;
+
+ id = g_strdup_printf ("monitor://%s", monitor_name);
+ profile = gth_color_manager_get_profile (self, id);
+ if (profile != NULL) {
+ g_task_return_pointer (task, g_object_ref (profile), g_object_unref);
+ g_object_unref (task);
+ g_object_unref (profile);
+ g_free (id);
+ return;
+ }
+
+#if HAVE_COLORD
+
+ {
+ data = g_slice_new (ProfilesData);
+ data->color_manager = g_object_ref (self);
+ data->monitor_name = g_strdup (monitor_name);
+ data->cache_id = g_strdup (id);
+ data->icc_file = NULL;
+ g_task_set_task_data (task, data, (GDestroyNotify) profiles_data_free);
+
+ if (self->priv->cd_client == NULL)
+ self->priv->cd_client = cd_client_new ();
+
+ if (! cd_client_get_connected (self->priv->cd_client))
+ cd_client_connect (self->priv->cd_client,
+ g_task_get_cancellable (task),
+ cd_client_connected_cb,
+ task);
+ else
+ _cd_client_find_device_for_task (self->priv->cd_client, task);
+
+ g_free (id);
+ return;
+ }
+
+#endif /* HAVE_COLORD */
+
+ g_free (id);
+ }
+
+#endif /* HAVE_LCMS2 */
+
+ g_task_return_pointer (task, NULL, NULL);
+ g_object_unref (task);
+}
+
+
+GthICCData *
+gth_color_manager_get_profile_finish (GthColorManager *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (g_task_is_valid (result, self), NULL);
+ return g_task_propagate_pointer (G_TASK (result), error);
+}
+
+
+void
+gth_color_manager_add_profile (GthColorManager *self,
+ const char *id,
+ GthICCData *profile)
+{
+ g_return_if_fail (self != NULL);
+ g_return_if_fail (id != NULL);
+ g_return_if_fail (profile != NULL);
+
+ g_hash_table_insert (self->priv->profile_cache, g_strdup (id), g_object_ref (profile));
+}
+
+
+GthICCData *
+gth_color_manager_get_profile (GthColorManager *self,
+ const char *id)
+{
+ GthICCData *profile;
+
+ g_return_val_if_fail (self != NULL, NULL);
+ g_return_val_if_fail (id != NULL, NULL);
+
+ profile = g_hash_table_lookup (self->priv->profile_cache, id);
+ return _g_object_ref (profile);
+}
+
+
+#if HAVE_LCMS2
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN /* BGRA */
+#define _LCMS2_CAIRO_FORMAT TYPE_BGRA_8
+#elif G_BYTE_ORDER == G_BIG_ENDIAN /* ARGB */
+#define _LCMS2_CAIRO_FORMAT TYPE_ARGB_8
+#else
+#define _LCMS2_CAIRO_FORMAT TYPE_ABGR_8
+#endif
+#endif
+
+
+static char *
+create_transform_id (GthICCData *from_profile,
+ GthICCData *to_profile)
+{
+ const char *from_filename = gth_icc_data_get_filename (from_profile);
+ const char *to_filename = gth_icc_data_get_filename (to_profile);
+
+ if ((g_strcmp0 (from_filename, "") != 0) && (g_strcmp0 (to_filename, "") != 0))
+ return g_strdup_printf ("%s -> %s", from_filename, to_filename);
+ else
+ return NULL;
+}
+
+
+GthICCTransform
+gth_color_manager_create_transform (GthColorManager *self,
+ GthICCData *from_profile,
+ GthICCData *to_profile)
+{
+#if HAVE_LCMS2
+ g_print ("gth_color_manager_create_transform (%p, %p)\n", gth_icc_data_get_profile (from_profile),
gth_icc_data_get_profile (to_profile));
+
+ return (GthICCTransform) cmsCreateTransform ((cmsHPROFILE) gth_icc_data_get_profile (from_profile),
+ _LCMS2_CAIRO_FORMAT,
+ (cmsHPROFILE) gth_icc_data_get_profile (to_profile),
+ _LCMS2_CAIRO_FORMAT,
+ INTENT_PERCEPTUAL,
+ 0);
+#else
+ return NULL;
+#endif
+}
+
+
+GthICCTransform
+gth_color_manager_get_transform (GthColorManager *self,
+ GthICCData *from_profile,
+ GthICCData *to_profile)
+{
+#if HAVE_LCMS2
+
+ GthICCTransform transform = NULL;
+ char *transform_id;
+
+ g_return_val_if_fail (self != NULL, NULL);
+
+ transform_id = create_transform_id (from_profile, to_profile);
+ if (transform_id != NULL) {
+ TransformData *transform_data = g_hash_table_lookup (self->priv->transform_cache,
transform_id);
+
+ if (transform_data == NULL) {
+ transform_data = transform_data_new ();
+ transform_data->in_profile = g_object_ref (from_profile);
+ transform_data->out_profile = g_object_ref (to_profile);
+ transform_data->transform = gth_color_manager_create_transform (self,
transform_data->in_profile, transform_data->out_profile);
+
+ if (transform_data->transform != NULL) {
+ g_hash_table_insert (self->priv->transform_cache, g_strdup (transform_id),
transform_data);
+ }
+ else {
+ transform_data_free (transform_data);
+ transform_data = NULL;
+ }
+ }
+
+ if (transform_data != NULL)
+ transform = transform_data->transform;
+
+ g_free (transform_id);
+ }
+
+ return transform;
+
+#endif
+
+ return NULL;
+}
diff --git a/gthumb/gth-color-manager.h b/gthumb/gth-color-manager.h
new file mode 100644
index 0000000..71a7770
--- /dev/null
+++ b/gthumb/gth-color-manager.h
@@ -0,0 +1,79 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2017 Free Software Foundation, Inc.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GTH_COLOR_MANAGER_H
+#define GTH_COLOR_MANAGER_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include "gth-icc-profile.h"
+
+G_BEGIN_DECLS
+
+#define GTH_TYPE_COLOR_MANAGER (gth_color_manager_get_type ())
+#define GTH_COLOR_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTH_TYPE_COLOR_MANAGER,
GthColorManager))
+#define GTH_COLOR_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTH_TYPE_COLOR_MANAGER,
GthColorManagerClass))
+#define GTH_IS_COLOR_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTH_TYPE_COLOR_MANAGER))
+#define GTH_IS_COLOR_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTH_TYPE_COLOR_MANAGER))
+#define GTH_COLOR_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GTH_TYPE_COLOR_MANAGER,
GthColorManagerClass))
+
+typedef struct _GthColorManager GthColorManager;
+typedef struct _GthColorManagerPrivate GthColorManagerPrivate;
+typedef struct _GthColorManagerClass GthColorManagerClass;
+
+struct _GthColorManager {
+ GObject __parent;
+ GthColorManagerPrivate *priv;
+};
+
+struct _GthColorManagerClass {
+ GObjectClass __parent_class;
+
+ /*< signals >*/
+
+ void (*changed) (GthColorManager *color_manager);
+};
+
+GType gth_color_manager_get_type (void) G_GNUC_CONST;
+GthColorManager * gth_color_manager_new (void);
+void gth_color_manager_get_profile_async (GthColorManager *color_manager,
+ char *monitor_name,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+GthICCData * gth_color_manager_get_profile_finish (GthColorManager *color_manager,
+ GAsyncResult *result,
+ GError **error);
+void gth_color_manager_add_profile (GthColorManager *color_manager,
+ const char *id,
+ GthICCData *profile);
+GthICCData * gth_color_manager_get_profile (GthColorManager *color_manager,
+ const char *id);
+GthICCTransform gth_color_manager_create_transform (GthColorManager *self,
+ GthICCData *from_profile,
+ GthICCData *to_profile);
+GthICCTransform gth_color_manager_get_transform (GthColorManager *color_manager,
+ GthICCData *from_profile,
+ GthICCData *to_profile);
+
+G_END_DECLS
+
+#endif /* GTH_COLOR_MANAGER_H */
diff --git a/gthumb/gth-icc-profile.c b/gthumb/gth-icc-profile.c
new file mode 100644
index 0000000..35af682
--- /dev/null
+++ b/gthumb/gth-icc-profile.c
@@ -0,0 +1,179 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2017 The Free Software Foundation, Inc.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <glib.h>
+#include <glib-object.h>
+#ifdef HAVE_LCMS2
+#include <lcms2.h>
+#endif /* HAVE_LCMS2 */
+#include "gth-icc-profile.h"
+
+
+struct _GthICCDataPrivate {
+ GthICCProfile icc_profile;
+ char *filename;
+};
+
+
+G_DEFINE_TYPE (GthICCData, gth_icc_data, G_TYPE_OBJECT)
+
+
+static void
+gth_icc_data_finalize (GObject *object)
+{
+ GthICCData *icc_data;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GTH_IS_ICC_DATA (object));
+
+ icc_data = GTH_ICC_DATA (object);
+ gth_icc_profile_free (icc_data->priv->icc_profile);
+ g_free (icc_data->priv->filename);
+
+ /* Chain up */
+ G_OBJECT_CLASS (gth_icc_data_parent_class)->finalize (object);
+}
+
+
+static void
+gth_icc_data_class_init (GthICCDataClass *klass)
+{
+ GObjectClass *gobject_class;
+
+ g_type_class_add_private (klass, sizeof (GthICCDataPrivate));
+
+ gobject_class = (GObjectClass*) klass;
+ gobject_class->finalize = gth_icc_data_finalize;
+}
+
+
+static void
+gth_icc_data_init (GthICCData *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_ICC_DATA, GthICCDataPrivate);
+ self->priv->icc_profile = NULL;
+ self->priv->filename = NULL;
+}
+
+
+void
+gth_icc_profile_free (GthICCProfile icc_profile)
+{
+#ifdef HAVE_LCMS2
+ if (icc_profile != NULL)
+ cmsCloseProfile ((cmsHPROFILE) icc_profile);
+#endif
+}
+
+
+static char *
+gth_icc_profile_get_id (GthICCProfile icc_profile)
+{
+ GString *str;
+
+ str = g_string_new ("");
+
+#ifdef HAVE_LCMS2
+ {
+ /* taken from colord:
+ * Copyright (C) 2013 Richard Hughes <richard hughsie com>
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ * */
+ cmsUInt8Number icc_id[16];
+ gboolean md5_precooked = FALSE;
+ gchar *md5 = NULL;
+ guint i;
+
+ cmsGetHeaderProfileID ((cmsHPROFILE) icc_profile, icc_id);
+ for (i = 0; i < 16; i++) {
+ if (icc_id[i] != 0) {
+ md5_precooked = TRUE;
+ break;
+ }
+ }
+ if (md5_precooked) {
+ /* convert to a hex string */
+ md5 = g_new0 (gchar, 32 + 1);
+ for (i = 0; i < 16; i++)
+ g_snprintf (md5 + i * 2, 3, "%02x", icc_id[i]);
+ }
+
+ if (md5 != NULL) {
+ g_string_append (str, "md5://");
+ g_string_append (str, md5);
+ }
+ }
+#endif
+
+ return g_string_free (str, FALSE);
+}
+
+void
+gth_icc_transform_free (GthICCTransform transform)
+{
+#ifdef HAVE_LCMS2
+ if (transform != NULL)
+ cmsDeleteTransform ((cmsHTRANSFORM) transform);
+#endif
+}
+
+
+GthICCData *
+gth_icc_data_new (const char *filename,
+ GthICCProfile profile)
+{
+ GthICCData *icc_data;
+
+ icc_data = g_object_new (GTH_TYPE_ICC_DATA, NULL);
+ if (filename != NULL)
+ icc_data->priv->filename = g_strdup (filename);
+ else
+ icc_data->priv->filename = gth_icc_profile_get_id (profile);
+ icc_data->priv->icc_profile = profile;
+
+ return icc_data;
+}
+
+
+const char *
+gth_icc_data_get_filename (GthICCData *self)
+{
+ g_return_val_if_fail (self != NULL, NULL);
+ return self->priv->filename;
+}
+
+
+GthICCProfile
+gth_icc_data_get_profile (GthICCData *self)
+{
+ g_return_val_if_fail (self != NULL, NULL);
+ return self->priv->icc_profile;
+}
+
+
+gboolean
+gth_icc_data_equal (GthICCData *a,
+ GthICCData *b)
+{
+ g_return_val_if_fail ((a == NULL) || (b == NULL), NULL);
+ return g_strcmp0 (a->priv->filename, b->priv->filename) == 0;
+}
diff --git a/gthumb/gth-icc-profile.h b/gthumb/gth-icc-profile.h
new file mode 100644
index 0000000..9562423
--- /dev/null
+++ b/gthumb/gth-icc-profile.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2017 The Free Software Foundation, Inc.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GTH_ICC_PROFILE_H
+#define GTH_ICC_PROFILE_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef gpointer GthICCProfile;
+typedef gpointer GthICCTransform;
+
+#define GTH_TYPE_ICC_DATA (gth_icc_data_get_type ())
+#define GTH_ICC_DATA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTH_TYPE_ICC_DATA, GthICCData))
+#define GTH_ICC_DATA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTH_TYPE_ICC_DATA, GthICCDataClass))
+#define GTH_IS_ICC_DATA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTH_TYPE_ICC_DATA))
+#define GTH_IS_ICC_DATA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTH_TYPE_ICC_DATA))
+#define GTH_ICC_DATA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GTH_TYPE_ICC_DATA, GthICCDataClass))
+
+typedef struct _GthICCData GthICCData;
+typedef struct _GthICCDataPrivate GthICCDataPrivate;
+typedef struct _GthICCDataClass GthICCDataClass;
+
+struct _GthICCData {
+ GObject __parent;
+ GthICCDataPrivate *priv;
+};
+
+struct _GthICCDataClass {
+ GObjectClass __parent_class;
+};
+
+void gth_icc_profile_free (GthICCProfile icc_profile);
+void gth_icc_transform_free (GthICCTransform transform);
+
+GType gth_icc_data_get_type (void);
+GthICCData * gth_icc_data_new (const char *filename,
+ GthICCProfile profile);
+const char * gth_icc_data_get_filename (GthICCData *icc_data);
+GthICCProfile gth_icc_data_get_profile (GthICCData *icc_data);
+gboolean gth_icc_data_equal (GthICCData *a,
+ GthICCData *b);
+
+G_END_DECLS
+
+#endif /* GTH_ICC_PROFILE_H */
diff --git a/gthumb/gth-image-loader.c b/gthumb/gth-image-loader.c
index db2fbd0..595dcfa 100644
--- a/gthumb/gth-image-loader.c
+++ b/gthumb/gth-image-loader.c
@@ -33,7 +33,7 @@ struct _GthImageLoaderPrivate {
gboolean as_animation; /* Whether to load the image in a
* GdkPixbufAnimation structure. */
GthImageFormat preferred_format;
- GthICCProfile out_profile;
+ GthICCData *out_profile;
GthImageLoaderFunc loader_func;
gpointer loader_data;
};
@@ -45,6 +45,10 @@ G_DEFINE_TYPE (GthImageLoader, gth_image_loader, G_TYPE_OBJECT)
static void
gth_image_loader_finalize (GObject *object)
{
+ GthImageLoader *self = GTH_IMAGE_LOADER (object);
+
+ _g_object_unref (self->priv->out_profile);
+
G_OBJECT_CLASS (gth_image_loader_parent_class)->finalize (object);
}
@@ -110,9 +114,12 @@ gth_image_loader_set_preferred_format (GthImageLoader *self,
void
gth_image_loader_set_out_profile (GthImageLoader *self,
- GthICCProfile out_profile)
+ GthICCData *out_profile)
{
g_return_if_fail (self != NULL);
+
+ _g_object_ref (out_profile);
+ _g_object_unref (self->priv->out_profile);
self->priv->out_profile = out_profile;
}
diff --git a/gthumb/gth-image-loader.h b/gthumb/gth-image-loader.h
index 187db5b..2877501 100644
--- a/gthumb/gth-image-loader.h
+++ b/gthumb/gth-image-loader.h
@@ -58,7 +58,7 @@ void gth_image_loader_set_loader_func (GthImageLoader
void gth_image_loader_set_preferred_format (GthImageLoader *loader,
GthImageFormat preferred_format);
void gth_image_loader_set_out_profile (GthImageLoader *loader,
- GthICCProfile profile);
+ GthICCData *profile);
void gth_image_loader_load (GthImageLoader *loader,
GthFileData *file_data,
int requested_size,
diff --git a/gthumb/gth-image-preloader.c b/gthumb/gth-image-preloader.c
index 607bb46..3079f33 100644
--- a/gthumb/gth-image-preloader.c
+++ b/gthumb/gth-image-preloader.c
@@ -78,7 +78,7 @@ struct _GthImagePreloaderPrivate {
GthImageLoader *loader;
GQueue *cache;
guint load_next_id;
- GthICCProfile out_profile;
+ GthICCData *out_profile;
};
@@ -251,6 +251,7 @@ gth_image_preloader_finalize (GObject *object)
g_list_free (self->priv->requests);
g_object_unref (self->priv->loader);
+ _g_object_unref (self->priv->out_profile);
g_queue_free_full (self->priv->cache, (GDestroyNotify) cache_data_unref);
G_OBJECT_CLASS (gth_image_preloader_parent_class)->finalize (object);
@@ -292,9 +293,12 @@ gth_image_preloader_new (void)
void
gth_image_preloader_set_out_profile (GthImagePreloader *self,
- GthICCProfile out_profile)
+ GthICCData *out_profile)
{
g_return_if_fail (self != NULL);
+
+ _g_object_ref (out_profile);
+ _g_object_unref (self->priv->out_profile);
self->priv->out_profile = out_profile;
}
diff --git a/gthumb/gth-image-preloader.h b/gthumb/gth-image-preloader.h
index d5de045..aa59ba3 100644
--- a/gthumb/gth-image-preloader.h
+++ b/gthumb/gth-image-preloader.h
@@ -52,7 +52,7 @@ struct _GthImagePreloaderClass {
GType gth_image_preloader_get_type (void) G_GNUC_CONST;
GthImagePreloader * gth_image_preloader_new (void);
void gth_image_preloader_set_out_profile (GthImagePreloader
*loader,
- GthICCProfile profile);
+ GthICCData *profile);
void gth_image_preloader_load (GthImagePreloader *self,
GthFileData *requested,
int
requested_size,
diff --git a/gthumb/gth-image.c b/gthumb/gth-image.c
index a53cf12..6f8dd82 100644
--- a/gthumb/gth-image.c
+++ b/gthumb/gth-image.c
@@ -30,91 +30,10 @@
#include "cairo-utils.h"
#include "glib-utils.h"
#include "gth-image.h"
+#include "gth-main.h"
#include "pixbuf-utils.h"
-/* -- GthICCData -- */
-
-
-#define GTH_TYPE_ICC_DATA (gth_icc_data_get_type ())
-#define GTH_ICC_DATA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTH_TYPE_ICC_DATA, GthICCData))
-#define GTH_ICC_DATA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTH_TYPE_ICC_DATA, GthICCDataClass))
-#define GTH_IS_ICC_DATA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTH_TYPE_ICC_DATA))
-#define GTH_IS_ICC_DATA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTH_TYPE_ICC_DATA))
-#define GTH_ICC_DATA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GTH_TYPE_ICC_DATA, GthICCDataClass))
-
-typedef struct _GthICCData GthICCData;
-typedef struct _GthICCDataClass GthICCDataClass;
-
-struct _GthICCData {
- GObject __parent;
- GthICCProfile icc_profile;
-};
-
-struct _GthICCDataClass {
- GObjectClass __parent_class;
-};
-
-
-static GType gth_icc_data_get_type (void);
-
-
-G_DEFINE_TYPE (GthICCData, gth_icc_data, G_TYPE_OBJECT)
-
-
-static void
-gth_icc_data_finalize (GObject *object)
-{
- GthICCData *icc_data;
-
- g_return_if_fail (object != NULL);
- g_return_if_fail (GTH_IS_ICC_DATA (object));
-
- icc_data = GTH_ICC_DATA (object);
- gth_icc_profile_free (icc_data->icc_profile);
-
- /* Chain up */
- G_OBJECT_CLASS (gth_icc_data_parent_class)->finalize (object);
-}
-
-
-static void
-gth_icc_data_class_init (GthICCDataClass *klass)
-{
- GObjectClass *gobject_class;
-
- gobject_class = (GObjectClass*) klass;
- gobject_class->finalize = gth_icc_data_finalize;
-}
-
-
-static void
-gth_icc_data_init (GthICCData *self)
-{
- self->icc_profile = NULL;
-}
-
-
-static GthICCData *
-gth_icc_data_new (GthICCProfile profile)
-{
- GthICCData *icc_data;
-
- icc_data = g_object_new (GTH_TYPE_ICC_DATA, NULL);
- icc_data->icc_profile = profile;
-
- return icc_data;
-}
-
-
-static GthICCProfile
-gth_icc_data_get_profile (GthICCData *self)
-{
- g_return_val_if_fail (self != NULL, NULL);
- return self->icc_profile;
-}
-
-
/* -- GthImage -- */
@@ -502,55 +421,43 @@ gth_image_get_is_animation (GthImage *image)
void
-gth_image_set_icc_profile (GthImage *image,
- GthICCProfile profile)
+gth_image_set_icc_profile (GthImage *image,
+ GthICCData *profile)
{
+ _g_object_ref (profile);
_gth_image_free_icc_profile (image);
- if (profile != NULL)
- image->priv->icc_data = gth_icc_data_new (profile);
+ image->priv->icc_data = profile;
}
-GthICCProfile
+GthICCData *
gth_image_get_icc_profile (GthImage *image)
{
g_return_val_if_fail (image != NULL, NULL);
- return (image->priv->icc_data != NULL) ? gth_icc_data_get_profile (image->priv->icc_data) : NULL;
+ return image->priv->icc_data;
}
/* -- gth_image_apply_icc_profile -- */
-#if HAVE_LCMS2
-#if G_BYTE_ORDER == G_LITTLE_ENDIAN /* BGRA */
-#define _LCMS2_CAIRO_FORMAT TYPE_BGRA_8
-#elif G_BYTE_ORDER == G_BIG_ENDIAN /* ARGB */
-#define _LCMS2_CAIRO_FORMAT TYPE_ARGB_8
-#else
-#define _LCMS2_CAIRO_FORMAT TYPE_ABGR_8
-#endif
-#endif
-
-
void
gth_image_apply_icc_profile (GthImage *image,
- GthICCProfile out_profile,
+ GthICCData *out_profile,
GCancellable *cancellable)
{
#if HAVE_LCMS2
- GthICCProfile image_profile;
- cmsHTRANSFORM hTransform;
cairo_surface_t *surface;
+ cmsHTRANSFORM hTransform;
+ gboolean delete_transform = FALSE;
g_return_if_fail (image != NULL);
if (out_profile == NULL)
return;
- image_profile = gth_image_get_icc_profile (image);
- if (image_profile == NULL)
+ if (image->priv->icc_data == NULL)
return;
if (image->priv->format != GTH_IMAGE_FORMAT_CAIRO_SURFACE)
@@ -560,11 +467,16 @@ gth_image_apply_icc_profile (GthImage *image,
if (surface == NULL)
return;
- hTransform = cmsCreateTransform ((cmsHPROFILE) image_profile,
- _LCMS2_CAIRO_FORMAT,
- (cmsHPROFILE) out_profile,
- _LCMS2_CAIRO_FORMAT,
- INTENT_PERCEPTUAL, 0);
+ hTransform = (cmsHTRANSFORM) gth_color_manager_get_transform (gth_main_get_default_color_manager (),
+ image->priv->icc_data,
+ out_profile);
+
+ if (hTransform == NULL) {
+ hTransform = (cmsHTRANSFORM) gth_color_manager_create_transform
(gth_main_get_default_color_manager (),
+ image->priv->icc_data,
+ out_profile);
+ delete_transform = (hTransform != NULL);
+ }
if (hTransform != NULL) {
unsigned char *surface_row;
@@ -587,9 +499,10 @@ gth_image_apply_icc_profile (GthImage *image,
cairo_surface_mark_dirty (surface);
cairo_surface_destroy (surface);
- cmsDeleteTransform (hTransform);
}
+ if (delete_transform)
+ cmsDeleteTransform (hTransform);
#endif
}
@@ -598,8 +511,8 @@ gth_image_apply_icc_profile (GthImage *image,
typedef struct {
- GthImage *image;
- GthICCProfile out_profile;
+ GthImage *image;
+ GthICCData *out_profile;
} ApplyProfileData;
@@ -609,6 +522,7 @@ apply_profile_data_free (gpointer user_data)
ApplyProfileData *apd = user_data;
g_object_unref (apd->image);
+ _g_object_unref (apd->out_profile);
g_free (apd);
}
@@ -636,7 +550,7 @@ _gth_image_apply_icc_profile_thread (GSimpleAsyncResult *result,
void
gth_image_apply_icc_profile_async (GthImage *image,
- GthICCProfile out_profile,
+ GthICCData *out_profile,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
@@ -653,7 +567,7 @@ gth_image_apply_icc_profile_async (GthImage *image,
apd = g_new (ApplyProfileData, 1);
apd->image = g_object_ref (image);
- apd->out_profile = out_profile;
+ apd->out_profile = _g_object_ref (out_profile);
g_simple_async_result_set_op_res_gpointer (result, apd, apply_profile_data_free);
g_simple_async_result_run_in_thread (result,
_gth_image_apply_icc_profile_thread,
@@ -671,13 +585,3 @@ gth_image_apply_icc_profile_finish (GAsyncResult *result,
g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
gth_image_apply_icc_profile_async), FALSE);
return g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error);
}
-
-
-void
-gth_icc_profile_free (GthICCProfile icc_profile)
-{
-#ifdef HAVE_LCMS2
- if (icc_profile != NULL)
- cmsCloseProfile ((cmsHPROFILE) icc_profile);
-#endif
-}
diff --git a/gthumb/gth-image.h b/gthumb/gth-image.h
index c55f9d8..566c123 100644
--- a/gthumb/gth-image.h
+++ b/gthumb/gth-image.h
@@ -28,6 +28,7 @@
#include <gio/gio.h>
#include <cairo.h>
#include "gth-file-data.h"
+#include "gth-icc-profile.h"
G_BEGIN_DECLS
@@ -38,8 +39,6 @@ typedef enum {
GTH_IMAGE_N_FORMATS
} GthImageFormat;
-typedef gpointer GthICCProfile;
-
#define GTH_TYPE_IMAGE (gth_image_get_type ())
#define GTH_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTH_TYPE_IMAGE, GthImage))
#define GTH_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTH_TYPE_IMAGE, GthImageClass))
@@ -104,21 +103,19 @@ void gth_image_set_pixbuf_animation (GthImage
GdkPixbufAnimation * gth_image_get_pixbuf_animation (GthImage *image);
gboolean gth_image_get_is_animation (GthImage *image);
void gth_image_set_icc_profile (GthImage *image,
- GthICCProfile profile);
-GthICCProfile gth_image_get_icc_profile (GthImage *image);
+ GthICCData *profile);
+GthICCData * gth_image_get_icc_profile (GthImage *image);
void gth_image_apply_icc_profile (GthImage *image,
- GthICCProfile out_profile,
+ GthICCData *out_profile,
GCancellable *cancellable);
void gth_image_apply_icc_profile_async (GthImage *image,
- GthICCProfile out_profile,
+ GthICCData *out_profile,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean gth_image_apply_icc_profile_finish (GAsyncResult *result,
GError **error);
-void gth_icc_profile_free (GthICCProfile icc_profile);
-
G_END_DECLS
#endif /* GTH_IMAGE_H */
diff --git a/gthumb/gth-main.c b/gthumb/gth-main.c
index 38a5f8f..63569c3 100644
--- a/gthumb/gth-main.c
+++ b/gthumb/gth-main.c
@@ -110,6 +110,7 @@ struct _GthMainPrivate
GthTagsFile *tags;
GthMonitor *monitor;
GthExtensionManager *extension_manager;
+ GthColorManager *color_manager;
};
@@ -146,6 +147,7 @@ gth_main_finalize (GObject *object)
_g_object_unref (gth_main->priv->monitor);
_g_object_unref (gth_main->priv->extension_manager);
+ _g_object_unref (gth_main->priv->color_manager);
gth_filter_file_free (gth_main->priv->filters);
gth_tags_file_free (gth_main->priv->tags);
@@ -180,6 +182,7 @@ gth_main_init (GthMain *main)
main->priv->metadata_info = g_ptr_array_new ();
main->priv->metadata_info_hash = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
main->priv->metadata_info_sorted = FALSE;
+ main->priv->extension_manager = gth_extension_manager_new ();
}
@@ -1199,6 +1202,15 @@ gth_main_get_default_extension_manager (void)
}
+GthColorManager *
+gth_main_get_default_color_manager (void)
+{
+ if (Main->priv->color_manager == NULL)
+ Main->priv->color_manager = gth_color_manager_new ();
+ return Main->priv->color_manager;
+}
+
+
void
gth_main_activate_extensions (void)
{
diff --git a/gthumb/gth-main.h b/gthumb/gth-main.h
index 78f21d1..8ba74d9 100644
--- a/gthumb/gth-main.h
+++ b/gthumb/gth-main.h
@@ -25,6 +25,7 @@
#include <glib.h>
#include <glib-object.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
+#include "gth-color-manager.h"
#include "gth-extensions.h"
#include "gth-file-data.h"
#include "gth-file-source.h"
@@ -118,6 +119,7 @@ char ** gth_main_get_all_tags (void);
void gth_main_tags_changed (void);
GthMonitor * gth_main_get_default_monitor (void);
GthExtensionManager * gth_main_get_default_extension_manager (void);
+GthColorManager * gth_main_get_default_color_manager (void);
void gth_main_register_default_hooks (void);
void gth_main_register_default_tests (void);
void gth_main_register_default_types (void);
diff --git a/gthumb/gtk-utils.c b/gthumb/gtk-utils.c
index d99e907..d714978 100644
--- a/gthumb/gtk-utils.c
+++ b/gthumb/gtk-utils.c
@@ -1151,9 +1151,10 @@ _gtk_window_get_is_maximized (GtkWindow *window)
gboolean
-_gtk_window_get_monitor_info (GtkWindow *window,
- GdkRectangle *geometry,
- int *number)
+_gtk_window_get_monitor_info (GtkWindow *window,
+ GdkRectangle *geometry,
+ int *number,
+ char **name)
{
#if GTK_CHECK_VERSION(3, 22, 0)
@@ -1171,9 +1172,10 @@ _gtk_window_get_monitor_info (GtkWindow *window,
if (geometry != NULL)
gdk_monitor_get_geometry (monitor, geometry);
- if (number != NULL) {
+ if ((number != NULL) || (name != NULL)) {
GdkDisplay *display;
int monitor_num;
+ const char *monitor_name;
int i;
display = gdk_monitor_get_display (monitor);
@@ -1182,12 +1184,15 @@ _gtk_window_get_monitor_info (GtkWindow *window,
GdkMonitor *m = gdk_display_get_monitor (display, i);
if (m == monitor) {
monitor_num = i;
+ monitor_name = gdk_monitor_get_model (monitor);
break;
}
if (m == NULL)
break;
}
- *number = monitor_num;
+
+ if (number != NULL) *number = monitor_num;
+ if (name != NULL) *name = g_strdup (monitor_name);
}
#else
@@ -1207,9 +1212,11 @@ _gtk_window_get_monitor_info (GtkWindow *window,
monitor_num = gdk_screen_get_monitor_at_window (screen, win);
if (number != NULL)
*number = monitor_num;
-
if (geometry != NULL)
gdk_screen_get_monitor_geometry (screen, monitor_num, geometry);
+ if (name != NULL)
+ *name = gdk_screen_get_monitor_plug_name (screen, monitor_num);
+
#endif
return TRUE;
diff --git a/gthumb/gtk-utils.h b/gthumb/gtk-utils.h
index 4ddc0ce..c2431a4 100644
--- a/gthumb/gtk-utils.h
+++ b/gthumb/gtk-utils.h
@@ -152,7 +152,8 @@ void _gtk_window_add_accelerators_from_menu (GtkWindow
*window,
gboolean _gtk_window_get_is_maximized (GtkWindow *window);
gboolean _gtk_window_get_monitor_info (GtkWindow *window,
GdkRectangle *geometry,
- int *number);
+ int *number,
+ char **name);
GdkDevice * _gtk_widget_get_client_pointer (GtkWidget *widget);
void _gtk_list_box_add_separator (GtkListBox *list_box);
gboolean _gtk_settings_get_dialogs_use_header (void);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]