/* Copyright (C) 2000-2011 by George Williams */ /* * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef _NO_LIBJPEG static int a_file_must_define_something=0; /* ANSI says so */ #elif !defined(_STATIC_LIBJPEG) && !defined(NODYNAMIC) /* I don't know how to deal with dynamic libs on mac OS/X, hence this */ #include #undef HAVE_STDLIB_H /* Defined by libtool, redefined by jconfig.h, annoying warning msg */ #include #include #include #include #include #include "gimage.h" static DL_CONST void *libjpeg=NULL; static struct jpeg_error_mgr *(*_jpeg_std_error)(struct jpeg_error_mgr *); static void (*_jpeg_destroy_compress)(j_compress_ptr); static void (*_jpeg_create_compress)(j_compress_ptr,int,size_t); static void (*_jpeg_stdio_src)(j_compress_ptr, FILE *); static int (*_jpeg_set_defaults)(j_compress_ptr); static int (*_jpeg_set_quality)(j_compress_ptr,int,boolean); static int (*_jpeg_simple_progression)(j_compress_ptr); static boolean (*_jpeg_start_compress)(j_compress_ptr,boolean); static boolean (*_jpeg_write_scanlines)(j_compress_ptr, JSAMPARRAY, JDIMENSION); static boolean (*_jpeg_finish_compress)(j_compress_ptr); static void (*_jpeg_stdio_dest)(j_compress_ptr, FILE *); static int loadjpeg() { char *err; libjpeg = dlopen("libjpeg" SO_EXT,RTLD_LAZY); if ( libjpeg==NULL ) { fprintf(stderr,"%s\n", dlerror()); return( 0 ); } _jpeg_std_error = (struct jpeg_error_mgr *(*)(struct jpeg_error_mgr *)) dlsym(libjpeg,"jpeg_std_error"); _jpeg_destroy_compress = (void (*)(j_compress_ptr)) dlsym(libjpeg,"jpeg_destroy_compress"); _jpeg_create_compress = (void (*)(j_compress_ptr,int,size_t)) dlsym(libjpeg,"jpeg_CreateCompress"); _jpeg_stdio_src = (void (*)(j_compress_ptr, FILE *)) dlsym(libjpeg,"jpeg_stdio_src"); _jpeg_set_defaults = (int (*)(j_compress_ptr)) dlsym(libjpeg,"jpeg_set_defaults"); _jpeg_set_quality = (int (*)(j_compress_ptr,int,boolean)) dlsym(libjpeg,"jpeg_set_quality"); _jpeg_simple_progression = (int (*)(j_compress_ptr)) dlsym(libjpeg,"jpeg_simple_progression"); _jpeg_start_compress = (boolean (*)(j_compress_ptr,boolean)) dlsym(libjpeg,"jpeg_start_compress"); _jpeg_write_scanlines = (boolean (*)(j_compress_ptr, JSAMPARRAY, JDIMENSION)) dlsym(libjpeg,"jpeg_write_scanlines"); _jpeg_finish_compress = (boolean (*)(j_compress_ptr)) dlsym(libjpeg,"jpeg_finish_compress"); _jpeg_stdio_dest = (void (*)(j_compress_ptr, FILE *)) dlsym(libjpeg,"jpeg_stdio_dest"); if ( _jpeg_std_error && _jpeg_destroy_compress && _jpeg_create_compress && _jpeg_stdio_src && _jpeg_set_defaults && _jpeg_set_quality && _jpeg_simple_progression && _jpeg_start_compress && _jpeg_write_scanlines && _jpeg_finish_compress && _jpeg_stdio_dest ) return( 1 ); dlclose(libjpeg); err = dlerror(); if ( err==NULL ) err = "Couldn't load needed symbol from libjpeg.so"; fprintf(stderr,"%s\n", err); return( 0 ); } /******************************************************************************/ struct my_error_mgr { struct jpeg_error_mgr pub; /* "public" fields */ jmp_buf setjmp_buffer; /* for return to caller */ int padding[8]; /* On my solaris box jmp_buf is the wrong size */ }; typedef struct my_error_mgr * my_error_ptr; METHODDEF(void) my_error_exit (j_common_ptr cinfo) { /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ my_error_ptr myerr = (my_error_ptr) cinfo->err; /* Always display the message. */ /* We could postpone this until after returning, if we chose. */ (*cinfo->err->output_message) (cinfo); /* Return control to the setjmp point */ longjmp(myerr->setjmp_buffer, 1); } static void transferImageToBuffer(struct _GImage *base,JSAMPLE *buffer,int w,int ypos) { JSAMPLE *pt, *end; uint32 *ppt; ppt = (uint32 *) (base->data + ypos*base->bytes_per_line); if ( base->image_type==it_index && base->clut==NULL ) { unsigned char *px = (unsigned char *) ppt; int col; register int bit=0x80; for ( pt = buffer, end = pt+3*w; pt>= 1 )== 0 ) { ++px; bit = 0x80; } *pt++ = COLOR_RED(col); *pt++ = COLOR_GREEN(col); *pt++ = COLOR_BLUE(col); } } else if ( base->image_type==it_index ) { unsigned char *px = (unsigned char *) ppt; int col; register int bit=0x80; for ( pt = buffer, end = pt+3*w; ptclut->clut[1]; else col = base->clut->clut[0]; if (( bit >>= 1 )== 0 ) { ++px; bit = 0x80; } *pt++ = COLOR_RED(col); *pt++ = COLOR_GREEN(col); *pt++ = COLOR_BLUE(col); } } else if ( base->image_type==it_index ) { unsigned char *px = (unsigned char *) ppt; int col; for ( pt = buffer, end = pt+3*w; ptclut->clut[ *px++ ]; *pt++ = COLOR_RED(col); *pt++ = COLOR_GREEN(col); *pt++ = COLOR_BLUE(col); } } else { for ( pt = buffer, end = pt+3*w; ptinput_components = 3; /* # of color components per pixel */ cinfo->in_color_space = JCS_RGB; /* colorspace of input image */ if ( base->image_type==it_index ) { if ( base->clut->clut_len!=256 ) return; for ( i=0; i<256; ++i ) if ( base->clut->clut[i]!=COLOR_CREATE(i,i,i)) break; if ( i==256 ) { cinfo->input_components = 1; cinfo->in_color_space = JCS_GRAYSCALE; } } } /* quality is a number between 0 and 100 */ int GImageWrite_Jpeg(GImage *gi, FILE *outfile, int quality, int progressive) { struct _GImage *base = gi->list_len==0?gi->u.image:gi->u.images[0]; struct jpeg_compress_struct cinfo; struct my_error_mgr jerr; JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ if ( libjpeg==NULL ) if ( !loadjpeg()) return( 0 ); cinfo.err = _jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; if (setjmp(jerr.setjmp_buffer)) { _jpeg_destroy_compress(&cinfo); return 0; } _jpeg_create_compress(&cinfo,JPEG_LIB_VERSION,(size_t) sizeof(struct jpeg_compress_struct)); _jpeg_stdio_dest(&cinfo, outfile); cinfo.image_width = base->width; cinfo.image_height = base->height; setColorSpace(&cinfo,base); _jpeg_set_defaults(&cinfo); _jpeg_set_quality(&cinfo, quality, TRUE ); if ( progressive ) _jpeg_simple_progression(&cinfo); _jpeg_start_compress(&cinfo, TRUE); if ( cinfo.in_color_space != JCS_GRAYSCALE ) row_pointer[0]=galloc(3*base->width); while (cinfo.next_scanline < cinfo.image_height) { if ( cinfo.in_color_space == JCS_GRAYSCALE ) row_pointer[0] = (unsigned char *) (base->data + cinfo.next_scanline*base->bytes_per_line); else transferImageToBuffer(base,row_pointer[0],base->width,cinfo.next_scanline); (void) _jpeg_write_scanlines(&cinfo, row_pointer, 1); } _jpeg_finish_compress(&cinfo); _jpeg_destroy_compress(&cinfo); if ( cinfo.in_color_space != JCS_GRAYSCALE ) gfree(row_pointer[0]); return( 1 ); } int GImageWriteJpeg(GImage *gi, char *filename, int quality, int progressive) { FILE * outfile; /* target file */ int ret; if ( libjpeg==NULL ) { if ( !loadjpeg()) return( 0 ); } if ((outfile = fopen(filename, "wb")) == NULL) { fprintf(stderr, "can't open %s\n", filename); return(0); } ret = GImageWrite_Jpeg(gi,outfile,quality,progressive); fclose(outfile); return( ret ); } #else #include #include #include #include #include #include "gimage.h" /******************************************************************************/ struct my_error_mgr { struct jpeg_error_mgr pub; /* "public" fields */ jmp_buf setjmp_buffer; /* for return to caller */ int padding[8]; /* On my solaris box jmp_buf is the wrong size */ }; typedef struct my_error_mgr * my_error_ptr; METHODDEF(void) my_error_exit (j_common_ptr cinfo) { /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ my_error_ptr myerr = (my_error_ptr) cinfo->err; /* Always display the message. */ /* We could postpone this until after returning, if we chose. */ (*cinfo->err->output_message) (cinfo); /* Return control to the setjmp point */ longjmp(myerr->setjmp_buffer, 1); } static void transferImageToBuffer(struct _GImage *base,JSAMPLE *buffer,int w,int ypos) { JSAMPLE *pt, *end; uint32 *ppt; ppt = (uint32 *) (base->data + ypos*base->bytes_per_line); if ( base->image_type==it_index && base->clut==NULL ) { unsigned char *px = (unsigned char *) ppt; int col; register int bit=0x80; for ( pt = buffer, end = pt+3*w; pt>= 1 )== 0 ) { ++px; bit = 0x80; } *pt++ = COLOR_RED(col); *pt++ = COLOR_GREEN(col); *pt++ = COLOR_BLUE(col); } } else if ( base->image_type==it_index ) { unsigned char *px = (unsigned char *) ppt; int col; register int bit=0x80; for ( pt = buffer, end = pt+3*w; ptclut->clut[1]; else col = base->clut->clut[0]; if (( bit >>= 1 )== 0 ) { ++px; bit = 0x80; } *pt++ = COLOR_RED(col); *pt++ = COLOR_GREEN(col); *pt++ = COLOR_BLUE(col); } } else if ( base->image_type==it_index ) { unsigned char *px = (unsigned char *) ppt; int col; for ( pt = buffer, end = pt+3*w; ptclut->clut[ *px++ ]; *pt++ = COLOR_RED(col); *pt++ = COLOR_GREEN(col); *pt++ = COLOR_BLUE(col); } } else { for ( pt = buffer, end = pt+3*w; ptinput_components = 3; /* # of color components per pixel */ cinfo->in_color_space = JCS_RGB; /* colorspace of input image */ if ( base->image_type==it_index ) { if ( base->clut->clut_len!=256 ) return; for ( i=0; i<256; ++i ) if ( base->clut->clut[i]!=COLOR_CREATE(i,i,i)) break; if ( i==256 ) { cinfo->input_components = 1; cinfo->in_color_space = JCS_GRAYSCALE; } } } /* quality is a number between 0 and 100 */ int GImageWrite_Jpeg(GImage *gi, FILE *outfile, int quality, int progressive) { struct _GImage *base = gi->list_len==0?gi->u.image:gi->u.images[0]; struct jpeg_compress_struct cinfo; struct my_error_mgr jerr; JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; if (setjmp(jerr.setjmp_buffer)) { jpeg_destroy_compress(&cinfo); return 0; } jpeg_CreateCompress(&cinfo,JPEG_LIB_VERSION,(size_t) sizeof(struct jpeg_compress_struct)); jpeg_stdio_dest(&cinfo, outfile); cinfo.image_width = base->width; cinfo.image_height = base->height; setColorSpace(&cinfo,base); jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, TRUE ); if ( progressive ) jpeg_simple_progression(&cinfo); jpeg_start_compress(&cinfo, TRUE); if ( cinfo.in_color_space != JCS_GRAYSCALE ) row_pointer[0]=galloc(3*base->width); while (cinfo.next_scanline < cinfo.image_height) { if ( cinfo.in_color_space == JCS_GRAYSCALE ) row_pointer[0] = (unsigned char *) (base->data + cinfo.next_scanline*base->bytes_per_line); else transferImageToBuffer(base,row_pointer[0],base->width,cinfo.next_scanline); (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); } jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); if ( cinfo.in_color_space != JCS_GRAYSCALE ) gfree(row_pointer[0]); return( 1 ); } int GImageWriteJpeg(GImage *gi, char *filename, int quality, int progressive) { FILE * outfile; /* target file */ int ret; if ((outfile = fopen(filename, "wb")) == NULL) { fprintf(stderr, "can't open %s\n", filename); return(0); } ret = GImageWrite_Jpeg(gi,outfile,quality,progressive); fclose(outfile); return( ret ); } #endif