1/* -*- mode: C; c-file-style: "linux" -*- */
2/* GdkPixbuf library - JPEG image loader
3 *
4 * Copyright (C) 1999 Michael Zucchi
5 * Copyright (C) 1999 The Free Software Foundation
6 *
7 * Progressive loading code Copyright (C) 1999 Red Hat, Inc.
8 *
9 * Authors: Michael Zucchi <zucchi@zedzone.mmc.com.au>
10 * Federico Mena-Quintero <federico@gimp.org>
11 * Michael Fulbright <drmike@redhat.com>
12 *
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2 of the License, or (at your option) any later version.
17 *
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
25 */
26
27
28#include "config.h"
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <setjmp.h>
33#include <jpeglib.h>
34#include <jerror.h>
35#include <math.h>
36#include <glib/gi18n-lib.h>
37#include "gdk-pixbuf-io.h"
38#include "fallback-c89.c"
39
40#ifndef HAVE_SIGSETJMP
41#define sigjmp_buf jmp_buf
42#define sigsetjmp(jb, x) setjmp(jb)
43#define siglongjmp longjmp
44#endif
45
46
47/* Helper macros to convert between density units */
48#define DPCM_TO_DPI(value) ((int) round ((value) * 2.54))
49
50/* we are a "source manager" as far as libjpeg is concerned */
51#define JPEG_PROG_BUF_SIZE 65536
52
53typedef struct {
54 struct jpeg_source_mgr pub; /* public fields */
55
56 JOCTET buffer[JPEG_PROG_BUF_SIZE]; /* start of buffer */
57 long skip_next; /* number of bytes to skip next read */
58
59} my_source_mgr;
60
61typedef my_source_mgr * my_src_ptr;
62
63/* error handler data */
64struct error_handler_data {
65 struct jpeg_error_mgr pub;
66 sigjmp_buf setjmp_buffer;
67 GError **error;
68};
69
70/* progressive loader context */
71typedef struct {
72 GdkPixbufModuleSizeFunc size_func;
73 GdkPixbufModuleUpdatedFunc updated_func;
74 GdkPixbufModulePreparedFunc prepared_func;
75 gpointer user_data;
76
77 GdkPixbuf *pixbuf;
78 guchar *dptr; /* current position in pixbuf */
79
80 gboolean did_prescan; /* are we in image data yet? */
81 gboolean got_header; /* have we loaded jpeg header? */
82 gboolean src_initialized;/* TRUE when jpeg lib initialized */
83 gboolean in_output; /* did we get suspended in an output pass? */
84 struct jpeg_decompress_struct cinfo;
85 struct error_handler_data jerr;
86} JpegProgContext;
87
88/* EXIF context */
89typedef struct {
90 gint orientation;
91 gchar *icc_profile;
92 gsize icc_profile_size;
93 gsize icc_profile_size_allocated;
94} JpegExifContext;
95
96static GdkPixbuf *gdk_pixbuf__jpeg_image_load (FILE *f, GError **error);
97static gpointer gdk_pixbuf__jpeg_image_begin_load (GdkPixbufModuleSizeFunc func0,
98 GdkPixbufModulePreparedFunc func1,
99 GdkPixbufModuleUpdatedFunc func2,
100 gpointer user_data,
101 GError **error);
102static gboolean gdk_pixbuf__jpeg_image_stop_load (gpointer context, GError **error);
103static gboolean gdk_pixbuf__jpeg_image_load_increment(gpointer context,
104 const guchar *buf, guint size,
105 GError **error);
106static gboolean gdk_pixbuf__jpeg_image_load_lines (JpegProgContext *context,
107 GError **error);
108
109static void
110fatal_error_handler (j_common_ptr cinfo)
111{
112 struct error_handler_data *errmgr;
113 char buffer[JMSG_LENGTH_MAX];
114
115 errmgr = (struct error_handler_data *) cinfo->err;
116
117 /* Create the message */
118 (* cinfo->err->format_message) (cinfo, buffer);
119
120 /* broken check for *error == NULL for robustness against
121 * crappy JPEG library
122 */
123 if (errmgr->error && *errmgr->error == NULL) {
124 g_set_error (err: errmgr->error,
125 GDK_PIXBUF_ERROR,
126 code: cinfo->err->msg_code == JERR_OUT_OF_MEMORY
127 ? GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY
128 : GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
129 _("Error interpreting JPEG image file (%s)"),
130 buffer);
131 }
132
133 siglongjmp (env: errmgr->setjmp_buffer, val: 1);
134
135 g_assert_not_reached ();
136}
137
138static void
139output_message_handler (j_common_ptr cinfo)
140{
141 /* This method keeps libjpeg from dumping crap to stderr */
142
143 /* do nothing */
144}
145
146/* explode gray image data from jpeg library into rgb components in pixbuf */
147static void
148explode_gray_into_buf (struct jpeg_decompress_struct *cinfo,
149 guchar **lines)
150{
151 gint i, j;
152 guint w;
153
154 g_return_if_fail (cinfo != NULL);
155 g_return_if_fail (cinfo->output_components == 1);
156 g_return_if_fail (cinfo->out_color_space == JCS_GRAYSCALE);
157
158 /* Expand grey->colour. Expand from the end of the
159 * memory down, so we can use the same buffer.
160 */
161 w = cinfo->output_width;
162 for (i = cinfo->rec_outbuf_height - 1; i >= 0; i--) {
163 guchar *from, *to;
164
165 from = lines[i] + w - 1;
166 to = lines[i] + (w - 1) * 3;
167 for (j = w - 1; j >= 0; j--) {
168 to[0] = from[0];
169 to[1] = from[0];
170 to[2] = from[0];
171 to -= 3;
172 from--;
173 }
174 }
175}
176
177
178static void
179convert_cmyk_to_rgb (struct jpeg_decompress_struct *cinfo,
180 guchar **lines)
181{
182 gint i, j;
183
184 g_return_if_fail (cinfo != NULL);
185 g_return_if_fail (cinfo->output_components == 4);
186 g_return_if_fail (cinfo->out_color_space == JCS_CMYK);
187
188 for (i = cinfo->rec_outbuf_height - 1; i >= 0; i--) {
189 guchar *p;
190
191 p = lines[i];
192 for (j = 0; j < cinfo->output_width; j++) {
193 int c, m, y, k;
194 c = p[0];
195 m = p[1];
196 y = p[2];
197 k = p[3];
198
199 /* We now assume that all CMYK JPEG files
200 * use inverted CMYK, as Photoshop does
201 * See https://bugzilla.gnome.org/show_bug.cgi?id=618096 */
202 p[0] = k*c / 255;
203 p[1] = k*m / 255;
204 p[2] = k*y / 255;
205 p[3] = 255;
206 p += 4;
207 }
208 }
209}
210
211typedef struct {
212 struct jpeg_source_mgr pub; /* public fields */
213
214 FILE * infile; /* source stream */
215 JOCTET * buffer; /* start of buffer */
216 boolean start_of_file; /* have we gotten any data yet? */
217} stdio_source_mgr;
218
219typedef stdio_source_mgr * stdio_src_ptr;
220
221static void
222stdio_init_source (j_decompress_ptr cinfo)
223{
224 stdio_src_ptr src = (stdio_src_ptr)cinfo->src;
225 src->start_of_file = FALSE;
226}
227
228static boolean
229stdio_fill_input_buffer (j_decompress_ptr cinfo)
230{
231 stdio_src_ptr src = (stdio_src_ptr) cinfo->src;
232 size_t nbytes;
233
234 nbytes = fread (ptr: src->buffer, size: 1, JPEG_PROG_BUF_SIZE, stream: src->infile);
235
236 if (nbytes <= 0) {
237#if 0
238 if (src->start_of_file) /* Treat empty input file as fatal error */
239 ERREXIT(cinfo, JERR_INPUT_EMPTY);
240 WARNMS(cinfo, JWRN_JPEG_EOF);
241#endif
242 /* Insert a fake EOI marker */
243 src->buffer[0] = (JOCTET) 0xFF;
244 src->buffer[1] = (JOCTET) JPEG_EOI;
245 nbytes = 2;
246 }
247
248 src->pub.next_input_byte = src->buffer;
249 src->pub.bytes_in_buffer = nbytes;
250 src->start_of_file = FALSE;
251
252 return TRUE;
253}
254
255static void
256stdio_skip_input_data (j_decompress_ptr cinfo, long num_bytes)
257{
258 stdio_src_ptr src = (stdio_src_ptr) cinfo->src;
259
260 if (num_bytes > 0) {
261 while (num_bytes > (long) src->pub.bytes_in_buffer) {
262 num_bytes -= (long) src->pub.bytes_in_buffer;
263 (void)stdio_fill_input_buffer(cinfo);
264 }
265 src->pub.next_input_byte += (size_t) num_bytes;
266 src->pub.bytes_in_buffer -= (size_t) num_bytes;
267 }
268}
269
270static void
271stdio_term_source (j_decompress_ptr cinfo)
272{
273}
274
275static gchar *
276colorspace_name (const J_COLOR_SPACE jpeg_color_space)
277{
278 switch (jpeg_color_space) {
279 case JCS_UNKNOWN: return "UNKNOWN";
280 case JCS_GRAYSCALE: return "GRAYSCALE";
281 case JCS_RGB: return "RGB";
282 case JCS_YCbCr: return "YCbCr";
283 case JCS_CMYK: return "CMYK";
284 case JCS_YCCK: return "YCCK";
285 default: return "invalid";
286 }
287}
288
289#define DE_ENDIAN16(val) endian == G_BIG_ENDIAN ? GUINT16_FROM_BE(val) : GUINT16_FROM_LE(val)
290#define DE_ENDIAN32(val) endian == G_BIG_ENDIAN ? GUINT32_FROM_BE(val) : GUINT32_FROM_LE(val)
291
292#define ENDIAN16_IT(val) endian == G_BIG_ENDIAN ? GUINT16_TO_BE(val) : GUINT16_TO_LE(val)
293#define ENDIAN32_IT(val) endian == G_BIG_ENDIAN ? GUINT32_TO_BE(val) : GUINT32_TO_LE(val)
294
295static unsigned short de_get16(void *ptr, guint endian)
296{
297 unsigned short val;
298
299 memcpy(dest: &val, src: ptr, n: sizeof(val));
300 val = DE_ENDIAN16(val);
301
302 return val;
303}
304
305static unsigned int de_get32(void *ptr, guint endian)
306{
307 unsigned int val;
308
309 memcpy(dest: &val, src: ptr, n: sizeof(val));
310 val = DE_ENDIAN32(val);
311
312 return val;
313}
314
315/* application specific data segment */
316static gboolean
317jpeg_parse_exif_app2_segment (JpegExifContext *context, jpeg_saved_marker_ptr marker)
318{
319 guint ret = FALSE;
320 guint sequence_number;
321 guint number_of_chunks;
322 guint chunk_size;
323 guint offset;
324
325 /* do we have enough data? */
326 if (marker->data_length < 16)
327 goto out;
328
329 /* unique identification string */
330 if (memcmp (s1: marker->data, s2: "ICC_PROFILE\0", n: 12) != 0)
331 goto out;
332
333 /* get data about this segment */
334 sequence_number = marker->data[12];
335 number_of_chunks = marker->data[13];
336
337 /* this is invalid, the base offset is 1 */
338 if (sequence_number == 0)
339 goto out;
340
341 /* this is invalid, the base offset is 1 */
342 if (sequence_number > number_of_chunks)
343 goto out;
344
345 /* size includes the id (12 bytes), length field (1 byte), and sequence field (1 byte) */
346 chunk_size = marker->data_length - 14;
347 offset = (sequence_number - 1) * 0xffef;
348
349 /* Deal with the trivial profile (99% of images) to avoid allocating
350 * 64kb when we might only use a few kb. */
351 if (number_of_chunks == 1) {
352 if (context->icc_profile_size_allocated > 0)
353 goto out;
354 context->icc_profile_size = chunk_size;
355 context->icc_profile_size_allocated = chunk_size;
356 context->icc_profile = g_new (gchar, chunk_size);
357 /* copy the segment data to the profile space */
358 memcpy (dest: context->icc_profile, src: marker->data + 14, n: chunk_size);
359 goto out;
360 }
361
362 /* There is no promise the APP2 segments are going to be in order, so we
363 * have to allocate a huge swathe of memory and fill in the gaps when
364 * (if) we get the segment.
365 * Theoretically this could be as much as 16Mb, but display profiles are
366 * vary rarely above 100kb, and printer profiles are usually less than
367 * 2Mb */
368 if (context->icc_profile_size_allocated == 0) {
369 context->icc_profile_size_allocated = number_of_chunks * 0xffff;
370 context->icc_profile = g_new0 (gchar, number_of_chunks * 0xffff);
371 }
372
373 /* check the data will fit in our previously allocated buffer */
374 if (offset + chunk_size > context->icc_profile_size_allocated)
375 goto out;
376
377 /* copy the segment data to the profile space */
378 memcpy (dest: context->icc_profile + offset, src: marker->data + 14, n: chunk_size);
379
380 /* it's now this big plus the new data we've just copied */
381 context->icc_profile_size += chunk_size;
382
383 /* success */
384 ret = TRUE;
385out:
386 return ret;
387}
388
389static gboolean
390jpeg_parse_exif_app1 (JpegExifContext *context, jpeg_saved_marker_ptr marker)
391{
392 guint i;
393 guint ret = FALSE;
394 guint offset;
395 guint tags; /* number of tags in current ifd */
396 guint endian = 0; /* detected endian of data */
397 const char leth[] = {0x49, 0x49, 0x2a, 0x00}; // Little endian TIFF header
398 const char beth[] = {0x4d, 0x4d, 0x00, 0x2a}; // Big endian TIFF header
399
400 /* do we have enough data? */
401 if (marker->data_length < 4)
402 goto out;
403
404 /* unique identification string */
405 if (memcmp (s1: marker->data, s2: "Exif", n: 4) != 0)
406 goto out;
407
408 /* do we have enough data? */
409 if (marker->data_length < 32)
410 goto out;
411
412 /* Just skip data until TIFF header - it should be within 16 bytes from marker start.
413 Normal structure relative to APP1 marker -
414 0x0000: APP1 marker entry = 2 bytes
415 0x0002: APP1 length entry = 2 bytes
416 0x0004: Exif Identifier entry = 6 bytes
417 0x000A: Start of TIFF header (Byte order entry) - 4 bytes
418 - This is what we look for, to determine endianess.
419 0x000E: 0th IFD offset pointer - 4 bytes
420
421 marker->data points to the first data after the APP1 marker
422 and length entries, which is the exif identification string.
423 The TIFF header should thus normally be found at i=6, below,
424 and the pointer to IFD0 will be at 6+4 = 10.
425 */
426
427 for (i=0; i<16; i++) {
428 /* little endian TIFF header */
429 if (memcmp (s1: &marker->data[i], s2: leth, n: 4) == 0) {
430 endian = G_LITTLE_ENDIAN;
431 ret = TRUE;
432 break;
433 }
434
435 /* big endian TIFF header */
436 if (memcmp (s1: &marker->data[i], s2: beth, n: 4) == 0) {
437 endian = G_BIG_ENDIAN;
438 ret = TRUE;
439 break;
440 }
441 }
442
443 /* could not find header */
444 if (!ret)
445 goto out;
446
447 /* read out the offset pointer to IFD0 */
448 offset = de_get32(ptr: &marker->data[i] + 4, endian);
449 i = i + offset;
450
451 /* check that we still are within the buffer and can read the tag count */
452 {
453 const size_t new_i = i + 2;
454 if (new_i < i || new_i > marker->data_length) {
455 ret = FALSE;
456 goto out;
457 }
458
459 /* find out how many tags we have in IFD0. As per the TIFF spec, the first
460 two bytes of the IFD contain a count of the number of tags. */
461 tags = de_get16(ptr: &marker->data[i], endian);
462 i = new_i;
463 }
464
465 /* check that we still have enough data for all tags to check. The tags
466 are listed in consecutive 12-byte blocks. The tag ID, type, size, and
467 a pointer to the actual value, are packed into these 12 byte entries. */
468 {
469 const size_t new_i = i + tags * 12;
470 if (new_i < i || new_i > marker->data_length) {
471 ret = FALSE;
472 goto out;
473 }
474 }
475
476 /* check through IFD0 for tags */
477 while (tags--) {
478 size_t new_i;
479
480 /* We check for integer overflow before the loop and
481 * at the end of each iteration */
482 guint tag = de_get16(ptr: &marker->data[i + 0], endian);
483 guint type = de_get16(ptr: &marker->data[i + 2], endian);
484 guint count = de_get32(ptr: &marker->data[i + 4], endian);
485
486 /* orientation tag? */
487 if (tag == 0x112){
488
489 /* The orientation field should consist of a single 2-byte integer,
490 * but might be a signed long.
491 * Values of types smaller than 4 bytes are stored directly in the
492 * Value Offset field */
493 if (type == 0x3 && count == 1) {
494 guint short_value = de_get16(ptr: &marker->data[i + 8], endian);
495
496 context->orientation = short_value <= 8 ? short_value : 0;
497 } else if (type == 0x9 && count == 1) {
498 guint long_value = de_get32(ptr: &marker->data[i + 8], endian);
499
500 context->orientation = long_value <= 8 ? long_value : 0;
501 }
502 }
503 /* move the pointer to the next 12-byte tag field. */
504 new_i = i + 12;
505 if (new_i < i || new_i > marker->data_length) {
506 ret = FALSE;
507 goto out;
508 }
509 i = new_i;
510 }
511
512out:
513 return ret;
514}
515
516static void
517jpeg_parse_exif (JpegExifContext *context, j_decompress_ptr cinfo)
518{
519 jpeg_saved_marker_ptr cmarker;
520
521 /* check for interesting Exif markers */
522 cmarker = cinfo->marker_list;
523 while (cmarker != NULL) {
524 if (cmarker->marker == JPEG_APP0+1)
525 jpeg_parse_exif_app1 (context, marker: cmarker);
526 else if (cmarker->marker == JPEG_APP0+2)
527 jpeg_parse_exif_app2_segment (context, marker: cmarker);
528 cmarker = cmarker->next;
529 }
530}
531
532static gchar *
533jpeg_get_comment (j_decompress_ptr cinfo)
534{
535 jpeg_saved_marker_ptr cmarker;
536
537 cmarker = cinfo->marker_list;
538 while (cmarker != NULL) {
539 if (cmarker->marker == JPEG_COM)
540 return g_strndup (str: (const gchar *) cmarker->data, n: cmarker->data_length);
541 cmarker = cmarker->next;
542 }
543
544 return NULL;
545}
546
547static void
548jpeg_destroy_exif_context (JpegExifContext *context)
549{
550 g_free (mem: context->icc_profile);
551}
552
553/* Shared library entry point */
554static GdkPixbuf *
555gdk_pixbuf__real_jpeg_image_load (FILE *f, struct jpeg_decompress_struct *cinfo, GError **error)
556{
557 gint i;
558 char otag_str[5];
559 char *density_str;
560 GdkPixbuf * volatile pixbuf = NULL;
561 guchar *dptr;
562 guchar *lines[4]; /* Used to expand rows, via rec_outbuf_height,
563 * from the header file:
564 * " Usually rec_outbuf_height will be 1 or 2,
565 * at most 4."
566 */
567 guchar **lptr;
568 struct error_handler_data jerr;
569 stdio_src_ptr src;
570 gchar *icc_profile_base64;
571 gchar *comment;
572 JpegExifContext exif_context = { 0, };
573
574 /* setup error handler */
575 cinfo->err = jpeg_std_error (err: &jerr.pub);
576 jerr.pub.error_exit = fatal_error_handler;
577 jerr.pub.output_message = output_message_handler;
578 jerr.error = error;
579
580 if (sigsetjmp (jerr.setjmp_buffer, 1)) {
581 /* Whoops there was a jpeg error */
582 if (pixbuf)
583 g_object_unref (object: pixbuf);
584
585 jpeg_destroy_decompress (cinfo);
586 jpeg_destroy_exif_context (context: &exif_context);
587
588 /* error should have been set by fatal_error_handler () */
589 return NULL;
590 }
591
592 /* load header, setup */
593 jpeg_create_decompress (cinfo);
594
595 cinfo->src = (struct jpeg_source_mgr *)
596 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
597 sizeof (stdio_source_mgr));
598 src = (stdio_src_ptr) cinfo->src;
599 src->buffer = (JOCTET *)
600 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
601 JPEG_PROG_BUF_SIZE * sizeof (JOCTET));
602
603 src->pub.init_source = stdio_init_source;
604 src->pub.fill_input_buffer = stdio_fill_input_buffer;
605 src->pub.skip_input_data = stdio_skip_input_data;
606 src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
607 src->pub.term_source = stdio_term_source;
608 src->infile = f;
609 src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
610 src->pub.next_input_byte = NULL; /* until buffer loaded */
611
612 jpeg_save_markers (cinfo, JPEG_APP0+1, length_limit: 0xffff);
613 jpeg_save_markers (cinfo, JPEG_APP0+2, length_limit: 0xffff);
614 jpeg_save_markers (cinfo, JPEG_COM, length_limit: 0xffff);
615 jpeg_read_header (cinfo, TRUE);
616
617 /* parse exif data */
618 jpeg_parse_exif (context: &exif_context, cinfo);
619
620 jpeg_start_decompress (cinfo);
621 cinfo->do_fancy_upsampling = FALSE;
622 cinfo->do_block_smoothing = FALSE;
623
624 pixbuf = gdk_pixbuf_new (colorspace: GDK_COLORSPACE_RGB,
625 has_alpha: cinfo->out_color_components == 4 ? TRUE : FALSE,
626 bits_per_sample: 8,
627 width: cinfo->output_width,
628 height: cinfo->output_height);
629
630 if (!pixbuf) {
631 /* broken check for *error == NULL for robustness against
632 * crappy JPEG library
633 */
634 if (error && *error == NULL) {
635 g_set_error_literal (err: error,
636 GDK_PIXBUF_ERROR,
637 code: GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
638 _("Insufficient memory to load image, try exiting some applications to free memory"));
639 }
640
641 goto out;
642 }
643
644 comment = jpeg_get_comment (cinfo);
645 if (comment != NULL) {
646 gdk_pixbuf_set_option (pixbuf, key: "comment", value: comment);
647 g_free (mem: comment);
648 }
649
650 switch (cinfo->density_unit) {
651 case 1:
652 /* Dots per inch (no conversion required) */
653 density_str = g_strdup_printf (format: "%d", cinfo->X_density);
654 gdk_pixbuf_set_option (pixbuf, key: "x-dpi", value: density_str);
655 g_free (mem: density_str);
656 density_str = g_strdup_printf (format: "%d", cinfo->Y_density);
657 gdk_pixbuf_set_option (pixbuf, key: "y-dpi", value: density_str);
658 g_free (mem: density_str);
659 break;
660 case 2:
661 /* Dots per cm - convert into dpi */
662 density_str = g_strdup_printf (format: "%d", DPCM_TO_DPI (cinfo->X_density));
663 gdk_pixbuf_set_option (pixbuf, key: "x-dpi", value: density_str);
664 g_free (mem: density_str);
665 density_str = g_strdup_printf (format: "%d", DPCM_TO_DPI (cinfo->Y_density));
666 gdk_pixbuf_set_option (pixbuf, key: "y-dpi", value: density_str);
667 g_free (mem: density_str);
668 break;
669 }
670
671 /* if orientation tag was found */
672 if (exif_context.orientation != 0) {
673 g_snprintf (string: otag_str, n: sizeof (otag_str), format: "%d", exif_context.orientation);
674 gdk_pixbuf_set_option (pixbuf, key: "orientation", value: otag_str);
675 }
676
677 /* if icc profile was found */
678 if (exif_context.icc_profile != NULL) {
679 icc_profile_base64 = g_base64_encode (data: (const guchar *) exif_context.icc_profile, len: exif_context.icc_profile_size);
680 gdk_pixbuf_set_option (pixbuf, key: "icc-profile", value: icc_profile_base64);
681 g_free (mem: icc_profile_base64);
682 }
683
684 dptr = gdk_pixbuf_get_pixels (pixbuf);
685
686 /* decompress all the lines, a few at a time */
687 while (cinfo->output_scanline < cinfo->output_height) {
688 lptr = lines;
689 for (i = 0; i < cinfo->rec_outbuf_height; i++) {
690 *lptr++ = dptr;
691 dptr += gdk_pixbuf_get_rowstride (pixbuf);
692 }
693
694 jpeg_read_scanlines (cinfo, scanlines: lines, max_lines: cinfo->rec_outbuf_height);
695
696 switch (cinfo->out_color_space) {
697 case JCS_GRAYSCALE:
698 explode_gray_into_buf (cinfo, lines);
699 break;
700 case JCS_RGB:
701 /* do nothing */
702 break;
703 case JCS_CMYK:
704 convert_cmyk_to_rgb (cinfo, lines);
705 break;
706 default:
707 g_clear_object (&pixbuf);
708 g_set_error (err: error,
709 GDK_PIXBUF_ERROR,
710 code: GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
711 _("Unsupported JPEG color space (%s)"),
712 colorspace_name (jpeg_color_space: cinfo->out_color_space));
713 goto out;
714 }
715 }
716
717out:
718 jpeg_finish_decompress (cinfo);
719 jpeg_destroy_decompress (cinfo);
720 jpeg_destroy_exif_context (context: &exif_context);
721
722 return pixbuf;
723}
724
725static GdkPixbuf *
726gdk_pixbuf__jpeg_image_load (FILE *f, GError **error)
727{
728 struct jpeg_decompress_struct cinfo;
729
730 return gdk_pixbuf__real_jpeg_image_load (f, cinfo: &cinfo, error);
731}
732
733
734/**** Progressive image loading handling *****/
735
736/* these routines required because we are acting as a source manager for */
737/* libjpeg. */
738static void
739init_source (j_decompress_ptr cinfo)
740{
741 my_src_ptr src = (my_src_ptr) cinfo->src;
742
743 src->skip_next = 0;
744}
745
746
747static void
748term_source (j_decompress_ptr cinfo)
749{
750 /* XXXX - probably should scream something has happened */
751}
752
753
754/* for progressive loading (called "I/O Suspension" by libjpeg docs) */
755/* we do nothing except return "FALSE" */
756static boolean
757fill_input_buffer (j_decompress_ptr cinfo)
758{
759 return FALSE;
760}
761
762
763static void
764skip_input_data (j_decompress_ptr cinfo, long num_bytes)
765{
766 my_src_ptr src = (my_src_ptr) cinfo->src;
767 long num_can_do;
768
769 /* move as far as we can into current buffer */
770 /* then set skip_next to catch the rest */
771 if (num_bytes > 0) {
772 num_can_do = MIN (src->pub.bytes_in_buffer, num_bytes);
773 src->pub.next_input_byte += (size_t) num_can_do;
774 src->pub.bytes_in_buffer -= (size_t) num_can_do;
775
776 src->skip_next = num_bytes - num_can_do;
777 }
778}
779
780
781/*
782 * func - called when we have pixmap created (but no image data)
783 * user_data - passed as arg 1 to func
784 * return context (opaque to user)
785 */
786
787static gpointer
788gdk_pixbuf__jpeg_image_begin_load (GdkPixbufModuleSizeFunc size_func,
789 GdkPixbufModulePreparedFunc prepared_func,
790 GdkPixbufModuleUpdatedFunc updated_func,
791 gpointer user_data,
792 GError **error)
793{
794 JpegProgContext *context;
795 my_source_mgr *src;
796
797 g_assert (size_func != NULL);
798 g_assert (prepared_func != NULL);
799 g_assert (updated_func != NULL);
800
801 context = g_new0 (JpegProgContext, 1);
802 context->size_func = size_func;
803 context->prepared_func = prepared_func;
804 context->updated_func = updated_func;
805 context->user_data = user_data;
806 context->pixbuf = NULL;
807 context->got_header = FALSE;
808 context->did_prescan = FALSE;
809 context->src_initialized = FALSE;
810 context->in_output = FALSE;
811
812 /* From jpeglib.h: "NB: you must set up the error-manager
813 * BEFORE calling jpeg_create_xxx". */
814 context->cinfo.err = jpeg_std_error (err: &context->jerr.pub);
815 context->jerr.pub.error_exit = fatal_error_handler;
816 context->jerr.pub.output_message = output_message_handler;
817 context->jerr.error = error;
818
819 if (sigsetjmp (context->jerr.setjmp_buffer, 1)) {
820 jpeg_destroy_decompress (cinfo: &context->cinfo);
821 g_free(mem: context);
822 /* error should have been set by fatal_error_handler () */
823 return NULL;
824 }
825
826 /* create libjpeg structures */
827 jpeg_create_decompress (&context->cinfo);
828
829 context->cinfo.src = (struct jpeg_source_mgr *) g_try_malloc (n_bytes: sizeof (my_source_mgr));
830 if (!context->cinfo.src) {
831 g_set_error_literal (err: error,
832 GDK_PIXBUF_ERROR,
833 code: GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
834 _("Couldn’t allocate memory for loading JPEG file"));
835 return NULL;
836 }
837 memset (s: context->cinfo.src, c: 0, n: sizeof (my_source_mgr));
838
839 src = (my_src_ptr) context->cinfo.src;
840 src->pub.init_source = init_source;
841 src->pub.fill_input_buffer = fill_input_buffer;
842 src->pub.skip_input_data = skip_input_data;
843 src->pub.resync_to_restart = jpeg_resync_to_restart;
844 src->pub.term_source = term_source;
845 src->pub.bytes_in_buffer = 0;
846 src->pub.next_input_byte = NULL;
847
848 context->jerr.error = NULL;
849
850 return (gpointer) context;
851}
852
853/*
854 * context - returned from image_begin_load
855 *
856 * free context, unref gdk_pixbuf
857 */
858static gboolean
859gdk_pixbuf__jpeg_image_stop_load (gpointer data, GError **error)
860{
861 JpegProgContext *context = (JpegProgContext *) data;
862 struct jpeg_decompress_struct *cinfo;
863 gboolean retval;
864
865 g_return_val_if_fail (context != NULL, TRUE);
866
867 cinfo = &context->cinfo;
868
869 context->jerr.error = error;
870 if (!sigsetjmp (context->jerr.setjmp_buffer, 1)) {
871 /* Try to finish loading truncated files */
872 if (context->pixbuf &&
873 cinfo->output_scanline < cinfo->output_height) {
874 my_src_ptr src = (my_src_ptr) cinfo->src;
875
876 /* But only if there's enough buffer space left */
877 if (src->skip_next < sizeof(src->buffer) - 2) {
878 /* Insert a fake EOI marker */
879 src->buffer[src->skip_next] = (JOCTET) 0xFF;
880 src->buffer[src->skip_next + 1] = (JOCTET) JPEG_EOI;
881 src->pub.next_input_byte = src->buffer + src->skip_next;
882 src->pub.bytes_in_buffer = 2;
883
884 gdk_pixbuf__jpeg_image_load_lines (context, NULL);
885 }
886 }
887 }
888
889 /* FIXME this thing needs to report errors if
890 * we have unused image data
891 */
892
893 if (context->pixbuf)
894 g_object_unref (object: context->pixbuf);
895
896 /* if we have an error? */
897 context->jerr.error = error;
898 if (sigsetjmp (context->jerr.setjmp_buffer, 1)) {
899 retval = FALSE;
900 } else {
901 jpeg_finish_decompress (cinfo);
902 retval = TRUE;
903 }
904
905 jpeg_destroy_decompress (cinfo: &context->cinfo);
906
907 if (cinfo->src) {
908 my_src_ptr src = (my_src_ptr) cinfo->src;
909 g_free (mem: src);
910 }
911
912 g_free (mem: context);
913
914 return retval;
915}
916
917
918static gboolean
919gdk_pixbuf__jpeg_image_load_lines (JpegProgContext *context,
920 GError **error)
921{
922 struct jpeg_decompress_struct *cinfo = &context->cinfo;
923 guchar *lines[4];
924 guchar **lptr;
925 guchar *rowptr;
926 gint nlines, i;
927
928 /* keep going until we've done all scanlines */
929 while (cinfo->output_scanline < cinfo->output_height) {
930 lptr = lines;
931 rowptr = context->dptr;
932 for (i=0; i < cinfo->rec_outbuf_height; i++) {
933 *lptr++ = rowptr;
934 rowptr += gdk_pixbuf_get_rowstride (pixbuf: context->pixbuf);
935 }
936
937 nlines = jpeg_read_scanlines (cinfo, scanlines: lines,
938 max_lines: cinfo->rec_outbuf_height);
939 if (nlines == 0)
940 break;
941
942 switch (cinfo->out_color_space) {
943 case JCS_GRAYSCALE:
944 explode_gray_into_buf (cinfo, lines);
945 break;
946 case JCS_RGB:
947 /* do nothing */
948 break;
949 case JCS_CMYK:
950 convert_cmyk_to_rgb (cinfo, lines);
951 break;
952 default:
953 g_set_error (err: error,
954 GDK_PIXBUF_ERROR,
955 code: GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
956 _("Unsupported JPEG color space (%s)"),
957 colorspace_name (jpeg_color_space: cinfo->out_color_space));
958
959 return FALSE;
960 }
961
962 context->dptr += (gsize)nlines * gdk_pixbuf_get_rowstride (pixbuf: context->pixbuf);
963
964 /* send updated signal */
965 (* context->updated_func) (context->pixbuf,
966 0,
967 cinfo->output_scanline - 1,
968 cinfo->image_width,
969 nlines,
970 context->user_data);
971 }
972
973 return TRUE;
974}
975
976
977/*
978 * context - from image_begin_load
979 * buf - new image data
980 * size - length of new image data
981 *
982 * append image data onto incrementally built output image
983 */
984static gboolean
985gdk_pixbuf__jpeg_image_load_increment (gpointer data,
986 const guchar *buf, guint size,
987 GError **error)
988{
989 JpegProgContext *context = (JpegProgContext *)data;
990 struct jpeg_decompress_struct *cinfo;
991 my_src_ptr src;
992 guint num_left, num_copy;
993 guint last_num_left, last_bytes_left;
994 guint spinguard;
995 gboolean first;
996 const guchar *bufhd;
997 gint width, height;
998 char otag_str[5];
999 gchar *icc_profile_base64;
1000 char *density_str;
1001 JpegExifContext exif_context = { 0, };
1002 gboolean retval;
1003
1004 g_return_val_if_fail (context != NULL, FALSE);
1005 g_return_val_if_fail (buf != NULL, FALSE);
1006
1007 src = (my_src_ptr) context->cinfo.src;
1008
1009 cinfo = &context->cinfo;
1010
1011 context->jerr.error = error;
1012
1013 /* check for fatal error */
1014 if (sigsetjmp (context->jerr.setjmp_buffer, 1)) {
1015 retval = FALSE;
1016 goto out;
1017 }
1018
1019 num_left = size;
1020 bufhd = buf;
1021
1022 if (num_left == 0) {
1023 retval = TRUE;
1024 goto out;
1025 }
1026
1027 last_num_left = num_left;
1028 last_bytes_left = 0;
1029 spinguard = 0;
1030 first = TRUE;
1031 while (TRUE) {
1032 /* skip over data if requested, handle unsigned int sizes cleanly */
1033 /* only can happen if we've already called jpeg_get_header */
1034 if (context->src_initialized && src->skip_next) {
1035 if (src->skip_next >= num_left) {
1036 src->skip_next -= num_left;
1037 retval = TRUE;
1038 goto out;
1039 } else {
1040 num_left -= src->skip_next;
1041 bufhd += src->skip_next;
1042 src->skip_next = 0;
1043 }
1044 }
1045
1046 /* handle any data from caller we haven't processed yet */
1047 if (num_left > 0) {
1048 if(src->pub.bytes_in_buffer &&
1049 src->pub.next_input_byte != src->buffer)
1050 memmove(dest: src->buffer, src: src->pub.next_input_byte,
1051 n: src->pub.bytes_in_buffer);
1052
1053
1054 num_copy = MIN (JPEG_PROG_BUF_SIZE - src->pub.bytes_in_buffer,
1055 num_left);
1056
1057 memcpy(dest: src->buffer + src->pub.bytes_in_buffer, src: bufhd,n: num_copy);
1058 src->pub.next_input_byte = src->buffer;
1059 src->pub.bytes_in_buffer += num_copy;
1060 bufhd += num_copy;
1061 num_left -= num_copy;
1062 }
1063
1064 /* did anything change from last pass, if not return */
1065 if (first) {
1066 last_bytes_left = src->pub.bytes_in_buffer;
1067 first = FALSE;
1068 } else if (src->pub.bytes_in_buffer == last_bytes_left
1069 && num_left == last_num_left) {
1070 spinguard++;
1071 } else {
1072 last_bytes_left = src->pub.bytes_in_buffer;
1073 last_num_left = num_left;
1074 }
1075
1076 /* should not go through twice and not pull bytes out of buf */
1077 if (spinguard > 2) {
1078 retval = TRUE;
1079 goto out;
1080 }
1081
1082 /* try to load jpeg header */
1083 if (!context->got_header) {
1084 int rc;
1085 gchar* comment;
1086 gboolean has_alpha;
1087
1088 jpeg_save_markers (cinfo, JPEG_APP0+1, length_limit: 0xffff);
1089 jpeg_save_markers (cinfo, JPEG_APP0+2, length_limit: 0xffff);
1090 jpeg_save_markers (cinfo, JPEG_COM, length_limit: 0xffff);
1091 rc = jpeg_read_header (cinfo, TRUE);
1092 context->src_initialized = TRUE;
1093
1094 cinfo->mem->max_memory_to_use = 300 * 1024 * 1024;
1095
1096 if (rc == JPEG_SUSPENDED)
1097 continue;
1098
1099 context->got_header = TRUE;
1100
1101 /* parse exif data */
1102 jpeg_parse_exif (context: &exif_context, cinfo);
1103
1104 width = cinfo->image_width;
1105 height = cinfo->image_height;
1106 (* context->size_func) (&width, &height, context->user_data);
1107 if (width == 0 || height == 0) {
1108 g_set_error_literal (err: error,
1109 GDK_PIXBUF_ERROR,
1110 code: GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
1111 _("Transformed JPEG has zero width or height."));
1112 retval = FALSE;
1113 goto out;
1114 }
1115
1116 cinfo->scale_num = 1;
1117 for (cinfo->scale_denom = 2; cinfo->scale_denom <= 8; cinfo->scale_denom *= 2) {
1118 jpeg_calc_output_dimensions (cinfo);
1119 if (cinfo->output_width < width || cinfo->output_height < height) {
1120 cinfo->scale_denom /= 2;
1121 break;
1122 }
1123 }
1124 jpeg_calc_output_dimensions (cinfo);
1125
1126 if (cinfo->output_components == 3) {
1127 has_alpha = FALSE;
1128 } else if (cinfo->output_components == 4) {
1129 has_alpha = TRUE;
1130 } else if (cinfo->output_components == 1 &&
1131 cinfo->out_color_space == JCS_GRAYSCALE) {
1132 has_alpha = FALSE;
1133 } else {
1134 g_set_error (err: error,
1135 GDK_PIXBUF_ERROR,
1136 code: GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
1137 _("Unsupported number of color components (%d)"),
1138 cinfo->output_components);
1139 retval = FALSE;
1140 goto out;
1141 }
1142
1143 context->pixbuf = gdk_pixbuf_new (colorspace: GDK_COLORSPACE_RGB,
1144 has_alpha,
1145 bits_per_sample: 8,
1146 width: cinfo->output_width,
1147 height: cinfo->output_height);
1148
1149 if (context->pixbuf == NULL) {
1150 g_set_error_literal (err: error,
1151 GDK_PIXBUF_ERROR,
1152 code: GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
1153 _("Couldn’t allocate memory for loading JPEG file"));
1154 retval = FALSE;
1155 goto out;
1156 }
1157
1158 comment = jpeg_get_comment (cinfo);
1159 if (comment != NULL) {
1160 gdk_pixbuf_set_option (pixbuf: context->pixbuf, key: "comment", value: comment);
1161 g_free (mem: comment);
1162 }
1163
1164 switch (cinfo->density_unit) {
1165 case 1:
1166 /* Dots per inch (no conversion required) */
1167 density_str = g_strdup_printf (format: "%d", cinfo->X_density);
1168 gdk_pixbuf_set_option (pixbuf: context->pixbuf, key: "x-dpi", value: density_str);
1169 g_free (mem: density_str);
1170 density_str = g_strdup_printf (format: "%d", cinfo->Y_density);
1171 gdk_pixbuf_set_option (pixbuf: context->pixbuf, key: "y-dpi", value: density_str);
1172 g_free (mem: density_str);
1173 break;
1174 case 2:
1175 /* Dots per cm - convert into dpi */
1176 density_str = g_strdup_printf (format: "%d", DPCM_TO_DPI (cinfo->X_density));
1177 gdk_pixbuf_set_option (pixbuf: context->pixbuf, key: "x-dpi", value: density_str);
1178 g_free (mem: density_str);
1179 density_str = g_strdup_printf (format: "%d", DPCM_TO_DPI (cinfo->Y_density));
1180 gdk_pixbuf_set_option (pixbuf: context->pixbuf, key: "y-dpi", value: density_str);
1181 g_free (mem: density_str);
1182 break;
1183 }
1184
1185 /* if orientation tag was found set an option to remember its value */
1186 if (exif_context.orientation != 0) {
1187 g_snprintf (string: otag_str, n: sizeof (otag_str), format: "%d", exif_context.orientation);
1188 gdk_pixbuf_set_option (pixbuf: context->pixbuf, key: "orientation", value: otag_str);
1189 }
1190 /* if icc profile was found */
1191 if (exif_context.icc_profile != NULL) {
1192 icc_profile_base64 = g_base64_encode (data: (const guchar *) exif_context.icc_profile, len: exif_context.icc_profile_size);
1193 gdk_pixbuf_set_option (pixbuf: context->pixbuf, key: "icc-profile", value: icc_profile_base64);
1194 g_free (mem: icc_profile_base64);
1195 }
1196
1197
1198 /* Use pixbuf buffer to store decompressed data */
1199 context->dptr = gdk_pixbuf_get_pixels (pixbuf: context->pixbuf);
1200
1201 /* Notify the client that we are ready to go */
1202 (* context->prepared_func) (context->pixbuf,
1203 NULL,
1204 context->user_data);
1205
1206 } else if (!context->did_prescan) {
1207 int rc;
1208
1209 /* start decompression */
1210 cinfo->buffered_image = cinfo->progressive_mode;
1211 rc = jpeg_start_decompress (cinfo);
1212 cinfo->do_fancy_upsampling = FALSE;
1213 cinfo->do_block_smoothing = FALSE;
1214
1215 if (rc == JPEG_SUSPENDED)
1216 continue;
1217
1218 context->did_prescan = TRUE;
1219 } else if (!cinfo->buffered_image) {
1220 /* we're decompressing unbuffered so
1221 * simply get scanline by scanline from jpeg lib
1222 */
1223 if (! gdk_pixbuf__jpeg_image_load_lines (context,
1224 error)) {
1225 retval = FALSE;
1226 goto out;
1227 }
1228
1229 if (cinfo->output_scanline >= cinfo->output_height) {
1230 retval = TRUE;
1231 goto out;
1232 }
1233 } else {
1234 /* we're decompressing buffered (progressive)
1235 * so feed jpeg lib scanlines
1236 */
1237
1238 /* keep going until we've done all passes */
1239 while (!jpeg_input_complete (cinfo)) {
1240 if (!context->in_output) {
1241 if (jpeg_start_output (cinfo, scan_number: cinfo->input_scan_number)) {
1242 context->in_output = TRUE;
1243 context->dptr = gdk_pixbuf_get_pixels (pixbuf: context->pixbuf);
1244 }
1245 else
1246 break;
1247 }
1248
1249 /* get scanlines from jpeg lib */
1250 if (! gdk_pixbuf__jpeg_image_load_lines (context,
1251 error)) {
1252 retval = FALSE;
1253 goto out;
1254 }
1255
1256 if (cinfo->output_scanline >= cinfo->output_height &&
1257 jpeg_finish_output (cinfo))
1258 context->in_output = FALSE;
1259 else
1260 break;
1261 }
1262 if (jpeg_input_complete (cinfo)) {
1263 /* did entire image */
1264 retval = TRUE;
1265 goto out;
1266 }
1267 else
1268 continue;
1269 }
1270 }
1271out:
1272 jpeg_destroy_exif_context (context: &exif_context);
1273 return retval;
1274}
1275
1276/* Save */
1277
1278#define TO_FUNCTION_BUF_SIZE 4096
1279
1280typedef struct {
1281 struct jpeg_destination_mgr pub;
1282 JOCTET *buffer;
1283 GdkPixbufSaveFunc save_func;
1284 gpointer user_data;
1285 GError **error;
1286} ToFunctionDestinationManager;
1287
1288void
1289to_callback_init (j_compress_ptr cinfo)
1290{
1291 ToFunctionDestinationManager *destmgr;
1292
1293 destmgr = (ToFunctionDestinationManager*) cinfo->dest;
1294 destmgr->pub.next_output_byte = destmgr->buffer;
1295 destmgr->pub.free_in_buffer = TO_FUNCTION_BUF_SIZE;
1296}
1297
1298static void
1299to_callback_do_write (j_compress_ptr cinfo, gsize length)
1300{
1301 ToFunctionDestinationManager *destmgr;
1302
1303 destmgr = (ToFunctionDestinationManager*) cinfo->dest;
1304 if (!destmgr->save_func ((gchar *)destmgr->buffer,
1305 length,
1306 destmgr->error,
1307 destmgr->user_data)) {
1308 struct error_handler_data *errmgr;
1309
1310 errmgr = (struct error_handler_data *) cinfo->err;
1311 /* Use a default error message if the callback didn't set one,
1312 * which it should have.
1313 */
1314 if (errmgr->error && *errmgr->error == NULL) {
1315 g_set_error_literal (err: errmgr->error,
1316 GDK_PIXBUF_ERROR,
1317 code: GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
1318 message: "write function failed");
1319 }
1320 siglongjmp (env: errmgr->setjmp_buffer, val: 1);
1321 g_assert_not_reached ();
1322 }
1323}
1324
1325static boolean
1326to_callback_empty_output_buffer (j_compress_ptr cinfo)
1327{
1328 ToFunctionDestinationManager *destmgr;
1329
1330 destmgr = (ToFunctionDestinationManager*) cinfo->dest;
1331 to_callback_do_write (cinfo, TO_FUNCTION_BUF_SIZE);
1332 destmgr->pub.next_output_byte = destmgr->buffer;
1333 destmgr->pub.free_in_buffer = TO_FUNCTION_BUF_SIZE;
1334 return TRUE;
1335}
1336
1337void
1338to_callback_terminate (j_compress_ptr cinfo)
1339{
1340 ToFunctionDestinationManager *destmgr;
1341
1342 destmgr = (ToFunctionDestinationManager*) cinfo->dest;
1343 to_callback_do_write (cinfo, TO_FUNCTION_BUF_SIZE - destmgr->pub.free_in_buffer);
1344}
1345
1346static gboolean
1347real_save_jpeg (GdkPixbuf *pixbuf,
1348 gchar **keys,
1349 gchar **values,
1350 GError **error,
1351 gboolean to_callback,
1352 FILE *f,
1353 GdkPixbufSaveFunc save_func,
1354 gpointer user_data)
1355{
1356 /* FIXME error handling is broken */
1357
1358 struct jpeg_compress_struct cinfo;
1359 guchar *buf = NULL;
1360 guchar *ptr;
1361 guchar *pixels = NULL;
1362 JSAMPROW *jbuf;
1363 int y = 0;
1364 volatile int quality = 75; /* default; must be between 0 and 100 */
1365 int i, j;
1366 int w, h = 0;
1367 int rowstride = 0;
1368 int n_channels;
1369 struct error_handler_data jerr;
1370 ToFunctionDestinationManager to_callback_destmgr;
1371 int x_density = 0;
1372 int y_density = 0;
1373 gchar *icc_profile = NULL;
1374 gchar *data;
1375 gint retval = TRUE;
1376 gsize icc_profile_size = 0;
1377
1378 to_callback_destmgr.buffer = NULL;
1379
1380 if (keys && *keys) {
1381 gchar **kiter = keys;
1382 gchar **viter = values;
1383
1384 while (*kiter) {
1385 if (strcmp (s1: *kiter, s2: "quality") == 0) {
1386 char *endptr = NULL;
1387 quality = strtol (nptr: *viter, endptr: &endptr, base: 10);
1388
1389 if (endptr == *viter) {
1390 g_set_error (err: error,
1391 GDK_PIXBUF_ERROR,
1392 code: GDK_PIXBUF_ERROR_BAD_OPTION,
1393 _("JPEG quality must be a value between 0 and 100; value “%s” could not be parsed."),
1394 *viter);
1395
1396 retval = FALSE;
1397 goto cleanup;
1398 }
1399
1400 if (quality < 0 ||
1401 quality > 100) {
1402 /* This is a user-visible error;
1403 * lets people skip the range-checking
1404 * in their app.
1405 */
1406 g_set_error (err: error,
1407 GDK_PIXBUF_ERROR,
1408 code: GDK_PIXBUF_ERROR_BAD_OPTION,
1409 _("JPEG quality must be a value between 0 and 100; value “%d” is not allowed."),
1410 quality);
1411
1412 retval = FALSE;
1413 goto cleanup;
1414 }
1415 } else if (strcmp (s1: *kiter, s2: "x-dpi") == 0) {
1416 char *endptr = NULL;
1417 x_density = strtol (nptr: *viter, endptr: &endptr, base: 10);
1418 if (endptr == *viter)
1419 x_density = -1;
1420
1421 if (x_density <= 0 ||
1422 x_density > 65535) {
1423 /* This is a user-visible error;
1424 * lets people skip the range-checking
1425 * in their app.
1426 */
1427 g_set_error (err: error,
1428 GDK_PIXBUF_ERROR,
1429 code: GDK_PIXBUF_ERROR_BAD_OPTION,
1430 _("JPEG x-dpi must be a value between 1 and 65535; value “%s” is not allowed."),
1431 *viter);
1432
1433 retval = FALSE;
1434 goto cleanup;
1435 }
1436 } else if (strcmp (s1: *kiter, s2: "y-dpi") == 0) {
1437 char *endptr = NULL;
1438 y_density = strtol (nptr: *viter, endptr: &endptr, base: 10);
1439 if (endptr == *viter)
1440 y_density = -1;
1441
1442 if (y_density <= 0 ||
1443 y_density > 65535) {
1444 /* This is a user-visible error;
1445 * lets people skip the range-checking
1446 * in their app.
1447 */
1448 g_set_error (err: error,
1449 GDK_PIXBUF_ERROR,
1450 code: GDK_PIXBUF_ERROR_BAD_OPTION,
1451 _("JPEG y-dpi must be a value between 1 and 65535; value “%s” is not allowed."),
1452 *viter);
1453
1454 retval = FALSE;
1455 goto cleanup;
1456 }
1457 } else if (strcmp (s1: *kiter, s2: "icc-profile") == 0) {
1458 /* decode from base64 */
1459 icc_profile = (gchar*) g_base64_decode (text: *viter, out_len: &icc_profile_size);
1460 if (icc_profile_size < 127) {
1461 /* This is a user-visible error */
1462 g_set_error (err: error,
1463 GDK_PIXBUF_ERROR,
1464 code: GDK_PIXBUF_ERROR_BAD_OPTION,
1465 _("Color profile has invalid length “%u”."),
1466 (guint) icc_profile_size);
1467 retval = FALSE;
1468 goto cleanup;
1469 }
1470 } else {
1471 g_warning ("Unrecognized parameter (%s) passed to JPEG saver.", *kiter);
1472 }
1473
1474 ++kiter;
1475 ++viter;
1476 }
1477 }
1478
1479 rowstride = gdk_pixbuf_get_rowstride (pixbuf);
1480 n_channels = gdk_pixbuf_get_n_channels (pixbuf);
1481
1482 w = gdk_pixbuf_get_width (pixbuf);
1483 h = gdk_pixbuf_get_height (pixbuf);
1484 pixels = gdk_pixbuf_get_pixels (pixbuf);
1485
1486 /* Guaranteed by the caller. */
1487 g_assert (w >= 0);
1488 g_assert (h >= 0);
1489 g_assert (rowstride >= 0);
1490 g_assert (n_channels >= 0);
1491
1492 /* Allocate a small buffer to convert image data,
1493 * and a larger buffer if doing to_callback save.
1494 */
1495 buf = g_try_malloc (n_bytes: w * 3 * sizeof (guchar));
1496 if (!buf) {
1497 g_set_error_literal (err: error,
1498 GDK_PIXBUF_ERROR,
1499 code: GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
1500 _("Couldn’t allocate memory for loading JPEG file"));
1501 retval = FALSE;
1502 goto cleanup;
1503 }
1504 if (to_callback) {
1505 to_callback_destmgr.buffer = g_try_malloc (TO_FUNCTION_BUF_SIZE);
1506 if (!to_callback_destmgr.buffer) {
1507 g_set_error_literal (err: error,
1508 GDK_PIXBUF_ERROR,
1509 code: GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
1510 _("Couldn’t allocate memory for loading JPEG file"));
1511 retval = FALSE;
1512 goto cleanup;
1513 }
1514 }
1515
1516 /* set up error handling */
1517 cinfo.err = jpeg_std_error (err: &(jerr.pub));
1518 jerr.pub.error_exit = fatal_error_handler;
1519 jerr.pub.output_message = output_message_handler;
1520 jerr.error = error;
1521
1522 if (sigsetjmp (jerr.setjmp_buffer, 1)) {
1523 jpeg_destroy_compress (cinfo: &cinfo);
1524 retval = FALSE;
1525 goto cleanup;
1526 }
1527
1528 /* setup compress params */
1529 jpeg_create_compress (&cinfo);
1530 if (to_callback) {
1531 to_callback_destmgr.pub.init_destination = to_callback_init;
1532 to_callback_destmgr.pub.empty_output_buffer = to_callback_empty_output_buffer;
1533 to_callback_destmgr.pub.term_destination = to_callback_terminate;
1534 to_callback_destmgr.error = error;
1535 to_callback_destmgr.save_func = save_func;
1536 to_callback_destmgr.user_data = user_data;
1537 cinfo.dest = (struct jpeg_destination_mgr*) &to_callback_destmgr;
1538 } else {
1539 jpeg_stdio_dest (cinfo: &cinfo, outfile: f);
1540 }
1541 cinfo.image_width = w;
1542 cinfo.image_height = h;
1543 cinfo.input_components = 3;
1544 cinfo.in_color_space = JCS_RGB;
1545
1546 /* set up jepg compression parameters */
1547 jpeg_set_defaults (cinfo: &cinfo);
1548 jpeg_set_quality (cinfo: &cinfo, quality, TRUE);
1549
1550 /* set density information */
1551 if (x_density > 0 && y_density > 0) {
1552 cinfo.density_unit = 1; /* Dots per inch */
1553 cinfo.X_density = x_density;
1554 cinfo.Y_density = y_density;
1555 }
1556
1557 jpeg_start_compress (cinfo: &cinfo, TRUE);
1558
1559 /* write ICC profile data */
1560 if (icc_profile != NULL) {
1561 /* optimise for the common case where only one APP2 segment is required */
1562 if (icc_profile_size < 0xffef) {
1563 data = g_new (gchar, icc_profile_size + 14);
1564 memcpy (dest: data, src: "ICC_PROFILE\000\001\001", n: 14);
1565 memcpy (dest: data + 14, src: icc_profile, n: icc_profile_size);
1566 jpeg_write_marker (cinfo: &cinfo, JPEG_APP0+2, dataptr: (const JOCTET *) data, datalen: icc_profile_size + 14);
1567 g_free (mem: data);
1568 } else {
1569 guint segments;
1570 guint size = 0xffef;
1571 guint offset;
1572
1573 segments = (guint) ceilf (x: (gfloat) icc_profile_size / (gfloat) 0xffef);
1574 data = g_new (gchar, 0xffff);
1575 memcpy (dest: data, src: "ICC_PROFILE\000", n: 12);
1576 data[13] = segments;
1577 for (i=0; i<=segments; i++) {
1578 data[12] = i;
1579 offset = 0xffef * i;
1580
1581 /* last segment */
1582 if (i == segments)
1583 size = icc_profile_size % 0xffef;
1584
1585 memcpy (dest: data + 14, src: icc_profile + offset, n: size);
1586 jpeg_write_marker (cinfo: &cinfo, JPEG_APP0+2, dataptr: (const JOCTET *) data, datalen: size + 14);
1587 }
1588 g_free (mem: data);
1589 }
1590 }
1591
1592 /* get the start pointer */
1593 ptr = pixels;
1594 /* go one scanline at a time... and save */
1595 i = 0;
1596 while (cinfo.next_scanline < cinfo.image_height) {
1597 /* convert scanline from ARGB to RGB packed */
1598 for (j = 0; j < w; j++)
1599 memcpy (dest: &(buf[j*3]), src: &(ptr[(gsize)i*rowstride + j*n_channels]), n: 3);
1600
1601 /* write scanline */
1602 jbuf = (JSAMPROW *)(&buf);
1603 if (jpeg_write_scanlines (cinfo: &cinfo, scanlines: jbuf, num_lines: 1) == 0) {
1604 jpeg_destroy_compress (cinfo: &cinfo);
1605 retval = FALSE;
1606 goto cleanup;
1607 }
1608
1609 i++;
1610 y++;
1611
1612 }
1613
1614 /* finish off */
1615 jpeg_finish_compress (cinfo: &cinfo);
1616 jpeg_destroy_compress(cinfo: &cinfo);
1617cleanup:
1618 g_free (mem: buf);
1619 g_free (mem: to_callback_destmgr.buffer);
1620 g_free (mem: icc_profile);
1621 return retval;
1622}
1623
1624static gboolean
1625gdk_pixbuf__jpeg_image_save (FILE *f,
1626 GdkPixbuf *pixbuf,
1627 gchar **keys,
1628 gchar **values,
1629 GError **error)
1630{
1631 return real_save_jpeg (pixbuf, keys, values, error,
1632 FALSE, f, NULL, NULL);
1633}
1634
1635static gboolean
1636gdk_pixbuf__jpeg_image_save_to_callback (GdkPixbufSaveFunc save_func,
1637 gpointer user_data,
1638 GdkPixbuf *pixbuf,
1639 gchar **keys,
1640 gchar **values,
1641 GError **error)
1642{
1643 return real_save_jpeg (pixbuf, keys, values, error,
1644 TRUE, NULL, save_func, user_data);
1645}
1646
1647static gboolean
1648gdk_pixbuf__jpeg_is_save_option_supported (const gchar *option_key)
1649{
1650 if (g_strcmp0 (str1: option_key, str2: "quality") == 0 ||
1651 g_strcmp0 (str1: option_key, str2: "icc-profile") == 0)
1652 return TRUE;
1653
1654 return FALSE;
1655}
1656
1657#ifndef INCLUDE_jpeg
1658#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
1659#else
1660#define MODULE_ENTRY(function) void _gdk_pixbuf__jpeg_ ## function
1661#endif
1662
1663MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
1664{
1665 module->load = gdk_pixbuf__jpeg_image_load;
1666 module->begin_load = gdk_pixbuf__jpeg_image_begin_load;
1667 module->stop_load = gdk_pixbuf__jpeg_image_stop_load;
1668 module->load_increment = gdk_pixbuf__jpeg_image_load_increment;
1669 module->save = gdk_pixbuf__jpeg_image_save;
1670 module->save_to_callback = gdk_pixbuf__jpeg_image_save_to_callback;
1671 module->is_save_option_supported = gdk_pixbuf__jpeg_is_save_option_supported;
1672}
1673
1674MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
1675{
1676 static const GdkPixbufModulePattern signature[] = {
1677 { "\xff\xd8", NULL, 100 },
1678 { NULL, NULL, 0 }
1679 };
1680 static const gchar *mime_types[] = {
1681 "image/jpeg",
1682 NULL
1683 };
1684 static const gchar *extensions[] = {
1685 "jpeg",
1686 "jpe",
1687 "jpg",
1688 NULL
1689 };
1690
1691 info->name = "jpeg";
1692 info->signature = (GdkPixbufModulePattern *) signature;
1693 info->description = NC_("image format", "JPEG");
1694 info->mime_types = (gchar **) mime_types;
1695 info->extensions = (gchar **) extensions;
1696 info->flags = GDK_PIXBUF_FORMAT_WRITABLE | GDK_PIXBUF_FORMAT_THREADSAFE;
1697 info->license = "LGPL";
1698}
1699

source code of gtk/subprojects/gdk-pixbuf/gdk-pixbuf/io-jpeg.c