Mercurial > geeqie
annotate src/color-man.c @ 114:50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
* bar_exif.c, cache-loader.c, pan-view.c: Pass new arg for exif_read().
* color-man.[ch]: Add color_man_new_embedded for using in-memory color
profiles.
* exif.[ch]: Add support for extracting color profiles embedded in jpeg
and tiff images. This resulted in a rewrite of the jpeg parser; both
to allow searching for any marker type, and to make the code readable.
* format_raw.c: Add color profile tag to the debug code.
* image.c, layout.c: Use embedded color profiles when found and
enabled, also add toggle for the option in color profile menu.
author | gqview |
---|---|
date | Mon, 27 Nov 2006 06:37:48 +0000 |
parents | 55166d93498d |
children | 53b2bfdcff69 |
rev | line source |
---|---|
113 | 1 /* |
2 * GQview | |
3 * (C) 2006 John Ellis | |
4 * | |
5 * Author: John Ellis | |
6 * | |
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! | |
10 */ | |
11 | |
12 | |
13 #include "gqview.h" | |
14 #include "color-man.h" | |
15 | |
16 #include "image.h" | |
17 #include "ui_fileops.h" | |
18 | |
19 | |
20 #ifdef HAVE_LCMS | |
21 /*** color support enabled ***/ | |
22 | |
23 #ifdef HAVE_LCMS_LCMS_H | |
24 #include <lcms/lcms.h> | |
25 #else | |
26 #include <lcms.h> | |
27 #endif | |
28 | |
29 | |
30 typedef struct _ColorManCache ColorManCache; | |
31 struct _ColorManCache { | |
32 cmsHPROFILE profile_in; | |
33 cmsHPROFILE profile_out; | |
34 cmsHTRANSFORM transform; | |
35 | |
36 ColorManProfileType profile_in_type; | |
37 gchar *profile_in_file; | |
38 | |
39 ColorManProfileType profile_out_type; | |
40 gchar *profile_out_file; | |
41 | |
42 gint has_alpha; | |
43 | |
44 gint refcount; | |
45 }; | |
46 | |
47 /* pixels to transform per idle call */ | |
48 #define COLOR_MAN_CHUNK_SIZE 81900 | |
49 | |
50 | |
51 static void color_man_lib_init(void) | |
52 { | |
53 static gint init_done = FALSE; | |
54 | |
55 if (init_done) return; | |
56 init_done = TRUE; | |
57 | |
58 cmsErrorAction(LCMS_ERROR_IGNORE); | |
59 } | |
60 | |
61 | |
62 /* | |
63 *------------------------------------------------------------------- | |
64 * color transform cache | |
65 *------------------------------------------------------------------- | |
66 */ | |
67 | |
68 static GList *cm_cache_list = NULL; | |
69 | |
70 | |
71 static void color_man_cache_ref(ColorManCache *cc) | |
72 { | |
73 if (!cc) return; | |
74 | |
75 cc->refcount++; | |
76 } | |
77 | |
78 static void color_man_cache_unref(ColorManCache *cc) | |
79 { | |
80 if (!cc) return; | |
81 | |
82 cc->refcount--; | |
83 if (cc->refcount < 1) | |
84 { | |
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); | |
88 | |
89 g_free(cc->profile_in_file); | |
90 g_free(cc->profile_out_file); | |
91 | |
92 g_free(cc); | |
93 } | |
94 } | |
95 | |
114
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
96 static cmsHPROFILE color_man_cache_load_profile(ColorManProfileType type, const gchar *file, |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
97 unsigned char *data, guint data_len) |
113 | 98 { |
99 cmsHPROFILE profile = NULL; | |
100 | |
101 switch (type) | |
102 { | |
103 case COLOR_PROFILE_FILE: | |
104 if (file) | |
105 { | |
106 gchar *pathl; | |
107 | |
108 pathl = path_from_utf8(file); | |
109 profile = cmsOpenProfileFromFile(pathl, "r"); | |
110 g_free(pathl); | |
111 } | |
112 break; | |
113 case COLOR_PROFILE_SRGB: | |
114 profile = cmsCreate_sRGBProfile(); | |
115 break; | |
114
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
116 case COLOR_PROFILE_MEM: |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
117 if (data) |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
118 { |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
119 profile = cmsOpenProfileFromMem(data, data_len); |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
120 } |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
121 break; |
113 | 122 case COLOR_PROFILE_NONE: |
123 default: | |
124 break; | |
125 } | |
126 | |
127 return profile; | |
128 } | |
129 | |
130 static ColorManCache *color_man_cache_new(ColorManProfileType in_type, const gchar *in_file, | |
114
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
131 unsigned char *in_data, guint in_data_len, |
113 | 132 ColorManProfileType out_type, const gchar *out_file, |
133 gint has_alpha) | |
134 { | |
135 ColorManCache *cc; | |
136 | |
137 color_man_lib_init(); | |
138 | |
139 cc = g_new0(ColorManCache, 1); | |
140 cc->refcount = 1; | |
141 | |
142 cc->profile_in_type = in_type; | |
143 cc->profile_in_file = g_strdup(in_file); | |
144 | |
145 cc->profile_out_type = out_type; | |
146 cc->profile_out_file = g_strdup(out_file); | |
147 | |
148 cc->has_alpha = has_alpha; | |
149 | |
114
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
150 cc->profile_in = color_man_cache_load_profile(cc->profile_in_type, cc->profile_in_file, |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
151 in_data, in_data_len); |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
152 cc->profile_out = color_man_cache_load_profile(cc->profile_out_type, cc->profile_out_file, |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
153 NULL, 0); |
113 | 154 |
155 if (!cc->profile_in || !cc->profile_out) | |
156 { | |
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); | |
161 | |
162 color_man_cache_unref(cc); | |
163 return NULL; | |
164 } | |
165 | |
166 cc->transform = cmsCreateTransform(cc->profile_in, | |
167 (has_alpha) ? TYPE_RGBA_8 : TYPE_RGB_8, | |
168 cc->profile_out, | |
169 (has_alpha) ? TYPE_RGBA_8 : TYPE_RGB_8, | |
170 INTENT_PERCEPTUAL, 0); | |
171 | |
172 if (!cc->transform) | |
173 { | |
174 if (debug) printf("failed to create color profile transform\n"); | |
175 | |
176 color_man_cache_unref(cc); | |
177 return NULL; | |
178 } | |
179 | |
114
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
180 if (cc->profile_in_type != COLOR_PROFILE_MEM) |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
181 { |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
182 cm_cache_list = g_list_append(cm_cache_list, cc); |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
183 color_man_cache_ref(cc); |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
184 } |
113 | 185 |
186 return cc; | |
187 } | |
188 | |
189 static void color_man_cache_free(ColorManCache *cc) | |
190 { | |
191 if (!cc) return; | |
192 | |
193 cm_cache_list = g_list_remove(cm_cache_list, cc); | |
194 color_man_cache_unref(cc); | |
195 } | |
196 | |
197 static void color_man_cache_reset(void) | |
198 { | |
199 while (cm_cache_list) | |
200 { | |
201 ColorManCache *cc; | |
202 | |
203 cc = cm_cache_list->data; | |
204 color_man_cache_free(cc); | |
205 } | |
206 } | |
207 | |
208 static ColorManCache *color_man_cache_find(ColorManProfileType in_type, const gchar *in_file, | |
209 ColorManProfileType out_type, const gchar *out_file, | |
210 gint has_alpha) | |
211 { | |
212 GList *work; | |
213 | |
214 work = cm_cache_list; | |
215 while (work) | |
216 { | |
217 ColorManCache *cc; | |
218 gint match = FALSE; | |
219 | |
220 cc = work->data; | |
221 work = work->next; | |
222 | |
223 if (cc->profile_in_type == in_type && | |
224 cc->profile_out_type == out_type && | |
225 cc->has_alpha == has_alpha) | |
226 { | |
227 match = TRUE; | |
228 } | |
229 | |
230 if (match && cc->profile_in_type == COLOR_PROFILE_FILE) | |
231 { | |
232 match = (cc->profile_in_file && in_file && | |
233 strcmp(cc->profile_in_file, in_file) == 0); | |
234 } | |
235 if (match && cc->profile_out_type == COLOR_PROFILE_FILE) | |
236 { | |
237 match = (cc->profile_out_file && out_file && | |
238 strcmp(cc->profile_out_file, out_file) == 0); | |
239 } | |
240 | |
241 if (match) return cc; | |
242 } | |
243 | |
244 return NULL; | |
245 } | |
246 | |
247 static ColorManCache *color_man_cache_get(ColorManProfileType in_type, const gchar *in_file, | |
114
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
248 unsigned char *in_data, guint in_data_len, |
113 | 249 ColorManProfileType out_type, const gchar *out_file, |
250 gint has_alpha) | |
251 { | |
252 ColorManCache *cc; | |
253 | |
254 cc = color_man_cache_find(in_type, in_file, out_type, out_file, has_alpha); | |
114
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
255 if (cc) |
113 | 256 { |
114
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
257 color_man_cache_ref(cc); |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
258 return cc; |
113 | 259 } |
260 | |
114
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
261 return color_man_cache_new(in_type, in_file, in_data, in_data_len, |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
262 out_type, out_file, has_alpha); |
113 | 263 } |
264 | |
265 | |
266 /* | |
267 *------------------------------------------------------------------- | |
268 * color manager | |
269 *------------------------------------------------------------------- | |
270 */ | |
271 | |
272 static void color_man_done(ColorMan *cm, ColorManReturnType type) | |
273 { | |
274 if (cm->func_done) | |
275 { | |
276 cm->func_done(cm, type, cm->func_done_data); | |
277 } | |
278 } | |
279 | |
280 static void color_man_correct_region(ColorMan *cm, gint x, gint y, gint w, gint h, | |
281 gint pixbuf_width, gint pixbuf_height) | |
282 { | |
283 ColorManCache *cc; | |
284 guchar *pix; | |
285 gint rs; | |
286 gint i; | |
287 | |
288 cc = cm->profile; | |
289 | |
290 pix = gdk_pixbuf_get_pixels(cm->pixbuf); | |
291 rs = gdk_pixbuf_get_rowstride(cm->pixbuf); | |
292 | |
293 w = MIN(w, pixbuf_width - x); | |
294 h = MIN(h, pixbuf_height - y); | |
295 | |
296 pix += x * ((cc->has_alpha) ? 4 : 3); | |
297 for (i = 0; i < h; i++) | |
298 { | |
299 guchar *pbuf; | |
300 | |
301 pbuf = pix + ((y + i) * rs); | |
302 cmsDoTransform(cc->transform, pbuf, pbuf, w); | |
303 } | |
304 | |
305 image_area_changed(cm->imd, x, y, w, h); | |
306 } | |
307 | |
308 static gint color_man_idle_cb(gpointer data) | |
309 { | |
310 ColorMan *cm = data; | |
311 gint width, height; | |
312 gint rh; | |
313 | |
314 if (cm->pixbuf != image_get_pixbuf(cm->imd)) | |
315 { | |
316 cm->idle_id = -1; | |
317 color_man_done(cm, COLOR_RETURN_IMAGE_CHANGED); | |
318 return FALSE; | |
319 } | |
320 | |
321 width = gdk_pixbuf_get_width(cm->pixbuf); | |
322 height = gdk_pixbuf_get_height(cm->pixbuf); | |
323 | |
324 if (cm->row > height) | |
325 { | |
326 cm->idle_id = -1; | |
327 color_man_done(cm, COLOR_RETURN_SUCCESS); | |
328 return FALSE; | |
329 } | |
330 | |
331 rh = COLOR_MAN_CHUNK_SIZE / width + 1; | |
332 color_man_correct_region(cm, 0, cm->row, width, rh, width, height); | |
333 cm->row += rh; | |
334 | |
335 return TRUE; | |
336 } | |
337 | |
114
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
338 static ColorMan *color_man_new_real(ImageWindow *imd, |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
339 ColorManProfileType input_type, const gchar *input_file, |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
340 unsigned char *input_data, guint input_data_len, |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
341 ColorManProfileType screen_type, const gchar *screen_file, |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
342 ColorManDoneFunc done_func, gpointer done_data) |
113 | 343 { |
344 ColorMan *cm; | |
345 GdkPixbuf *pixbuf; | |
346 gint has_alpha; | |
347 | |
348 if (!imd) return NULL; | |
349 | |
350 pixbuf = image_get_pixbuf(imd); | |
351 if (!pixbuf) return NULL; | |
352 | |
353 cm = g_new0(ColorMan, 1); | |
354 cm->imd = imd; | |
355 cm->pixbuf = pixbuf; | |
356 cm->row = 0; | |
357 cm->idle_id = -1; | |
358 | |
359 cm->func_done = done_func; | |
360 cm->func_done_data = done_data; | |
361 | |
362 has_alpha = gdk_pixbuf_get_has_alpha(pixbuf); | |
114
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
363 cm->profile = color_man_cache_get(input_type, input_file, input_data, input_data_len, |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
364 screen_type, screen_file, has_alpha); |
113 | 365 if (!cm->profile) |
366 { | |
367 color_man_free(cm); | |
368 return NULL; | |
369 } | |
370 | |
371 cm->idle_id = g_idle_add(color_man_idle_cb, cm); | |
372 | |
373 return cm; | |
374 } | |
375 | |
114
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
376 ColorMan *color_man_new(ImageWindow *imd, |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
377 ColorManProfileType input_type, const gchar *input_file, |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
378 ColorManProfileType screen_type, const gchar *screen_file, |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
379 ColorManDoneFunc done_func, gpointer done_data) |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
380 { |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
381 return color_man_new_real(imd, |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
382 input_type, input_file, NULL, 0, |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
383 screen_type, screen_file, |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
384 done_func, done_data); |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
385 } |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
386 |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
387 ColorMan *color_man_new_embedded(ImageWindow *imd, |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
388 unsigned char *input_data, guint input_data_len, |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
389 ColorManProfileType screen_type, const gchar *screen_file, |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
390 ColorManDoneFunc done_func, gpointer done_data) |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
391 { |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
392 return color_man_new_real(imd, |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
393 COLOR_PROFILE_MEM, NULL, input_data, input_data_len, |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
394 screen_type, screen_file, |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
395 done_func, done_data); |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
396 } |
50fc73e08550
Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
gqview
parents:
113
diff
changeset
|
397 |
113 | 398 void color_man_free(ColorMan *cm) |
399 { | |
400 if (!cm) return; | |
401 | |
402 if (cm->idle_id != -1) g_source_remove(cm->idle_id); | |
403 | |
404 color_man_cache_unref(cm->profile); | |
405 | |
406 g_free(cm); | |
407 } | |
408 | |
409 void color_man_update(void) | |
410 { | |
411 color_man_cache_reset(); | |
412 } | |
413 | |
414 #else | |
415 /*** color support not enabled ***/ | |
416 | |
417 | |
418 ColorMan *color_man_new(ImageWindow *imd, | |
419 ColorManProfileType input_type, const gchar *input_file, | |
420 ColorManProfileType screen_type, const gchar *screen_file, | |
421 ColorManDoneFunc don_func, gpointer done_data) | |
422 { | |
423 /* no op */ | |
424 return NULL; | |
425 } | |
426 | |
427 void color_man_free(ColorMan *cm) | |
428 { | |
429 /* no op */ | |
430 } | |
431 | |
432 void color_man_update(void) | |
433 { | |
434 /* no op */ | |
435 } | |
436 | |
437 | |
438 #endif | |
439 | |
440 |