]> Pileus Git - ~andy/gtk/blob - gdk-pixbuf/io-jpeg.c
more work on the incremental loading
[~andy/gtk] / gdk-pixbuf / io-jpeg.c
1 /* GdkPixbuf library - JPEG image loader
2  *
3  * Copyright (C) 1999 Michael Zucchi
4  * Copyright (C) 1999 The Free Software Foundation
5  *
6  * Authors: Michael Zucchi <zucchi@zedzone.mmc.com.au>
7  *          Federico Mena-Quintero <federico@gimp.org>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 #include <config.h>
26 #include <stdio.h>
27 #include <setjmp.h>
28 #include <jpeglib.h>
29 #include "gdk-pixbuf.h"
30
31 \f
32
33 /* error handler data */
34 struct error_handler_data {
35         struct jpeg_error_mgr pub;
36         sigjmp_buf setjmp_buffer;
37 };
38
39 static void
40 fatal_error_handler (j_common_ptr cinfo)
41 {
42         /* FIXME:
43          * We should somehow signal what error occurred to the caller so the
44          * caller can handle the error message */
45         struct error_handler_data *errmgr;
46
47         errmgr = (struct error_handler_data *) cinfo->err;
48         cinfo->err->output_message (cinfo);
49         siglongjmp (errmgr->setjmp_buffer, 1);
50         return;
51 }
52
53 /* Destroy notification function for the libart pixbuf */
54 static void
55 free_buffer (gpointer user_data, gpointer data)
56 {
57         free (data);
58 }
59
60 /* Shared library entry point */
61 GdkPixbuf *
62 image_load (FILE *f)
63 {
64         int w, h, i, j;
65         guchar *pixels = NULL;
66         guchar *dptr;
67         guchar *lines[4]; /* Used to expand rows, via rec_outbuf_height, from the header file:
68                            * "* Usually rec_outbuf_height will be 1 or 2, at most 4."
69                            */
70         guchar **lptr;
71         struct jpeg_decompress_struct cinfo;
72         struct error_handler_data jerr;
73         GdkPixbuf *pixbuf;
74
75         /* setup error handler */
76         cinfo.err = jpeg_std_error (&jerr.pub);
77         jerr.pub.error_exit = fatal_error_handler;
78
79         if (sigsetjmp (jerr.setjmp_buffer, 1)) {
80                 /* Whoops there was a jpeg error */
81                 if (pixels)
82                         free (pixels);
83
84                 jpeg_destroy_decompress (&cinfo);
85                 return NULL;
86         }
87
88         /* load header, setup */
89         jpeg_create_decompress (&cinfo);
90         jpeg_stdio_src (&cinfo, f);
91         jpeg_read_header (&cinfo, TRUE);
92         jpeg_start_decompress (&cinfo);
93         cinfo.do_fancy_upsampling = FALSE;
94         cinfo.do_block_smoothing = FALSE;
95
96         w = cinfo.output_width;
97         h = cinfo.output_height;
98
99         pixels = malloc (h * w * 3);
100         if (!pixels) {
101                 jpeg_destroy_decompress (&cinfo);
102                 return NULL;
103         }
104
105         dptr = pixels;
106
107         /* decompress all the lines, a few at a time */
108
109         while (cinfo.output_scanline < cinfo.output_height) {
110                 lptr = lines;
111                 for (i = 0; i < cinfo.rec_outbuf_height; i++) {
112                         *lptr++ = dptr;
113                         dptr += w * 3;
114                 }
115
116                 jpeg_read_scanlines (&cinfo, lines, cinfo.rec_outbuf_height);
117                 if (cinfo.output_components == 1) {
118                         /* Expand grey->colour.  Expand from the end of the
119                          * memory down, so we can use the same buffer.
120                          */
121                         for (i = cinfo.rec_outbuf_height - 1; i >= 0; i--) {
122                                 guchar *from, *to;
123
124                                 from = lines[i] + w - 1;
125                                 to = lines[i] + w * 3 - 3;
126                                 for (j = w - 1; j >= 0; j--) {
127                                         to[0] = from[0];
128                                         to[1] = from[0];
129                                         to[2] = from[0];
130                                         to -= 3;
131                                         from--;
132                                 }
133                         }
134                 }
135         }
136
137         jpeg_finish_decompress (&cinfo);
138         jpeg_destroy_decompress (&cinfo);
139
140         return gdk_pixbuf_new_from_data (pixels, ART_PIX_RGB, FALSE,
141                                          w, h, w * 3,
142                                          free_buffer, NULL);
143
144         return pixbuf;
145 }