PageRenderTime 36ms CodeModel.GetById 1ms app.highlight 30ms RepoModel.GetById 1ms app.codeStats 1ms

/src/FreeImage/Source/FreeImageToolkit/JPEGTransform.cpp

https://bitbucket.org/cabalistic/ogredeps/
C++ | 410 lines | 241 code | 65 blank | 104 comment | 38 complexity | 70cce1fdb5764c20144a3dfa3e97e2bd MD5 | raw file
  1// ==========================================================
  2// JPEG lossless transformations
  3//
  4// Design and implementation by
  5// - Petr Pytelka (pyta@lightcomp.com)
  6// - Hervé Drolon (drolon@infonie.fr)
  7//
  8// This file is part of FreeImage 3
  9//
 10// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
 11// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
 12// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
 13// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
 14// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
 15// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
 16// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
 17// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
 18// THIS DISCLAIMER.
 19//
 20// Use at your own risk!
 21// ==========================================================
 22
 23extern "C" {
 24#define XMD_H
 25#undef FAR
 26#include <setjmp.h>
 27
 28#include "../LibJPEG/jinclude.h"
 29#include "../LibJPEG/jpeglib.h"
 30#include "../LibJPEG/jerror.h"
 31#include "../LibJPEG/transupp.h"
 32}
 33
 34#include "FreeImage.h"
 35#include "Utilities.h"
 36
 37// ----------------------------------------------------------
 38//   IO filename handling
 39// ----------------------------------------------------------
 40
 41typedef struct tagFilenameIO {
 42	const char *src_file;
 43	const char *dst_file;
 44	const wchar_t *wsrc_file;
 45	const wchar_t *wdst_file;
 46} FilenameIO;
 47
 48// ----------------------------------------------------------
 49//   Error handling
 50// ----------------------------------------------------------
 51
 52/**
 53	Receives control for a fatal error.  Information sufficient to
 54	generate the error message has been stored in cinfo->err; call
 55	output_message to display it.  Control must NOT return to the caller;
 56	generally this routine will exit() or longjmp() somewhere.
 57*/
 58METHODDEF(void)
 59ls_jpeg_error_exit (j_common_ptr cinfo) {
 60	// always display the message
 61	(*cinfo->err->output_message)(cinfo);
 62
 63	// allow JPEG with a premature end of file
 64	if((cinfo)->err->msg_parm.i[0] != 13) {
 65	
 66		// let the memory manager delete any temp files before we die
 67		jpeg_destroy(cinfo);
 68		
 69		throw FIF_JPEG;
 70	}
 71}
 72
 73/**
 74	Actual output of any JPEG message.  Note that this method does not know
 75	how to generate a message, only where to send it.
 76*/
 77METHODDEF(void)
 78ls_jpeg_output_message (j_common_ptr cinfo) {
 79	char buffer[JMSG_LENGTH_MAX];
 80
 81	// create the message
 82	(*cinfo->err->format_message)(cinfo, buffer);
 83	// send it to user's message proc
 84	FreeImage_OutputMessageProc(FIF_JPEG, buffer);
 85}
 86
 87// ----------------------------------------------------------
 88//   Main program
 89// ----------------------------------------------------------
 90
 91static BOOL  
 92LosslessTransform(const FilenameIO *filenameIO, FREE_IMAGE_JPEG_OPERATION operation, const char *crop, BOOL perfect) {
 93	// We assume all-in-memory processing and can therefore use only a
 94	// single file pointer for sequential input and output operation
 95	FILE *fp = NULL;
 96
 97	// check for UNICODE filenames - previous structure filling was done before
 98	bool bUseUnicode = filenameIO && filenameIO->wsrc_file && filenameIO->wdst_file;
 99
100	// Set up the jpeglib structures
101	jpeg_decompress_struct srcinfo;
102	jpeg_compress_struct dstinfo;
103	jpeg_error_mgr jsrcerr, jdsterr;
104	jvirt_barray_ptr *src_coef_arrays = NULL;
105	jvirt_barray_ptr *dst_coef_arrays = NULL;
106	// Support for copying optional markers from source to destination file
107	JCOPY_OPTION copyoption;
108	// Image transformation options
109	jpeg_transform_info transfoptions;
110	
111	// Initialize structures
112	memset(&srcinfo, 0, sizeof(srcinfo));
113	memset(&jsrcerr, 0, sizeof(jsrcerr));
114	memset(&jdsterr, 0, sizeof(jdsterr));
115	memset(&dstinfo, 0, sizeof(dstinfo));
116	memset(&transfoptions, 0, sizeof(transfoptions));
117	
118	// Copy all extra markers from source file
119	copyoption = JCOPYOPT_ALL;
120	
121	// Set up default JPEG parameters
122	transfoptions.force_grayscale = FALSE;
123	transfoptions.crop = FALSE;
124
125	// Select the transform option
126	switch(operation) {
127		case FIJPEG_OP_FLIP_H:		// horizontal flip
128			transfoptions.transform = JXFORM_FLIP_H;
129			break;
130		case FIJPEG_OP_FLIP_V:		// vertical flip
131			transfoptions.transform = JXFORM_FLIP_V;
132			break;
133		case FIJPEG_OP_TRANSPOSE:	// transpose across UL-to-LR axis
134			transfoptions.transform = JXFORM_TRANSPOSE;
135			break;
136		case FIJPEG_OP_TRANSVERSE:	// transpose across UR-to-LL axis
137			transfoptions.transform = JXFORM_TRANSVERSE;
138			break;
139		case FIJPEG_OP_ROTATE_90:	// 90-degree clockwise rotation
140			transfoptions.transform = JXFORM_ROT_90;
141			break;
142		case FIJPEG_OP_ROTATE_180:	// 180-degree rotation
143			transfoptions.transform = JXFORM_ROT_180;
144			break;
145		case FIJPEG_OP_ROTATE_270:	// 270-degree clockwise (or 90 ccw)
146			transfoptions.transform = JXFORM_ROT_270;
147			break;
148		default:
149		case FIJPEG_OP_NONE:		// no transformation
150			transfoptions.transform = JXFORM_NONE;
151			break;
152	}
153	// (perfect == TRUE) ==> fail if there is non-transformable edge blocks
154	transfoptions.perfect = (perfect == TRUE) ? TRUE : FALSE;
155	// Drop non-transformable edge blocks: trim off any partial edge MCUs that the transform can't handle.
156	transfoptions.trim = TRUE;
157
158	try {
159
160		// Initialize the JPEG decompression object with default error handling
161		srcinfo.err = jpeg_std_error(&jsrcerr);
162		srcinfo.err->error_exit = ls_jpeg_error_exit;
163		srcinfo.err->output_message = ls_jpeg_output_message;
164		jpeg_create_decompress(&srcinfo);
165
166		// Initialize the JPEG compression object with default error handling
167		dstinfo.err = jpeg_std_error(&jdsterr);
168		dstinfo.err->error_exit = ls_jpeg_error_exit;
169		dstinfo.err->output_message = ls_jpeg_output_message;
170		jpeg_create_compress(&dstinfo);
171
172		// crop option
173		if(crop != NULL) {
174			if(!jtransform_parse_crop_spec(&transfoptions, crop)) {
175				FreeImage_OutputMessageProc(FIF_JPEG, "Bogus crop argument %s", crop);
176				throw(1);
177			}
178		}
179
180		// Open the input file
181		if(bUseUnicode) {
182#ifdef _WIN32
183			if((fp = _wfopen(filenameIO->wsrc_file, L"rb")) == NULL) {
184				FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open input file for reading");
185			}
186#else
187			fp = NULL;
188#endif // _WIN32
189		} else {
190			if((fp = fopen(filenameIO->src_file, "rb")) == NULL) {
191				FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open %s for reading", filenameIO->src_file);
192			}
193		}
194		if(fp == NULL) {
195			jpeg_destroy_compress(&dstinfo);
196			jpeg_destroy_decompress(&srcinfo);
197			return FALSE;
198		}
199		
200		// Specify data source for decompression
201		jpeg_stdio_src(&srcinfo, fp);
202		
203		// Enable saving of extra markers that we want to copy
204		jcopy_markers_setup(&srcinfo, copyoption);
205		
206		// Read the file header
207		jpeg_read_header(&srcinfo, TRUE);
208		
209		// Any space needed by a transform option must be requested before
210		// jpeg_read_coefficients so that memory allocation will be done right
211
212		// Prepare transformation workspace
213		// Fails right away if perfect flag is TRUE and transformation is not perfect
214		if( !jtransform_request_workspace(&srcinfo, &transfoptions) ) {
215			FreeImage_OutputMessageProc(FIF_JPEG, "Transformation is not perfect");
216			throw(1);
217		}
218
219		// Read source file as DCT coefficients
220		src_coef_arrays = jpeg_read_coefficients(&srcinfo);
221		
222		// Initialize destination compression parameters from source values
223		jpeg_copy_critical_parameters(&srcinfo, &dstinfo);
224
225		// Adjust destination parameters if required by transform options;
226		// also find out which set of coefficient arrays will hold the output
227		dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo, src_coef_arrays, &transfoptions);
228		
229		// Close the input file.
230		// Note: we assume that jpeg_read_coefficients consumed all input
231		// until JPEG_REACHED_EOI, and that jpeg_finish_decompress will
232		// only consume more while (! cinfo->inputctl->eoi_reached).
233		// We cannot call jpeg_finish_decompress here since we still need the
234		// virtual arrays allocated from the source object for processing.
235		fclose(fp);
236
237		// Open the output file
238		if(bUseUnicode) {
239#ifdef _WIN32
240			if((fp = _wfopen(filenameIO->wdst_file, L"wb")) == NULL) {
241				FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open output file for writing");
242			}
243#else
244			fp = NULL;
245#endif // _WIN32
246		} else {
247			if((fp = fopen(filenameIO->dst_file, "wb")) == NULL) {
248				FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open %s for writing", filenameIO->dst_file);
249			}
250		}
251		if(fp == NULL) {
252			throw(1);
253		}
254		
255		// Specify data destination for compression
256		jpeg_stdio_dest(&dstinfo, fp);
257		
258		// Start compressor (note no image data is actually written here)
259		jpeg_write_coefficients(&dstinfo, dst_coef_arrays);
260		
261		// Copy to the output file any extra markers that we want to preserve
262		jcopy_markers_execute(&srcinfo, &dstinfo, copyoption);
263		
264		// Execute image transformation, if any
265		jtransform_execute_transformation(&srcinfo, &dstinfo, src_coef_arrays, &transfoptions);
266		
267		// Finish compression and release memory
268		jpeg_finish_compress(&dstinfo);
269		jpeg_destroy_compress(&dstinfo);
270		jpeg_finish_decompress(&srcinfo);
271		jpeg_destroy_decompress(&srcinfo);
272		
273		// Close output file and return
274		fclose(fp);
275	}
276	catch(...) {
277		if(fp) fclose(fp);
278		jpeg_destroy_compress(&dstinfo);
279		jpeg_destroy_decompress(&srcinfo);
280		return FALSE;
281	}
282
283	return TRUE;
284}
285
286// ----------------------------------------------------------
287//   FreeImage interface
288// ----------------------------------------------------------
289
290BOOL DLL_CALLCONV 
291FreeImage_JPEGTransform(const char *src_file, const char *dst_file, FREE_IMAGE_JPEG_OPERATION operation, BOOL perfect) {
292	try {
293		// check the src file format
294		if(FreeImage_GetFileType(src_file) != FIF_JPEG) {
295			throw FI_MSG_ERROR_MAGIC_NUMBER;
296		}
297
298		// setup IO
299		FilenameIO filenameIO;
300		memset(&filenameIO, 0, sizeof(FilenameIO));
301		filenameIO.src_file = src_file;
302		filenameIO.dst_file = dst_file;
303
304		// perform the transformation
305		return LosslessTransform(&filenameIO, operation, NULL, perfect);
306
307	} catch(const char *text) {
308		FreeImage_OutputMessageProc(FIF_JPEG, text);
309		return FALSE;
310	}
311}
312
313BOOL DLL_CALLCONV 
314FreeImage_JPEGCrop(const char *src_file, const char *dst_file, int left, int top, int right, int bottom) {
315	char crop[64];
316
317	try {
318		// check the src file format
319		if(FreeImage_GetFileType(src_file) != FIF_JPEG) {
320			throw FI_MSG_ERROR_MAGIC_NUMBER;
321		}
322		
323		// normalize the rectangle
324		if(right < left) {
325			INPLACESWAP(left, right);
326		}
327		if(bottom < top) {
328			INPLACESWAP(top, bottom);
329		}
330
331		// build the crop option
332		sprintf(crop, "%dx%d+%d+%d", right - left, bottom - top, left, top);
333
334		// setup IO
335		FilenameIO filenameIO;
336		memset(&filenameIO, 0, sizeof(FilenameIO));
337		filenameIO.src_file = src_file;
338		filenameIO.dst_file = dst_file;
339
340		// perform the transformation
341		return LosslessTransform(&filenameIO, FIJPEG_OP_NONE, crop, FALSE);
342
343	} catch(const char *text) {
344		FreeImage_OutputMessageProc(FIF_JPEG, text);
345		return FALSE;
346	}
347}
348
349BOOL DLL_CALLCONV 
350FreeImage_JPEGTransformU(const wchar_t *src_file, const wchar_t *dst_file, FREE_IMAGE_JPEG_OPERATION operation, BOOL perfect) {
351#ifdef _WIN32
352	try {
353		// check the src file format
354		if(FreeImage_GetFileTypeU(src_file) != FIF_JPEG) {
355			throw FI_MSG_ERROR_MAGIC_NUMBER;
356		}
357
358		// setup IO
359		FilenameIO filenameIO;
360		memset(&filenameIO, 0, sizeof(FilenameIO));
361		filenameIO.wsrc_file = src_file;
362		filenameIO.wdst_file = dst_file;
363
364		// perform the transformation
365		return LosslessTransform(&filenameIO, operation, NULL, perfect);
366
367	} catch(const char *text) {
368		FreeImage_OutputMessageProc(FIF_JPEG, text);
369	}
370#endif /// _WIN32
371	return FALSE;
372}
373
374BOOL DLL_CALLCONV 
375FreeImage_JPEGCropU(const wchar_t *src_file, const wchar_t *dst_file, int left, int top, int right, int bottom) {
376#ifdef _WIN32
377	char crop[64];
378
379	try {
380		// check the src file format
381		if(FreeImage_GetFileTypeU(src_file) != FIF_JPEG) {
382			throw FI_MSG_ERROR_MAGIC_NUMBER;
383		}
384		
385		// normalize the rectangle
386		if(right < left) {
387			INPLACESWAP(left, right);
388		}
389		if(bottom < top) {
390			INPLACESWAP(top, bottom);
391		}
392
393		// build the crop option
394		sprintf(crop, "%dx%d+%d+%d", right - left, bottom - top, left, top);
395
396		// setup IO
397		FilenameIO filenameIO;
398		memset(&filenameIO, 0, sizeof(FilenameIO));
399		filenameIO.wsrc_file = src_file;
400		filenameIO.wdst_file = dst_file;
401
402		// perform the transformation
403		return LosslessTransform(&filenameIO, FIJPEG_OP_NONE, crop, FALSE);
404
405	} catch(const char *text) {
406		FreeImage_OutputMessageProc(FIF_JPEG, text);
407	}
408#endif // _WIN32
409	return FALSE;
410}