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

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