diff options
Diffstat (limited to 'plugins/FreeImage/Source/FreeImageToolkit/JPEGTransform.cpp')
| -rw-r--r-- | plugins/FreeImage/Source/FreeImageToolkit/JPEGTransform.cpp | 410 | 
1 files changed, 410 insertions, 0 deletions
diff --git a/plugins/FreeImage/Source/FreeImageToolkit/JPEGTransform.cpp b/plugins/FreeImage/Source/FreeImageToolkit/JPEGTransform.cpp new file mode 100644 index 0000000000..5b5fcefe2b --- /dev/null +++ b/plugins/FreeImage/Source/FreeImageToolkit/JPEGTransform.cpp @@ -0,0 +1,410 @@ +// ==========================================================
 +// JPEG lossless transformations
 +//
 +// Design and implementation by
 +// - Petr Pytelka (pyta@lightcomp.com)
 +// - Hervé Drolon (drolon@infonie.fr)
 +//
 +// This file is part of FreeImage 3
 +//
 +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
 +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
 +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
 +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
 +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
 +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
 +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
 +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
 +// THIS DISCLAIMER.
 +//
 +// Use at your own risk!
 +// ==========================================================
 +
 +extern "C" {
 +#define XMD_H
 +#undef FAR
 +#include <setjmp.h>
 +
 +#include "../LibJPEG/jinclude.h"
 +#include "../LibJPEG/jpeglib.h"
 +#include "../LibJPEG/jerror.h"
 +#include "../LibJPEG/transupp.h"
 +}
 +
 +#include "FreeImage.h"
 +#include "Utilities.h"
 +
 +// ----------------------------------------------------------
 +//   IO filename handling
 +// ----------------------------------------------------------
 +
 +typedef struct tagFilenameIO {
 +	const char *src_file;
 +	const char *dst_file;
 +	const wchar_t *wsrc_file;
 +	const wchar_t *wdst_file;
 +} FilenameIO;
 +
 +// ----------------------------------------------------------
 +//   Error handling
 +// ----------------------------------------------------------
 +
 +/**
 +	Receives control for a fatal error.  Information sufficient to
 +	generate the error message has been stored in cinfo->err; call
 +	output_message to display it.  Control must NOT return to the caller;
 +	generally this routine will exit() or longjmp() somewhere.
 +*/
 +METHODDEF(void)
 +ls_jpeg_error_exit (j_common_ptr cinfo) {
 +	// always display the message
 +	(*cinfo->err->output_message)(cinfo);
 +
 +	// allow JPEG with a premature end of file
 +	if((cinfo)->err->msg_parm.i[0] != 13) {
 +	
 +		// let the memory manager delete any temp files before we die
 +		jpeg_destroy(cinfo);
 +		
 +		throw FIF_JPEG;
 +	}
 +}
 +
 +/**
 +	Actual output of any JPEG message.  Note that this method does not know
 +	how to generate a message, only where to send it.
 +*/
 +METHODDEF(void)
 +ls_jpeg_output_message (j_common_ptr cinfo) {
 +	char buffer[JMSG_LENGTH_MAX];
 +
 +	// create the message
 +	(*cinfo->err->format_message)(cinfo, buffer);
 +	// send it to user's message proc
 +	FreeImage_OutputMessageProc(FIF_JPEG, buffer);
 +}
 +
 +// ----------------------------------------------------------
 +//   Main program
 +// ----------------------------------------------------------
 +
 +static BOOL  
 +LosslessTransform(const FilenameIO *filenameIO, FREE_IMAGE_JPEG_OPERATION operation, const char *crop, BOOL perfect) {
 +	// We assume all-in-memory processing and can therefore use only a
 +	// single file pointer for sequential input and output operation
 +	FILE *fp = NULL;
 +
 +	// check for UNICODE filenames - previous structure filling was done before
 +	bool bUseUnicode = filenameIO && filenameIO->wsrc_file && filenameIO->wdst_file;
 +
 +	// Set up the jpeglib structures
 +	jpeg_decompress_struct srcinfo;
 +	jpeg_compress_struct dstinfo;
 +	jpeg_error_mgr jsrcerr, jdsterr;
 +	jvirt_barray_ptr *src_coef_arrays = NULL;
 +	jvirt_barray_ptr *dst_coef_arrays = NULL;
 +	// Support for copying optional markers from source to destination file
 +	JCOPY_OPTION copyoption;
 +	// Image transformation options
 +	jpeg_transform_info transfoptions;
 +	
 +	// Initialize structures
 +	memset(&srcinfo, 0, sizeof(srcinfo));
 +	memset(&jsrcerr, 0, sizeof(jsrcerr));
 +	memset(&jdsterr, 0, sizeof(jdsterr));
 +	memset(&dstinfo, 0, sizeof(dstinfo));
 +	memset(&transfoptions, 0, sizeof(transfoptions));
 +	
 +	// Copy all extra markers from source file
 +	copyoption = JCOPYOPT_ALL;
 +	
 +	// Set up default JPEG parameters
 +	transfoptions.force_grayscale = FALSE;
 +	transfoptions.crop = FALSE;
 +
 +	// Select the transform option
 +	switch(operation) {
 +		case FIJPEG_OP_FLIP_H:		// horizontal flip
 +			transfoptions.transform = JXFORM_FLIP_H;
 +			break;
 +		case FIJPEG_OP_FLIP_V:		// vertical flip
 +			transfoptions.transform = JXFORM_FLIP_V;
 +			break;
 +		case FIJPEG_OP_TRANSPOSE:	// transpose across UL-to-LR axis
 +			transfoptions.transform = JXFORM_TRANSPOSE;
 +			break;
 +		case FIJPEG_OP_TRANSVERSE:	// transpose across UR-to-LL axis
 +			transfoptions.transform = JXFORM_TRANSVERSE;
 +			break;
 +		case FIJPEG_OP_ROTATE_90:	// 90-degree clockwise rotation
 +			transfoptions.transform = JXFORM_ROT_90;
 +			break;
 +		case FIJPEG_OP_ROTATE_180:	// 180-degree rotation
 +			transfoptions.transform = JXFORM_ROT_180;
 +			break;
 +		case FIJPEG_OP_ROTATE_270:	// 270-degree clockwise (or 90 ccw)
 +			transfoptions.transform = JXFORM_ROT_270;
 +			break;
 +		default:
 +		case FIJPEG_OP_NONE:		// no transformation
 +			transfoptions.transform = JXFORM_NONE;
 +			break;
 +	}
 +	// (perfect == TRUE) ==> fail if there is non-transformable edge blocks
 +	transfoptions.perfect = (perfect == TRUE) ? TRUE : FALSE;
 +	// Drop non-transformable edge blocks: trim off any partial edge MCUs that the transform can't handle.
 +	transfoptions.trim = TRUE;
 +
 +	try {
 +
 +		// Initialize the JPEG decompression object with default error handling
 +		srcinfo.err = jpeg_std_error(&jsrcerr);
 +		srcinfo.err->error_exit = ls_jpeg_error_exit;
 +		srcinfo.err->output_message = ls_jpeg_output_message;
 +		jpeg_create_decompress(&srcinfo);
 +
 +		// Initialize the JPEG compression object with default error handling
 +		dstinfo.err = jpeg_std_error(&jdsterr);
 +		dstinfo.err->error_exit = ls_jpeg_error_exit;
 +		dstinfo.err->output_message = ls_jpeg_output_message;
 +		jpeg_create_compress(&dstinfo);
 +
 +		// crop option
 +		if(crop != NULL) {
 +			if(!jtransform_parse_crop_spec(&transfoptions, crop)) {
 +				FreeImage_OutputMessageProc(FIF_JPEG, "Bogus crop argument %s", crop);
 +				throw(1);
 +			}
 +		}
 +
 +		// Open the input file
 +		if(bUseUnicode) {
 +#ifdef _WIN32
 +			if((fp = _wfopen(filenameIO->wsrc_file, L"rb")) == NULL) {
 +				FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open input file for reading");
 +			}
 +#else
 +			fp = NULL;
 +#endif // _WIN32
 +		} else {
 +			if((fp = fopen(filenameIO->src_file, "rb")) == NULL) {
 +				FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open %s for reading", filenameIO->src_file);
 +			}
 +		}
 +		if(fp == NULL) {
 +			jpeg_destroy_compress(&dstinfo);
 +			jpeg_destroy_decompress(&srcinfo);
 +			return FALSE;
 +		}
 +		
 +		// Specify data source for decompression
 +		jpeg_stdio_src(&srcinfo, fp);
 +		
 +		// Enable saving of extra markers that we want to copy
 +		jcopy_markers_setup(&srcinfo, copyoption);
 +		
 +		// Read the file header
 +		jpeg_read_header(&srcinfo, TRUE);
 +		
 +		// Any space needed by a transform option must be requested before
 +		// jpeg_read_coefficients so that memory allocation will be done right
 +
 +		// Prepare transformation workspace
 +		// Fails right away if perfect flag is TRUE and transformation is not perfect
 +		if( !jtransform_request_workspace(&srcinfo, &transfoptions) ) {
 +			FreeImage_OutputMessageProc(FIF_JPEG, "Transformation is not perfect");
 +			throw(1);
 +		}
 +
 +		// Read source file as DCT coefficients
 +		src_coef_arrays = jpeg_read_coefficients(&srcinfo);
 +		
 +		// Initialize destination compression parameters from source values
 +		jpeg_copy_critical_parameters(&srcinfo, &dstinfo);
 +
 +		// Adjust destination parameters if required by transform options;
 +		// also find out which set of coefficient arrays will hold the output
 +		dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo, src_coef_arrays, &transfoptions);
 +		
 +		// Close the input file.
 +		// Note: we assume that jpeg_read_coefficients consumed all input
 +		// until JPEG_REACHED_EOI, and that jpeg_finish_decompress will
 +		// only consume more while (! cinfo->inputctl->eoi_reached).
 +		// We cannot call jpeg_finish_decompress here since we still need the
 +		// virtual arrays allocated from the source object for processing.
 +		fclose(fp);
 +
 +		// Open the output file
 +		if(bUseUnicode) {
 +#ifdef _WIN32
 +			if((fp = _wfopen(filenameIO->wdst_file, L"wb")) == NULL) {
 +				FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open output file for writing");
 +			}
 +#else
 +			fp = NULL;
 +#endif // _WIN32
 +		} else {
 +			if((fp = fopen(filenameIO->dst_file, "wb")) == NULL) {
 +				FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open %s for writing", filenameIO->dst_file);
 +			}
 +		}
 +		if(fp == NULL) {
 +			throw(1);
 +		}
 +		
 +		// Specify data destination for compression
 +		jpeg_stdio_dest(&dstinfo, fp);
 +		
 +		// Start compressor (note no image data is actually written here)
 +		jpeg_write_coefficients(&dstinfo, dst_coef_arrays);
 +		
 +		// Copy to the output file any extra markers that we want to preserve
 +		jcopy_markers_execute(&srcinfo, &dstinfo, copyoption);
 +		
 +		// Execute image transformation, if any
 +		jtransform_execute_transformation(&srcinfo, &dstinfo, src_coef_arrays, &transfoptions);
 +		
 +		// Finish compression and release memory
 +		jpeg_finish_compress(&dstinfo);
 +		jpeg_destroy_compress(&dstinfo);
 +		jpeg_finish_decompress(&srcinfo);
 +		jpeg_destroy_decompress(&srcinfo);
 +		
 +		// Close output file and return
 +		fclose(fp);
 +	}
 +	catch(...) {
 +		if(fp) fclose(fp);
 +		jpeg_destroy_compress(&dstinfo);
 +		jpeg_destroy_decompress(&srcinfo);
 +		return FALSE;
 +	}
 +
 +	return TRUE;
 +}
 +
 +// ----------------------------------------------------------
 +//   FreeImage interface
 +// ----------------------------------------------------------
 +
 +BOOL DLL_CALLCONV 
 +FreeImage_JPEGTransform(const char *src_file, const char *dst_file, FREE_IMAGE_JPEG_OPERATION operation, BOOL perfect) {
 +	try {
 +		// check the src file format
 +		if(FreeImage_GetFileType(src_file) != FIF_JPEG) {
 +			throw FI_MSG_ERROR_MAGIC_NUMBER;
 +		}
 +
 +		// setup IO
 +		FilenameIO filenameIO;
 +		memset(&filenameIO, 0, sizeof(FilenameIO));
 +		filenameIO.src_file = src_file;
 +		filenameIO.dst_file = dst_file;
 +
 +		// perform the transformation
 +		return LosslessTransform(&filenameIO, operation, NULL, perfect);
 +
 +	} catch(const char *text) {
 +		FreeImage_OutputMessageProc(FIF_JPEG, text);
 +		return FALSE;
 +	}
 +}
 +
 +BOOL DLL_CALLCONV 
 +FreeImage_JPEGCrop(const char *src_file, const char *dst_file, int left, int top, int right, int bottom) {
 +	char crop[64];
 +
 +	try {
 +		// check the src file format
 +		if(FreeImage_GetFileType(src_file) != FIF_JPEG) {
 +			throw FI_MSG_ERROR_MAGIC_NUMBER;
 +		}
 +		
 +		// normalize the rectangle
 +		if(right < left) {
 +			INPLACESWAP(left, right);
 +		}
 +		if(bottom < top) {
 +			INPLACESWAP(top, bottom);
 +		}
 +
 +		// build the crop option
 +		sprintf(crop, "%dx%d+%d+%d", right - left, bottom - top, left, top);
 +
 +		// setup IO
 +		FilenameIO filenameIO;
 +		memset(&filenameIO, 0, sizeof(FilenameIO));
 +		filenameIO.src_file = src_file;
 +		filenameIO.dst_file = dst_file;
 +
 +		// perform the transformation
 +		return LosslessTransform(&filenameIO, FIJPEG_OP_NONE, crop, FALSE);
 +
 +	} catch(const char *text) {
 +		FreeImage_OutputMessageProc(FIF_JPEG, text);
 +		return FALSE;
 +	}
 +}
 +
 +BOOL DLL_CALLCONV 
 +FreeImage_JPEGTransformU(const wchar_t *src_file, const wchar_t *dst_file, FREE_IMAGE_JPEG_OPERATION operation, BOOL perfect) {
 +#ifdef _WIN32
 +	try {
 +		// check the src file format
 +		if(FreeImage_GetFileTypeU(src_file) != FIF_JPEG) {
 +			throw FI_MSG_ERROR_MAGIC_NUMBER;
 +		}
 +
 +		// setup IO
 +		FilenameIO filenameIO;
 +		memset(&filenameIO, 0, sizeof(FilenameIO));
 +		filenameIO.wsrc_file = src_file;
 +		filenameIO.wdst_file = dst_file;
 +
 +		// perform the transformation
 +		return LosslessTransform(&filenameIO, operation, NULL, perfect);
 +
 +	} catch(const char *text) {
 +		FreeImage_OutputMessageProc(FIF_JPEG, text);
 +	}
 +#endif /// _WIN32
 +	return FALSE;
 +}
 +
 +BOOL DLL_CALLCONV 
 +FreeImage_JPEGCropU(const wchar_t *src_file, const wchar_t *dst_file, int left, int top, int right, int bottom) {
 +#ifdef _WIN32
 +	char crop[64];
 +
 +	try {
 +		// check the src file format
 +		if(FreeImage_GetFileTypeU(src_file) != FIF_JPEG) {
 +			throw FI_MSG_ERROR_MAGIC_NUMBER;
 +		}
 +		
 +		// normalize the rectangle
 +		if(right < left) {
 +			INPLACESWAP(left, right);
 +		}
 +		if(bottom < top) {
 +			INPLACESWAP(top, bottom);
 +		}
 +
 +		// build the crop option
 +		sprintf(crop, "%dx%d+%d+%d", right - left, bottom - top, left, top);
 +
 +		// setup IO
 +		FilenameIO filenameIO;
 +		memset(&filenameIO, 0, sizeof(FilenameIO));
 +		filenameIO.wsrc_file = src_file;
 +		filenameIO.wdst_file = dst_file;
 +
 +		// perform the transformation
 +		return LosslessTransform(&filenameIO, FIJPEG_OP_NONE, crop, FALSE);
 +
 +	} catch(const char *text) {
 +		FreeImage_OutputMessageProc(FIF_JPEG, text);
 +	}
 +#endif // _WIN32
 +	return FALSE;
 +}
  | 
