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 ; /* 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 |
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 (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 | |
138 | static void |
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 |
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 |
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 |
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 |
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 (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 | |
255 | static void |
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 |
271 | stdio_term_source (j_decompress_ptr cinfo) |
272 | { |
273 | } |
274 | |
275 | static gchar * |
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 | |
295 | static 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 | |
305 | static 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 */ |
316 | static gboolean |
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 (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; |
385 | out: |
386 | return ret; |
387 | } |
388 | |
389 | static gboolean |
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 (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 | |
512 | out: |
513 | return ret; |
514 | } |
515 | |
516 | static void |
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, 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 | |
532 | static gchar * |
533 | (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 | |
547 | static void |
548 | jpeg_destroy_exif_context (JpegExifContext *context) |
549 | { |
550 | g_free (mem: context->icc_profile); |
551 | } |
552 | |
553 | /* Shared library entry point */ |
554 | static GdkPixbuf * |
555 | gdk_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 *; |
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 | |
717 | out: |
718 | jpeg_finish_decompress (cinfo); |
719 | jpeg_destroy_decompress (cinfo); |
720 | jpeg_destroy_exif_context (context: &exif_context); |
721 | |
722 | return pixbuf; |
723 | } |
724 | |
725 | static GdkPixbuf * |
726 | gdk_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. */ |
738 | static void |
739 | init_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 | |
747 | static void |
748 | term_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" */ |
756 | static boolean |
757 | fill_input_buffer (j_decompress_ptr cinfo) |
758 | { |
759 | return FALSE; |
760 | } |
761 | |
762 | |
763 | static void |
764 | skip_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 | |
787 | static gpointer |
788 | gdk_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 | */ |
858 | static gboolean |
859 | gdk_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 | |
918 | static gboolean |
919 | gdk_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 | */ |
984 | static gboolean |
985 | gdk_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* ; |
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 | } |
1271 | out: |
1272 | jpeg_destroy_exif_context (context: &exif_context); |
1273 | return retval; |
1274 | } |
1275 | |
1276 | /* Save */ |
1277 | |
1278 | #define TO_FUNCTION_BUF_SIZE 4096 |
1279 | |
1280 | typedef struct { |
1281 | struct jpeg_destination_mgr pub; |
1282 | JOCTET *buffer; |
1283 | GdkPixbufSaveFunc save_func; |
1284 | gpointer user_data; |
1285 | GError **error; |
1286 | } ToFunctionDestinationManager; |
1287 | |
1288 | void |
1289 | to_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 | |
1298 | static void |
1299 | to_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 | |
1325 | static boolean |
1326 | to_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 | |
1337 | void |
1338 | to_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 | |
1346 | static gboolean |
1347 | real_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); |
1617 | cleanup: |
1618 | g_free (mem: buf); |
1619 | g_free (mem: to_callback_destmgr.buffer); |
1620 | g_free (mem: icc_profile); |
1621 | return retval; |
1622 | } |
1623 | |
1624 | static gboolean |
1625 | gdk_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 | |
1635 | static gboolean |
1636 | gdk_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 | |
1647 | static gboolean |
1648 | gdk_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 | |
1663 | MODULE_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 | |
1674 | MODULE_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 | |