/* Save a JPEG to a file. cjpeg.c and example.c from jpeglib were helpful in writing this. */ bool RageSurfaceUtils::SaveJPEG( RageSurface *surface, RageFile &f, bool bHighQual ) { RageSurface *dst_surface; if( RageSurfaceUtils::ConvertSurface( surface, dst_surface, surface->w, surface->h, 24, Swap24BE(0xFF0000), Swap24BE(0x00FF00), Swap24BE(0x0000FF), 0 ) ) surface = dst_surface; struct jpeg::jpeg_compress_struct cinfo; /* Set up the error handler. */ struct jpeg::jpeg_error_mgr jerr; cinfo.err = jpeg::jpeg_std_error( &jerr ); /* Now we can initialize the JPEG compression object. */ jpeg::jpeg_CreateCompress(&cinfo, JPEG_LIB_VERSION, \ (size_t) sizeof(struct jpeg::jpeg_compress_struct)); cinfo.image_width = surface->w; /* image width and height, in pixels */ cinfo.image_height = surface->h; cinfo.input_components = 3; /* # of color components per pixel */ cinfo.in_color_space = jpeg::JCS_RGB; /* colorspace of input image */ /* Set compression parameters. You must set at least cinfo.in_color_space before * calling this.*/ jpeg::jpeg_set_defaults(&cinfo); if( bHighQual ) jpeg::jpeg_set_quality( &cinfo, 150, TRUE ); else jpeg::jpeg_set_quality( &cinfo, 70, TRUE ); jpeg_RageFile_dest( &cinfo, f ); /* Start the compressor. */ jpeg::jpeg_start_compress( &cinfo, TRUE ); /* Here we use the library's state variable cinfo.next_scanline as the * loop counter, so that we don't have to keep track ourselves. * To keep things simple, we pass one scanline per call; you can pass * more if you wish, though. */ const int row_stride = surface->pitch; /* JSAMPLEs per row in image_buffer */ while( cinfo.next_scanline < cinfo.image_height ) { /* jpeg_write_scanlines expects an array of pointers to scanlines. * Here the array is only one element long, but you could pass * more than one scanline at a time if that's more convenient. */ jpeg::JSAMPROW row_pointer = & ((jpeg::JSAMPLE*)surface->pixels)[cinfo.next_scanline * row_stride]; jpeg::jpeg_write_scanlines( &cinfo, &row_pointer, 1 ); } /* Finish compression. */ jpeg::jpeg_finish_compress( &cinfo ); jpeg::jpeg_destroy_compress( &cinfo ); delete dst_surface; return true; }
static RageSurface *RageSurface_Load_JPEG( RageFile *f, const char *fn, char errorbuf[JMSG_LENGTH_MAX] ) { struct jpeg_decompress_struct cinfo; struct my_jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; jerr.pub.output_message = my_output_message; RageSurface *volatile img = NULL; /* volatile to prevent possible problems with setjmp */ if( setjmp(jerr.setjmp_buffer) ) { my_jpeg_error_mgr *myerr = (my_jpeg_error_mgr *) cinfo.err; memcpy( errorbuf, myerr->errorbuf, JMSG_LENGTH_MAX ); jpeg_destroy_decompress( &cinfo ); delete img; return NULL; } /* Now we can initialize the JPEG decompression object. */ jpeg_create_decompress( &cinfo ); /* Step 2: specify data source (eg, a file) */ RageFile_source_mgr RageFileJpegSource; RageFileJpegSource.pub.init_source = RageFile_JPEG_init_source; RageFileJpegSource.pub.fill_input_buffer = RageFile_JPEG_fill_input_buffer; RageFileJpegSource.pub.skip_input_data = RageFile_JPEG_skip_input_data; RageFileJpegSource.pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ RageFileJpegSource.pub.term_source = RageFile_JPEG_term_source; RageFileJpegSource.file = f; cinfo.src = (jpeg_source_mgr *) &RageFileJpegSource; jpeg_read_header( &cinfo, TRUE ); switch( cinfo.jpeg_color_space ) { case JCS_GRAYSCALE: cinfo.out_color_space = JCS_GRAYSCALE; break; case JCS_YCCK: case JCS_CMYK: sprintf( errorbuf, "Color format \"%s\" not supported", cinfo.jpeg_color_space == JCS_YCCK? "YCCK":"CMYK" ); jpeg_destroy_decompress( &cinfo ); return NULL; default: cinfo.out_color_space = JCS_RGB; break; } jpeg_start_decompress( &cinfo ); if( cinfo.out_color_space == JCS_GRAYSCALE ) { img = CreateSurface( cinfo.output_width, cinfo.output_height, 8, 0, 0, 0, 0 ); for( int i = 0; i < 256; ++i ) { RageSurfaceColor color; color.r = color.g = color.b = (int8_t) i; color.a = 0xFF; img->fmt.palette->colors[i] = color; } } else { img = CreateSurface( cinfo.output_width, cinfo.output_height, 24, Swap24BE( 0xFF0000 ), Swap24BE( 0x00FF00 ), Swap24BE( 0x0000FF ), Swap24BE( 0x000000 ) ); } while( cinfo.output_scanline < cinfo.output_height ) { JSAMPROW p = (JSAMPROW) img->pixels; p += cinfo.output_scanline * img->pitch; jpeg_read_scanlines(&cinfo, &p, 1); } jpeg_finish_decompress( &cinfo ); jpeg_destroy_decompress( &cinfo ); return img; }