4 * Copyright (C) 2008 - 2009 The Geeqie Team
8 * This software is released under the GNU General Public License (GNU GPL).
9 * Please read the included file COPYING for more information.
10 * This software comes with no warranty of any kind, use at your own risk!
15 #include "color-man.h"
18 #include "ui_fileops.h"
22 /*** color support enabled ***/
27 typedef struct _ColorManCache ColorManCache;
28 struct _ColorManCache {
29 cmsHPROFILE profile_in;
30 cmsHPROFILE profile_out;
31 cmsHTRANSFORM transform;
33 ColorManProfileType profile_in_type;
34 gchar *profile_in_file;
36 ColorManProfileType profile_out_type;
37 gchar *profile_out_file;
44 /* pixels to transform per idle call */
45 #define COLOR_MAN_CHUNK_SIZE 81900
48 static void color_man_lib_init(void)
50 static gint init_done = FALSE;
52 if (init_done) return;
55 cmsErrorAction(LCMS_ERROR_IGNORE);
58 static cmsHPROFILE color_man_create_adobe_comp(void)
60 /* ClayRGB1998 is AdobeRGB compatible */
61 #include "ClayRGB1998_icc.h"
62 return cmsOpenProfileFromMem(ClayRGB1998_icc, ClayRGB1998_icc_len);
66 *-------------------------------------------------------------------
67 * color transform cache
68 *-------------------------------------------------------------------
71 static GList *cm_cache_list = NULL;
74 static void color_man_cache_ref(ColorManCache *cc)
81 static void color_man_cache_unref(ColorManCache *cc)
88 if (cc->transform) cmsDeleteTransform(cc->transform);
89 if (cc->profile_in) cmsCloseProfile(cc->profile_in);
90 if (cc->profile_out) cmsCloseProfile(cc->profile_out);
92 g_free(cc->profile_in_file);
93 g_free(cc->profile_out_file);
99 static cmsHPROFILE color_man_cache_load_profile(ColorManProfileType type, const gchar *file,
100 guchar *data, guint data_len)
102 cmsHPROFILE profile = NULL;
106 case COLOR_PROFILE_FILE:
111 pathl = path_from_utf8(file);
112 profile = cmsOpenProfileFromFile(pathl, "r");
116 case COLOR_PROFILE_SRGB:
117 profile = cmsCreate_sRGBProfile();
119 case COLOR_PROFILE_ADOBERGB:
120 profile = color_man_create_adobe_comp();
122 case COLOR_PROFILE_MEM:
125 profile = cmsOpenProfileFromMem(data, data_len);
128 case COLOR_PROFILE_NONE:
136 static ColorManCache *color_man_cache_new(ColorManProfileType in_type, const gchar *in_file,
137 guchar *in_data, guint in_data_len,
138 ColorManProfileType out_type, const gchar *out_file,
143 color_man_lib_init();
145 cc = g_new0(ColorManCache, 1);
148 cc->profile_in_type = in_type;
149 cc->profile_in_file = g_strdup(in_file);
151 cc->profile_out_type = out_type;
152 cc->profile_out_file = g_strdup(out_file);
154 cc->has_alpha = has_alpha;
156 cc->profile_in = color_man_cache_load_profile(cc->profile_in_type, cc->profile_in_file,
157 in_data, in_data_len);
158 cc->profile_out = color_man_cache_load_profile(cc->profile_out_type, cc->profile_out_file,
161 if (!cc->profile_in || !cc->profile_out)
163 DEBUG_1("failed to load color profile for %s: %d %s",
164 (!cc->profile_in) ? "input" : "screen",
165 (!cc->profile_in) ? cc->profile_in_type : cc->profile_out_type,
166 (!cc->profile_in) ? cc->profile_in_file : cc->profile_out_file);
168 color_man_cache_unref(cc);
172 cc->transform = cmsCreateTransform(cc->profile_in,
173 (has_alpha) ? TYPE_RGBA_8 : TYPE_RGB_8,
175 (has_alpha) ? TYPE_RGBA_8 : TYPE_RGB_8,
176 INTENT_PERCEPTUAL, 0);
180 DEBUG_1("failed to create color profile transform");
182 color_man_cache_unref(cc);
186 if (cc->profile_in_type != COLOR_PROFILE_MEM)
188 cm_cache_list = g_list_append(cm_cache_list, cc);
189 color_man_cache_ref(cc);
195 static void color_man_cache_free(ColorManCache *cc)
199 cm_cache_list = g_list_remove(cm_cache_list, cc);
200 color_man_cache_unref(cc);
203 static void color_man_cache_reset(void)
205 while (cm_cache_list)
209 cc = cm_cache_list->data;
210 color_man_cache_free(cc);
214 static ColorManCache *color_man_cache_find(ColorManProfileType in_type, const gchar *in_file,
215 ColorManProfileType out_type, const gchar *out_file,
220 work = cm_cache_list;
229 if (cc->profile_in_type == in_type &&
230 cc->profile_out_type == out_type &&
231 cc->has_alpha == has_alpha)
236 if (match && cc->profile_in_type == COLOR_PROFILE_FILE)
238 match = (cc->profile_in_file && in_file &&
239 strcmp(cc->profile_in_file, in_file) == 0);
241 if (match && cc->profile_out_type == COLOR_PROFILE_FILE)
243 match = (cc->profile_out_file && out_file &&
244 strcmp(cc->profile_out_file, out_file) == 0);
247 if (match) return cc;
253 static ColorManCache *color_man_cache_get(ColorManProfileType in_type, const gchar *in_file,
254 guchar *in_data, guint in_data_len,
255 ColorManProfileType out_type, const gchar *out_file,
260 cc = color_man_cache_find(in_type, in_file, out_type, out_file, has_alpha);
263 color_man_cache_ref(cc);
267 return color_man_cache_new(in_type, in_file, in_data, in_data_len,
268 out_type, out_file, has_alpha);
273 *-------------------------------------------------------------------
275 *-------------------------------------------------------------------
278 static void color_man_done(ColorMan *cm, ColorManReturnType type)
282 cm->func_done(cm, type, cm->func_done_data);
286 void color_man_correct_region(ColorMan *cm, GdkPixbuf *pixbuf, gint x, gint y, gint w, gint h)
292 gint pixbuf_width, pixbuf_height;
295 pixbuf_width = gdk_pixbuf_get_width(pixbuf);
296 pixbuf_height = gdk_pixbuf_get_height(pixbuf);
300 pix = gdk_pixbuf_get_pixels(pixbuf);
301 rs = gdk_pixbuf_get_rowstride(pixbuf);
303 w = MIN(w, pixbuf_width - x);
304 h = MIN(h, pixbuf_height - y);
306 pix += x * ((cc->has_alpha) ? 4 : 3);
307 for (i = 0; i < h; i++)
311 pbuf = pix + ((y + i) * rs);
313 cmsDoTransform(cc->transform, pbuf, pbuf, w);
318 static gint color_man_idle_cb(gpointer data)
323 if (!cm->pixbuf) return FALSE;
326 cm->pixbuf != image_get_pixbuf(cm->imd))
329 color_man_done(cm, COLOR_RETURN_IMAGE_CHANGED);
333 width = gdk_pixbuf_get_width(cm->pixbuf);
334 height = gdk_pixbuf_get_height(cm->pixbuf);
336 if (cm->row > height)
338 if (!cm->incremental_sync && cm->imd)
340 image_area_changed(cm->imd, 0, 0, width, height);
344 color_man_done(cm, COLOR_RETURN_SUCCESS);
348 rh = COLOR_MAN_CHUNK_SIZE / width + 1;
349 color_man_correct_region(cm, cm->pixbuf, 0, cm->row, width, rh);
350 if (cm->incremental_sync && cm->imd) image_area_changed(cm->imd, 0, cm->row, width, rh);
356 static ColorMan *color_man_new_real(ImageWindow *imd, GdkPixbuf *pixbuf,
357 ColorManProfileType input_type, const gchar *input_file,
358 guchar *input_data, guint input_data_len,
359 ColorManProfileType screen_type, const gchar *screen_file)
364 if (imd) pixbuf = image_get_pixbuf(imd);
366 cm = g_new0(ColorMan, 1);
369 if (cm->pixbuf) g_object_ref(cm->pixbuf);
371 cm->incremental_sync = FALSE;
375 has_alpha = pixbuf ? gdk_pixbuf_get_has_alpha(pixbuf) : FALSE;
377 cm->profile = color_man_cache_get(input_type, input_file, input_data, input_data_len,
378 screen_type, screen_file, has_alpha);
388 ColorMan *color_man_new(ImageWindow *imd, GdkPixbuf *pixbuf,
389 ColorManProfileType input_type, const gchar *input_file,
390 ColorManProfileType screen_type, const gchar *screen_file)
392 return color_man_new_real(imd, pixbuf,
393 input_type, input_file, NULL, 0,
394 screen_type, screen_file);
397 void color_man_start_bg(ColorMan *cm, ColorManDoneFunc done_func, gpointer done_data)
399 cm->func_done = done_func;
400 cm->func_done_data = done_data;
401 cm->idle_id = g_idle_add(color_man_idle_cb, cm);
404 ColorMan *color_man_new_embedded(ImageWindow *imd, GdkPixbuf *pixbuf,
405 guchar *input_data, guint input_data_len,
406 ColorManProfileType screen_type, const gchar *screen_file)
408 return color_man_new_real(imd, pixbuf,
409 COLOR_PROFILE_MEM, NULL, input_data, input_data_len,
410 screen_type, screen_file);
413 void color_man_free(ColorMan *cm)
417 if (cm->idle_id != -1) g_source_remove(cm->idle_id);
418 if (cm->pixbuf) g_object_unref(cm->pixbuf);
420 color_man_cache_unref(cm->profile);
425 void color_man_update(void)
427 color_man_cache_reset();
430 #else /* define HAVE_LCMS */
431 /*** color support not enabled ***/
434 ColorMan *color_man_new(ImageWindow *imd, GdkPixbuf *pixbuf,
435 ColorManProfileType input_type, const gchar *input_file,
436 ColorManProfileType screen_type, const gchar *screen_file)
442 ColorMan *color_man_new_embedded(ImageWindow *imd, GdkPixbuf *pixbuf,
443 guchar *input_data, guint input_data_len,
444 ColorManProfileType screen_type, const gchar *screen_file)
450 void color_man_free(ColorMan *cm)
455 void color_man_update(void)
460 void color_man_correct_region(ColorMan *cm, GdkPixbuf *pixbuf, gint x, gint y, gint w, gint h)
465 void color_man_start_bg(ColorMan *cm, ColorManDoneFunc done_func, gpointer done_data)
470 #endif /* define HAVE_LCMS */
471 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */