X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fnetradiant.git;a=blobdiff_plain;f=plugins%2Fimage%2Fjpeg.cpp;h=138151a2f62c81de5270f9188ff211d53c59a745;hp=ade0ad52d3248e478cb7ef90bec8d8f5766b1e16;hb=e4287c28bb2dafedc81c66e63951d947cfbeb225;hpb=6bc28ad466df5fef38e607a2bde2da83c3e2c029 diff --git a/plugins/image/jpeg.cpp b/plugins/image/jpeg.cpp index ade0ad52..138151a2 100644 --- a/plugins/image/jpeg.cpp +++ b/plugins/image/jpeg.cpp @@ -1,32 +1,32 @@ /* -Copyright (c) 2001, Loki software, inc. -All rights reserved. - -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. - -Neither the name of Loki software nor the names of its contributors may be used -to endorse or promote products derived from this software without specific prior -written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. -*/ + Copyright (c) 2001, Loki software, inc. + All rights reserved. + + 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. + + Neither the name of Loki software nor the names of its contributors may be used + to endorse or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. + */ // // Functions to load JPEG files from a buffer, based on jdatasrc.c @@ -55,18 +55,18 @@ typedef unsigned char byte; /* Expanded data source object for stdio input */ typedef struct { - struct jpeg_source_mgr pub; /* public fields */ + struct jpeg_source_mgr pub; /* public fields */ - int src_size; - JOCTET * src_buffer; + int src_size; + JOCTET * src_buffer; - JOCTET * buffer; /* start of buffer */ - boolean start_of_file; /* have we gotten any data yet? */ + JOCTET * buffer; /* start of buffer */ + boolean start_of_file; /* have we gotten any data yet? */ } my_source_mgr; typedef my_source_mgr * my_src_ptr; -#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */ +#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */ /* @@ -74,15 +74,14 @@ typedef my_source_mgr * my_src_ptr; * before any data is actually read. */ -static void my_init_source (j_decompress_ptr cinfo) -{ - my_src_ptr src = (my_src_ptr) cinfo->src; +static void my_init_source( j_decompress_ptr cinfo ){ + my_src_ptr src = (my_src_ptr) cinfo->src; - /* We reset the empty-input-file flag for each image, - * but we don't clear the input buffer. - * This is correct behavior for reading a series of images from one source. - */ - src->start_of_file = TRUE; + /* We reset the empty-input-file flag for each image, + * but we don't clear the input buffer. + * This is correct behavior for reading a series of images from one source. + */ + src->start_of_file = TRUE; } @@ -119,35 +118,37 @@ static void my_init_source (j_decompress_ptr cinfo) * the front of the buffer rather than discarding it. */ -static boolean my_fill_input_buffer (j_decompress_ptr cinfo) -{ - my_src_ptr src = (my_src_ptr) cinfo->src; - size_t nbytes; - - if (src->src_size > INPUT_BUF_SIZE) - nbytes = INPUT_BUF_SIZE; - else - nbytes = src->src_size; - - memcpy (src->buffer, src->src_buffer, nbytes); - src->src_buffer += nbytes; - src->src_size -= nbytes; - - if (nbytes <= 0) { - if (src->start_of_file) /* Treat empty input file as fatal error */ - ERREXIT(cinfo, JERR_INPUT_EMPTY); - WARNMS(cinfo, JWRN_JPEG_EOF); - /* Insert a fake EOI marker */ - src->buffer[0] = (JOCTET) 0xFF; - src->buffer[1] = (JOCTET) JPEG_EOI; - nbytes = 2; - } - - src->pub.next_input_byte = src->buffer; - src->pub.bytes_in_buffer = nbytes; - src->start_of_file = FALSE; - - return TRUE; +static boolean my_fill_input_buffer( j_decompress_ptr cinfo ){ + my_src_ptr src = (my_src_ptr) cinfo->src; + size_t nbytes; + + if ( src->src_size > INPUT_BUF_SIZE ) { + nbytes = INPUT_BUF_SIZE; + } + else{ + nbytes = src->src_size; + } + + memcpy( src->buffer, src->src_buffer, nbytes ); + src->src_buffer += nbytes; + src->src_size -= nbytes; + + if ( nbytes <= 0 ) { + if ( src->start_of_file ) { /* Treat empty input file as fatal error */ + ERREXIT( cinfo, JERR_INPUT_EMPTY ); + } + WARNMS( cinfo, JWRN_JPEG_EOF ); + /* Insert a fake EOI marker */ + src->buffer[0] = (JOCTET) 0xFF; + src->buffer[1] = (JOCTET) JPEG_EOI; + nbytes = 2; + } + + src->pub.next_input_byte = src->buffer; + src->pub.bytes_in_buffer = nbytes; + src->start_of_file = FALSE; + + return TRUE; } @@ -163,25 +164,24 @@ static boolean my_fill_input_buffer (j_decompress_ptr cinfo) * buffer is the application writer's problem. */ -static void my_skip_input_data (j_decompress_ptr cinfo, long num_bytes) -{ - my_src_ptr src = (my_src_ptr) cinfo->src; - - /* Just a dumb implementation for now. Could use fseek() except - * it doesn't work on pipes. Not clear that being smart is worth - * any trouble anyway --- large skips are infrequent. - */ - if (num_bytes > 0) { - while (num_bytes > (long) src->pub.bytes_in_buffer) { - num_bytes -= (long) src->pub.bytes_in_buffer; - (void) my_fill_input_buffer(cinfo); - /* note we assume that fill_input_buffer will never return FALSE, - * so suspension need not be handled. - */ - } - src->pub.next_input_byte += (size_t) num_bytes; - src->pub.bytes_in_buffer -= (size_t) num_bytes; - } +static void my_skip_input_data( j_decompress_ptr cinfo, long num_bytes ){ + my_src_ptr src = (my_src_ptr) cinfo->src; + + /* Just a dumb implementation for now. Could use fseek() except + * it doesn't work on pipes. Not clear that being smart is worth + * any trouble anyway --- large skips are infrequent. + */ + if ( num_bytes > 0 ) { + while ( num_bytes > (long) src->pub.bytes_in_buffer ) { + num_bytes -= (long) src->pub.bytes_in_buffer; + (void) my_fill_input_buffer( cinfo ); + /* note we assume that fill_input_buffer will never return FALSE, + * so suspension need not be handled. + */ + } + src->pub.next_input_byte += (size_t) num_bytes; + src->pub.bytes_in_buffer -= (size_t) num_bytes; + } } @@ -203,9 +203,8 @@ static void my_skip_input_data (j_decompress_ptr cinfo, long num_bytes) * for error exit. */ -static void my_term_source (j_decompress_ptr cinfo) -{ - /* no work necessary here */ +static void my_term_source( j_decompress_ptr cinfo ){ + /* no work necessary here */ } @@ -215,37 +214,36 @@ static void my_term_source (j_decompress_ptr cinfo) * for closing it after finishing decompression. */ -static void jpeg_buffer_src (j_decompress_ptr cinfo, void* buffer, int bufsize) -{ - my_src_ptr src; - - /* The source object and input buffer are made permanent so that a series - * of JPEG images can be read from the same file by calling jpeg_stdio_src - * only before the first one. (If we discarded the buffer at the end of - * one image, we'd likely lose the start of the next one.) - * This makes it unsafe to use this manager and a different source - * manager serially with the same JPEG object. Caveat programmer. - */ - 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 (my_source_mgr)); - src = (my_src_ptr) cinfo->src; - src->buffer = (JOCTET *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, - INPUT_BUF_SIZE * sizeof (JOCTET)); - } - - src = (my_src_ptr) cinfo->src; - src->pub.init_source = my_init_source; - src->pub.fill_input_buffer = my_fill_input_buffer; - src->pub.skip_input_data = my_skip_input_data; - src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ - src->pub.term_source = my_term_source; - src->src_buffer = (JOCTET *)buffer; - src->src_size = bufsize; - src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ - src->pub.next_input_byte = NULL; /* until buffer loaded */ +static void jpeg_buffer_src( j_decompress_ptr cinfo, void* buffer, int bufsize ){ + my_src_ptr src; + + /* The source object and input buffer are made permanent so that a series + * of JPEG images can be read from the same file by calling jpeg_stdio_src + * only before the first one. (If we discarded the buffer at the end of + * one image, we'd likely lose the start of the next one.) + * This makes it unsafe to use this manager and a different source + * manager serially with the same JPEG object. Caveat programmer. + */ + 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( my_source_mgr ) ); + src = (my_src_ptr) cinfo->src; + src->buffer = (JOCTET *) + ( *cinfo->mem->alloc_small )( (j_common_ptr) cinfo, JPOOL_PERMANENT, + INPUT_BUF_SIZE * sizeof( JOCTET ) ); + } + + src = (my_src_ptr) cinfo->src; + src->pub.init_source = my_init_source; + src->pub.fill_input_buffer = my_fill_input_buffer; + src->pub.skip_input_data = my_skip_input_data; + src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ + src->pub.term_source = my_term_source; + src->src_buffer = (JOCTET *)buffer; + src->src_size = bufsize; + src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ + src->pub.next_input_byte = NULL; /* until buffer loaded */ } // ============================================================================= @@ -254,153 +252,148 @@ static char errormsg[JMSG_LENGTH_MAX]; typedef struct my_jpeg_error_mgr { - struct jpeg_error_mgr pub; // "public" fields - jmp_buf setjmp_buffer; // for return to caller + struct jpeg_error_mgr pub; // "public" fields + jmp_buf setjmp_buffer; // for return to caller } bt_jpeg_error_mgr; -static void my_jpeg_error_exit (j_common_ptr cinfo) -{ - my_jpeg_error_mgr* myerr = (bt_jpeg_error_mgr*) cinfo->err; +static void my_jpeg_error_exit( j_common_ptr cinfo ){ + my_jpeg_error_mgr* myerr = (bt_jpeg_error_mgr*) cinfo->err; - (*cinfo->err->format_message) (cinfo, errormsg); + ( *cinfo->err->format_message )( cinfo, errormsg ); - longjmp (myerr->setjmp_buffer, 1); + longjmp( myerr->setjmp_buffer, 1 ); } // stash a scanline -static void j_putRGBScanline (unsigned char* jpegline, int widthPix, unsigned char* outBuf, int row) -{ - int offset = row * widthPix * 4; - int count; - - for (count = 0; count < widthPix; count++) - { - unsigned char iRed, iBlu, iGrn; - unsigned char *oRed, *oBlu, *oGrn, *oAlp; - - iRed = *(jpegline + count * 3 + 0); - iGrn = *(jpegline + count * 3 + 1); - iBlu = *(jpegline + count * 3 + 2); - - oRed = outBuf + offset + count * 4 + 0; - oGrn = outBuf + offset + count * 4 + 1; - oBlu = outBuf + offset + count * 4 + 2; - oAlp = outBuf + offset + count * 4 + 3; - - *oRed = iRed; - *oGrn = iGrn; - *oBlu = iBlu; - *oAlp = 255; - } +static void j_putRGBScanline( unsigned char* jpegline, int widthPix, unsigned char* outBuf, int row ){ + int offset = row * widthPix * 4; + int count; + + for ( count = 0; count < widthPix; count++ ) + { + unsigned char iRed, iBlu, iGrn; + unsigned char *oRed, *oBlu, *oGrn, *oAlp; + + iRed = *( jpegline + count * 3 + 0 ); + iGrn = *( jpegline + count * 3 + 1 ); + iBlu = *( jpegline + count * 3 + 2 ); + + oRed = outBuf + offset + count * 4 + 0; + oGrn = outBuf + offset + count * 4 + 1; + oBlu = outBuf + offset + count * 4 + 2; + oAlp = outBuf + offset + count * 4 + 3; + + *oRed = iRed; + *oGrn = iGrn; + *oBlu = iBlu; + *oAlp = 255; + } } // stash a scanline -static void j_putRGBAScanline (unsigned char* jpegline, int widthPix, unsigned char* outBuf, int row) -{ - int offset = row * widthPix * 4; - int count; - - for (count = 0; count < widthPix; count++) - { - unsigned char iRed, iBlu, iGrn, iAlp; - unsigned char *oRed, *oBlu, *oGrn, *oAlp; - - iRed = *(jpegline + count * 4 + 0); - iGrn = *(jpegline + count * 4 + 1); - iBlu = *(jpegline + count * 4 + 2); - iAlp = *(jpegline + count * 4 + 3); - - oRed = outBuf + offset + count * 4 + 0; - oGrn = outBuf + offset + count * 4 + 1; - oBlu = outBuf + offset + count * 4 + 2; - oAlp = outBuf + offset + count * 4 + 3; - - *oRed = iRed; - *oGrn = iGrn; - *oBlu = iBlu; - - //!\todo fix jpeglib, it leaves alpha channel uninitialised +static void j_putRGBAScanline( unsigned char* jpegline, int widthPix, unsigned char* outBuf, int row ){ + int offset = row * widthPix * 4; + int count; + + for ( count = 0; count < widthPix; count++ ) + { + unsigned char iRed, iBlu, iGrn, iAlp; + unsigned char *oRed, *oBlu, *oGrn, *oAlp; + + iRed = *( jpegline + count * 4 + 0 ); + iGrn = *( jpegline + count * 4 + 1 ); + iBlu = *( jpegline + count * 4 + 2 ); + iAlp = *( jpegline + count * 4 + 3 ); + + oRed = outBuf + offset + count * 4 + 0; + oGrn = outBuf + offset + count * 4 + 1; + oBlu = outBuf + offset + count * 4 + 2; + oAlp = outBuf + offset + count * 4 + 3; + + *oRed = iRed; + *oGrn = iGrn; + *oBlu = iBlu; + + //!\todo fix jpeglib, it leaves alpha channel uninitialised #if 1 - *oAlp = 255; + *oAlp = 255; #else - *oAlp = iAlp; + *oAlp = iAlp; #endif - } + } } // stash a gray scanline -static void j_putGrayScanlineToRGB (unsigned char* jpegline, int widthPix, unsigned char* outBuf, int row) -{ - int offset = row * widthPix * 4; - int count; - - for (count = 0; count < widthPix; count++) - { - unsigned char iGray; - unsigned char *oRed, *oBlu, *oGrn, *oAlp; - - // get our grayscale value - iGray = *(jpegline + count); - - oRed = outBuf + offset + count * 4; - oGrn = outBuf + offset + count * 4 + 1; - oBlu = outBuf + offset + count * 4 + 2; - oAlp = outBuf + offset + count * 4 + 3; - - *oRed = iGray; - *oGrn = iGray; - *oBlu = iGray; - *oAlp = 255; - } +static void j_putGrayScanlineToRGB( unsigned char* jpegline, int widthPix, unsigned char* outBuf, int row ){ + int offset = row * widthPix * 4; + int count; + + for ( count = 0; count < widthPix; count++ ) + { + unsigned char iGray; + unsigned char *oRed, *oBlu, *oGrn, *oAlp; + + // get our grayscale value + iGray = *( jpegline + count ); + + oRed = outBuf + offset + count * 4; + oGrn = outBuf + offset + count * 4 + 1; + oBlu = outBuf + offset + count * 4 + 2; + oAlp = outBuf + offset + count * 4 + 3; + + *oRed = iGray; + *oGrn = iGray; + *oBlu = iGray; + *oAlp = 255; + } } -static Image* LoadJPGBuff_(const void *src_buffer, int src_size) -{ - struct jpeg_decompress_struct cinfo; - struct my_jpeg_error_mgr jerr; +static Image* LoadJPGBuff_( const void *src_buffer, int src_size ){ + struct jpeg_decompress_struct cinfo; + struct my_jpeg_error_mgr jerr; - cinfo.err = jpeg_std_error (&jerr.pub); - jerr.pub.error_exit = my_jpeg_error_exit; + cinfo.err = jpeg_std_error( &jerr.pub ); + jerr.pub.error_exit = my_jpeg_error_exit; - if (setjmp (jerr.setjmp_buffer)) //< TODO: use c++ exceptions instead of setjmp/longjmp to handle errors - { - globalErrorStream() << "WARNING: JPEG library error: " << errormsg << "\n"; - jpeg_destroy_decompress (&cinfo); - return 0; - } + if ( setjmp( jerr.setjmp_buffer ) ) { //< TODO: use c++ exceptions instead of setjmp/longjmp to handle errors + globalErrorStream() << "WARNING: JPEG library error: " << errormsg << "\n"; + jpeg_destroy_decompress( &cinfo ); + return 0; + } - jpeg_create_decompress (&cinfo); - jpeg_buffer_src (&cinfo, const_cast(src_buffer), src_size); - jpeg_read_header (&cinfo, TRUE); - jpeg_start_decompress (&cinfo); + jpeg_create_decompress( &cinfo ); + jpeg_buffer_src( &cinfo, const_cast( src_buffer ), src_size ); + jpeg_read_header( &cinfo, TRUE ); + jpeg_start_decompress( &cinfo ); - int row_stride = cinfo.output_width * cinfo.output_components; + int row_stride = cinfo.output_width * cinfo.output_components; - RGBAImage* image = new RGBAImage(cinfo.output_width, cinfo.output_height); + RGBAImage* image = new RGBAImage( cinfo.output_width, cinfo.output_height ); - JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); + JSAMPARRAY buffer = ( *cinfo.mem->alloc_sarray )( ( j_common_ptr ) & cinfo, JPOOL_IMAGE, row_stride, 1 ); - while (cinfo.output_scanline < cinfo.output_height) - { - jpeg_read_scanlines (&cinfo, buffer, 1); + while ( cinfo.output_scanline < cinfo.output_height ) + { + jpeg_read_scanlines( &cinfo, buffer, 1 ); - if (cinfo.out_color_components == 4) - j_putRGBAScanline (buffer[0], cinfo.output_width, image->getRGBAPixels(), cinfo.output_scanline-1); - else if (cinfo.out_color_components == 3) - j_putRGBScanline (buffer[0], cinfo.output_width, image->getRGBAPixels(), cinfo.output_scanline-1); - else if (cinfo.out_color_components == 1) - j_putGrayScanlineToRGB (buffer[0], cinfo.output_width, image->getRGBAPixels(), cinfo.output_scanline-1); - } + if ( cinfo.out_color_components == 4 ) { + j_putRGBAScanline( buffer[0], cinfo.output_width, image->getRGBAPixels(), cinfo.output_scanline - 1 ); + } + else if ( cinfo.out_color_components == 3 ) { + j_putRGBScanline( buffer[0], cinfo.output_width, image->getRGBAPixels(), cinfo.output_scanline - 1 ); + } + else if ( cinfo.out_color_components == 1 ) { + j_putGrayScanlineToRGB( buffer[0], cinfo.output_width, image->getRGBAPixels(), cinfo.output_scanline - 1 ); + } + } - jpeg_finish_decompress (&cinfo); - jpeg_destroy_decompress (&cinfo); + jpeg_finish_decompress( &cinfo ); + jpeg_destroy_decompress( &cinfo ); - return image; + return image; } -Image* LoadJPG(ArchiveFile& file) -{ - ScopedArchiveBuffer buffer(file); - return LoadJPGBuff_(buffer.buffer, static_cast(buffer.length)); +Image* LoadJPG( ArchiveFile& file ){ + ScopedArchiveBuffer buffer( file ); + return LoadJPGBuff_( buffer.buffer, static_cast( buffer.length ) ); } -