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