/***** * readJPEG.c : XmHTML jpeg image loading from a memory buffer * * This file Version $Revision: 1.5 $ * * Creation date: Wed Feb 19 03:13:58 GMT+0100 1997 * Last modification: $Date: 1999/07/29 01:26:29 $ * By: $Author: sopwith $ * Current State: $State: Exp $ * * Author: newt * memory manager: Dick Porter * * Copyright (C) 1994-1997 by Ripley Software Development * All Rights Reserved * * This file is part of the XmHTML Widget Library. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * *****/ /***** * ChangeLog * $Log: readJPEG.c,v $ * Revision 1.5 1999/07/29 01:26:29 sopwith * * * Fix all warnings. * * Revision 1.4 1998/02/12 03:09:46 unammx * Merge to Koen's XmHTML 1.1.2 + following fixes: * * Wed Feb 11 20:27:19 1998 Miguel de Icaza * * * gtk-forms.c (freeForm): gtk_destroy_widget is no longer needed * with the refcounting changes. * * * gtk-xmhtml.c (gtk_xmhtml_remove): Only god knows why I was * adding the just removed widget. * * Revision 1.3 1998/01/07 01:45:41 unammx * Gtk/XmHTML is ready to be used by the Gnome hackers now! * Weeeeeee! * * This afternoon: * * - Changes to integrate gtk-xmhtml into an autoconf setup. * * - Changes to make gtk-xmhtml a library to be used by Gnome * (simply include #endif #include #include #ifdef HAVE_LIBJPEG #include #include #endif #include "XmHTMLP.h" #include "XmHTMLfuncs.h" #ifdef HAVE_LIBJPEG /*** External Function Prototype Declarations ***/ /*** Public Variable Declarations ***/ /*** Private Datatype Declarations ****/ struct my_error_mgr { struct jpeg_error_mgr pub; /* "public" fields */ jmp_buf setjmp_buffer; /* for return to caller */ }; /*** Private Function Prototype Declarations ****/ /*** Private Variable Declarations ***/ typedef struct my_error_mgr * my_error_ptr; static void my_error_exit (j_common_ptr cinfo) { my_error_ptr myerr = (my_error_ptr) cinfo->err; longjmp(myerr->setjmp_buffer, 1); } typedef struct { struct jpeg_source_mgr pub; /* public fields */ JOCTET *buffer; } buffer_source_mgr; typedef buffer_source_mgr *buffer_src_ptr; static JOCTET jpeg_EOI_buffer[2]; static void jpeg_buffer_init_source(j_decompress_ptr cinfo) { /* This should really only be done once */ jpeg_EOI_buffer[0]=(JOCTET)0xFF; jpeg_EOI_buffer[1]=(JOCTET)JPEG_EOI; } /* * We cant give any more data, because all we know about the image is already * in the buffer! * * Therefore, if fill_input_buffer is called, we have a bogus JPEG image, and * all we can do is try and fake some EOIs. */ static boolean jpeg_buffer_fill_input_buffer(j_decompress_ptr cinfo) { buffer_src_ptr src=(buffer_src_ptr)cinfo->src; src->buffer=jpeg_EOI_buffer; src->pub.next_input_byte=src->buffer; src->pub.bytes_in_buffer=2; return(TRUE); } /* * Skip over uninteresting data in the JPEG stream. If we have to seek past * the end of our buffer, then we have a bogus image. The call to * jpeg_buffer_fill_input_buffer handles this case for us. */ static void jpeg_buffer_skip_input_data(j_decompress_ptr cinfo, long num_bytes) { buffer_src_ptr src=(buffer_src_ptr)cinfo->src; if(num_bytes>0) { /* we have been told to seek off the end of the image! */ if(num_bytes>(long)src->pub.bytes_in_buffer) { (void)jpeg_buffer_fill_input_buffer(cinfo); } else { src->pub.next_input_byte+=(size_t)num_bytes; src->pub.bytes_in_buffer-=(size_t)num_bytes; } } } static void jpeg_buffer_term_source(j_decompress_ptr cinfo) { /* no-op */ } /* * Set up input from a memory buffer */ static void jpeg_buffer_src(j_decompress_ptr cinfo, Byte *data, unsigned int len) { buffer_src_ptr src; if(cinfo->src==NULL) { /* first time for this JPEG object */ cinfo->src=(struct jpeg_source_mgr *) (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_PERMANENT, sizeof(buffer_source_mgr)); } src=(buffer_src_ptr)cinfo->src; src->buffer=(JOCTET *)data; src->pub.init_source=jpeg_buffer_init_source; src->pub.fill_input_buffer=jpeg_buffer_fill_input_buffer; src->pub.skip_input_data=jpeg_buffer_skip_input_data; src->pub.resync_to_restart=jpeg_resync_to_restart; /* default */ src->pub.term_source=jpeg_buffer_term_source; src->pub.bytes_in_buffer=len; src->pub.next_input_byte=data; } /***** * Name: readJPEG * Return Type: XmHTMLRawImageData* * Description: reads a JPEG buffer and returns image data. * In: * * Returns: * loaded image data on success, NULL on failure. *****/ XmHTMLRawImageData* _XmHTMLReadJPEG(TWidget html, ImageBuffer *ib) { struct jpeg_decompress_struct cinfo; struct my_error_mgr jerr; Byte *r; JSAMPROW buffer[1]; /* row pointer array for read_scanlines */ int i, row_stride; /* physical row width in output buffer */ static XmHTMLRawImageData *img_data; img_data = NULL; _XmHTMLDebug(15, ("readJPEG.c: _XmHTMLreadJPEG Start, loading %s\n", ib->file)); /* We set up the normal JPEG error routines, then override error_exit. */ cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; /* Establish the setjmp return context for my_error_exit to use. */ if(setjmp(jerr.setjmp_buffer)) { /* * JPEG signalled an error. Destroy image data, free any allocated * buffers and return NULL. */ _XmHTMLDebug(15, ("_XmHTMLreadJPEG: end, libjpeg internal error.\n")); jpeg_destroy_decompress(&cinfo); if(img_data) FreeRawImage(img_data); return((XmHTMLRawImageData*)NULL); } jpeg_create_decompress(&cinfo); jpeg_buffer_src(&cinfo, ib->buffer, ib->size); jpeg_read_header(&cinfo, TRUE); cinfo.quantize_colors = TRUE; cinfo.two_pass_quantize = TRUE; /* * Get configuration defaults: color quantization and gamma correction. */ if(XmIsHTML(html)) { /* color quantization */ cinfo.desired_number_of_colors = ((XmHTMLWidget)html)->html.max_image_colors; /* gamma correction */ cinfo.output_gamma = ((XmHTMLWidget)html)->html.screen_gamma; /* no dither selection for XmHTML itself. Always use FS */ cinfo.dither_mode = JDITHER_FS; } else { /* external image support */ /* color quantization */ if(_xmimage_cfg != NULL && _xmimage_cfg->flags && ImageQuantize) cinfo.desired_number_of_colors = _xmimage_cfg->ncolors; else cinfo.desired_number_of_colors = MAX_IMAGE_COLORS; /* gamma correction */ if(_xmimage_cfg && (_xmimage_cfg->flags & ImageScreenGamma)) cinfo.output_gamma = _xmimage_cfg->gamma; else cinfo.output_gamma = XmHTML_DEFAULT_GAMMA; /* dither mode. Default is ordered dithering */ if(_xmimage_cfg && (_xmimage_cfg->flags & ImageFSDither)) cinfo.dither_mode = JDITHER_FS; else cinfo.dither_mode = JDITHER_ORDERED; } jpeg_start_decompress(&cinfo); row_stride = cinfo.output_width * cinfo.output_components; /* fix 03/24/97-01, rr */ /* allocate raw image */ AllocRawImage(img_data, cinfo.output_height, row_stride); r = img_data->data; while (cinfo.output_scanline < cinfo.output_height) { buffer[0] = r; jpeg_read_scanlines(&cinfo, buffer, 1); r += row_stride; } /* update raw image data */ img_data->width = cinfo.output_width; img_data->height = cinfo.output_height; ib->depth = cinfo.data_precision; /* add colormap */ AllocRawImageCmap(img_data, cinfo.actual_number_of_colors); /* set up X colormap. Upscale RGB to 16bits precision */ if(cinfo.out_color_components == 3) { int cshift = 16 - cinfo.data_precision; img_data->color_class = XmIMAGE_COLORSPACE_RGB; for (i=0; i < img_data->cmapsize; i++) { img_data->cmap[i].red = cinfo.colormap[0][i] << cshift; img_data->cmap[i].green = cinfo.colormap[1][i] << cshift; img_data->cmap[i].blue = cinfo.colormap[2][i] << cshift; } } else { int cshift = 16 - cinfo.data_precision; img_data->color_class = XmIMAGE_COLORSPACE_GRAYSCALE; for(i = 0; i < img_data->cmapsize; i++) { img_data->cmap[i].red = img_data->cmap[i].green = img_data->cmap[i].blue = cinfo.colormap[0][i] << cshift; } } /***** * as we are now sure every color values lies within the range 0-2^16, * we can downscale to the range 0-255 *****/ for(i = 0; i < img_data->cmapsize; i++) { img_data->cmap[i].red >>= 8; img_data->cmap[i].green >>= 8; img_data->cmap[i].blue >>= 8; } jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); _XmHTMLDebug(15, ("_XmHTMLreadJPEG: end, image loaded.\n")); return(img_data); } #else /* !HAVE_LIBJPEG */ /* empty func if JPEG isn't supported */ /* ARGSUSED */ XmHTMLRawImageData* _XmHTMLReadJPEG(TWidget html, ImageBuffer *ib) { return((XmHTMLRawImageData*)NULL); } #endif /* HAVE_LIBJPEG */