예제 #1
0
/* 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;
}
예제 #2
0
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;
}