1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /*
4 * GThumb
5 *
6 * Copyright (C) 2011 Free Software Foundation, Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <setjmp.h>
27 #include <jpeglib.h>
28 #if HAVE_LCMS2
29 #include <lcms2.h>
30 #endif
31 #include <gthumb.h>
32 #include <extensions/jpeg_utils/jmemorysrc.h>
33 #include <extensions/jpeg_utils/jpeg-info.h>
34 #include "cairo-image-surface-jpeg.h"
35
36
37 /* error handler data */
38
39
40 struct error_handler_data {
41 struct jpeg_error_mgr pub;
42 sigjmp_buf setjmp_buffer;
43 GError **error;
44 };
45
46
47 static void
fatal_error_handler(j_common_ptr cinfo)48 fatal_error_handler (j_common_ptr cinfo)
49 {
50 struct error_handler_data *errmgr;
51
52 errmgr = (struct error_handler_data *) cinfo->err;
53 if ((errmgr->error != NULL) && (*errmgr->error == NULL)) {
54 char buffer[JMSG_LENGTH_MAX];
55
56 /* Create the message */
57 (* cinfo->err->format_message) (cinfo, buffer);
58
59 g_set_error (errmgr->error,
60 GDK_PIXBUF_ERROR,
61 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
62 _("Error interpreting JPEG image file: %s"),
63 buffer);
64 siglongjmp (errmgr->setjmp_buffer, 1);
65 }
66 }
67
68
69 static void
output_message_handler(j_common_ptr cinfo)70 output_message_handler (j_common_ptr cinfo)
71 {
72 /* This method keeps libjpeg from dumping text to stderr */
73 /* do nothing */
74 }
75
76
77 /* tables with pre-multiplied values */
78
79
80 static unsigned char *CMYK_Tab = NULL;
81 static int *YCbCr_R_Cr_Tab = NULL;
82 static int *YCbCr_G_Cb_Tab = NULL;
83 static int *YCbCr_G_Cr_Tab = NULL;
84 static int *YCbCr_B_Cb_Tab = NULL;
85 static GMutex Tables_Mutex;
86
87
88 #define SCALE_FACTOR 16
89 #define SCALE_UP(x) ((gint32) ((x) * (1L << SCALE_FACTOR) + 0.5))
90 #define SCALE_DOWN(x) ((x) >> SCALE_FACTOR)
91 #define ONE_HALF ((gint32) (1 << (SCALE_FACTOR - 1)))
92
93
94 static void
CMYK_table_init(void)95 CMYK_table_init (void)
96 {
97 g_mutex_lock (&Tables_Mutex);
98
99 if (CMYK_Tab == NULL) {
100 int v, k, i;
101 double k1;
102
103 /* tab[k * 256 + v] = v * k / 255.0 */
104
105 CMYK_Tab = g_new (unsigned char, 256 * 256);
106 i = 0;
107 for (k = 0; k <= 255; k++) {
108 k1 = (double) k / 255.0;
109 for (v = 0; v <= 255; v++)
110 CMYK_Tab[i++] = (double) v * k1;
111 }
112 }
113
114 g_mutex_unlock (&Tables_Mutex);
115 }
116
117
118 static void
YCbCr_tables_init(void)119 YCbCr_tables_init (void)
120 {
121 g_mutex_lock (&Tables_Mutex);
122
123 if (YCbCr_R_Cr_Tab == NULL) {
124 int i, v;
125
126 YCbCr_R_Cr_Tab = g_new (int, 256);
127 YCbCr_G_Cb_Tab = g_new (int, 256);
128 YCbCr_G_Cr_Tab = g_new (int, 256);
129 YCbCr_B_Cb_Tab = g_new (int, 256);
130
131 for (i = 0, v = -128; i <= 255; i++, v++) {
132 YCbCr_R_Cr_Tab[i] = SCALE_DOWN (SCALE_UP (1.402) * v + ONE_HALF);
133 YCbCr_G_Cb_Tab[i] = - SCALE_UP (0.34414) * v;
134 YCbCr_G_Cr_Tab[i] = - SCALE_UP (0.71414) * v + ONE_HALF;
135 YCbCr_B_Cb_Tab[i] = SCALE_DOWN (SCALE_UP (1.77200) * v + ONE_HALF);
136 }
137 }
138
139 g_mutex_unlock (&Tables_Mutex);
140 }
141
142
143 GthImage *
_cairo_image_surface_create_from_jpeg(GInputStream * istream,GthFileData * file_data,int requested_size,int * original_width_p,int * original_height_p,gboolean * loaded_original_p,gpointer user_data,GCancellable * cancellable,GError ** error)144 _cairo_image_surface_create_from_jpeg (GInputStream *istream,
145 GthFileData *file_data,
146 int requested_size,
147 int *original_width_p,
148 int *original_height_p,
149 gboolean *loaded_original_p,
150 gpointer user_data,
151 GCancellable *cancellable,
152 GError **error)
153 {
154 GthImage *image;
155 JpegInfoFlags info_flags;
156 gboolean load_scaled;
157 GthTransform orientation;
158 int output_width;
159 int output_height;
160 int destination_width;
161 int destination_height;
162 int line_start;
163 int line_step;
164 int pixel_step;
165 void *in_buffer;
166 gsize in_buffer_size;
167 JpegInfoData jpeg_info;
168 struct error_handler_data jsrcerr;
169 struct jpeg_decompress_struct srcinfo;
170 cairo_surface_t *surface;
171 cairo_surface_metadata_t *metadata;
172 unsigned char *surface_data;
173 unsigned char *surface_row;
174 JSAMPARRAY buffer;
175 int buffer_stride;
176 int scanned_lines;
177 JDIMENSION n_lines;
178 JSAMPARRAY buffer_row;
179 int l;
180 unsigned char *p_surface;
181 guchar r, g, b;
182 guint32 pixel;
183 unsigned char *p_buffer;
184 int x;
185 gboolean read_all_scanlines = FALSE;
186 volatile gboolean finished = FALSE;
187
188 image = gth_image_new ();
189 surface = NULL;
190
191 if (! _g_input_stream_read_all (istream,
192 &in_buffer,
193 &in_buffer_size,
194 cancellable,
195 error))
196 {
197 return image;
198 }
199
200 _jpeg_info_data_init (&jpeg_info);
201 info_flags = _JPEG_INFO_EXIF_ORIENTATION;
202 #if HAVE_LCMS2
203 info_flags |= _JPEG_INFO_EXIF_COLOR_SPACE | _JPEG_INFO_ICC_PROFILE;
204 #endif
205 _jpeg_info_get_from_buffer (in_buffer, in_buffer_size, info_flags, &jpeg_info);
206 if (jpeg_info.valid & _JPEG_INFO_EXIF_ORIENTATION)
207 orientation = jpeg_info.orientation;
208 else
209 orientation = GTH_TRANSFORM_NONE;
210 #if HAVE_LCMS2
211 {
212 GthICCProfile *profile = NULL;
213
214 if (jpeg_info.valid & _JPEG_INFO_ICC_PROFILE) {
215 profile = gth_icc_profile_new (GTH_ICC_PROFILE_ID_UNKNOWN, cmsOpenProfileFromMem (jpeg_info.icc_data, jpeg_info.icc_data_size));
216 }
217 else if (jpeg_info.valid & _JPEG_INFO_EXIF_COLOR_SPACE) {
218 if (jpeg_info.color_space == GTH_COLOR_SPACE_SRGB)
219 profile = gth_icc_profile_new_srgb ();
220 }
221
222 if (profile != NULL) {
223 gth_image_set_icc_profile (image, profile);
224 g_object_unref (profile);
225 }
226 }
227 #endif
228 _jpeg_info_data_dispose (&jpeg_info);
229
230 srcinfo.err = jpeg_std_error (&(jsrcerr.pub));
231 jsrcerr.pub.error_exit = fatal_error_handler;
232 jsrcerr.pub.output_message = output_message_handler;
233 jsrcerr.error = error;
234
235 jpeg_create_decompress (&srcinfo);
236
237 if (sigsetjmp (jsrcerr.setjmp_buffer, 1))
238 goto stop_loading;
239
240 _jpeg_memory_src (&srcinfo, in_buffer, in_buffer_size);
241
242 jpeg_read_header (&srcinfo, TRUE);
243
244 srcinfo.out_color_space = srcinfo.jpeg_color_space; /* make all the color space conversions manually */
245
246 load_scaled = (requested_size > 0) && (requested_size < srcinfo.image_width) && (requested_size < srcinfo.image_height);
247 if (load_scaled) {
248 for (srcinfo.scale_denom = 1; srcinfo.scale_denom <= 16; srcinfo.scale_denom++) {
249 jpeg_calc_output_dimensions (&srcinfo);
250 if ((srcinfo.output_width < requested_size) || (srcinfo.output_height < requested_size)) {
251 srcinfo.scale_denom -= 1;
252 break;
253 }
254 }
255
256 if (srcinfo.scale_denom <= 0) {
257 srcinfo.scale_denom = srcinfo.scale_num;
258 load_scaled = FALSE;
259 }
260 }
261
262 jpeg_calc_output_dimensions (&srcinfo);
263
264 buffer_stride = srcinfo.output_width * srcinfo.output_components;
265 buffer = (*srcinfo.mem->alloc_sarray) ((j_common_ptr) &srcinfo, JPOOL_IMAGE, buffer_stride, srcinfo.rec_outbuf_height);
266
267 jpeg_start_decompress (&srcinfo);
268
269 output_width = MIN (srcinfo.output_width, CAIRO_MAX_IMAGE_SIZE);
270 output_height = MIN (srcinfo.output_height, CAIRO_MAX_IMAGE_SIZE);
271 _cairo_image_surface_transform_get_steps (CAIRO_FORMAT_ARGB32,
272 output_width,
273 output_height,
274 orientation,
275 &destination_width,
276 &destination_height,
277 &line_start,
278 &line_step,
279 &pixel_step);
280
281 #if 0
282 g_print ("requested: %d, original [%d, %d] ==> load at [%d, %d]\n",
283 requested_size,
284 srcinfo.image_width,
285 srcinfo.image_height,
286 destination_width,
287 destination_height);
288 #endif
289
290 surface = _cairo_image_surface_create (CAIRO_FORMAT_ARGB32, destination_width, destination_height);
291 if (surface == NULL) {
292 jpeg_destroy_decompress (&srcinfo);
293 g_free (in_buffer);
294
295 return image;
296 }
297
298 metadata = _cairo_image_surface_get_metadata (surface);
299 _cairo_metadata_set_has_alpha (metadata, FALSE);
300 surface_data = _cairo_image_surface_flush_and_get_data (surface);
301 surface_row = surface_data + line_start;
302 scanned_lines = 0;
303
304 switch (srcinfo.out_color_space) {
305 case JCS_CMYK:
306 {
307 register unsigned char *cmyk_tab;
308 int c, m, y, k, ki;
309
310 CMYK_table_init ();
311 cmyk_tab = CMYK_Tab;
312
313 while (srcinfo.output_scanline < output_height) {
314 if (g_cancellable_is_cancelled (cancellable))
315 goto stop_loading;
316
317 n_lines = jpeg_read_scanlines (&srcinfo, buffer, srcinfo.rec_outbuf_height);
318 if (scanned_lines + n_lines > output_height)
319 n_lines = output_height - scanned_lines;
320
321 buffer_row = buffer;
322 for (l = 0; l < n_lines; l++) {
323 p_surface = surface_row;
324 p_buffer = buffer_row[l];
325
326 if (g_cancellable_is_cancelled (cancellable))
327 goto stop_loading;
328
329 for (x = 0; x < output_width; x++) {
330 if (srcinfo.saw_Adobe_marker) {
331 c = p_buffer[0];
332 m = p_buffer[1];
333 y = p_buffer[2];
334 k = p_buffer[3];
335 }
336 else {
337 c = 255 - p_buffer[0];
338 m = 255 - p_buffer[1];
339 y = 255 - p_buffer[2];
340 k = 255 - p_buffer[3];
341 }
342
343 ki = k << 8; /* ki = k * 256 */
344 r = cmyk_tab[ki + c];
345 g = cmyk_tab[ki + m];
346 b = cmyk_tab[ki + y];
347 pixel = CAIRO_RGBA_TO_UINT32 (r, g, b, 0xff);
348 memcpy (p_surface, &pixel, sizeof (guint32));
349
350 p_surface += pixel_step;
351 p_buffer += 4 /*srcinfo.output_components*/;
352 }
353
354 surface_row += line_step;
355 buffer_row += buffer_stride;
356 scanned_lines += 1;
357 }
358 }
359 }
360 break;
361
362 case JCS_GRAYSCALE:
363 {
364 while (srcinfo.output_scanline < output_height) {
365 if (g_cancellable_is_cancelled (cancellable))
366 goto stop_loading;
367
368 n_lines = jpeg_read_scanlines (&srcinfo, buffer, srcinfo.rec_outbuf_height);
369 if (scanned_lines + n_lines > output_height)
370 n_lines = output_height - scanned_lines;
371
372 buffer_row = buffer;
373 for (l = 0; l < n_lines; l++) {
374 p_surface = surface_row;
375 p_buffer = buffer_row[l];
376
377 if (g_cancellable_is_cancelled (cancellable))
378 goto stop_loading;
379
380 for (x = 0; x < output_width; x++) {
381 r = g = b = p_buffer[0];
382 pixel = CAIRO_RGBA_TO_UINT32 (r, g, b, 0xff);
383 memcpy (p_surface, &pixel, sizeof (guint32));
384
385 p_surface += pixel_step;
386 p_buffer += 1 /*srcinfo.output_components*/;
387 }
388
389 surface_row += line_step;
390 buffer_row += buffer_stride;
391 scanned_lines += 1;
392 }
393 }
394 }
395 break;
396
397 case JCS_RGB:
398 {
399 while (srcinfo.output_scanline < output_height) {
400 if (g_cancellable_is_cancelled (cancellable))
401 goto stop_loading;
402
403 n_lines = jpeg_read_scanlines (&srcinfo, buffer, srcinfo.rec_outbuf_height);
404 if (scanned_lines + n_lines > output_height)
405 n_lines = output_height - scanned_lines;
406
407 buffer_row = buffer;
408 for (l = 0; l < n_lines; l++) {
409 p_surface = surface_row;
410 p_buffer = buffer_row[l];
411
412 if (g_cancellable_is_cancelled (cancellable))
413 goto stop_loading;
414
415 for (x = 0; x < output_width; x++) {
416 r = p_buffer[0];
417 g = p_buffer[1];
418 b = p_buffer[2];
419 pixel = CAIRO_RGBA_TO_UINT32 (r, g, b, 0xff);
420 memcpy (p_surface, &pixel, sizeof (guint32));
421
422 p_surface += pixel_step;
423 p_buffer += 3 /*srcinfo.output_components*/;
424 }
425
426 surface_row += line_step;
427 buffer_row += buffer_stride;
428 scanned_lines += 1;
429 }
430 }
431 }
432 break;
433
434 case JCS_YCbCr:
435 {
436 register JSAMPLE *range_limit = srcinfo.sample_range_limit;
437 register int *r_cr_tab;
438 register int *g_cb_tab;
439 register int *g_cr_tab;
440 register int *b_cb_tab;
441 int Y, Cb, Cr;
442
443 YCbCr_tables_init ();
444 r_cr_tab = YCbCr_R_Cr_Tab;
445 g_cb_tab = YCbCr_G_Cb_Tab;
446 g_cr_tab = YCbCr_G_Cr_Tab;
447 b_cb_tab = YCbCr_B_Cb_Tab;
448
449 while (srcinfo.output_scanline < output_height) {
450 if (g_cancellable_is_cancelled (cancellable))
451 goto stop_loading;
452
453 n_lines = jpeg_read_scanlines (&srcinfo, buffer, srcinfo.rec_outbuf_height);
454 if (scanned_lines + n_lines > output_height)
455 n_lines = output_height - scanned_lines;
456
457 buffer_row = buffer;
458 for (l = 0; l < n_lines; l++) {
459 p_surface = surface_row;
460 p_buffer = buffer_row[l];
461
462 if (g_cancellable_is_cancelled (cancellable))
463 goto stop_loading;
464
465 for (x = 0; x < output_width; x++) {
466 Y = p_buffer[0];
467 Cb = p_buffer[1];
468 Cr = p_buffer[2];
469
470 r = range_limit[Y + r_cr_tab[Cr]];
471 g = range_limit[Y + SCALE_DOWN (g_cb_tab[Cb] + g_cr_tab[Cr])];
472 b = range_limit[Y + b_cb_tab[Cb]];
473 pixel = CAIRO_RGBA_TO_UINT32 (r, g, b, 0xff);
474 memcpy (p_surface, &pixel, sizeof (guint32));
475
476 p_surface += pixel_step;
477 p_buffer += 3 /*srcinfo.output_components*/;
478 }
479
480 surface_row += line_step;
481 buffer_row += buffer_stride;
482 scanned_lines += 1;
483 }
484 }
485 }
486 break;
487
488 case JCS_YCCK:
489 {
490 register JSAMPLE *range_limit = srcinfo.sample_range_limit;
491 register int *r_cr_tab;
492 register int *g_cb_tab;
493 register int *g_cr_tab;
494 register int *b_cb_tab;
495 register guchar *cmyk_tab;
496 int Y, Cb, Cr, K, Ki, c, m , y;
497
498 YCbCr_tables_init ();
499 r_cr_tab = YCbCr_R_Cr_Tab;
500 g_cb_tab = YCbCr_G_Cb_Tab;
501 g_cr_tab = YCbCr_G_Cr_Tab;
502 b_cb_tab = YCbCr_B_Cb_Tab;
503
504 CMYK_table_init ();
505 cmyk_tab = CMYK_Tab;
506
507 while (srcinfo.output_scanline < output_height) {
508 if (g_cancellable_is_cancelled (cancellable))
509 goto stop_loading;
510
511 n_lines = jpeg_read_scanlines (&srcinfo, buffer, srcinfo.rec_outbuf_height);
512 if (scanned_lines + n_lines > output_height)
513 n_lines = output_height - scanned_lines;
514
515 buffer_row = buffer;
516 for (l = 0; l < n_lines; l++) {
517 p_surface = surface_row;
518 p_buffer = buffer_row[l];
519
520 if (g_cancellable_is_cancelled (cancellable))
521 goto stop_loading;
522
523 for (x = 0; x < output_width; x++) {
524 Y = p_buffer[0];
525 Cb = p_buffer[1];
526 Cr = p_buffer[2];
527 K = p_buffer[3];
528
529 c = range_limit[255 - (Y + r_cr_tab[Cr])];
530 m = range_limit[255 - (Y + SCALE_DOWN (g_cb_tab[Cb] + g_cr_tab[Cr]))];
531 y = range_limit[255 - (Y + b_cb_tab[Cb])];
532
533 Ki = K << 8; /* ki = K * 256 */
534
535 r = cmyk_tab[Ki + c];
536 g = cmyk_tab[Ki + m];
537 b = cmyk_tab[Ki + y];
538 pixel = CAIRO_RGBA_TO_UINT32 (r, g, b, 0xff);
539 memcpy (p_surface, &pixel, sizeof (guint32));
540
541 p_surface += pixel_step;
542 p_buffer += 4 /*srcinfo.output_components*/;
543 }
544
545 surface_row += line_step;
546 buffer_row += buffer_stride;
547 scanned_lines += 1;
548 }
549 }
550 }
551 break;
552
553 case JCS_UNKNOWN:
554 default:
555 g_set_error (error,
556 GDK_PIXBUF_ERROR,
557 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
558 _("Unknown JPEG color space (%d)"),
559 srcinfo.out_color_space);
560 break;
561 }
562
563 read_all_scanlines = TRUE;
564
565 stop_loading:
566
567 if (! finished) {
568 finished = TRUE;
569
570 if (surface != NULL) {
571 cairo_surface_mark_dirty (surface);
572
573 if (! g_cancellable_is_cancelled (cancellable)) {
574 int original_width;
575 int original_height;
576
577 /* Set the original dimensions */
578
579 if ((orientation == GTH_TRANSFORM_ROTATE_90)
580 || (orientation == GTH_TRANSFORM_ROTATE_270)
581 || (orientation == GTH_TRANSFORM_TRANSPOSE)
582 || (orientation == GTH_TRANSFORM_TRANSVERSE))
583 {
584 original_width = srcinfo.image_height;
585 original_height = srcinfo.image_width;
586 }
587 else {
588 original_width = srcinfo.image_width;
589 original_height = srcinfo.image_height;
590 }
591
592 _cairo_metadata_set_original_size (metadata, original_width, original_height);
593
594 if (original_width_p != NULL)
595 *original_width_p = original_width;
596 if (original_height_p != NULL)
597 *original_height_p = original_height;
598 if (loaded_original_p != NULL)
599 *loaded_original_p = ! load_scaled;
600
601 /*_cairo_image_surface_set_attribute_int (surface, "Image::Rotation", rotation); FIXME*/
602 /* FIXME _cairo_image_surface_set_attribute (surface, "Jpeg::ColorSpace", jpeg_color_space_name (srcinfo.jpeg_color_space)); */
603
604 gth_image_set_cairo_surface (image, surface);
605 }
606 else
607 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CANCELLED, "");
608
609 cairo_surface_destroy (surface);
610 surface = NULL; /* ignore other jpeg errors */
611 }
612
613 if (read_all_scanlines)
614 jpeg_finish_decompress (&srcinfo);
615 else
616 jpeg_abort_decompress (&srcinfo);
617 jpeg_destroy_decompress (&srcinfo);
618 }
619
620 g_free (in_buffer);
621
622 return image;
623 }
624
625
626 #undef SCALE_FACTOR
627 #undef SCALE_UP
628 #undef SCALE_DOWN
629 #undef ONE_HALF
630