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
53 typedef 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
61 typedef my_source_mgr * my_src_ptr;
62
63 /* error handler data */
64 struct error_handler_data {
65 struct jpeg_error_mgr pub;
66 sigjmp_buf setjmp_buffer;
67 GError **error;
68 };
69
70 /* progressive loader context */
71 typedef 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 */
89 typedef struct {
90 gint orientation;
91 gchar *icc_profile;
92 gsize icc_profile_size;
93 gsize icc_profile_size_allocated;
94 } JpegExifContext;
95
96 static GdkPixbuf *gdk_pixbuf__jpeg_image_load (FILE *f, GError **error);
97 static gpointer gdk_pixbuf__jpeg_image_begin_load (GdkPixbufModuleSizeFunc func0,
98 GdkPixbufModulePreparedFunc func1,
99 GdkPixbufModuleUpdatedFunc func2,
100 gpointer user_data,
101 GError **error);
102 static gboolean gdk_pixbuf__jpeg_image_stop_load (gpointer context, GError **error);
103 static gboolean gdk_pixbuf__jpeg_image_load_increment(gpointer context,
104 const guchar *buf, guint size,
105 GError **error);
106 static gboolean gdk_pixbuf__jpeg_image_load_lines (JpegProgContext *context,
107 GError **error);
108
109 static void
fatal_error_handler(j_common_ptr cinfo)110 fatal_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 (errmgr->error,
125 GDK_PIXBUF_ERROR,
126 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 (errmgr->setjmp_buffer, 1);
134
135 g_assert_not_reached ();
136 }
137
138 static void
output_message_handler(j_common_ptr cinfo)139 output_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 */
147 static void
explode_gray_into_buf(struct jpeg_decompress_struct * cinfo,guchar ** lines)148 explode_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
178 static void
convert_cmyk_to_rgb(struct jpeg_decompress_struct * cinfo,guchar ** lines)179 convert_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
211 typedef 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
219 typedef stdio_source_mgr * stdio_src_ptr;
220
221 static void
stdio_init_source(j_decompress_ptr cinfo)222 stdio_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
228 static boolean
stdio_fill_input_buffer(j_decompress_ptr cinfo)229 stdio_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 (src->buffer, 1, JPEG_PROG_BUF_SIZE, 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
255 static void
stdio_skip_input_data(j_decompress_ptr cinfo,long num_bytes)256 stdio_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
270 static void
stdio_term_source(j_decompress_ptr cinfo)271 stdio_term_source (j_decompress_ptr cinfo)
272 {
273 }
274
275 static gchar *
colorspace_name(const J_COLOR_SPACE jpeg_color_space)276 colorspace_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
de_get16(void * ptr,guint endian)295 static unsigned short de_get16(void *ptr, guint endian)
296 {
297 unsigned short val;
298
299 memcpy(&val, ptr, sizeof(val));
300 val = DE_ENDIAN16(val);
301
302 return val;
303 }
304
de_get32(void * ptr,guint endian)305 static unsigned int de_get32(void *ptr, guint endian)
306 {
307 unsigned int val;
308
309 memcpy(&val, ptr, sizeof(val));
310 val = DE_ENDIAN32(val);
311
312 return val;
313 }
314
315 /* application specific data segment */
316 static gboolean
jpeg_parse_exif_app2_segment(JpegExifContext * context,jpeg_saved_marker_ptr marker)317 jpeg_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 (marker->data, "ICC_PROFILE\0", 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 (context->icc_profile, marker->data + 14, 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 (context->icc_profile + offset, marker->data + 14, 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;
385 out:
386 return ret;
387 }
388
389 static gboolean
jpeg_parse_exif_app1(JpegExifContext * context,jpeg_saved_marker_ptr marker)390 jpeg_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 (marker->data, "Exif", 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 (&marker->data[i], leth, 4) == 0) {
430 endian = G_LITTLE_ENDIAN;
431 ret = TRUE;
432 break;
433 }
434
435 /* big endian TIFF header */
436 if (memcmp (&marker->data[i], beth, 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(&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(&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(&marker->data[i + 0], endian);
483 guint type = de_get16(&marker->data[i + 2], endian);
484 guint count = de_get32(&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(&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(&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
512 out:
513 return ret;
514 }
515
516 static void
jpeg_parse_exif(JpegExifContext * context,j_decompress_ptr cinfo)517 jpeg_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, cmarker);
526 else if (cmarker->marker == JPEG_APP0+2)
527 jpeg_parse_exif_app2_segment (context, cmarker);
528 cmarker = cmarker->next;
529 }
530 }
531
532 static gchar *
jpeg_get_comment(j_decompress_ptr cinfo)533 jpeg_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 ((const gchar *) cmarker->data, cmarker->data_length);
541 cmarker = cmarker->next;
542 }
543
544 return NULL;
545 }
546
547 static void
jpeg_destroy_exif_context(JpegExifContext * context)548 jpeg_destroy_exif_context (JpegExifContext *context)
549 {
550 g_free (context->icc_profile);
551 }
552
553 /* Shared library entry point */
554 static GdkPixbuf *
gdk_pixbuf__jpeg_image_load(FILE * f,GError ** error)555 gdk_pixbuf__jpeg_image_load (FILE *f, 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 jpeg_decompress_struct cinfo;
569 struct error_handler_data jerr;
570 stdio_src_ptr src;
571 gchar *icc_profile_base64;
572 gchar *comment;
573 JpegExifContext exif_context = { 0, };
574
575 /* setup error handler */
576 cinfo.err = jpeg_std_error (&jerr.pub);
577 jerr.pub.error_exit = fatal_error_handler;
578 jerr.pub.output_message = output_message_handler;
579 jerr.error = error;
580
581 if (sigsetjmp (jerr.setjmp_buffer, 1)) {
582 /* Whoops there was a jpeg error */
583 if (pixbuf)
584 g_object_unref (pixbuf);
585
586 jpeg_destroy_decompress (&cinfo);
587 jpeg_destroy_exif_context (&exif_context);
588
589 /* error should have been set by fatal_error_handler () */
590 return NULL;
591 }
592
593 /* load header, setup */
594 jpeg_create_decompress (&cinfo);
595
596 cinfo.src = (struct jpeg_source_mgr *)
597 (*cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_PERMANENT,
598 sizeof (stdio_source_mgr));
599 src = (stdio_src_ptr) cinfo.src;
600 src->buffer = (JOCTET *)
601 (*cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_PERMANENT,
602 JPEG_PROG_BUF_SIZE * sizeof (JOCTET));
603
604 src->pub.init_source = stdio_init_source;
605 src->pub.fill_input_buffer = stdio_fill_input_buffer;
606 src->pub.skip_input_data = stdio_skip_input_data;
607 src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
608 src->pub.term_source = stdio_term_source;
609 src->infile = f;
610 src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
611 src->pub.next_input_byte = NULL; /* until buffer loaded */
612
613 jpeg_save_markers (&cinfo, JPEG_APP0+1, 0xffff);
614 jpeg_save_markers (&cinfo, JPEG_APP0+2, 0xffff);
615 jpeg_save_markers (&cinfo, JPEG_COM, 0xffff);
616 jpeg_read_header (&cinfo, TRUE);
617
618 /* parse exif data */
619 jpeg_parse_exif (&exif_context, &cinfo);
620
621 jpeg_start_decompress (&cinfo);
622 cinfo.do_fancy_upsampling = FALSE;
623 cinfo.do_block_smoothing = FALSE;
624
625 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
626 cinfo.out_color_components == 4 ? TRUE : FALSE,
627 8, cinfo.output_width, cinfo.output_height);
628
629 if (!pixbuf) {
630 /* broken check for *error == NULL for robustness against
631 * crappy JPEG library
632 */
633 if (error && *error == NULL) {
634 g_set_error_literal (error,
635 GDK_PIXBUF_ERROR,
636 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
637 _("Insufficient memory to load image, try exiting some applications to free memory"));
638 }
639
640 goto out;
641 }
642
643 comment = jpeg_get_comment (&cinfo);
644 if (comment != NULL) {
645 gdk_pixbuf_set_option (pixbuf, "comment", comment);
646 g_free (comment);
647 }
648
649 switch (cinfo.density_unit) {
650 case 1:
651 /* Dots per inch (no conversion required) */
652 density_str = g_strdup_printf ("%d", cinfo.X_density);
653 gdk_pixbuf_set_option (pixbuf, "x-dpi", density_str);
654 g_free (density_str);
655 density_str = g_strdup_printf ("%d", cinfo.Y_density);
656 gdk_pixbuf_set_option (pixbuf, "y-dpi", density_str);
657 g_free (density_str);
658 break;
659 case 2:
660 /* Dots per cm - convert into dpi */
661 density_str = g_strdup_printf ("%d", DPCM_TO_DPI (cinfo.X_density));
662 gdk_pixbuf_set_option (pixbuf, "x-dpi", density_str);
663 g_free (density_str);
664 density_str = g_strdup_printf ("%d", DPCM_TO_DPI (cinfo.Y_density));
665 gdk_pixbuf_set_option (pixbuf, "y-dpi", density_str);
666 g_free (density_str);
667 break;
668 }
669
670 /* if orientation tag was found */
671 if (exif_context.orientation != 0) {
672 g_snprintf (otag_str, sizeof (otag_str), "%d", exif_context.orientation);
673 gdk_pixbuf_set_option (pixbuf, "orientation", otag_str);
674 }
675
676 /* if icc profile was found */
677 if (exif_context.icc_profile != NULL) {
678 icc_profile_base64 = g_base64_encode ((const guchar *) exif_context.icc_profile, exif_context.icc_profile_size);
679 gdk_pixbuf_set_option (pixbuf, "icc-profile", icc_profile_base64);
680 g_free (icc_profile_base64);
681 }
682
683 dptr = gdk_pixbuf_get_pixels (pixbuf);
684
685 /* decompress all the lines, a few at a time */
686 while (cinfo.output_scanline < cinfo.output_height) {
687 lptr = lines;
688 for (i = 0; i < cinfo.rec_outbuf_height; i++) {
689 *lptr++ = dptr;
690 dptr += gdk_pixbuf_get_rowstride (pixbuf);
691 }
692
693 jpeg_read_scanlines (&cinfo, lines, cinfo.rec_outbuf_height);
694
695 switch (cinfo.out_color_space) {
696 case JCS_GRAYSCALE:
697 explode_gray_into_buf (&cinfo, lines);
698 break;
699 case JCS_RGB:
700 /* do nothing */
701 break;
702 case JCS_CMYK:
703 convert_cmyk_to_rgb (&cinfo, lines);
704 break;
705 default:
706 g_clear_object (&pixbuf);
707 g_set_error (error,
708 GDK_PIXBUF_ERROR,
709 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
710 _("Unsupported JPEG color space (%s)"),
711 colorspace_name (cinfo.out_color_space));
712 goto out;
713 }
714 }
715
716 out:
717 jpeg_finish_decompress (&cinfo);
718 jpeg_destroy_decompress (&cinfo);
719 jpeg_destroy_exif_context (&exif_context);
720
721 return pixbuf;
722 }
723
724
725 /**** Progressive image loading handling *****/
726
727 /* these routines required because we are acting as a source manager for */
728 /* libjpeg. */
729 static void
init_source(j_decompress_ptr cinfo)730 init_source (j_decompress_ptr cinfo)
731 {
732 my_src_ptr src = (my_src_ptr) cinfo->src;
733
734 src->skip_next = 0;
735 }
736
737
738 static void
term_source(j_decompress_ptr cinfo)739 term_source (j_decompress_ptr cinfo)
740 {
741 /* XXXX - probably should scream something has happened */
742 }
743
744
745 /* for progressive loading (called "I/O Suspension" by libjpeg docs) */
746 /* we do nothing except return "FALSE" */
747 static boolean
fill_input_buffer(j_decompress_ptr cinfo)748 fill_input_buffer (j_decompress_ptr cinfo)
749 {
750 return FALSE;
751 }
752
753
754 static void
skip_input_data(j_decompress_ptr cinfo,long num_bytes)755 skip_input_data (j_decompress_ptr cinfo, long num_bytes)
756 {
757 my_src_ptr src = (my_src_ptr) cinfo->src;
758 long num_can_do;
759
760 /* move as far as we can into current buffer */
761 /* then set skip_next to catch the rest */
762 if (num_bytes > 0) {
763 num_can_do = MIN (src->pub.bytes_in_buffer, num_bytes);
764 src->pub.next_input_byte += (size_t) num_can_do;
765 src->pub.bytes_in_buffer -= (size_t) num_can_do;
766
767 src->skip_next = num_bytes - num_can_do;
768 }
769 }
770
771
772 /*
773 * func - called when we have pixmap created (but no image data)
774 * user_data - passed as arg 1 to func
775 * return context (opaque to user)
776 */
777
778 static gpointer
gdk_pixbuf__jpeg_image_begin_load(GdkPixbufModuleSizeFunc size_func,GdkPixbufModulePreparedFunc prepared_func,GdkPixbufModuleUpdatedFunc updated_func,gpointer user_data,GError ** error)779 gdk_pixbuf__jpeg_image_begin_load (GdkPixbufModuleSizeFunc size_func,
780 GdkPixbufModulePreparedFunc prepared_func,
781 GdkPixbufModuleUpdatedFunc updated_func,
782 gpointer user_data,
783 GError **error)
784 {
785 JpegProgContext *context;
786 my_source_mgr *src;
787
788 context = g_new0 (JpegProgContext, 1);
789 context->size_func = size_func;
790 context->prepared_func = prepared_func;
791 context->updated_func = updated_func;
792 context->user_data = user_data;
793 context->pixbuf = NULL;
794 context->got_header = FALSE;
795 context->did_prescan = FALSE;
796 context->src_initialized = FALSE;
797 context->in_output = FALSE;
798
799 /* From jpeglib.h: "NB: you must set up the error-manager
800 * BEFORE calling jpeg_create_xxx". */
801 context->cinfo.err = jpeg_std_error (&context->jerr.pub);
802 context->jerr.pub.error_exit = fatal_error_handler;
803 context->jerr.pub.output_message = output_message_handler;
804 context->jerr.error = error;
805
806 if (sigsetjmp (context->jerr.setjmp_buffer, 1)) {
807 jpeg_destroy_decompress (&context->cinfo);
808 g_free(context);
809 /* error should have been set by fatal_error_handler () */
810 return NULL;
811 }
812
813 /* create libjpeg structures */
814 jpeg_create_decompress (&context->cinfo);
815
816 context->cinfo.src = (struct jpeg_source_mgr *) g_try_malloc (sizeof (my_source_mgr));
817 if (!context->cinfo.src) {
818 g_set_error_literal (error,
819 GDK_PIXBUF_ERROR,
820 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
821 _("Couldn’t allocate memory for loading JPEG file"));
822 return NULL;
823 }
824 memset (context->cinfo.src, 0, sizeof (my_source_mgr));
825
826 src = (my_src_ptr) context->cinfo.src;
827 src->pub.init_source = init_source;
828 src->pub.fill_input_buffer = fill_input_buffer;
829 src->pub.skip_input_data = skip_input_data;
830 src->pub.resync_to_restart = jpeg_resync_to_restart;
831 src->pub.term_source = term_source;
832 src->pub.bytes_in_buffer = 0;
833 src->pub.next_input_byte = NULL;
834
835 context->jerr.error = NULL;
836
837 return (gpointer) context;
838 }
839
840 /*
841 * context - returned from image_begin_load
842 *
843 * free context, unref gdk_pixbuf
844 */
845 static gboolean
gdk_pixbuf__jpeg_image_stop_load(gpointer data,GError ** error)846 gdk_pixbuf__jpeg_image_stop_load (gpointer data, GError **error)
847 {
848 JpegProgContext *context = (JpegProgContext *) data;
849 struct jpeg_decompress_struct *cinfo;
850 gboolean retval;
851
852 g_return_val_if_fail (context != NULL, TRUE);
853
854 cinfo = &context->cinfo;
855
856 context->jerr.error = error;
857 if (!sigsetjmp (context->jerr.setjmp_buffer, 1)) {
858 /* Try to finish loading truncated files */
859 if (context->pixbuf &&
860 cinfo->output_scanline < cinfo->output_height) {
861 my_src_ptr src = (my_src_ptr) cinfo->src;
862
863 /* But only if there's enough buffer space left */
864 if (src->skip_next < sizeof(src->buffer) - 2) {
865 /* Insert a fake EOI marker */
866 src->buffer[src->skip_next] = (JOCTET) 0xFF;
867 src->buffer[src->skip_next + 1] = (JOCTET) JPEG_EOI;
868 src->pub.next_input_byte = src->buffer + src->skip_next;
869 src->pub.bytes_in_buffer = 2;
870
871 gdk_pixbuf__jpeg_image_load_lines (context, NULL);
872 }
873 }
874 }
875
876 /* FIXME this thing needs to report errors if
877 * we have unused image data
878 */
879
880 if (context->pixbuf)
881 g_object_unref (context->pixbuf);
882
883 /* if we have an error? */
884 context->jerr.error = error;
885 if (sigsetjmp (context->jerr.setjmp_buffer, 1)) {
886 retval = FALSE;
887 } else {
888 jpeg_finish_decompress (cinfo);
889 retval = TRUE;
890 }
891
892 jpeg_destroy_decompress (&context->cinfo);
893
894 if (cinfo->src) {
895 my_src_ptr src = (my_src_ptr) cinfo->src;
896 g_free (src);
897 }
898
899 g_free (context);
900
901 return retval;
902 }
903
904
905 static gboolean
gdk_pixbuf__jpeg_image_load_lines(JpegProgContext * context,GError ** error)906 gdk_pixbuf__jpeg_image_load_lines (JpegProgContext *context,
907 GError **error)
908 {
909 struct jpeg_decompress_struct *cinfo = &context->cinfo;
910 guchar *lines[4];
911 guchar **lptr;
912 guchar *rowptr;
913 gint nlines, i;
914
915 /* keep going until we've done all scanlines */
916 while (cinfo->output_scanline < cinfo->output_height) {
917 lptr = lines;
918 rowptr = context->dptr;
919 for (i=0; i < cinfo->rec_outbuf_height; i++) {
920 *lptr++ = rowptr;
921 rowptr += gdk_pixbuf_get_rowstride (context->pixbuf);
922 }
923
924 nlines = jpeg_read_scanlines (cinfo, lines,
925 cinfo->rec_outbuf_height);
926 if (nlines == 0)
927 break;
928
929 switch (cinfo->out_color_space) {
930 case JCS_GRAYSCALE:
931 explode_gray_into_buf (cinfo, lines);
932 break;
933 case JCS_RGB:
934 /* do nothing */
935 break;
936 case JCS_CMYK:
937 convert_cmyk_to_rgb (cinfo, lines);
938 break;
939 default:
940 g_set_error (error,
941 GDK_PIXBUF_ERROR,
942 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
943 _("Unsupported JPEG color space (%s)"),
944 colorspace_name (cinfo->out_color_space));
945
946 return FALSE;
947 }
948
949 context->dptr += (gsize)nlines * gdk_pixbuf_get_rowstride (context->pixbuf);
950
951 /* send updated signal */
952 if (context->updated_func)
953 (* context->updated_func) (context->pixbuf,
954 0,
955 cinfo->output_scanline - 1,
956 cinfo->image_width,
957 nlines,
958 context->user_data);
959 }
960
961 return TRUE;
962 }
963
964
965 /*
966 * context - from image_begin_load
967 * buf - new image data
968 * size - length of new image data
969 *
970 * append image data onto inrecrementally built output image
971 */
972 static gboolean
gdk_pixbuf__jpeg_image_load_increment(gpointer data,const guchar * buf,guint size,GError ** error)973 gdk_pixbuf__jpeg_image_load_increment (gpointer data,
974 const guchar *buf, guint size,
975 GError **error)
976 {
977 JpegProgContext *context = (JpegProgContext *)data;
978 struct jpeg_decompress_struct *cinfo;
979 my_src_ptr src;
980 guint num_left, num_copy;
981 guint last_num_left, last_bytes_left;
982 guint spinguard;
983 gboolean first;
984 const guchar *bufhd;
985 gint width, height;
986 char otag_str[5];
987 gchar *icc_profile_base64;
988 char *density_str;
989 JpegExifContext exif_context = { 0, };
990 gboolean retval;
991
992 g_return_val_if_fail (context != NULL, FALSE);
993 g_return_val_if_fail (buf != NULL, FALSE);
994
995 src = (my_src_ptr) context->cinfo.src;
996
997 cinfo = &context->cinfo;
998
999 context->jerr.error = error;
1000
1001 /* check for fatal error */
1002 if (sigsetjmp (context->jerr.setjmp_buffer, 1)) {
1003 retval = FALSE;
1004 goto out;
1005 }
1006
1007 /* skip over data if requested, handle unsigned int sizes cleanly */
1008 /* only can happen if we've already called jpeg_get_header once */
1009 if (context->src_initialized && src->skip_next) {
1010 if (src->skip_next > size) {
1011 src->skip_next -= size;
1012 retval = TRUE;
1013 goto out;
1014 } else {
1015 num_left = size - src->skip_next;
1016 bufhd = buf + src->skip_next;
1017 src->skip_next = 0;
1018 }
1019 } else {
1020 num_left = size;
1021 bufhd = buf;
1022 }
1023
1024 if (num_left == 0) {
1025 retval = TRUE;
1026 goto out;
1027 }
1028
1029 last_num_left = num_left;
1030 last_bytes_left = 0;
1031 spinguard = 0;
1032 first = TRUE;
1033 while (TRUE) {
1034
1035 /* handle any data from caller we haven't processed yet */
1036 if (num_left > 0) {
1037 if(src->pub.bytes_in_buffer &&
1038 src->pub.next_input_byte != src->buffer)
1039 memmove(src->buffer, src->pub.next_input_byte,
1040 src->pub.bytes_in_buffer);
1041
1042
1043 num_copy = MIN (JPEG_PROG_BUF_SIZE - src->pub.bytes_in_buffer,
1044 num_left);
1045
1046 memcpy(src->buffer + src->pub.bytes_in_buffer, bufhd,num_copy);
1047 src->pub.next_input_byte = src->buffer;
1048 src->pub.bytes_in_buffer += num_copy;
1049 bufhd += num_copy;
1050 num_left -= num_copy;
1051 }
1052
1053 /* did anything change from last pass, if not return */
1054 if (first) {
1055 last_bytes_left = src->pub.bytes_in_buffer;
1056 first = FALSE;
1057 } else if (src->pub.bytes_in_buffer == last_bytes_left
1058 && num_left == last_num_left) {
1059 spinguard++;
1060 } else {
1061 last_bytes_left = src->pub.bytes_in_buffer;
1062 last_num_left = num_left;
1063 }
1064
1065 /* should not go through twice and not pull bytes out of buf */
1066 if (spinguard > 2) {
1067 retval = TRUE;
1068 goto out;
1069 }
1070
1071 /* try to load jpeg header */
1072 if (!context->got_header) {
1073 int rc;
1074 gchar* comment;
1075 gboolean has_alpha;
1076
1077 jpeg_save_markers (cinfo, JPEG_APP0+1, 0xffff);
1078 jpeg_save_markers (cinfo, JPEG_APP0+2, 0xffff);
1079 jpeg_save_markers (cinfo, JPEG_COM, 0xffff);
1080 rc = jpeg_read_header (cinfo, TRUE);
1081 context->src_initialized = TRUE;
1082
1083 if (rc == JPEG_SUSPENDED)
1084 continue;
1085
1086 context->got_header = TRUE;
1087
1088 /* parse exif data */
1089 jpeg_parse_exif (&exif_context, cinfo);
1090
1091 width = cinfo->image_width;
1092 height = cinfo->image_height;
1093 if (context->size_func) {
1094 (* context->size_func) (&width, &height, context->user_data);
1095 if (width == 0 || height == 0) {
1096 g_set_error_literal (error,
1097 GDK_PIXBUF_ERROR,
1098 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
1099 _("Transformed JPEG has zero width or height."));
1100 retval = FALSE;
1101 goto out;
1102 }
1103 }
1104
1105 cinfo->scale_num = 1;
1106 for (cinfo->scale_denom = 2; cinfo->scale_denom <= 8; cinfo->scale_denom *= 2) {
1107 jpeg_calc_output_dimensions (cinfo);
1108 if (cinfo->output_width < width || cinfo->output_height < height) {
1109 cinfo->scale_denom /= 2;
1110 break;
1111 }
1112 }
1113 jpeg_calc_output_dimensions (cinfo);
1114
1115 if (cinfo->output_components == 3) {
1116 has_alpha = FALSE;
1117 } else if (cinfo->output_components == 4) {
1118 has_alpha = TRUE;
1119 } else if (cinfo->output_components == 1 &&
1120 cinfo->out_color_space == JCS_GRAYSCALE) {
1121 has_alpha = FALSE;
1122 } else {
1123 g_set_error (error,
1124 GDK_PIXBUF_ERROR,
1125 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
1126 _("Unsupported number of color components (%d)"),
1127 cinfo->output_components);
1128 retval = FALSE;
1129 goto out;
1130 }
1131
1132 context->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
1133 has_alpha,
1134 8,
1135 cinfo->output_width,
1136 cinfo->output_height);
1137
1138 if (context->pixbuf == NULL) {
1139 g_set_error_literal (error,
1140 GDK_PIXBUF_ERROR,
1141 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
1142 _("Couldn’t allocate memory for loading JPEG file"));
1143 retval = FALSE;
1144 goto out;
1145 }
1146
1147 comment = jpeg_get_comment (cinfo);
1148 if (comment != NULL) {
1149 gdk_pixbuf_set_option (context->pixbuf, "comment", comment);
1150 g_free (comment);
1151 }
1152
1153 switch (cinfo->density_unit) {
1154 case 1:
1155 /* Dots per inch (no conversion required) */
1156 density_str = g_strdup_printf ("%d", cinfo->X_density);
1157 gdk_pixbuf_set_option (context->pixbuf, "x-dpi", density_str);
1158 g_free (density_str);
1159 density_str = g_strdup_printf ("%d", cinfo->Y_density);
1160 gdk_pixbuf_set_option (context->pixbuf, "y-dpi", density_str);
1161 g_free (density_str);
1162 break;
1163 case 2:
1164 /* Dots per cm - convert into dpi */
1165 density_str = g_strdup_printf ("%d", DPCM_TO_DPI (cinfo->X_density));
1166 gdk_pixbuf_set_option (context->pixbuf, "x-dpi", density_str);
1167 g_free (density_str);
1168 density_str = g_strdup_printf ("%d", DPCM_TO_DPI (cinfo->Y_density));
1169 gdk_pixbuf_set_option (context->pixbuf, "y-dpi", density_str);
1170 g_free (density_str);
1171 break;
1172 }
1173
1174 /* if orientation tag was found set an option to remember its value */
1175 if (exif_context.orientation != 0) {
1176 g_snprintf (otag_str, sizeof (otag_str), "%d", exif_context.orientation);
1177 gdk_pixbuf_set_option (context->pixbuf, "orientation", otag_str);
1178 }
1179 /* if icc profile was found */
1180 if (exif_context.icc_profile != NULL) {
1181 icc_profile_base64 = g_base64_encode ((const guchar *) exif_context.icc_profile, exif_context.icc_profile_size);
1182 gdk_pixbuf_set_option (context->pixbuf, "icc-profile", icc_profile_base64);
1183 g_free (icc_profile_base64);
1184 }
1185
1186
1187 /* Use pixbuf buffer to store decompressed data */
1188 context->dptr = gdk_pixbuf_get_pixels (context->pixbuf);
1189
1190 /* Notify the client that we are ready to go */
1191 if (context->prepared_func)
1192 (* context->prepared_func) (context->pixbuf,
1193 NULL,
1194 context->user_data);
1195
1196 } else if (!context->did_prescan) {
1197 int rc;
1198
1199 /* start decompression */
1200 cinfo->buffered_image = cinfo->progressive_mode;
1201 rc = jpeg_start_decompress (cinfo);
1202 cinfo->do_fancy_upsampling = FALSE;
1203 cinfo->do_block_smoothing = FALSE;
1204
1205 if (rc == JPEG_SUSPENDED)
1206 continue;
1207
1208 context->did_prescan = TRUE;
1209 } else if (!cinfo->buffered_image) {
1210 /* we're decompressing unbuffered so
1211 * simply get scanline by scanline from jpeg lib
1212 */
1213 if (! gdk_pixbuf__jpeg_image_load_lines (context,
1214 error)) {
1215 retval = FALSE;
1216 goto out;
1217 }
1218
1219 if (cinfo->output_scanline >= cinfo->output_height) {
1220 retval = TRUE;
1221 goto out;
1222 }
1223 } else {
1224 /* we're decompressing buffered (progressive)
1225 * so feed jpeg lib scanlines
1226 */
1227
1228 /* keep going until we've done all passes */
1229 while (!jpeg_input_complete (cinfo)) {
1230 if (!context->in_output) {
1231 if (jpeg_start_output (cinfo, cinfo->input_scan_number)) {
1232 context->in_output = TRUE;
1233 context->dptr = gdk_pixbuf_get_pixels (context->pixbuf);
1234 }
1235 else
1236 break;
1237 }
1238
1239 /* get scanlines from jpeg lib */
1240 if (! gdk_pixbuf__jpeg_image_load_lines (context,
1241 error)) {
1242 retval = FALSE;
1243 goto out;
1244 }
1245
1246 if (cinfo->output_scanline >= cinfo->output_height &&
1247 jpeg_finish_output (cinfo))
1248 context->in_output = FALSE;
1249 else
1250 break;
1251 }
1252 if (jpeg_input_complete (cinfo)) {
1253 /* did entire image */
1254 retval = TRUE;
1255 goto out;
1256 }
1257 else
1258 continue;
1259 }
1260 }
1261 out:
1262 jpeg_destroy_exif_context (&exif_context);
1263 return retval;
1264 }
1265
1266 /* Save */
1267
1268 #define TO_FUNCTION_BUF_SIZE 4096
1269
1270 typedef struct {
1271 struct jpeg_destination_mgr pub;
1272 JOCTET *buffer;
1273 GdkPixbufSaveFunc save_func;
1274 gpointer user_data;
1275 GError **error;
1276 } ToFunctionDestinationManager;
1277
1278 void
to_callback_init(j_compress_ptr cinfo)1279 to_callback_init (j_compress_ptr cinfo)
1280 {
1281 ToFunctionDestinationManager *destmgr;
1282
1283 destmgr = (ToFunctionDestinationManager*) cinfo->dest;
1284 destmgr->pub.next_output_byte = destmgr->buffer;
1285 destmgr->pub.free_in_buffer = TO_FUNCTION_BUF_SIZE;
1286 }
1287
1288 static void
to_callback_do_write(j_compress_ptr cinfo,gsize length)1289 to_callback_do_write (j_compress_ptr cinfo, gsize length)
1290 {
1291 ToFunctionDestinationManager *destmgr;
1292
1293 destmgr = (ToFunctionDestinationManager*) cinfo->dest;
1294 if (!destmgr->save_func ((gchar *)destmgr->buffer,
1295 length,
1296 destmgr->error,
1297 destmgr->user_data)) {
1298 struct error_handler_data *errmgr;
1299
1300 errmgr = (struct error_handler_data *) cinfo->err;
1301 /* Use a default error message if the callback didn't set one,
1302 * which it should have.
1303 */
1304 if (errmgr->error && *errmgr->error == NULL) {
1305 g_set_error_literal (errmgr->error,
1306 GDK_PIXBUF_ERROR,
1307 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
1308 "write function failed");
1309 }
1310 siglongjmp (errmgr->setjmp_buffer, 1);
1311 g_assert_not_reached ();
1312 }
1313 }
1314
1315 static boolean
to_callback_empty_output_buffer(j_compress_ptr cinfo)1316 to_callback_empty_output_buffer (j_compress_ptr cinfo)
1317 {
1318 ToFunctionDestinationManager *destmgr;
1319
1320 destmgr = (ToFunctionDestinationManager*) cinfo->dest;
1321 to_callback_do_write (cinfo, TO_FUNCTION_BUF_SIZE);
1322 destmgr->pub.next_output_byte = destmgr->buffer;
1323 destmgr->pub.free_in_buffer = TO_FUNCTION_BUF_SIZE;
1324 return TRUE;
1325 }
1326
1327 void
to_callback_terminate(j_compress_ptr cinfo)1328 to_callback_terminate (j_compress_ptr cinfo)
1329 {
1330 ToFunctionDestinationManager *destmgr;
1331
1332 destmgr = (ToFunctionDestinationManager*) cinfo->dest;
1333 to_callback_do_write (cinfo, TO_FUNCTION_BUF_SIZE - destmgr->pub.free_in_buffer);
1334 }
1335
1336 static gboolean
real_save_jpeg(GdkPixbuf * pixbuf,gchar ** keys,gchar ** values,GError ** error,gboolean to_callback,FILE * f,GdkPixbufSaveFunc save_func,gpointer user_data)1337 real_save_jpeg (GdkPixbuf *pixbuf,
1338 gchar **keys,
1339 gchar **values,
1340 GError **error,
1341 gboolean to_callback,
1342 FILE *f,
1343 GdkPixbufSaveFunc save_func,
1344 gpointer user_data)
1345 {
1346 /* FIXME error handling is broken */
1347
1348 struct jpeg_compress_struct cinfo;
1349 guchar *buf = NULL;
1350 guchar *ptr;
1351 guchar *pixels = NULL;
1352 JSAMPROW *jbuf;
1353 int y = 0;
1354 volatile int quality = 75; /* default; must be between 0 and 100 */
1355 int i, j;
1356 int w, h = 0;
1357 int rowstride = 0;
1358 int n_channels;
1359 struct error_handler_data jerr;
1360 ToFunctionDestinationManager to_callback_destmgr;
1361 int x_density = 0;
1362 int y_density = 0;
1363 gchar *icc_profile = NULL;
1364 gchar *data;
1365 gint retval = TRUE;
1366 gsize icc_profile_size = 0;
1367
1368 to_callback_destmgr.buffer = NULL;
1369
1370 if (keys && *keys) {
1371 gchar **kiter = keys;
1372 gchar **viter = values;
1373
1374 while (*kiter) {
1375 if (strcmp (*kiter, "quality") == 0) {
1376 char *endptr = NULL;
1377 quality = strtol (*viter, &endptr, 10);
1378
1379 if (endptr == *viter) {
1380 g_set_error (error,
1381 GDK_PIXBUF_ERROR,
1382 GDK_PIXBUF_ERROR_BAD_OPTION,
1383 _("JPEG quality must be a value between 0 and 100; value “%s” could not be parsed."),
1384 *viter);
1385
1386 retval = FALSE;
1387 goto cleanup;
1388 }
1389
1390 if (quality < 0 ||
1391 quality > 100) {
1392 /* This is a user-visible error;
1393 * lets people skip the range-checking
1394 * in their app.
1395 */
1396 g_set_error (error,
1397 GDK_PIXBUF_ERROR,
1398 GDK_PIXBUF_ERROR_BAD_OPTION,
1399 _("JPEG quality must be a value between 0 and 100; value “%d” is not allowed."),
1400 quality);
1401
1402 retval = FALSE;
1403 goto cleanup;
1404 }
1405 } else if (strcmp (*kiter, "x-dpi") == 0) {
1406 char *endptr = NULL;
1407 x_density = strtol (*viter, &endptr, 10);
1408 if (endptr == *viter)
1409 x_density = -1;
1410
1411 if (x_density <= 0 ||
1412 x_density > 65535) {
1413 /* This is a user-visible error;
1414 * lets people skip the range-checking
1415 * in their app.
1416 */
1417 g_set_error (error,
1418 GDK_PIXBUF_ERROR,
1419 GDK_PIXBUF_ERROR_BAD_OPTION,
1420 _("JPEG x-dpi must be a value between 1 and 65535; value “%s” is not allowed."),
1421 *viter);
1422
1423 retval = FALSE;
1424 goto cleanup;
1425 }
1426 } else if (strcmp (*kiter, "y-dpi") == 0) {
1427 char *endptr = NULL;
1428 y_density = strtol (*viter, &endptr, 10);
1429 if (endptr == *viter)
1430 y_density = -1;
1431
1432 if (y_density <= 0 ||
1433 y_density > 65535) {
1434 /* This is a user-visible error;
1435 * lets people skip the range-checking
1436 * in their app.
1437 */
1438 g_set_error (error,
1439 GDK_PIXBUF_ERROR,
1440 GDK_PIXBUF_ERROR_BAD_OPTION,
1441 _("JPEG y-dpi must be a value between 1 and 65535; value “%s” is not allowed."),
1442 *viter);
1443
1444 retval = FALSE;
1445 goto cleanup;
1446 }
1447 } else if (strcmp (*kiter, "icc-profile") == 0) {
1448 /* decode from base64 */
1449 icc_profile = (gchar*) g_base64_decode (*viter, &icc_profile_size);
1450 if (icc_profile_size < 127) {
1451 /* This is a user-visible error */
1452 g_set_error (error,
1453 GDK_PIXBUF_ERROR,
1454 GDK_PIXBUF_ERROR_BAD_OPTION,
1455 _("Color profile has invalid length “%u”."),
1456 (guint) icc_profile_size);
1457 retval = FALSE;
1458 goto cleanup;
1459 }
1460 } else {
1461 g_warning ("Unrecognized parameter (%s) passed to JPEG saver.", *kiter);
1462 }
1463
1464 ++kiter;
1465 ++viter;
1466 }
1467 }
1468
1469 rowstride = gdk_pixbuf_get_rowstride (pixbuf);
1470 n_channels = gdk_pixbuf_get_n_channels (pixbuf);
1471
1472 w = gdk_pixbuf_get_width (pixbuf);
1473 h = gdk_pixbuf_get_height (pixbuf);
1474 pixels = gdk_pixbuf_get_pixels (pixbuf);
1475
1476 /* Guaranteed by the caller. */
1477 g_assert (w >= 0);
1478 g_assert (h >= 0);
1479 g_assert (rowstride >= 0);
1480 g_assert (n_channels >= 0);
1481
1482 /* Allocate a small buffer to convert image data,
1483 * and a larger buffer if doing to_callback save.
1484 */
1485 buf = g_try_malloc (w * 3 * sizeof (guchar));
1486 if (!buf) {
1487 g_set_error_literal (error,
1488 GDK_PIXBUF_ERROR,
1489 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
1490 _("Couldn’t allocate memory for loading JPEG file"));
1491 retval = FALSE;
1492 goto cleanup;
1493 }
1494 if (to_callback) {
1495 to_callback_destmgr.buffer = g_try_malloc (TO_FUNCTION_BUF_SIZE);
1496 if (!to_callback_destmgr.buffer) {
1497 g_set_error_literal (error,
1498 GDK_PIXBUF_ERROR,
1499 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
1500 _("Couldn’t allocate memory for loading JPEG file"));
1501 retval = FALSE;
1502 goto cleanup;
1503 }
1504 }
1505
1506 /* set up error handling */
1507 cinfo.err = jpeg_std_error (&(jerr.pub));
1508 jerr.pub.error_exit = fatal_error_handler;
1509 jerr.pub.output_message = output_message_handler;
1510 jerr.error = error;
1511
1512 if (sigsetjmp (jerr.setjmp_buffer, 1)) {
1513 jpeg_destroy_compress (&cinfo);
1514 retval = FALSE;
1515 goto cleanup;
1516 }
1517
1518 /* setup compress params */
1519 jpeg_create_compress (&cinfo);
1520 if (to_callback) {
1521 to_callback_destmgr.pub.init_destination = to_callback_init;
1522 to_callback_destmgr.pub.empty_output_buffer = to_callback_empty_output_buffer;
1523 to_callback_destmgr.pub.term_destination = to_callback_terminate;
1524 to_callback_destmgr.error = error;
1525 to_callback_destmgr.save_func = save_func;
1526 to_callback_destmgr.user_data = user_data;
1527 cinfo.dest = (struct jpeg_destination_mgr*) &to_callback_destmgr;
1528 } else {
1529 jpeg_stdio_dest (&cinfo, f);
1530 }
1531 cinfo.image_width = w;
1532 cinfo.image_height = h;
1533 cinfo.input_components = 3;
1534 cinfo.in_color_space = JCS_RGB;
1535
1536 /* set up jepg compression parameters */
1537 jpeg_set_defaults (&cinfo);
1538 jpeg_set_quality (&cinfo, quality, TRUE);
1539
1540 /* set density information */
1541 if (x_density > 0 && y_density > 0) {
1542 cinfo.density_unit = 1; /* Dots per inch */
1543 cinfo.X_density = x_density;
1544 cinfo.Y_density = y_density;
1545 }
1546
1547 jpeg_start_compress (&cinfo, TRUE);
1548
1549 /* write ICC profile data */
1550 if (icc_profile != NULL) {
1551 /* optimise for the common case where only one APP2 segment is required */
1552 if (icc_profile_size < 0xffef) {
1553 data = g_new (gchar, icc_profile_size + 14);
1554 memcpy (data, "ICC_PROFILE\000\001\001", 14);
1555 memcpy (data + 14, icc_profile, icc_profile_size);
1556 jpeg_write_marker (&cinfo, JPEG_APP0+2, (const JOCTET *) data, icc_profile_size + 14);
1557 g_free (data);
1558 } else {
1559 guint segments;
1560 guint size = 0xffef;
1561 guint offset;
1562
1563 segments = (guint) ceilf ((gfloat) icc_profile_size / (gfloat) 0xffef);
1564 data = g_new (gchar, 0xffff);
1565 memcpy (data, "ICC_PROFILE\000", 12);
1566 data[13] = segments;
1567 for (i=0; i<=segments; i++) {
1568 data[12] = i;
1569 offset = 0xffef * i;
1570
1571 /* last segment */
1572 if (i == segments)
1573 size = icc_profile_size % 0xffef;
1574
1575 memcpy (data + 14, icc_profile + offset, size);
1576 jpeg_write_marker (&cinfo, JPEG_APP0+2, (const JOCTET *) data, size + 14);
1577 }
1578 g_free (data);
1579 }
1580 }
1581
1582 /* get the start pointer */
1583 ptr = pixels;
1584 /* go one scanline at a time... and save */
1585 i = 0;
1586 while (cinfo.next_scanline < cinfo.image_height) {
1587 /* convert scanline from ARGB to RGB packed */
1588 for (j = 0; j < w; j++)
1589 memcpy (&(buf[j*3]), &(ptr[(gsize)i*rowstride + j*n_channels]), 3);
1590
1591 /* write scanline */
1592 jbuf = (JSAMPROW *)(&buf);
1593 if (jpeg_write_scanlines (&cinfo, jbuf, 1) == 0) {
1594 jpeg_destroy_compress (&cinfo);
1595 retval = FALSE;
1596 goto cleanup;
1597 }
1598
1599 i++;
1600 y++;
1601
1602 }
1603
1604 /* finish off */
1605 jpeg_finish_compress (&cinfo);
1606 jpeg_destroy_compress(&cinfo);
1607 cleanup:
1608 g_free (buf);
1609 g_free (to_callback_destmgr.buffer);
1610 g_free (icc_profile);
1611 return retval;
1612 }
1613
1614 static gboolean
gdk_pixbuf__jpeg_image_save(FILE * f,GdkPixbuf * pixbuf,gchar ** keys,gchar ** values,GError ** error)1615 gdk_pixbuf__jpeg_image_save (FILE *f,
1616 GdkPixbuf *pixbuf,
1617 gchar **keys,
1618 gchar **values,
1619 GError **error)
1620 {
1621 return real_save_jpeg (pixbuf, keys, values, error,
1622 FALSE, f, NULL, NULL);
1623 }
1624
1625 static gboolean
gdk_pixbuf__jpeg_image_save_to_callback(GdkPixbufSaveFunc save_func,gpointer user_data,GdkPixbuf * pixbuf,gchar ** keys,gchar ** values,GError ** error)1626 gdk_pixbuf__jpeg_image_save_to_callback (GdkPixbufSaveFunc save_func,
1627 gpointer user_data,
1628 GdkPixbuf *pixbuf,
1629 gchar **keys,
1630 gchar **values,
1631 GError **error)
1632 {
1633 return real_save_jpeg (pixbuf, keys, values, error,
1634 TRUE, NULL, save_func, user_data);
1635 }
1636
1637 static gboolean
gdk_pixbuf__jpeg_is_save_option_supported(const gchar * option_key)1638 gdk_pixbuf__jpeg_is_save_option_supported (const gchar *option_key)
1639 {
1640 if (g_strcmp0 (option_key, "quality") == 0 ||
1641 g_strcmp0 (option_key, "icc-profile") == 0)
1642 return TRUE;
1643
1644 return FALSE;
1645 }
1646
1647 #ifndef INCLUDE_jpeg
1648 #define MODULE_ENTRY(function) G_MODULE_EXPORT void function
1649 #else
1650 #define MODULE_ENTRY(function) void _gdk_pixbuf__jpeg_ ## function
1651 #endif
1652
MODULE_ENTRY(fill_vtable)1653 MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
1654 {
1655 module->load = gdk_pixbuf__jpeg_image_load;
1656 module->begin_load = gdk_pixbuf__jpeg_image_begin_load;
1657 module->stop_load = gdk_pixbuf__jpeg_image_stop_load;
1658 module->load_increment = gdk_pixbuf__jpeg_image_load_increment;
1659 module->save = gdk_pixbuf__jpeg_image_save;
1660 module->save_to_callback = gdk_pixbuf__jpeg_image_save_to_callback;
1661 module->is_save_option_supported = gdk_pixbuf__jpeg_is_save_option_supported;
1662 }
1663
MODULE_ENTRY(fill_info)1664 MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
1665 {
1666 static const GdkPixbufModulePattern signature[] = {
1667 { "\xff\xd8", NULL, 100 },
1668 { NULL, NULL, 0 }
1669 };
1670 static const gchar *mime_types[] = {
1671 "image/jpeg",
1672 NULL
1673 };
1674 static const gchar *extensions[] = {
1675 "jpeg",
1676 "jpe",
1677 "jpg",
1678 NULL
1679 };
1680
1681 info->name = "jpeg";
1682 info->signature = (GdkPixbufModulePattern *) signature;
1683 info->description = NC_("image format", "JPEG");
1684 info->mime_types = (gchar **) mime_types;
1685 info->extensions = (gchar **) extensions;
1686 info->flags = GDK_PIXBUF_FORMAT_WRITABLE | GDK_PIXBUF_FORMAT_THREADSAFE;
1687 info->license = "LGPL";
1688 }
1689