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