]> Creatis software - clitk.git/blob - utilities/CxImage/ximajpg.cpp
cosmetic
[clitk.git] / utilities / CxImage / ximajpg.cpp
1 /*
2  * File:        ximajpg.cpp
3  * Purpose:     Platform Independent JPEG Image Class Loader and Writer
4  * 07/Aug/2001 Davide Pizzolato - www.xdp.it
5  * CxImage version 6.0.0 02/Feb/2008
6  */
7  
8 #include "ximajpg.h"
9
10 #if CXIMAGE_SUPPORT_JPG
11
12 #include "../jpeg/jmorecfg.h"
13
14 #include "ximaiter.h"
15          
16 #include <setjmp.h>
17
18 struct jpg_error_mgr {
19         struct jpeg_error_mgr pub;      /* "public" fields */
20         jmp_buf setjmp_buffer;          /* for return to caller */
21         char* buffer;                           /* error message <CSC>*/
22 };
23 typedef jpg_error_mgr *jpg_error_ptr;
24
25 ////////////////////////////////////////////////////////////////////////////////
26 // Here's the routine that will replace the standard error_exit method:
27 ////////////////////////////////////////////////////////////////////////////////
28 static void
29 ima_jpeg_error_exit (j_common_ptr cinfo)
30 {
31         /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
32         jpg_error_ptr myerr = (jpg_error_ptr) cinfo->err;
33         /* Create the message */
34         myerr->pub.format_message (cinfo, myerr->buffer);
35         /* Send it to stderr, adding a newline */
36         /* Return control to the setjmp point */
37         longjmp(myerr->setjmp_buffer, 1);
38 }
39 ////////////////////////////////////////////////////////////////////////////////
40 CxImageJPG::CxImageJPG(): CxImage(CXIMAGE_FORMAT_JPG)
41 {
42 #if CXIMAGEJPG_SUPPORT_EXIF
43         m_exif = NULL;
44         memset(&m_exifinfo, 0, sizeof(EXIFINFO));
45 #endif
46 }
47 ////////////////////////////////////////////////////////////////////////////////
48 CxImageJPG::~CxImageJPG()
49 {
50 #if CXIMAGEJPG_SUPPORT_EXIF
51         if (m_exif) delete m_exif;
52 #endif
53 }
54 ////////////////////////////////////////////////////////////////////////////////
55 #if CXIMAGEJPG_SUPPORT_EXIF
56 bool CxImageJPG::DecodeExif(CxFile * hFile)
57 {
58         m_exif = new CxExifInfo(&m_exifinfo);
59         if (m_exif){
60                 long pos=hFile->Tell();
61                 m_exif->DecodeExif(hFile);
62                 hFile->Seek(pos,SEEK_SET);
63                 return m_exif->m_exifinfo->IsExif;
64         } else {
65                 return false;
66         }
67 }
68 #endif //CXIMAGEJPG_SUPPORT_EXIF
69 ////////////////////////////////////////////////////////////////////////////////
70 #if CXIMAGE_SUPPORT_DECODE
71 ////////////////////////////////////////////////////////////////////////////////
72 bool CxImageJPG::Decode(CxFile * hFile)
73 {
74
75         bool is_exif = false;
76 #if CXIMAGEJPG_SUPPORT_EXIF
77         is_exif = DecodeExif(hFile);
78 #endif
79
80         CImageIterator iter(this);
81         /* This struct contains the JPEG decompression parameters and pointers to
82         * working space (which is allocated as needed by the JPEG library).
83         */
84         struct jpeg_decompress_struct cinfo;
85         /* We use our private extension JPEG error handler. <CSC> */
86         struct jpg_error_mgr jerr;
87         jerr.buffer=info.szLastError;
88         /* More stuff */
89         JSAMPARRAY buffer;      /* Output row buffer */
90         int row_stride;         /* physical row width in output buffer */
91
92         /* In this example we want to open the input file before doing anything else,
93         * so that the setjmp() error recovery below can assume the file is open.
94         * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
95         * requires it in order to read binary files.
96         */
97
98         /* Step 1: allocate and initialize JPEG decompression object */
99         /* We set up the normal JPEG error routines, then override error_exit. */
100         cinfo.err = jpeg_std_error(&jerr.pub);
101         jerr.pub.error_exit = ima_jpeg_error_exit;
102
103         /* Establish the setjmp return context for my_error_exit to use. */
104         if (setjmp(jerr.setjmp_buffer)) {
105                 /* If we get here, the JPEG code has signaled an error.
106                 * We need to clean up the JPEG object, close the input file, and return.
107                 */
108                 jpeg_destroy_decompress(&cinfo);
109                 return 0;
110         }
111         /* Now we can initialize the JPEG decompression object. */
112         jpeg_create_decompress(&cinfo);
113
114         /* Step 2: specify data source (eg, a file) */
115         //jpeg_stdio_src(&cinfo, infile);
116         CxFileJpg src(hFile);
117     cinfo.src = &src;
118
119         /* Step 3: read file parameters with jpeg_read_header() */
120         (void) jpeg_read_header(&cinfo, TRUE);
121
122         /* Step 4 <chupeev> handle decoder options*/
123         if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & DECODE_GRAYSCALE) != 0)
124                 cinfo.out_color_space = JCS_GRAYSCALE;
125         if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & DECODE_QUANTIZE) != 0) {
126                 cinfo.quantize_colors = TRUE;
127                 cinfo.desired_number_of_colors = GetJpegQuality();
128         }
129         if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & DECODE_DITHER) != 0)
130                 cinfo.dither_mode = m_nDither;
131         if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & DECODE_ONEPASS) != 0)
132                 cinfo.two_pass_quantize = FALSE;
133         if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & DECODE_NOSMOOTH) != 0)
134                 cinfo.do_fancy_upsampling = FALSE;
135
136 //<DP>: Load true color images as RGB (no quantize) 
137 /* Step 4: set parameters for decompression */
138 /*  if (cinfo.jpeg_color_space!=JCS_GRAYSCALE) {
139  *      cinfo.quantize_colors = TRUE;
140  *      cinfo.desired_number_of_colors = 128;
141  *}
142  */ //</DP>
143
144         // Set the scale <ignacio>
145         cinfo.scale_denom = GetJpegScale();
146
147         // Borrowed the idea from GIF implementation <ignacio>
148         if (info.nEscape == -1) {
149                 // Return output dimensions only
150                 jpeg_calc_output_dimensions(&cinfo);
151                 head.biWidth = cinfo.output_width;
152                 head.biHeight = cinfo.output_height;
153                 info.dwType = CXIMAGE_FORMAT_JPG;
154                 jpeg_destroy_decompress(&cinfo);
155                 return true;
156         }
157
158         /* Step 5: Start decompressor */
159         jpeg_start_decompress(&cinfo);
160
161         /* We may need to do some setup of our own at this point before reading
162         * the data.  After jpeg_start_decompress() we have the correct scaled
163         * output image dimensions available, as well as the output colormap
164         * if we asked for color quantization.
165         */
166         //Create the image using output dimensions <ignacio>
167         //Create(cinfo.image_width, cinfo.image_height, 8*cinfo.output_components, CXIMAGE_FORMAT_JPG);
168         Create(cinfo.output_width, cinfo.output_height, 8*cinfo.output_components, CXIMAGE_FORMAT_JPG);
169
170         if (!pDib) longjmp(jerr.setjmp_buffer, 1);  //<DP> check if the image has been created
171
172         if (is_exif){
173 #if CXIMAGEJPG_SUPPORT_EXIF
174         if ((m_exifinfo.Xresolution != 0.0) && (m_exifinfo.ResolutionUnit != 0))
175                 SetXDPI((long)(m_exifinfo.Xresolution/m_exifinfo.ResolutionUnit));
176         if ((m_exifinfo.Yresolution != 0.0) && (m_exifinfo.ResolutionUnit != 0))
177                 SetYDPI((long)(m_exifinfo.Yresolution/m_exifinfo.ResolutionUnit));
178 #endif
179         } else {
180                 switch (cinfo.density_unit) {
181                 case 0: // [andy] fix for aspect ratio...
182                         if((cinfo.Y_density > 0) && (cinfo.X_density > 0)){
183                                 SetYDPI((long)(GetXDPI()*(float(cinfo.Y_density)/float(cinfo.X_density))));
184                         }
185                         break;
186                 case 2: // [andy] fix: cinfo.X/Y_density is pixels per centimeter
187                         SetXDPI((long)floor(cinfo.X_density * 2.54 + 0.5));
188                         SetYDPI((long)floor(cinfo.Y_density * 2.54 + 0.5));
189                         break;
190                 default:
191                         SetXDPI(cinfo.X_density);
192                         SetYDPI(cinfo.Y_density);
193                 }
194         }
195
196         if (cinfo.out_color_space==JCS_GRAYSCALE){
197                 SetGrayPalette();
198                 head.biClrUsed =256;
199         } else {
200                 if (cinfo.quantize_colors){
201                         SetPalette(cinfo.actual_number_of_colors, cinfo.colormap[0], cinfo.colormap[1], cinfo.colormap[2]);
202                         head.biClrUsed=cinfo.actual_number_of_colors;
203                 } else {
204                         head.biClrUsed=0;
205                 }
206         }
207
208         /* JSAMPLEs per row in output buffer */
209         row_stride = cinfo.output_width * cinfo.output_components;
210
211         /* Make a one-row-high sample array that will go away when done with image */
212         buffer = (*cinfo.mem->alloc_sarray)
213                 ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
214
215         /* Step 6: while (scan lines remain to be read) */
216         /*           jpeg_read_scanlines(...); */
217         /* Here we use the library's state variable cinfo.output_scanline as the
218         * loop counter, so that we don't have to keep track ourselves.
219         */
220         iter.Upset();
221         while (cinfo.output_scanline < cinfo.output_height) {
222
223                 if (info.nEscape) longjmp(jerr.setjmp_buffer, 1); // <vho> - cancel decoding
224                 
225                 (void) jpeg_read_scanlines(&cinfo, buffer, 1);
226                 // info.nProgress = (long)(100*cinfo.output_scanline/cinfo.output_height);
227                 //<DP> Step 6a: CMYK->RGB */ 
228                 if ((cinfo.num_components==4)&&(cinfo.quantize_colors==FALSE)){
229                         BYTE k,*dst,*src;
230                         dst=iter.GetRow();
231                         src=buffer[0];
232                         for(long x3=0,x4=0; x3<(long)info.dwEffWidth && x4<row_stride; x3+=3, x4+=4){
233                                 k=src[x4+3];
234                                 dst[x3]  =(BYTE)((k * src[x4+2])/255);
235                                 dst[x3+1]=(BYTE)((k * src[x4+1])/255);
236                                 dst[x3+2]=(BYTE)((k * src[x4+0])/255);
237                         }
238                 } else {
239                         /* Assume put_scanline_someplace wants a pointer and sample count. */
240                         iter.SetRow(buffer[0], row_stride);
241                 }
242                         iter.PrevRow();
243         }
244
245         /* Step 7: Finish decompression */
246         (void) jpeg_finish_decompress(&cinfo);
247         /* We can ignore the return value since suspension is not possible
248         * with the stdio data source.
249         */
250
251         //<DP> Step 7A: Swap red and blue components
252         // not necessary if swapped red and blue definition in jmorecfg.h;ln322 <W. Morrison>
253         if ((cinfo.num_components==3)&&(cinfo.quantize_colors==FALSE)){
254                 BYTE* r0=GetBits();
255                 for(long y=0;y<head.biHeight;y++){
256                         if (info.nEscape) longjmp(jerr.setjmp_buffer, 1); // <vho> - cancel decoding
257                         RGBtoBGR(r0,3*head.biWidth);
258                         r0+=info.dwEffWidth;
259                 }
260         }
261
262         /* Step 8: Release JPEG decompression object */
263         /* This is an important step since it will release a good deal of memory. */
264         jpeg_destroy_decompress(&cinfo);
265
266         /* At this point you may want to check to see whether any corrupt-data
267         * warnings occurred (test whether jerr.pub.num_warnings is nonzero).
268         */
269
270         /* And we're done! */
271         return true;
272 }
273 ////////////////////////////////////////////////////////////////////////////////
274 #endif //CXIMAGE_SUPPORT_DECODE
275 ////////////////////////////////////////////////////////////////////////////////
276 #if CXIMAGE_SUPPORT_ENCODE
277 ////////////////////////////////////////////////////////////////////////////////
278 bool CxImageJPG::Encode(CxFile * hFile)
279 {
280         if (EncodeSafeCheck(hFile)) return false;
281
282         if (head.biClrUsed!=0 && !IsGrayScale()){
283                 strcpy(info.szLastError,"JPEG can save only RGB or GreyScale images");
284                 return false;
285         }       
286
287         // necessary for EXIF, and for roll backs
288         long pos=hFile->Tell();
289
290         /* This struct contains the JPEG compression parameters and pointers to
291         * working space (which is allocated as needed by the JPEG library).
292         * It is possible to have several such structures, representing multiple
293         * compression/decompression processes, in existence at once.  We refer
294         * to any one struct (and its associated working data) as a "JPEG object".
295         */
296         struct jpeg_compress_struct cinfo;
297         /* This struct represents a JPEG error handler.  It is declared separately
298         * because applications often want to supply a specialized error handler
299         * (see the second half of this file for an example).  But here we just
300         * take the easy way out and use the standard error handler, which will
301         * print a message on stderr and call exit() if compression fails.
302         * Note that this struct must live as long as the main JPEG parameter
303         * struct, to avoid dangling-pointer problems.
304         */
305         //struct jpeg_error_mgr jerr;
306         /* We use our private extension JPEG error handler. <CSC> */
307         struct jpg_error_mgr jerr;
308         jerr.buffer=info.szLastError;
309         /* More stuff */
310         int row_stride;         /* physical row width in image buffer */
311         JSAMPARRAY buffer;              /* Output row buffer */
312
313         /* Step 1: allocate and initialize JPEG compression object */
314         /* We have to set up the error handler first, in case the initialization
315         * step fails.  (Unlikely, but it could happen if you are out of memory.)
316         * This routine fills in the contents of struct jerr, and returns jerr's
317         * address which we place into the link field in cinfo.
318         */
319         //cinfo.err = jpeg_std_error(&jerr); <CSC>
320         /* We set up the normal JPEG error routines, then override error_exit. */
321         cinfo.err = jpeg_std_error(&jerr.pub);
322         jerr.pub.error_exit = ima_jpeg_error_exit;
323
324         /* Establish the setjmp return context for my_error_exit to use. */
325         if (setjmp(jerr.setjmp_buffer)) {
326                 /* If we get here, the JPEG code has signaled an error.
327                 * We need to clean up the JPEG object, close the input file, and return.
328                 */
329                 strcpy(info.szLastError, jerr.buffer); //<CSC>
330                 jpeg_destroy_compress(&cinfo);
331                 return 0;
332         }
333         
334         /* Now we can initialize the JPEG compression object. */
335         jpeg_create_compress(&cinfo);
336         /* Step 2: specify data destination (eg, a file) */
337         /* Note: steps 2 and 3 can be done in either order. */
338         /* Here we use the library-supplied code to send compressed data to a
339         * stdio stream.  You can also write your own code to do something else.
340         * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
341         * requires it in order to write binary files.
342         */
343
344         //jpeg_stdio_dest(&cinfo, outfile);
345         CxFileJpg dest(hFile);
346     cinfo.dest = &dest;
347
348         /* Step 3: set parameters for compression */
349         /* First we supply a description of the input image.
350         * Four fields of the cinfo struct must be filled in:
351         */
352         cinfo.image_width = GetWidth();         // image width and height, in pixels
353         cinfo.image_height = GetHeight();
354
355         if (IsGrayScale()){
356                 cinfo.input_components = 1;                     // # of color components per pixel
357                 cinfo.in_color_space = JCS_GRAYSCALE; /* colorspace of input image */
358         } else {
359                 cinfo.input_components = 3;     // # of color components per pixel
360                 cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
361         }
362
363         /* Now use the library's routine to set default compression parameters.
364         * (You must set at least cinfo.in_color_space before calling this,
365         * since the defaults depend on the source color space.)
366         */
367         jpeg_set_defaults(&cinfo);
368         /* Now you can set any non-default parameters you wish to.
369         * Here we just illustrate the use of quality (quantization table) scaling:
370         */
371
372 //#ifdef C_ARITH_CODING_SUPPORTED
373         if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_ARITHMETIC) != 0)
374                 cinfo.arith_code = TRUE;
375 //#endif
376
377 //#ifdef ENTROPY_OPT_SUPPORTED
378         if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_OPTIMIZE) != 0)
379                 cinfo.optimize_coding = TRUE;
380 //#endif
381
382         if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_GRAYSCALE) != 0)
383                 jpeg_set_colorspace(&cinfo, JCS_GRAYSCALE);
384
385         if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_SMOOTHING) != 0)
386                 cinfo.smoothing_factor = m_nSmoothing;
387
388         jpeg_set_quality(&cinfo, GetJpegQuality(), (GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_BASELINE) != 0);
389
390 //#ifdef C_PROGRESSIVE_SUPPORTED
391         if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_PROGRESSIVE) != 0)
392                 jpeg_simple_progression(&cinfo);
393 //#endif
394
395 #ifdef C_LOSSLESS_SUPPORTED
396         if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_LOSSLESS) != 0)
397                 jpeg_simple_lossless(&cinfo, m_nPredictor, m_nPointTransform);
398 #endif
399
400         //SetCodecOption(ENCODE_SUBSAMPLE_444 | GetCodecOption(CXIMAGE_FORMAT_JPG),CXIMAGE_FORMAT_JPG);
401
402                 // 2x2, 1x1, 1x1 (4:1:1) : High (default sub sampling)
403                 cinfo.comp_info[0].h_samp_factor = 2;
404                 cinfo.comp_info[0].v_samp_factor = 2;
405                 cinfo.comp_info[1].h_samp_factor = 1;
406                 cinfo.comp_info[1].v_samp_factor = 1;
407                 cinfo.comp_info[2].h_samp_factor = 1;
408                 cinfo.comp_info[2].v_samp_factor = 1;
409
410         if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_SUBSAMPLE_422) != 0){
411                 // 2x1, 1x1, 1x1 (4:2:2) : Medium
412                 cinfo.comp_info[0].h_samp_factor = 2;
413                 cinfo.comp_info[0].v_samp_factor = 1;
414                 cinfo.comp_info[1].h_samp_factor = 1;
415                 cinfo.comp_info[1].v_samp_factor = 1;
416                 cinfo.comp_info[2].h_samp_factor = 1;
417                 cinfo.comp_info[2].v_samp_factor = 1;
418         }
419
420         if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_SUBSAMPLE_444) != 0){
421                 // 1x1 1x1 1x1 (4:4:4) : None
422                 cinfo.comp_info[0].h_samp_factor = 1;
423                 cinfo.comp_info[0].v_samp_factor = 1;
424                 cinfo.comp_info[1].h_samp_factor = 1;
425                 cinfo.comp_info[1].v_samp_factor = 1;
426                 cinfo.comp_info[2].h_samp_factor = 1;
427                 cinfo.comp_info[2].v_samp_factor = 1;
428         }
429
430         cinfo.density_unit=1;
431         cinfo.X_density=(unsigned short)GetXDPI();
432         cinfo.Y_density=(unsigned short)GetYDPI();
433
434         /* Step 4: Start compressor */
435         /* TRUE ensures that we will write a complete interchange-JPEG file.
436         * Pass TRUE unless you are very sure of what you're doing.
437         */
438         jpeg_start_compress(&cinfo, TRUE);
439
440         /* Step 5: while (scan lines remain to be written) */
441         /*           jpeg_write_scanlines(...); */
442         /* Here we use the library's state variable cinfo.next_scanline as the
443         * loop counter, so that we don't have to keep track ourselves.
444         * To keep things simple, we pass one scanline per call; you can pass
445         * more if you wish, though.
446         */
447         row_stride = info.dwEffWidth;   /* JSAMPLEs per row in image_buffer */
448
449         //<DP> "8+row_stride" fix heap deallocation problem during debug???
450         buffer = (*cinfo.mem->alloc_sarray)
451                 ((j_common_ptr) &cinfo, JPOOL_IMAGE, 8+row_stride, 1);
452
453         CImageIterator iter(this);
454
455         iter.Upset();
456         while (cinfo.next_scanline < cinfo.image_height) {
457                 // info.nProgress = (long)(100*cinfo.next_scanline/cinfo.image_height);
458                 iter.GetRow(buffer[0], row_stride);
459                 // not necessary if swapped red and blue definition in jmorecfg.h;ln322 <W. Morrison>
460                 if (head.biClrUsed==0){                          // swap R & B for RGB images
461                         RGBtoBGR(buffer[0], row_stride); // Lance : 1998/09/01 : Bug ID: EXP-2.1.1-9
462                 }
463                 iter.PrevRow();
464                 (void) jpeg_write_scanlines(&cinfo, buffer, 1);
465         }
466
467         /* Step 6: Finish compression */
468         jpeg_finish_compress(&cinfo);
469
470         /* Step 7: release JPEG compression object */
471         /* This is an important step since it will release a good deal of memory. */
472         jpeg_destroy_compress(&cinfo);
473
474
475 #if CXIMAGEJPG_SUPPORT_EXIF
476         if (m_exif && m_exif->m_exifinfo->IsExif){
477                 // discard useless sections (if any) read from original image
478                 m_exif->DiscardAllButExif();
479                 // read new created image, to split the sections
480                 hFile->Seek(pos,SEEK_SET);
481                 m_exif->DecodeExif(hFile,EXIF_READ_IMAGE);
482                 // save back the image, adding EXIF section
483                 hFile->Seek(pos,SEEK_SET);
484                 m_exif->EncodeExif(hFile);
485         }
486 #endif
487
488
489         /* And we're done! */
490         return true;
491 }
492 ////////////////////////////////////////////////////////////////////////////////
493 #endif // CXIMAGE_SUPPORT_ENCODE
494 ////////////////////////////////////////////////////////////////////////////////
495 #endif // CXIMAGE_SUPPORT_JPG
496