gtk/gdk-pixbuf/io-jpeg.c
Mark Crichton 7befe28245 Fixed crash-on-loading bug (width and height are not set until
Fixed crash-on-loading bug (width and height are not set until decompression
starts)

Mark
1999-07-12 04:55:16 +00:00

132 lines
3.0 KiB
C

/*
io-jpeg.c: GdkPixBuf loader for jpeg files.
Based on io-jpeg from gdk_imlib, but not much.
This code is licensed under the Lesser GNU
General Public License, version 2.1.
Author:
Michael Zucchi <zucchi@zedzone.mmc.com.au>
*/
#include <config.h>
#include <stdio.h>
#include <glib.h>
#include <setjmp.h>
#include "gdk-pixbuf.h"
/*#include "gdk-pixbuf-io.h"*/
#include <jpeglib.h>
/* error handler data */
struct iojpeg_JPEG_error_mgr
{
struct jpeg_error_mgr pub;
sigjmp_buf setjmp_buffer;
};
static void
g_JPEGFatalErrorHandler(j_common_ptr cinfo)
{
/* FIXME:
* We should somehow signal what error occurred to the caller so the
* caller can handle the error message */
struct iojpeg_JPEG_error_mgr *errmgr;
errmgr = (struct iojpeg_JPEG_error_mgr *) cinfo->err;
cinfo->err->output_message(cinfo);
siglongjmp(errmgr->setjmp_buffer, 1);
return;
}
GdkPixBuf *image_load(FILE *f)
{
int w,h,i,j;
art_u8 *pixels=NULL, *dptr, *fptr, *pptr;
unsigned char *lines[4], /* Used to expand rows, via rec_outbuf_height, from
the header file:
"* Usually rec_outbuf_height will be 1 or 2, at most 4." */
**lptr;
struct jpeg_decompress_struct cinfo;
struct iojpeg_JPEG_error_mgr jerr;
GdkPixBuf *pixbuf;
/* setup error handler */
cinfo.err = jpeg_std_error(&(jerr.pub));
jerr.pub.error_exit = g_JPEGFatalErrorHandler;
if (sigsetjmp(jerr.setjmp_buffer, 1)) {
/* Whoops there was a jpeg error */
if (pixels != NULL)
art_free(pixels);
jpeg_destroy_decompress(&cinfo);
return NULL;
}
/* load header, setup */
jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, f);
jpeg_read_header(&cinfo, TRUE);
jpeg_start_decompress(&cinfo);
cinfo.do_fancy_upsampling = FALSE;
cinfo.do_block_smoothing = FALSE;
w = cinfo.output_width;
h = cinfo.output_height;
g_print("w: %d h: %d\n", w, h);
pixels = art_alloc(h * w * 3);
if (pixels == NULL) {
jpeg_destroy_decompress(&cinfo);
return NULL;
}
dptr = pixels;
/* decompress all the lines, a few at a time */
while (cinfo.output_scanline < cinfo.output_height) {
lptr = lines;
for (i=0;i<cinfo.rec_outbuf_height;i++) {
*lptr++=dptr;
dptr+=w*3;
}
jpeg_read_scanlines(&cinfo, lines, cinfo.rec_outbuf_height);
if (cinfo.output_components==1) {
/* expand grey->colour */
/* expand from the end of the memory down, so we can use
the same buffer */
for (i=cinfo.rec_outbuf_height-1;i>=0;i--) {
unsigned char *from, *to;
from = lines[i]+w-1;
to = lines[i]+w*3-3;
for (j=w-1;j>=0;j++) {
to[0] = from[0];
to[1] = from[0];
to[2] = from[0];
to-=3;
from--;
}
}
}
}
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
/* finish off, create the pixbuf */
pixbuf = g_new(GdkPixBuf, 1);
pixbuf->art_pixbuf = art_pixbuf_new_rgb(pixels, w, h, (w * 3));
if (!(pixbuf->art_pixbuf))
return NULL;
pixbuf->ref_count = 0;
pixbuf->unref_func = NULL;
return pixbuf;
}
/*
* Local variables:
* c-basic-offset: 8
* End:
*/