]> Pileus Git - ~andy/gtk/blob - gdk-pixbuf/io-jpeg.c
Changes to make gdk-pixbuf threadsafe (#157310, #157306, Colin Walters):
[~andy/gtk] / gdk-pixbuf / io-jpeg.c
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, write to the
25  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26  * Boston, MA 02111-1307, USA.
27  */
28
29
30 #include <config.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <setjmp.h>
35 #include <jpeglib.h>
36 #include "gdk-pixbuf-private.h"
37 #include "gdk-pixbuf-io.h"
38
39 #ifndef HAVE_SIGSETJMP
40 #define sigjmp_buf jmp_buf
41 #define sigsetjmp(jb, x) setjmp(jb)
42 #define siglongjmp longjmp
43 #endif
44 \f
45
46 /* we are a "source manager" as far as libjpeg is concerned */
47 #define JPEG_PROG_BUF_SIZE 65536
48
49 typedef struct {
50         struct jpeg_source_mgr pub;   /* public fields */
51
52         JOCTET buffer[JPEG_PROG_BUF_SIZE];              /* start of buffer */
53         long  skip_next;              /* number of bytes to skip next read */
54         
55 } my_source_mgr;
56
57 typedef my_source_mgr * my_src_ptr;
58
59 /* error handler data */
60 struct error_handler_data {
61         struct jpeg_error_mgr pub;
62         sigjmp_buf setjmp_buffer;
63         GError **error;
64 };
65
66 /* progressive loader context */
67 typedef struct {
68         GdkPixbufModuleSizeFunc     size_func;
69         GdkPixbufModuleUpdatedFunc  updated_func;
70         GdkPixbufModulePreparedFunc prepared_func;
71         gpointer                    user_data;
72         
73         GdkPixbuf                *pixbuf;
74         guchar                   *dptr;   /* current position in pixbuf */
75
76         gboolean                 did_prescan;  /* are we in image data yet? */
77         gboolean                 got_header;  /* have we loaded jpeg header? */
78         gboolean                 src_initialized;/* TRUE when jpeg lib initialized */
79         gboolean                 in_output;   /* did we get suspended in an output pass? */
80         struct jpeg_decompress_struct cinfo;
81         struct error_handler_data     jerr;
82 } JpegProgContext;
83
84 static GdkPixbuf *gdk_pixbuf__jpeg_image_load (FILE *f, GError **error);
85 static gpointer gdk_pixbuf__jpeg_image_begin_load (GdkPixbufModuleSizeFunc           func0,
86                                                    GdkPixbufModulePreparedFunc func1, 
87                                                    GdkPixbufModuleUpdatedFunc func2,
88                                                    gpointer user_data,
89                                                    GError **error);
90 static gboolean gdk_pixbuf__jpeg_image_stop_load (gpointer context, GError **error);
91 static gboolean gdk_pixbuf__jpeg_image_load_increment(gpointer context,
92                                                       const guchar *buf, guint size,
93                                                       GError **error);
94
95
96 static void
97 fatal_error_handler (j_common_ptr cinfo)
98 {
99         struct error_handler_data *errmgr;
100         char buffer[JMSG_LENGTH_MAX];
101         
102         errmgr = (struct error_handler_data *) cinfo->err;
103         
104         /* Create the message */
105         (* cinfo->err->format_message) (cinfo, buffer);
106
107         /* broken check for *error == NULL for robustness against
108          * crappy JPEG library
109          */
110         if (errmgr->error && *errmgr->error == NULL) {
111                 g_set_error (errmgr->error,
112                              GDK_PIXBUF_ERROR,
113                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
114                              _("Error interpreting JPEG image file (%s)"),
115                              buffer);
116         }
117         
118         siglongjmp (errmgr->setjmp_buffer, 1);
119
120         g_assert_not_reached ();
121 }
122
123 static void
124 output_message_handler (j_common_ptr cinfo)
125 {
126   /* This method keeps libjpeg from dumping crap to stderr */
127
128   /* do nothing */
129 }
130
131 /* explode gray image data from jpeg library into rgb components in pixbuf */
132 static void
133 explode_gray_into_buf (struct jpeg_decompress_struct *cinfo,
134                        guchar **lines) 
135 {
136         gint i, j;
137         guint w;
138
139         g_return_if_fail (cinfo != NULL);
140         g_return_if_fail (cinfo->output_components == 1);
141         g_return_if_fail (cinfo->out_color_space == JCS_GRAYSCALE);
142
143         /* Expand grey->colour.  Expand from the end of the
144          * memory down, so we can use the same buffer.
145          */
146         w = cinfo->output_width;
147         for (i = cinfo->rec_outbuf_height - 1; i >= 0; i--) {
148                 guchar *from, *to;
149                 
150                 from = lines[i] + w - 1;
151                 to = lines[i] + (w - 1) * 3;
152                 for (j = w - 1; j >= 0; j--) {
153                         to[0] = from[0];
154                         to[1] = from[0];
155                         to[2] = from[0];
156                         to -= 3;
157                         from--;
158                 }
159         }
160 }
161
162
163 static void
164 convert_cmyk_to_rgb (struct jpeg_decompress_struct *cinfo,
165                      guchar **lines) 
166 {
167         gint i, j;
168
169         g_return_if_fail (cinfo != NULL);
170         g_return_if_fail (cinfo->output_components == 4);
171         g_return_if_fail (cinfo->out_color_space == JCS_CMYK);
172
173         for (i = cinfo->rec_outbuf_height - 1; i >= 0; i--) {
174                 guchar *p;
175                 
176                 p = lines[i];
177                 for (j = 0; j < cinfo->output_width; j++) {
178                         int c, m, y, k;
179                         c = p[0];
180                         m = p[1];
181                         y = p[2];
182                         k = p[3];
183                         if (cinfo->saw_Adobe_marker) {
184                                 p[0] = k*c / 255;
185                                 p[1] = k*m / 255;
186                                 p[2] = k*y / 255;
187                         }
188                         else {
189                                 p[0] = (255 - k)*(255 - c) / 255;
190                                 p[1] = (255 - k)*(255 - m) / 255;
191                                 p[2] = (255 - k)*(255 - y) / 255;
192                         }
193                         p[3] = 255;
194                         p += 4;
195                 }
196         }
197 }
198
199 typedef struct {
200   struct jpeg_source_mgr pub;   /* public fields */
201
202   FILE * infile;                /* source stream */
203   JOCTET * buffer;              /* start of buffer */
204   boolean start_of_file;        /* have we gotten any data yet? */
205 } stdio_source_mgr;
206
207 typedef stdio_source_mgr * stdio_src_ptr;
208
209 static void
210 stdio_init_source (j_decompress_ptr cinfo)
211 {
212   stdio_src_ptr src = (stdio_src_ptr)cinfo->src;
213   src->start_of_file = FALSE;
214 }
215
216 static boolean
217 stdio_fill_input_buffer (j_decompress_ptr cinfo)
218 {
219   stdio_src_ptr src = (stdio_src_ptr) cinfo->src;
220   size_t nbytes;
221
222   nbytes = fread (src->buffer, 1, JPEG_PROG_BUF_SIZE, src->infile);
223
224   if (nbytes <= 0) {
225 #if 0
226     if (src->start_of_file)     /* Treat empty input file as fatal error */
227       ERREXIT(cinfo, JERR_INPUT_EMPTY);
228     WARNMS(cinfo, JWRN_JPEG_EOF);
229 #endif
230     /* Insert a fake EOI marker */
231     src->buffer[0] = (JOCTET) 0xFF;
232     src->buffer[1] = (JOCTET) JPEG_EOI;
233     nbytes = 2;
234   }
235
236   src->pub.next_input_byte = src->buffer;
237   src->pub.bytes_in_buffer = nbytes;
238   src->start_of_file = FALSE;
239
240   return TRUE;
241 }
242
243 static void
244 stdio_skip_input_data (j_decompress_ptr cinfo, long num_bytes)
245 {
246   stdio_src_ptr src = (stdio_src_ptr) cinfo->src;
247
248   if (num_bytes > 0) {
249     while (num_bytes > (long) src->pub.bytes_in_buffer) {
250       num_bytes -= (long) src->pub.bytes_in_buffer;
251       (void)stdio_fill_input_buffer(cinfo);
252     }
253     src->pub.next_input_byte += (size_t) num_bytes;
254     src->pub.bytes_in_buffer -= (size_t) num_bytes;
255   }
256 }
257
258 static void
259 stdio_term_source (j_decompress_ptr cinfo)
260 {
261 }
262
263 static gchar *
264 colorspace_name (const J_COLOR_SPACE jpeg_color_space) 
265 {
266         switch (jpeg_color_space) {
267             case JCS_UNKNOWN: return "UNKNOWN"; 
268             case JCS_GRAYSCALE: return "GRAYSCALE"; 
269             case JCS_RGB: return "RGB"; 
270             case JCS_YCbCr: return "YCbCr"; 
271             case JCS_CMYK: return "CMYK"; 
272             case JCS_YCCK: return "YCCK";
273             default: return "invalid";
274         }
275 }
276
277 /* Shared library entry point */
278 static GdkPixbuf *
279 gdk_pixbuf__jpeg_image_load (FILE *f, GError **error)
280 {
281         gint i;
282         GdkPixbuf * volatile pixbuf = NULL;
283         guchar *dptr;
284         guchar *lines[4]; /* Used to expand rows, via rec_outbuf_height, 
285                            * from the header file: 
286                            * " Usually rec_outbuf_height will be 1 or 2, 
287                            * at most 4."
288                            */
289         guchar **lptr;
290         struct jpeg_decompress_struct cinfo;
291         struct error_handler_data jerr;
292         stdio_src_ptr src;
293
294         /* setup error handler */
295         cinfo.err = jpeg_std_error (&jerr.pub);
296         jerr.pub.error_exit = fatal_error_handler;
297         jerr.pub.output_message = output_message_handler;
298
299         jerr.error = error;
300         
301         if (sigsetjmp (jerr.setjmp_buffer, 1)) {
302                 /* Whoops there was a jpeg error */
303                 if (pixbuf)
304                         g_object_unref (pixbuf);
305
306                 jpeg_destroy_decompress (&cinfo);
307                 return NULL;
308         }
309
310         /* load header, setup */
311         jpeg_create_decompress (&cinfo);
312
313         cinfo.src = (struct jpeg_source_mgr *)
314           (*cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_PERMANENT,
315                                   sizeof (stdio_source_mgr));
316         src = (stdio_src_ptr) cinfo.src;
317         src->buffer = (JOCTET *)
318           (*cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_PERMANENT,
319                                       JPEG_PROG_BUF_SIZE * sizeof (JOCTET));
320
321         src->pub.init_source = stdio_init_source;
322         src->pub.fill_input_buffer = stdio_fill_input_buffer;
323         src->pub.skip_input_data = stdio_skip_input_data;
324         src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
325         src->pub.term_source = stdio_term_source;
326         src->infile = f;
327         src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
328         src->pub.next_input_byte = NULL; /* until buffer loaded */
329
330         jpeg_read_header (&cinfo, TRUE);
331         jpeg_start_decompress (&cinfo);
332         cinfo.do_fancy_upsampling = FALSE;
333         cinfo.do_block_smoothing = FALSE;
334
335         pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, 
336                                  cinfo.out_color_components == 4 ? TRUE : FALSE, 
337                                  8, cinfo.output_width, cinfo.output_height);
338               
339         if (!pixbuf) {
340                 jpeg_destroy_decompress (&cinfo);
341
342                 /* broken check for *error == NULL for robustness against
343                  * crappy JPEG library
344                  */
345                 if (error && *error == NULL) {
346                         g_set_error (error,
347                                      GDK_PIXBUF_ERROR,
348                                      GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
349                                      _("Insufficient memory to load image, try exiting some applications to free memory"));
350                 }
351                 
352                 return NULL;
353         }
354
355         dptr = pixbuf->pixels;
356
357         /* decompress all the lines, a few at a time */
358         while (cinfo.output_scanline < cinfo.output_height) {
359                 lptr = lines;
360                 for (i = 0; i < cinfo.rec_outbuf_height; i++) {
361                         *lptr++ = dptr;
362                         dptr += pixbuf->rowstride;
363                 }
364
365                 jpeg_read_scanlines (&cinfo, lines, cinfo.rec_outbuf_height);
366
367                 switch (cinfo.out_color_space) {
368                     case JCS_GRAYSCALE:
369                       explode_gray_into_buf (&cinfo, lines);
370                       break;
371                     case JCS_RGB:
372                       /* do nothing */
373                       break;
374                     case JCS_CMYK:
375                       convert_cmyk_to_rgb (&cinfo, lines);
376                       break;
377                     default:
378                       g_object_unref (pixbuf);
379                       if (error && *error == NULL) {
380                         g_set_error (error,
381                                      GDK_PIXBUF_ERROR,
382                                      GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
383                                      _("Unsupported JPEG color space (%s)"),
384                                      colorspace_name (cinfo.out_color_space)); 
385                       }
386                 
387                       jpeg_destroy_decompress (&cinfo);
388                       return NULL;
389                 }
390         }
391
392         jpeg_finish_decompress (&cinfo);
393         jpeg_destroy_decompress (&cinfo);
394
395         return pixbuf;
396 }
397
398
399 /**** Progressive image loading handling *****/
400
401 /* these routines required because we are acting as a source manager for */
402 /* libjpeg. */
403 static void
404 init_source (j_decompress_ptr cinfo)
405 {
406         my_src_ptr src = (my_src_ptr) cinfo->src;
407
408         src->skip_next = 0;
409 }
410
411
412 static void
413 term_source (j_decompress_ptr cinfo)
414 {
415         /* XXXX - probably should scream something has happened */
416 }
417
418
419 /* for progressive loading (called "I/O Suspension" by libjpeg docs) */
420 /* we do nothing except return "FALSE"                               */
421 static boolean
422 fill_input_buffer (j_decompress_ptr cinfo)
423 {
424         return FALSE;
425 }
426
427
428 static void
429 skip_input_data (j_decompress_ptr cinfo, long num_bytes)
430 {
431         my_src_ptr src = (my_src_ptr) cinfo->src;
432         long   num_can_do;
433
434         /* move as far as we can into current buffer */
435         /* then set skip_next to catch the rest      */
436         if (num_bytes > 0) {
437                 num_can_do = MIN (src->pub.bytes_in_buffer, num_bytes);
438                 src->pub.next_input_byte += (size_t) num_can_do;
439                 src->pub.bytes_in_buffer -= (size_t) num_can_do;
440
441                 src->skip_next = num_bytes - num_can_do;
442         }
443 }
444
445  
446 /* 
447  * func - called when we have pixmap created (but no image data)
448  * user_data - passed as arg 1 to func
449  * return context (opaque to user)
450  */
451
452 static gpointer
453 gdk_pixbuf__jpeg_image_begin_load (GdkPixbufModuleSizeFunc size_func,
454                                    GdkPixbufModulePreparedFunc prepared_func, 
455                                    GdkPixbufModuleUpdatedFunc updated_func,
456                                    gpointer user_data,
457                                    GError **error)
458 {
459         JpegProgContext *context;
460         my_source_mgr   *src;
461
462         context = g_new0 (JpegProgContext, 1);
463         context->size_func = size_func;
464         context->prepared_func = prepared_func;
465         context->updated_func  = updated_func;
466         context->user_data = user_data;
467         context->pixbuf = NULL;
468         context->got_header = FALSE;
469         context->did_prescan = FALSE;
470         context->src_initialized = FALSE;
471         context->in_output = FALSE;
472
473         /* create libjpeg structures */
474         jpeg_create_decompress (&context->cinfo);
475
476         context->cinfo.src = (struct jpeg_source_mgr *) g_try_malloc (sizeof (my_source_mgr));
477         if (!context->cinfo.src) {
478                 g_set_error (error,
479                              GDK_PIXBUF_ERROR,
480                              GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
481                              _("Couldn't allocate memory for loading JPEG file"));
482                 return NULL;
483         }
484         memset (context->cinfo.src, 0, sizeof (my_source_mgr));
485        
486         src = (my_src_ptr) context->cinfo.src;
487
488         context->cinfo.err = jpeg_std_error (&context->jerr.pub);
489         context->jerr.pub.error_exit = fatal_error_handler;
490         context->jerr.pub.output_message = output_message_handler;
491         context->jerr.error = error;
492         
493         src = (my_src_ptr) context->cinfo.src;
494         src->pub.init_source = init_source;
495         src->pub.fill_input_buffer = fill_input_buffer;
496         src->pub.skip_input_data = skip_input_data;
497         src->pub.resync_to_restart = jpeg_resync_to_restart;
498         src->pub.term_source = term_source;
499         src->pub.bytes_in_buffer = 0;
500         src->pub.next_input_byte = NULL;
501
502         context->jerr.error = NULL;
503         
504         return (gpointer) context;
505 }
506
507 /*
508  * context - returned from image_begin_load
509  *
510  * free context, unref gdk_pixbuf
511  */
512 static gboolean
513 gdk_pixbuf__jpeg_image_stop_load (gpointer data, GError **error)
514 {
515         JpegProgContext *context = (JpegProgContext *) data;
516
517         g_return_val_if_fail (context != NULL, TRUE);
518         
519         /* FIXME this thing needs to report errors if
520          * we have unused image data
521          */
522         
523         if (context->pixbuf)
524                 g_object_unref (context->pixbuf);
525         
526         /* if we have an error? */
527         if (sigsetjmp (context->jerr.setjmp_buffer, 1)) {
528                 jpeg_destroy_decompress (&context->cinfo);
529         } else {
530                 jpeg_finish_decompress(&context->cinfo);
531                 jpeg_destroy_decompress(&context->cinfo);
532         }
533
534         if (context->cinfo.src) {
535                 my_src_ptr src = (my_src_ptr) context->cinfo.src;
536                 
537                 g_free (src);
538         }
539
540         g_free (context);
541
542         return TRUE;
543 }
544
545
546
547
548 /*
549  * context - from image_begin_load
550  * buf - new image data
551  * size - length of new image data
552  *
553  * append image data onto inrecrementally built output image
554  */
555 static gboolean
556 gdk_pixbuf__jpeg_image_load_increment (gpointer data,
557                                        const guchar *buf, guint size,
558                                        GError **error)
559 {
560         JpegProgContext *context = (JpegProgContext *)data;
561         struct jpeg_decompress_struct *cinfo;
562         my_src_ptr  src;
563         guint       num_left, num_copy;
564         guint       last_bytes_left;
565         guint       spinguard;
566         gboolean    first;
567         const guchar *bufhd;
568         gint        width, height;
569
570         g_return_val_if_fail (context != NULL, FALSE);
571         g_return_val_if_fail (buf != NULL, FALSE);
572
573         src = (my_src_ptr) context->cinfo.src;
574
575         cinfo = &context->cinfo;
576
577         context->jerr.error = error;
578         
579         /* check for fatal error */
580         if (sigsetjmp (context->jerr.setjmp_buffer, 1)) {
581                 return FALSE;
582         }
583
584         /* skip over data if requested, handle unsigned int sizes cleanly */
585         /* only can happen if we've already called jpeg_get_header once   */
586         if (context->src_initialized && src->skip_next) {
587                 if (src->skip_next > size) {
588                         src->skip_next -= size;
589                         return TRUE;
590                 } else {
591                         num_left = size - src->skip_next;
592                         bufhd = buf + src->skip_next;
593                         src->skip_next = 0;
594                 }
595         } else {
596                 num_left = size;
597                 bufhd = buf;
598         }
599
600         if (num_left == 0)
601                 return TRUE;
602
603         last_bytes_left = 0;
604         spinguard = 0;
605         first = TRUE;
606         while (TRUE) {
607
608                 /* handle any data from caller we haven't processed yet */
609                 if (num_left > 0) {
610                         if(src->pub.bytes_in_buffer && 
611                            src->pub.next_input_byte != src->buffer)
612                                 memmove(src->buffer, src->pub.next_input_byte,
613                                         src->pub.bytes_in_buffer);
614
615
616                         num_copy = MIN (JPEG_PROG_BUF_SIZE - src->pub.bytes_in_buffer,
617                                         num_left);
618
619                         memcpy(src->buffer + src->pub.bytes_in_buffer, bufhd,num_copy);
620                         src->pub.next_input_byte = src->buffer;
621                         src->pub.bytes_in_buffer += num_copy;
622                         bufhd += num_copy;
623                         num_left -= num_copy;
624                 } else {
625                 /* did anything change from last pass, if not return */
626                         if (first) {
627                                 last_bytes_left = src->pub.bytes_in_buffer;
628                                 first = FALSE;
629                         } else if (src->pub.bytes_in_buffer == last_bytes_left)
630                                 spinguard++;
631                         else
632                                 last_bytes_left = src->pub.bytes_in_buffer;
633                 }
634
635                 /* should not go through twice and not pull bytes out of buf */
636                 if (spinguard > 2)
637                         return TRUE;
638
639                 /* try to load jpeg header */
640                 if (!context->got_header) {
641                         int rc;
642                         
643                         rc = jpeg_read_header (cinfo, TRUE);
644                         context->src_initialized = TRUE;
645                         
646                         if (rc == JPEG_SUSPENDED)
647                                 continue;
648                         
649                         context->got_header = TRUE;
650                         
651                         width = cinfo->image_width;
652                         height = cinfo->image_height;
653                         if (context->size_func) {
654                                 (* context->size_func) (&width, &height, context->user_data);
655                                 if (width == 0 || height == 0)
656                                         return FALSE;
657                         }
658                         
659                         for (cinfo->scale_denom = 2; cinfo->scale_denom <= 8; cinfo->scale_denom *= 2) {
660                                 jpeg_calc_output_dimensions (cinfo);
661                                 if (cinfo->output_width < width || cinfo->output_height < height) {
662                                         cinfo->scale_denom /= 2;
663                                         break;
664                                 }
665                         }
666                         jpeg_calc_output_dimensions (cinfo);
667                         
668                         context->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, 
669                                                           cinfo->output_components == 4 ? TRUE : FALSE,
670                                                           8, 
671                                                           cinfo->output_width,
672                                                           cinfo->output_height);
673
674                         if (context->pixbuf == NULL) {
675                                 g_set_error (error,
676                                              GDK_PIXBUF_ERROR,
677                                              GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
678                                              _("Couldn't allocate memory for loading JPEG file"));
679                                 return FALSE;
680                         }
681                         
682                         /* Use pixbuf buffer to store decompressed data */
683                         context->dptr = context->pixbuf->pixels;
684                         
685                         /* Notify the client that we are ready to go */
686                         (* context->prepared_func) (context->pixbuf,
687                                                     NULL,
688                                                     context->user_data);
689                         
690                 } else if (!context->did_prescan) {
691                         int rc;                 
692                         
693                         /* start decompression */
694                         cinfo->buffered_image = TRUE;
695                         rc = jpeg_start_decompress (cinfo);
696                         cinfo->do_fancy_upsampling = FALSE;
697                         cinfo->do_block_smoothing = FALSE;
698
699                         if (rc == JPEG_SUSPENDED)
700                                 continue;
701
702                         context->did_prescan = TRUE;
703                 } else {
704                         /* we're decompressing so feed jpeg lib scanlines */
705                         guchar *lines[4];
706                         guchar **lptr;
707                         guchar *rowptr;
708                         gint   nlines, i;
709
710                         /* keep going until we've done all passes */
711                         while (!jpeg_input_complete (cinfo)) {
712                                 if (!context->in_output) {
713                                         if (jpeg_start_output (cinfo, cinfo->input_scan_number)) {
714                                                 context->in_output = TRUE;
715                                                 context->dptr = context->pixbuf->pixels;
716                                         }
717                                         else
718                                                 break;
719                                 }
720                                 /* keep going until we've done all scanlines */
721                                 while (cinfo->output_scanline < cinfo->output_height) {
722                                         lptr = lines;
723                                         rowptr = context->dptr;
724                                         for (i=0; i < cinfo->rec_outbuf_height; i++) {
725                                                 *lptr++ = rowptr;
726                                                 rowptr += context->pixbuf->rowstride;
727                                         }
728                                         
729                                         nlines = jpeg_read_scanlines (cinfo, lines,
730                                                                       cinfo->rec_outbuf_height);
731                                         if (nlines == 0)
732                                                 break;
733
734                                         switch (cinfo->out_color_space) {
735                                             case JCS_GRAYSCALE:
736                                                     explode_gray_into_buf (cinfo, lines);
737                                                     break;
738                                             case JCS_RGB:
739                                                     /* do nothing */
740                                                     break;
741                                             case JCS_CMYK:
742                                                     convert_cmyk_to_rgb (cinfo, lines);
743                                                     break;
744                                             default:
745                                                     if (error && *error == NULL) {
746                                                             g_set_error (error,
747                                                                          GDK_PIXBUF_ERROR,
748                                                                          GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
749                                                                          _("Unsupported JPEG color space (%s)"),
750                                                                          colorspace_name (cinfo->out_color_space)); 
751                                                     }
752                                                     
753                                                     return FALSE;
754                                         }
755
756                                         context->dptr += nlines * context->pixbuf->rowstride;
757                                         
758                                         /* send updated signal */
759                                         (* context->updated_func) (context->pixbuf,
760                                                                    0, 
761                                                                    cinfo->output_scanline-1,
762                                                                    cinfo->image_width, 
763                                                                    nlines,
764                                                                    context->user_data);
765                                 }
766                                 if (cinfo->output_scanline >= cinfo->output_height && 
767                                     jpeg_finish_output (cinfo))
768                                         context->in_output = FALSE;
769                                 else
770                                         break;
771                         }
772                         if (jpeg_input_complete (cinfo))
773                                 /* did entire image */
774                                 return TRUE;
775                         else
776                                 continue;
777                 }
778         }
779
780         return TRUE;
781 }
782
783 /* Save */
784
785 #define TO_FUNCTION_BUF_SIZE 4096
786
787 typedef struct {
788         struct jpeg_destination_mgr pub;
789         JOCTET             *buffer;
790         GdkPixbufSaveFunc   save_func;
791         gpointer            user_data;
792         GError            **error;
793 } ToFunctionDestinationManager;
794
795 void
796 to_callback_init (j_compress_ptr cinfo)
797 {
798         ToFunctionDestinationManager *destmgr;
799
800         destmgr = (ToFunctionDestinationManager*) cinfo->dest;
801         destmgr->pub.next_output_byte = destmgr->buffer;
802         destmgr->pub.free_in_buffer = TO_FUNCTION_BUF_SIZE;
803 }
804
805 static void
806 to_callback_do_write (j_compress_ptr cinfo, gsize length)
807 {
808         ToFunctionDestinationManager *destmgr;
809
810         destmgr = (ToFunctionDestinationManager*) cinfo->dest;
811         if (!destmgr->save_func (destmgr->buffer,
812                                  length,
813                                  destmgr->error,
814                                  destmgr->user_data)) {
815                 struct error_handler_data *errmgr;
816         
817                 errmgr = (struct error_handler_data *) cinfo->err;
818                 /* Use a default error message if the callback didn't set one,
819                  * which it should have.
820                  */
821                 if (errmgr->error && *errmgr->error == NULL) {
822                         g_set_error (errmgr->error,
823                                      GDK_PIXBUF_ERROR,
824                                      GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
825                                      "write function failed");
826                 }
827                 siglongjmp (errmgr->setjmp_buffer, 1);
828                 g_assert_not_reached ();
829         }
830 }
831
832 static boolean
833 to_callback_empty_output_buffer (j_compress_ptr cinfo)
834 {
835         ToFunctionDestinationManager *destmgr;
836
837         destmgr = (ToFunctionDestinationManager*) cinfo->dest;
838         to_callback_do_write (cinfo, TO_FUNCTION_BUF_SIZE);
839         destmgr->pub.next_output_byte = destmgr->buffer;
840         destmgr->pub.free_in_buffer = TO_FUNCTION_BUF_SIZE;
841         return TRUE;
842 }
843
844 void
845 to_callback_terminate (j_compress_ptr cinfo)
846 {
847         ToFunctionDestinationManager *destmgr;
848
849         destmgr = (ToFunctionDestinationManager*) cinfo->dest;
850         to_callback_do_write (cinfo, TO_FUNCTION_BUF_SIZE - destmgr->pub.free_in_buffer);
851 }
852
853 static gboolean
854 real_save_jpeg (GdkPixbuf          *pixbuf,
855                 gchar             **keys,
856                 gchar             **values,
857                 GError            **error,
858                 gboolean            to_callback,
859                 FILE               *f,
860                 GdkPixbufSaveFunc   save_func,
861                 gpointer            user_data)
862 {
863         /* FIXME error handling is broken */
864         
865        struct jpeg_compress_struct cinfo;
866        guchar *buf = NULL;
867        guchar *ptr;
868        guchar *pixels = NULL;
869        JSAMPROW *jbuf;
870        int y = 0;
871        volatile int quality = 75; /* default; must be between 0 and 100 */
872        int i, j;
873        int w, h = 0;
874        int rowstride = 0;
875        int n_channels;
876        struct error_handler_data jerr;
877        ToFunctionDestinationManager to_callback_destmgr;
878
879        to_callback_destmgr.buffer = NULL;
880
881        if (keys && *keys) {
882                gchar **kiter = keys;
883                gchar **viter = values;
884
885                while (*kiter) {
886                        if (strcmp (*kiter, "quality") == 0) {
887                                char *endptr = NULL;
888                                quality = strtol (*viter, &endptr, 10);
889
890                                if (endptr == *viter) {
891                                        g_set_error (error,
892                                                     GDK_PIXBUF_ERROR,
893                                                     GDK_PIXBUF_ERROR_BAD_OPTION,
894                                                     _("JPEG quality must be a value between 0 and 100; value '%s' could not be parsed."),
895                                                     *viter);
896
897                                        return FALSE;
898                                }
899                                
900                                if (quality < 0 ||
901                                    quality > 100) {
902                                        /* This is a user-visible error;
903                                         * lets people skip the range-checking
904                                         * in their app.
905                                         */
906                                        g_set_error (error,
907                                                     GDK_PIXBUF_ERROR,
908                                                     GDK_PIXBUF_ERROR_BAD_OPTION,
909                                                     _("JPEG quality must be a value between 0 and 100; value '%d' is not allowed."),
910                                                     quality);
911
912                                        return FALSE;
913                                }
914                        } else {
915                                g_warning ("Bad option name '%s' passed to JPEG saver",
916                                           *kiter);
917                                return FALSE;
918                        }
919                
920                        ++kiter;
921                        ++viter;
922                }
923        }
924        
925        rowstride = gdk_pixbuf_get_rowstride (pixbuf);
926        n_channels = gdk_pixbuf_get_n_channels (pixbuf);
927
928        w = gdk_pixbuf_get_width (pixbuf);
929        h = gdk_pixbuf_get_height (pixbuf);
930
931        /* no image data? abort */
932        pixels = gdk_pixbuf_get_pixels (pixbuf);
933        g_return_val_if_fail (pixels != NULL, FALSE);
934
935        /* Allocate a small buffer to convert image data,
936         * and a larger buffer if doing to_callback save.
937         */
938        buf = g_try_malloc (w * 3 * sizeof (guchar));
939        if (!buf) {
940                g_set_error (error,
941                             GDK_PIXBUF_ERROR,
942                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
943                             _("Couldn't allocate memory for loading JPEG file"));
944                return FALSE;
945        }
946        if (to_callback) {
947                to_callback_destmgr.buffer = g_try_malloc (TO_FUNCTION_BUF_SIZE);
948                if (!to_callback_destmgr.buffer) {
949                        g_set_error (error,
950                                     GDK_PIXBUF_ERROR,
951                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
952                                     _("Couldn't allocate memory for loading JPEG file"));
953                        return FALSE;
954                }
955        }
956
957        /* set up error handling */
958        jerr.pub.error_exit = fatal_error_handler;
959        jerr.pub.output_message = output_message_handler;
960        jerr.error = error;
961        
962        cinfo.err = jpeg_std_error (&(jerr.pub));
963        if (sigsetjmp (jerr.setjmp_buffer, 1)) {
964                jpeg_destroy_compress (&cinfo);
965                g_free (buf);
966                g_free (to_callback_destmgr.buffer);
967                return FALSE;
968        }
969
970        /* setup compress params */
971        jpeg_create_compress (&cinfo);
972        if (to_callback) {
973                to_callback_destmgr.pub.init_destination    = to_callback_init;
974                to_callback_destmgr.pub.empty_output_buffer = to_callback_empty_output_buffer;
975                to_callback_destmgr.pub.term_destination    = to_callback_terminate;
976                to_callback_destmgr.error = error;
977                to_callback_destmgr.save_func = save_func;
978                to_callback_destmgr.user_data = user_data;
979                cinfo.dest = (struct jpeg_destination_mgr*) &to_callback_destmgr;
980        } else {
981                jpeg_stdio_dest (&cinfo, f);
982        }
983        cinfo.image_width      = w;
984        cinfo.image_height     = h;
985        cinfo.input_components = 3; 
986        cinfo.in_color_space   = JCS_RGB;
987
988        /* set up jepg compression parameters */
989        jpeg_set_defaults (&cinfo);
990        jpeg_set_quality (&cinfo, quality, TRUE);
991        jpeg_start_compress (&cinfo, TRUE);
992        /* get the start pointer */
993        ptr = pixels;
994        /* go one scanline at a time... and save */
995        i = 0;
996        while (cinfo.next_scanline < cinfo.image_height) {
997                /* convert scanline from ARGB to RGB packed */
998                for (j = 0; j < w; j++)
999                        memcpy (&(buf[j*3]), &(ptr[i*rowstride + j*n_channels]), 3);
1000
1001                /* write scanline */
1002                jbuf = (JSAMPROW *)(&buf);
1003                jpeg_write_scanlines (&cinfo, jbuf, 1);
1004                i++;
1005                y++;
1006
1007        }
1008        
1009        /* finish off */
1010        jpeg_finish_compress (&cinfo);
1011        jpeg_destroy_compress(&cinfo);
1012        g_free (buf);
1013        g_free (to_callback_destmgr.buffer);
1014        return TRUE;
1015 }
1016
1017 static gboolean
1018 gdk_pixbuf__jpeg_image_save (FILE          *f, 
1019                              GdkPixbuf     *pixbuf, 
1020                              gchar        **keys,
1021                              gchar        **values,
1022                              GError       **error)
1023 {
1024         return real_save_jpeg (pixbuf, keys, values, error,
1025                                FALSE, f, NULL, NULL);
1026 }
1027
1028 static gboolean
1029 gdk_pixbuf__jpeg_image_save_to_callback (GdkPixbufSaveFunc   save_func,
1030                                          gpointer            user_data,
1031                                          GdkPixbuf          *pixbuf, 
1032                                          gchar             **keys,
1033                                          gchar             **values,
1034                                          GError            **error)
1035 {
1036         return real_save_jpeg (pixbuf, keys, values, error,
1037                                TRUE, NULL, save_func, user_data);
1038 }
1039
1040 void
1041 MODULE_ENTRY (jpeg, fill_vtable) (GdkPixbufModule *module)
1042 {
1043         module->load = gdk_pixbuf__jpeg_image_load;
1044         module->begin_load = gdk_pixbuf__jpeg_image_begin_load;
1045         module->stop_load = gdk_pixbuf__jpeg_image_stop_load;
1046         module->load_increment = gdk_pixbuf__jpeg_image_load_increment;
1047         module->save = gdk_pixbuf__jpeg_image_save;
1048         module->save_to_callback = gdk_pixbuf__jpeg_image_save_to_callback;
1049 }
1050
1051 void
1052 MODULE_ENTRY (jpeg, fill_info) (GdkPixbufFormat *info)
1053 {
1054         static GdkPixbufModulePattern signature[] = {
1055                 { "\xff\xd8", NULL, 100 },
1056                 { NULL, NULL, 0 }
1057         };
1058         static gchar * mime_types[] = {
1059                 "image/jpeg",
1060                 NULL
1061         };
1062         static gchar * extensions[] = {
1063                 "jpeg",
1064                 "jpe",
1065                 "jpg",
1066                 NULL
1067         };
1068
1069         info->name = "jpeg";
1070         info->signature = signature;
1071         info->description = N_("The JPEG image format");
1072         info->mime_types = mime_types;
1073         info->extensions = extensions;
1074         info->flags = GDK_PIXBUF_FORMAT_WRITABLE | GDK_PIXBUF_FORMAT_THREADSAFE;
1075         info->license = "LGPL";
1076 }