7 * This software is released under the GNU General Public License (GNU GPL).
8 * Please read the included file COPYING for more information.
9 * This software comes with no warranty of any kind, use at your own risk!
14 #include "color-man.h"
17 #include "ui_fileops.h"
21 /*** color support enabled ***/
23 #ifdef HAVE_LCMS_LCMS_H
24 #include <lcms/lcms.h>
30 typedef struct _ColorManCache ColorManCache;
31 struct _ColorManCache {
32 cmsHPROFILE profile_in;
33 cmsHPROFILE profile_out;
34 cmsHTRANSFORM transform;
36 ColorManProfileType profile_in_type;
37 gchar *profile_in_file;
39 ColorManProfileType profile_out_type;
40 gchar *profile_out_file;
47 /* pixels to transform per idle call */
48 #define COLOR_MAN_CHUNK_SIZE 81900
51 static void color_man_lib_init(void)
53 static gint init_done = FALSE;
55 if (init_done) return;
58 cmsErrorAction(LCMS_ERROR_IGNORE);
63 *-------------------------------------------------------------------
64 * color transform cache
65 *-------------------------------------------------------------------
68 static GList *cm_cache_list = NULL;
71 static void color_man_cache_ref(ColorManCache *cc)
78 static void color_man_cache_unref(ColorManCache *cc)
85 if (cc->transform) cmsDeleteTransform(cc->transform);
86 if (cc->profile_in) cmsCloseProfile(cc->profile_in);
87 if (cc->profile_out) cmsCloseProfile(cc->profile_out);
89 g_free(cc->profile_in_file);
90 g_free(cc->profile_out_file);
96 static cmsHPROFILE color_man_cache_load_profile(ColorManProfileType type, const gchar *file,
97 unsigned char *data, guint data_len)
99 cmsHPROFILE profile = NULL;
103 case COLOR_PROFILE_FILE:
108 pathl = path_from_utf8(file);
109 profile = cmsOpenProfileFromFile(pathl, "r");
113 case COLOR_PROFILE_SRGB:
114 profile = cmsCreate_sRGBProfile();
116 case COLOR_PROFILE_MEM:
119 profile = cmsOpenProfileFromMem(data, data_len);
122 case COLOR_PROFILE_NONE:
130 static ColorManCache *color_man_cache_new(ColorManProfileType in_type, const gchar *in_file,
131 unsigned char *in_data, guint in_data_len,
132 ColorManProfileType out_type, const gchar *out_file,
137 color_man_lib_init();
139 cc = g_new0(ColorManCache, 1);
142 cc->profile_in_type = in_type;
143 cc->profile_in_file = g_strdup(in_file);
145 cc->profile_out_type = out_type;
146 cc->profile_out_file = g_strdup(out_file);
148 cc->has_alpha = has_alpha;
150 cc->profile_in = color_man_cache_load_profile(cc->profile_in_type, cc->profile_in_file,
151 in_data, in_data_len);
152 cc->profile_out = color_man_cache_load_profile(cc->profile_out_type, cc->profile_out_file,
155 if (!cc->profile_in || !cc->profile_out)
157 if (debug) printf("failed to load color profile for %s: %d %s\n",
158 (!cc->profile_in) ? "input" : "screen",
159 (!cc->profile_in) ? cc->profile_in_type : cc->profile_out_type,
160 (!cc->profile_in) ? cc->profile_in_file : cc->profile_out_file);
162 color_man_cache_unref(cc);
166 cc->transform = cmsCreateTransform(cc->profile_in,
167 (has_alpha) ? TYPE_RGBA_8 : TYPE_RGB_8,
169 (has_alpha) ? TYPE_RGBA_8 : TYPE_RGB_8,
170 INTENT_PERCEPTUAL, 0);
174 if (debug) printf("failed to create color profile transform\n");
176 color_man_cache_unref(cc);
180 if (cc->profile_in_type != COLOR_PROFILE_MEM)
182 cm_cache_list = g_list_append(cm_cache_list, cc);
183 color_man_cache_ref(cc);
189 static void color_man_cache_free(ColorManCache *cc)
193 cm_cache_list = g_list_remove(cm_cache_list, cc);
194 color_man_cache_unref(cc);
197 static void color_man_cache_reset(void)
199 while (cm_cache_list)
203 cc = cm_cache_list->data;
204 color_man_cache_free(cc);
208 static ColorManCache *color_man_cache_find(ColorManProfileType in_type, const gchar *in_file,
209 ColorManProfileType out_type, const gchar *out_file,
214 work = cm_cache_list;
223 if (cc->profile_in_type == in_type &&
224 cc->profile_out_type == out_type &&
225 cc->has_alpha == has_alpha)
230 if (match && cc->profile_in_type == COLOR_PROFILE_FILE)
232 match = (cc->profile_in_file && in_file &&
233 strcmp(cc->profile_in_file, in_file) == 0);
235 if (match && cc->profile_out_type == COLOR_PROFILE_FILE)
237 match = (cc->profile_out_file && out_file &&
238 strcmp(cc->profile_out_file, out_file) == 0);
241 if (match) return cc;
247 static ColorManCache *color_man_cache_get(ColorManProfileType in_type, const gchar *in_file,
248 unsigned char *in_data, guint in_data_len,
249 ColorManProfileType out_type, const gchar *out_file,
254 cc = color_man_cache_find(in_type, in_file, out_type, out_file, has_alpha);
257 color_man_cache_ref(cc);
261 return color_man_cache_new(in_type, in_file, in_data, in_data_len,
262 out_type, out_file, has_alpha);
267 *-------------------------------------------------------------------
269 *-------------------------------------------------------------------
272 static void color_man_done(ColorMan *cm, ColorManReturnType type)
276 cm->func_done(cm, type, cm->func_done_data);
280 void color_man_correct_region(ColorMan *cm, GdkPixbuf *pixbuf, gint x, gint y, gint w, gint h)
286 gint pixbuf_width, pixbuf_height;
289 pixbuf_width = gdk_pixbuf_get_width(pixbuf);
290 pixbuf_height = gdk_pixbuf_get_height(pixbuf);
294 pix = gdk_pixbuf_get_pixels(pixbuf);
295 rs = gdk_pixbuf_get_rowstride(pixbuf);
297 w = MIN(w, pixbuf_width - x);
298 h = MIN(h, pixbuf_height - y);
300 pix += x * ((cc->has_alpha) ? 4 : 3);
301 for (i = 0; i < h; i++)
305 pbuf = pix + ((y + i) * rs);
307 cmsDoTransform(cc->transform, pbuf, pbuf, w);
312 static gint color_man_idle_cb(gpointer data)
317 if (!cm->pixbuf) return FALSE;
320 cm->pixbuf != image_get_pixbuf(cm->imd))
323 color_man_done(cm, COLOR_RETURN_IMAGE_CHANGED);
327 width = gdk_pixbuf_get_width(cm->pixbuf);
328 height = gdk_pixbuf_get_height(cm->pixbuf);
330 if (cm->row > height)
332 if (!cm->incremental_sync && cm->imd)
334 image_area_changed(cm->imd, 0, 0, width, height);
338 color_man_done(cm, COLOR_RETURN_SUCCESS);
342 rh = COLOR_MAN_CHUNK_SIZE / width + 1;
343 color_man_correct_region(cm, cm->pixbuf, 0, cm->row, width, rh);
344 if (cm->incremental_sync && cm->imd) image_area_changed(cm->imd, 0, cm->row, width, rh);
350 static ColorMan *color_man_new_real(ImageWindow *imd, GdkPixbuf *pixbuf,
351 ColorManProfileType input_type, const gchar *input_file,
352 unsigned char *input_data, guint input_data_len,
353 ColorManProfileType screen_type, const gchar *screen_file)
358 if (imd) pixbuf = image_get_pixbuf(imd);
360 cm = g_new0(ColorMan, 1);
363 if (cm->pixbuf) g_object_ref(cm->pixbuf);
365 cm->incremental_sync = FALSE;
369 has_alpha = pixbuf ? gdk_pixbuf_get_has_alpha(pixbuf) : FALSE;
371 cm->profile = color_man_cache_get(input_type, input_file, input_data, input_data_len,
372 screen_type, screen_file, has_alpha);
382 ColorMan *color_man_new(ImageWindow *imd, GdkPixbuf *pixbuf,
383 ColorManProfileType input_type, const gchar *input_file,
384 ColorManProfileType screen_type, const gchar *screen_file)
386 return color_man_new_real(imd, pixbuf,
387 input_type, input_file, NULL, 0,
388 screen_type, screen_file);
391 void color_man_start_bg(ColorMan *cm, ColorManDoneFunc done_func, gpointer done_data)
393 cm->func_done = done_func;
394 cm->func_done_data = done_data;
395 cm->idle_id = g_idle_add(color_man_idle_cb, cm);
398 ColorMan *color_man_new_embedded(ImageWindow *imd, GdkPixbuf *pixbuf,
399 unsigned char *input_data, guint input_data_len,
400 ColorManProfileType screen_type, const gchar *screen_file)
402 return color_man_new_real(imd, pixbuf,
403 COLOR_PROFILE_MEM, NULL, input_data, input_data_len,
404 screen_type, screen_file);
407 void color_man_free(ColorMan *cm)
411 if (cm->idle_id != -1) g_source_remove(cm->idle_id);
412 if (cm->pixbuf) g_object_unref(cm->pixbuf);
414 color_man_cache_unref(cm->profile);
419 void color_man_update(void)
421 color_man_cache_reset();
425 /*** color support not enabled ***/
428 ColorMan *color_man_new(ImageWindow *imd, GdkPixbuf *pixbuf,
429 ColorManProfileType input_type, const gchar *input_file,
430 ColorManProfileType screen_type, const gchar *screen_file)
436 ColorMan *color_man_new_embedded(ImageWindow *imd, GdkPixbuf *pixbuf,
437 unsigned char *input_data, guint input_data_len,
438 ColorManProfileType screen_type, const gchar *screen_file)
444 void color_man_free(ColorMan *cm)
449 void color_man_update(void)
454 void color_man_correct_region(ColorMan *cm, GdkPixbuf *pixbuf, gint x, gint y, gint w, gint h)
459 void color_man_start_bg(ColorMan *cm, ColorManDoneFunc done_func, gpointer done_data)