cairo-image-surface-jpeg.c 14.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */

/*
 *  GThumb
 *
 *  Copyright (C) 2011 Free Software Foundation, Inc.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <config.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <setjmp.h>
#include <jpeglib.h>
#include <gthumb.h>
#include <extensions/jpeg_utils/jmemorysrc.h>
Paolo Bacchilega's avatar
Paolo Bacchilega committed
30
#include <extensions/jpeg_utils/jpeg-info.h>
31
#include "cairo-image-surface-jpeg.h"
32 33 34 35


/* error handler data */

36

37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
struct error_handler_data {
	struct jpeg_error_mgr   pub;
	sigjmp_buf              setjmp_buffer;
        GError                **error;
};


static void
fatal_error_handler (j_common_ptr cinfo)
{
	struct error_handler_data *errmgr;
        char buffer[JMSG_LENGTH_MAX];

	errmgr = (struct error_handler_data *) cinfo->err;

        /* Create the message */
        (* cinfo->err->format_message) (cinfo, buffer);

        /* broken check for *error == NULL for robustness against
         * crappy JPEG library
         */
        if (errmgr->error && *errmgr->error == NULL) {
                g_set_error (errmgr->error,
                             GDK_PIXBUF_ERROR,
                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
62
			     _("Error interpreting JPEG image file: %s"),
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
                             buffer);
        }

	siglongjmp (errmgr->setjmp_buffer, 1);

        g_assert_not_reached ();
}


static void
output_message_handler (j_common_ptr cinfo)
{
	/* This method keeps libjpeg from dumping crap to stderr */
	/* do nothing */
}


80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
/* tables with pre-multiplied values */


static unsigned char *CMYK_Tab = NULL;
static int           *YCbCr_R_Cr_Tab = NULL;
static int           *YCbCr_G_Cb_Tab = NULL;
static int           *YCbCr_G_Cr_Tab = NULL;
static int           *YCbCr_B_Cb_Tab = NULL;


#define SCALE_FACTOR   16
#define SCALE_UP(x)    ((gint32) ((x) * (1L << SCALE_FACTOR) + 0.5))
#define SCALE_DOWN(x)  ((x) >> SCALE_FACTOR)
#define ONE_HALF       ((gint32) (1 << (SCALE_FACTOR - 1)))


static void
CMYK_table_init (void)
{
	if (CMYK_Tab == NULL) {
		int    v, k, i;
		double k1;

		/* tab[k * 256 + v] = v * k / 255.0 */

		CMYK_Tab = g_new (unsigned char, 256 * 256);
		i = 0;
		for (k = 0; k <= 255; k++) {
			k1 = (double) k / 255.0;
			for (v = 0; v <= 255; v++)
				CMYK_Tab[i++] = (double) v * k1;
		}
	}
}


static void
YCbCr_tables_init (void)
{
	if (YCbCr_R_Cr_Tab == NULL) {
		int i, v;

		YCbCr_R_Cr_Tab = g_new (int, 256);
		YCbCr_G_Cb_Tab = g_new (int, 256);
		YCbCr_G_Cr_Tab = g_new (int, 256);
		YCbCr_B_Cb_Tab = g_new (int, 256);

		for (i = 0, v = -128; i <= 255; i++, v++) {
			YCbCr_R_Cr_Tab[i] = SCALE_DOWN (SCALE_UP(1.402) * v + ONE_HALF);
			YCbCr_G_Cb_Tab[i] = - SCALE_UP (0.34414) * v;
			YCbCr_G_Cr_Tab[i] = - SCALE_UP (0.71414) * v + ONE_HALF;
			YCbCr_B_Cb_Tab[i] = SCALE_DOWN (SCALE_UP(1.77200) * v + ONE_HALF);
		}
	}
}


137
GthImage *
138 139
_cairo_image_surface_create_from_jpeg (GInputStream  *istream,
				       GthFileData   *file_data,
140 141 142 143 144 145 146 147
				       int            requested_size,
				       int           *original_width,
				       int           *original_height,
				       gpointer       user_data,
				       GCancellable  *cancellable,
				       GError       **error)
{
	GthImage                      *image;
148
	gboolean                       load_scaled;
149 150 151 152 153 154
	GthTransform                   orientation;
	int                            destination_width;
	int                            destination_height;
	int                            line_start;
	int                            line_step;
	int                            pixel_step;
155 156 157 158 159
	void                          *in_buffer;
	gsize                          in_buffer_size;
	struct error_handler_data      jsrcerr;
	struct jpeg_decompress_struct  srcinfo;
	cairo_surface_t               *surface;
160
	cairo_surface_metadata_t      *metadata;
161 162 163
	unsigned char                 *surface_row;
	JSAMPARRAY                     buffer;
	int                            buffer_stride;
164
	JDIMENSION                     n_lines;
165
	JSAMPARRAY                     buffer_row;
166
	int                            l;
167
	unsigned char                 *p_surface;
168 169
	guchar                         r, g, b;
	guint32                        pixel;
170
	unsigned char                 *p_buffer;
171
	int                            x;
172 173 174

	image = gth_image_new ();

175 176 177 178 179
	if (! _g_input_stream_read_all (istream,
			      	        &in_buffer,
			      	        &in_buffer_size,
			      	        cancellable,
			      	        error))
180 181 182 183
	{
		return image;
	}

184 185 186 187 188 189 190 191
	srcinfo.err = jpeg_std_error (&(jsrcerr.pub));
	jsrcerr.pub.error_exit = fatal_error_handler;
	jsrcerr.pub.output_message = output_message_handler;
	jsrcerr.error = error;

	jpeg_create_decompress (&srcinfo);

	if (sigsetjmp (jsrcerr.setjmp_buffer, 1)) {
Paolo Bacchilega's avatar
Paolo Bacchilega committed
192
		g_free (in_buffer);
193 194 195 196 197 198 199 200
		jpeg_destroy_decompress (&srcinfo);
		return image;
	}

	_jpeg_memory_src (&srcinfo, in_buffer, in_buffer_size);

	jpeg_read_header (&srcinfo, TRUE);

201 202
	srcinfo.out_color_space = srcinfo.jpeg_color_space; /* make all the color space conversions manually */

203 204 205
	load_scaled = (requested_size > 0) && (requested_size < srcinfo.image_width) && (requested_size < srcinfo.image_height);
	if (load_scaled) {
		for (srcinfo.scale_denom = 1; srcinfo.scale_denom <= 16; srcinfo.scale_denom++) {
206 207
			jpeg_calc_output_dimensions (&srcinfo);
			if ((srcinfo.output_width < requested_size) || (srcinfo.output_height < requested_size)) {
208
				srcinfo.scale_denom -= 1;
209 210 211 212 213 214
				break;
			}
		}

		if (srcinfo.scale_denom == 0)
			srcinfo.scale_denom = srcinfo.scale_num;
215 216

		jpeg_calc_output_dimensions (&srcinfo);
217 218 219 220
	}

	jpeg_start_decompress (&srcinfo);

221 222
	orientation = _jpeg_exif_orientation (in_buffer, in_buffer_size);
	_cairo_image_surface_transform_get_steps (CAIRO_FORMAT_ARGB32,
223 224
						  MIN (srcinfo.output_width, CAIRO_MAX_IMAGE_SIZE),
						  MIN (srcinfo.output_height, CAIRO_MAX_IMAGE_SIZE),
225 226 227 228 229 230 231
						  orientation,
						  &destination_width,
						  &destination_height,
						  &line_start,
						  &line_step,
						  &pixel_step);

232 233 234 235 236 237 238 239 240
#if 0
	g_print ("requested: %d, original [%d, %d] ==> load at [%d, %d]\n",
			requested_size,
			srcinfo.image_width,
			srcinfo.image_height,
			destination_width,
			destination_height);
#endif

241
	surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, destination_width, destination_height);
242 243 244 245 246 247 248 249 250
	if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) {
		/* g_warning ("%s", cairo_status_to_string (cairo_surface_status (surface))); */

		jpeg_destroy ((j_common_ptr) &srcinfo);
		cairo_surface_destroy (surface);
		g_free (in_buffer);

		return image;
	}
251 252
	metadata = _cairo_image_surface_get_metadata (surface);
	metadata->has_alpha = FALSE;
253
	cairo_surface_flush (surface);
254
	surface_row = cairo_image_surface_get_data (surface) + line_start;
255 256 257 258

	buffer_stride = srcinfo.output_width * srcinfo.output_components;
	buffer = (*srcinfo.mem->alloc_sarray) ((j_common_ptr) &srcinfo, JPOOL_IMAGE, buffer_stride, srcinfo.rec_outbuf_height);

259 260 261
	switch (srcinfo.out_color_space) {
	case JCS_CMYK:
		{
262 263 264 265 266
			register unsigned char *cmyk_tab;
			int c, m, y, k, ki;

			CMYK_table_init ();
			cmyk_tab = CMYK_Tab;
267 268 269 270 271 272 273 274 275 276 277 278 279

			while (srcinfo.output_scanline < srcinfo.output_height) {
				if (g_cancellable_is_cancelled (cancellable))
					break;

				n_lines = jpeg_read_scanlines (&srcinfo, buffer, srcinfo.rec_outbuf_height);

				buffer_row = buffer;
				for (l = 0; l < n_lines; l++) {
					p_surface = surface_row;
					p_buffer = buffer_row[l];

					for (x = 0; x < srcinfo.output_width; x++) {
280 281 282 283 284 285 286 287 288 289 290 291 292 293
						if (srcinfo.saw_Adobe_marker) {
							c = p_buffer[0];
							m = p_buffer[1];
							y = p_buffer[2];
							k = p_buffer[3];
						}
						else {
							c = 255 - p_buffer[0];
							m = 255 - p_buffer[1];
							y = 255 - p_buffer[2];
							k = 255 - p_buffer[3];
						}

						ki = k << 8; /* ki = k * 256 */
294 295 296
						r = cmyk_tab[ki + c];
						g = cmyk_tab[ki + m];
						b = cmyk_tab[ki + y];
297
						pixel = CAIRO_RGBA_TO_UINT32 (r, g, b, 0xff);
298
						memcpy (p_surface, &pixel, sizeof (guint32));
299

300
						p_surface += pixel_step;
301 302 303
						p_buffer += 4 /*srcinfo.output_components*/;
					}

304
					surface_row += line_step;
305 306
					buffer_row += buffer_stride;
				}
307
			}
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
		}
		break;

	case JCS_GRAYSCALE:
		{
			while (srcinfo.output_scanline < srcinfo.output_height) {
				if (g_cancellable_is_cancelled (cancellable))
					break;

				n_lines = jpeg_read_scanlines (&srcinfo, buffer, srcinfo.rec_outbuf_height);

				buffer_row = buffer;
				for (l = 0; l < n_lines; l++) {
					p_surface = surface_row;
					p_buffer = buffer_row[l];

					for (x = 0; x < srcinfo.output_width; x++) {
325
						r = g = b = p_buffer[0];
326
						pixel = CAIRO_RGBA_TO_UINT32 (r, g, b, 0xff);
327
						memcpy (p_surface, &pixel, sizeof (guint32));
328

329
						p_surface += pixel_step;
330 331 332
						p_buffer += 1 /*srcinfo.output_components*/;
					}

333
					surface_row += line_step;
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
					buffer_row += buffer_stride;
				}
			}
		}
		break;

	case JCS_RGB:
		{
			while (srcinfo.output_scanline < srcinfo.output_height) {
				if (g_cancellable_is_cancelled (cancellable))
					break;

				n_lines = jpeg_read_scanlines (&srcinfo, buffer, srcinfo.rec_outbuf_height);

				buffer_row = buffer;
				for (l = 0; l < n_lines; l++) {
					p_surface = surface_row;
					p_buffer = buffer_row[l];

					for (x = 0; x < srcinfo.output_width; x++) {
354 355 356
						r = p_buffer[0];
						g = p_buffer[1];
						b = p_buffer[2];
357
						pixel = CAIRO_RGBA_TO_UINT32 (r, g, b, 0xff);
358
						memcpy (p_surface, &pixel, sizeof (guint32));
359

360
						p_surface += pixel_step;
361 362 363
						p_buffer += 3 /*srcinfo.output_components*/;
					}

364
					surface_row += line_step;
365 366 367 368 369 370 371 372
					buffer_row += buffer_stride;
				}
			}
		}
		break;

	case JCS_YCbCr:
		{
373 374 375 376 377 378 379 380 381 382 383 384
			register JSAMPLE *range_limit = srcinfo.sample_range_limit;
			register int     *r_cr_tab;
			register int     *g_cb_tab;
			register int     *g_cr_tab;
			register int     *b_cb_tab;
			int               Y, Cb, Cr;

			YCbCr_tables_init ();
			r_cr_tab = YCbCr_R_Cr_Tab;
			g_cb_tab = YCbCr_G_Cb_Tab;
			g_cr_tab = YCbCr_G_Cr_Tab;
			b_cb_tab = YCbCr_B_Cb_Tab;
385 386 387 388 389 390

			while (srcinfo.output_scanline < srcinfo.output_height) {
				if (g_cancellable_is_cancelled (cancellable))
					break;

				n_lines = jpeg_read_scanlines (&srcinfo, buffer, srcinfo.rec_outbuf_height);
391

392 393 394 395 396 397
				buffer_row = buffer;
				for (l = 0; l < n_lines; l++) {
					p_surface = surface_row;
					p_buffer = buffer_row[l];

					for (x = 0; x < srcinfo.output_width; x++) {
398 399 400
						Y = p_buffer[0];
						Cb = p_buffer[1];
						Cr = p_buffer[2];
401

402 403 404
						r = range_limit[Y + r_cr_tab[Cr]];
						g = range_limit[Y + SCALE_DOWN (g_cb_tab[Cb] + g_cr_tab[Cr])];
						b = range_limit[Y + b_cb_tab[Cb]];
405
						pixel = CAIRO_RGBA_TO_UINT32 (r, g, b, 0xff);
406
						memcpy (p_surface, &pixel, sizeof (guint32));
407

408
						p_surface += pixel_step;
409 410 411
						p_buffer += 3 /*srcinfo.output_components*/;
					}

412
					surface_row += line_step;
413 414 415
					buffer_row += buffer_stride;
				}
			}
416
		}
417 418 419
		break;

	case JCS_YCCK:
420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
		{
			register JSAMPLE *range_limit = srcinfo.sample_range_limit;
			register int     *r_cr_tab;
			register int     *g_cb_tab;
			register int     *g_cr_tab;
			register int     *b_cb_tab;
			register guchar  *cmyk_tab;
			int               Y, Cb, Cr, K, Ki, c, m , y;

			YCbCr_tables_init ();
			r_cr_tab = YCbCr_R_Cr_Tab;
			g_cb_tab = YCbCr_G_Cb_Tab;
			g_cr_tab = YCbCr_G_Cr_Tab;
			b_cb_tab = YCbCr_B_Cb_Tab;

			CMYK_table_init ();
			cmyk_tab = CMYK_Tab;

			while (srcinfo.output_scanline < srcinfo.output_height) {
				if (g_cancellable_is_cancelled (cancellable))
					break;

				n_lines = jpeg_read_scanlines (&srcinfo, buffer, srcinfo.rec_outbuf_height);

				buffer_row = buffer;
				for (l = 0; l < n_lines; l++) {
					p_surface = surface_row;
					p_buffer = buffer_row[l];

					for (x = 0; x < srcinfo.output_width; x++) {
						Y = p_buffer[0];
						Cb = p_buffer[1];
						Cr = p_buffer[2];
						K = p_buffer[3];

						c = range_limit[255 - (Y + r_cr_tab[Cr])];
						m = range_limit[255 - (Y + SCALE_DOWN (g_cb_tab[Cb] + g_cr_tab[Cr]))];
						y = range_limit[255 - (Y + b_cb_tab[Cb])];

						Ki = K << 8; /* ki = K * 256 */
460 461 462 463

						r = cmyk_tab[Ki + c];
						g = cmyk_tab[Ki + m];
						b = cmyk_tab[Ki + y];
464
						pixel = CAIRO_RGBA_TO_UINT32 (r, g, b, 0xff);
465
						memcpy (p_surface, &pixel, sizeof (guint32));
466

467
						p_surface += pixel_step;
468 469 470
						p_buffer += 4 /*srcinfo.output_components*/;
					}

471
					surface_row += line_step;
472 473 474 475 476 477
					buffer_row += buffer_stride;
				}
			}
		}
		break;

478 479
	case JCS_UNKNOWN:
	default:
480 481 482 483 484
		g_set_error (error,
                             GDK_PIXBUF_ERROR,
                             GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
                             _("Unknown JPEG color space (%d)"),
                             srcinfo.out_color_space);
485
		break;
486 487
	}

488
	if (! g_cancellable_is_cancelled (cancellable)) {
489 490
		cairo_surface_mark_dirty (surface);

491 492
		/* Scale to the requested size */

493
		if (load_scaled) {
494 495 496 497 498 499 500
			cairo_surface_t *scaled;
			int              width;
			int              height;

			width = destination_width;
			height = destination_height;
			scale_keeping_ratio (&width, &height, requested_size, requested_size, TRUE);
501
			scaled = _cairo_image_surface_scale (surface, width, height, SCALE_FILTER_BEST, NULL);
502 503 504 505

			cairo_surface_destroy (surface);
			surface = scaled;
		}
506

507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
		/* Set the original dimensions */

		if ((orientation == GTH_TRANSFORM_ROTATE_90)
		     ||	(orientation == GTH_TRANSFORM_ROTATE_270)
		     ||	(orientation == GTH_TRANSFORM_TRANSPOSE)
		     ||	(orientation == GTH_TRANSFORM_TRANSVERSE))
		{
			if (original_width != NULL)
				*original_width = srcinfo.image_height;
			if (original_height != NULL)
				*original_height = srcinfo.image_width;
		}
		else {
			if (original_width != NULL)
				*original_width = srcinfo.image_width;
			if (original_height != NULL)
				*original_height = srcinfo.image_height;
		}

		/*_cairo_image_surface_set_attribute_int (surface, "Image::Rotation", rotation); FIXME*/

		/* FIXME _cairo_image_surface_set_attribute (surface, "Jpeg::ColorSpace", jpeg_color_space_name (srcinfo.jpeg_color_space)); */
529

530
		gth_image_set_cairo_surface (image, surface);
531 532 533

		jpeg_finish_decompress (&srcinfo);
		jpeg_destroy_decompress (&srcinfo);
534
	}
535
	else {
536
		jpeg_destroy ((j_common_ptr) &srcinfo);
537 538
		g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CANCELLED, "");
	}
539 540 541 542 543 544

	cairo_surface_destroy (surface);
	g_free (in_buffer);

	return image;
}
545 546 547 548 549 550


#undef SCALE_FACTOR
#undef SCALE_UP
#undef SCALE_DOWN
#undef ONE_HALF