1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                        Intel License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 //   * Redistribution's of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //
22 //   * Redistribution's in binary form must reproduce the above copyright notice,
23 //     this list of conditions and the following disclaimer in the documentation
24 //     and/or other materials provided with the distribution.
25 //
26 //   * The name of Intel Corporation may not be used to endorse or promote products
27 //     derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41 
42 #include "precomp.hpp"
43 #include "grfmt_jpeg.hpp"
44 
45 #ifdef HAVE_JPEG
46 
47 #ifdef _MSC_VER
48 //interaction between '_setjmp' and C++ object destruction is non-portable
49 #pragma warning(disable: 4611)
50 #endif
51 
52 #include <stdio.h>
53 #include <setjmp.h>
54 
55 // the following defines are a hack to avoid multiple problems with frame pointer handling and setjmp
56 // see http://gcc.gnu.org/ml/gcc/2011-10/msg00324.html for some details
57 #define mingw_getsp(...) 0
58 #define __builtin_frame_address(...) 0
59 
60 #ifdef _WIN32
61 
62 #define XMD_H // prevent redefinition of INT32
63 #undef FAR  // prevent FAR redefinition
64 
65 #endif
66 
67 #if defined _WIN32 && defined __GNUC__
68 typedef unsigned char boolean;
69 #endif
70 
71 #undef FALSE
72 #undef TRUE
73 
74 extern "C" {
75 #include "jpeglib.h"
76 }
77 
78 #ifndef CV_MANUAL_JPEG_STD_HUFF_TABLES
79   #if defined(LIBJPEG_TURBO_VERSION_NUMBER) && LIBJPEG_TURBO_VERSION_NUMBER >= 1003090
80     #define CV_MANUAL_JPEG_STD_HUFF_TABLES 0  // libjpeg-turbo handles standard huffman tables itself (jstdhuff.c)
81   #else
82     #define CV_MANUAL_JPEG_STD_HUFF_TABLES 1
83   #endif
84 #endif
85 #if CV_MANUAL_JPEG_STD_HUFF_TABLES == 0
86   #undef CV_MANUAL_JPEG_STD_HUFF_TABLES
87 #endif
88 
89 namespace cv
90 {
91 
92 struct JpegErrorMgr
93 {
94     struct jpeg_error_mgr pub;
95     jmp_buf setjmp_buffer;
96 };
97 
98 struct JpegSource
99 {
100     struct jpeg_source_mgr pub;
101     int skip;
102 };
103 
104 struct JpegState
105 {
106     jpeg_decompress_struct cinfo; // IJG JPEG codec structure
107     JpegErrorMgr jerr; // error processing manager state
108     JpegSource source; // memory buffer source
109 };
110 
111 /////////////////////// Error processing /////////////////////
112 
113 METHODDEF(void)
stub(j_decompress_ptr)114 stub(j_decompress_ptr)
115 {
116 }
117 
118 METHODDEF(boolean)
fill_input_buffer(j_decompress_ptr)119 fill_input_buffer(j_decompress_ptr)
120 {
121     return FALSE;
122 }
123 
124 // emulating memory input stream
125 
126 METHODDEF(void)
skip_input_data(j_decompress_ptr cinfo,long num_bytes)127 skip_input_data(j_decompress_ptr cinfo, long num_bytes)
128 {
129     JpegSource* source = (JpegSource*) cinfo->src;
130 
131     if( num_bytes > (long)source->pub.bytes_in_buffer )
132     {
133         // We need to skip more data than we have in the buffer.
134         // This will force the JPEG library to suspend decoding.
135         source->skip = (int)(num_bytes - source->pub.bytes_in_buffer);
136         source->pub.next_input_byte += source->pub.bytes_in_buffer;
137         source->pub.bytes_in_buffer = 0;
138     }
139     else
140     {
141         // Skip portion of the buffer
142         source->pub.bytes_in_buffer -= num_bytes;
143         source->pub.next_input_byte += num_bytes;
144         source->skip = 0;
145     }
146 }
147 
148 
jpeg_buffer_src(j_decompress_ptr cinfo,JpegSource * source)149 static void jpeg_buffer_src(j_decompress_ptr cinfo, JpegSource* source)
150 {
151     cinfo->src = &source->pub;
152 
153     // Prepare for suspending reader
154     source->pub.init_source = stub;
155     source->pub.fill_input_buffer = fill_input_buffer;
156     source->pub.skip_input_data = skip_input_data;
157     source->pub.resync_to_restart = jpeg_resync_to_restart;
158     source->pub.term_source = stub;
159     source->pub.bytes_in_buffer = 0; // forces fill_input_buffer on first read
160 
161     source->skip = 0;
162 }
163 
164 
165 METHODDEF(void)
error_exit(j_common_ptr cinfo)166 error_exit( j_common_ptr cinfo )
167 {
168     JpegErrorMgr* err_mgr = (JpegErrorMgr*)(cinfo->err);
169 
170     /* Return control to the setjmp point */
171     longjmp( err_mgr->setjmp_buffer, 1 );
172 }
173 
174 
175 /////////////////////// JpegDecoder ///////////////////
176 
177 
JpegDecoder()178 JpegDecoder::JpegDecoder()
179 {
180     m_signature = "\xFF\xD8\xFF";
181     m_state = 0;
182     m_f = 0;
183     m_buf_supported = true;
184 }
185 
186 
~JpegDecoder()187 JpegDecoder::~JpegDecoder()
188 {
189     close();
190 }
191 
192 
close()193 void  JpegDecoder::close()
194 {
195     if( m_state )
196     {
197         JpegState* state = (JpegState*)m_state;
198         jpeg_destroy_decompress( &state->cinfo );
199         delete state;
200         m_state = 0;
201     }
202 
203     if( m_f )
204     {
205         fclose( m_f );
206         m_f = 0;
207     }
208 
209     m_width = m_height = 0;
210     m_type = -1;
211 }
212 
newDecoder() const213 ImageDecoder JpegDecoder::newDecoder() const
214 {
215     return makePtr<JpegDecoder>();
216 }
217 
readHeader()218 bool  JpegDecoder::readHeader()
219 {
220     volatile bool result = false;
221     close();
222 
223     JpegState* state = new JpegState;
224     m_state = state;
225     state->cinfo.err = jpeg_std_error(&state->jerr.pub);
226     state->jerr.pub.error_exit = error_exit;
227 
228     if( setjmp( state->jerr.setjmp_buffer ) == 0 )
229     {
230         jpeg_create_decompress( &state->cinfo );
231 
232         if( !m_buf.empty() )
233         {
234             jpeg_buffer_src(&state->cinfo, &state->source);
235             state->source.pub.next_input_byte = m_buf.ptr();
236             state->source.pub.bytes_in_buffer = m_buf.cols*m_buf.rows*m_buf.elemSize();
237         }
238         else
239         {
240             m_f = fopen( m_filename.c_str(), "rb" );
241             if( m_f )
242                 jpeg_stdio_src( &state->cinfo, m_f );
243         }
244 
245         if (state->cinfo.src != 0)
246         {
247             jpeg_save_markers(&state->cinfo, APP1, 0xffff);
248             jpeg_read_header( &state->cinfo, TRUE );
249 
250             state->cinfo.scale_num=1;
251             state->cinfo.scale_denom = m_scale_denom;
252             m_scale_denom=1; // trick! to know which decoder used scale_denom see imread_
253             jpeg_calc_output_dimensions(&state->cinfo);
254             m_width = state->cinfo.output_width;
255             m_height = state->cinfo.output_height;
256             m_type = state->cinfo.num_components > 1 ? CV_8UC3 : CV_8UC1;
257             result = true;
258         }
259     }
260 
261     if( !result )
262         close();
263 
264     return result;
265 }
266 
267 #ifdef CV_MANUAL_JPEG_STD_HUFF_TABLES
268 /***************************************************************************
269  * following code is for supporting MJPEG image files
270  * based on a message of Laurent Pinchart on the video4linux mailing list
271  ***************************************************************************/
272 
273 /* JPEG DHT Segment for YCrCb omitted from MJPEG data */
274 static
275 unsigned char my_jpeg_odml_dht[0x1a4] = {
276     0xff, 0xc4, 0x01, 0xa2,
277 
278     0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,
279     0x00, 0x00, 0x00, 0x00, 0x00,
280     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
281 
282     0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
283     0x00, 0x00, 0x00, 0x00, 0x00,
284     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
285 
286     0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04,
287     0x04, 0x00, 0x00, 0x01, 0x7d,
288     0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06,
289     0x13, 0x51, 0x61, 0x07,
290     0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1,
291     0x15, 0x52, 0xd1, 0xf0,
292     0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a,
293     0x25, 0x26, 0x27, 0x28,
294     0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,
295     0x46, 0x47, 0x48, 0x49,
296     0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65,
297     0x66, 0x67, 0x68, 0x69,
298     0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85,
299     0x86, 0x87, 0x88, 0x89,
300     0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3,
301     0xa4, 0xa5, 0xa6, 0xa7,
302     0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
303     0xc2, 0xc3, 0xc4, 0xc5,
304     0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
305     0xd9, 0xda, 0xe1, 0xe2,
306     0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4,
307     0xf5, 0xf6, 0xf7, 0xf8,
308     0xf9, 0xfa,
309 
310     0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04,
311     0x04, 0x00, 0x01, 0x02, 0x77,
312     0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41,
313     0x51, 0x07, 0x61, 0x71,
314     0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09,
315     0x23, 0x33, 0x52, 0xf0,
316     0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17,
317     0x18, 0x19, 0x1a, 0x26,
318     0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44,
319     0x45, 0x46, 0x47, 0x48,
320     0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64,
321     0x65, 0x66, 0x67, 0x68,
322     0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83,
323     0x84, 0x85, 0x86, 0x87,
324     0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a,
325     0xa2, 0xa3, 0xa4, 0xa5,
326     0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8,
327     0xb9, 0xba, 0xc2, 0xc3,
328     0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
329     0xd7, 0xd8, 0xd9, 0xda,
330     0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4,
331     0xf5, 0xf6, 0xf7, 0xf8,
332     0xf9, 0xfa
333 };
334 
335 /*
336  * Parse the DHT table.
337  * This code comes from jpeg6b (jdmarker.c).
338  */
339 static
my_jpeg_load_dht(struct jpeg_decompress_struct * info,unsigned char * dht,JHUFF_TBL * ac_tables[],JHUFF_TBL * dc_tables[])340 int my_jpeg_load_dht (struct jpeg_decompress_struct *info, unsigned char *dht,
341               JHUFF_TBL *ac_tables[], JHUFF_TBL *dc_tables[])
342 {
343     unsigned int length = (dht[2] << 8) + dht[3] - 2;
344     unsigned int pos = 4;
345     unsigned int count, i;
346     int index;
347 
348     JHUFF_TBL **hufftbl;
349     unsigned char bits[17];
350     unsigned char huffval[256] = {0};
351 
352     while (length > 16)
353     {
354        bits[0] = 0;
355        index = dht[pos++];
356        count = 0;
357        for (i = 1; i <= 16; ++i)
358        {
359            bits[i] = dht[pos++];
360            count += bits[i];
361        }
362        length -= 17;
363 
364        if (count > 256 || count > length)
365            return -1;
366 
367        for (i = 0; i < count; ++i)
368            huffval[i] = dht[pos++];
369        length -= count;
370 
371        if (index & 0x10)
372        {
373            index &= ~0x10;
374            hufftbl = &ac_tables[index];
375        }
376        else
377            hufftbl = &dc_tables[index];
378 
379        if (index < 0 || index >= NUM_HUFF_TBLS)
380            return -1;
381 
382        if (*hufftbl == NULL)
383            *hufftbl = jpeg_alloc_huff_table ((j_common_ptr)info);
384        if (*hufftbl == NULL)
385            return -1;
386 
387        memcpy ((*hufftbl)->bits, bits, sizeof (*hufftbl)->bits);
388        memcpy ((*hufftbl)->huffval, huffval, sizeof (*hufftbl)->huffval);
389     }
390 
391     if (length != 0)
392        return -1;
393 
394     return 0;
395 }
396 
397 /***************************************************************************
398  * end of code for supportting MJPEG image files
399  * based on a message of Laurent Pinchart on the video4linux mailing list
400  ***************************************************************************/
401 #endif  // CV_MANUAL_JPEG_STD_HUFF_TABLES
402 
readData(Mat & img)403 bool  JpegDecoder::readData( Mat& img )
404 {
405     volatile bool result = false;
406     size_t step = img.step;
407     bool color = img.channels() > 1;
408 
409     if( m_state && m_width && m_height )
410     {
411         jpeg_decompress_struct* cinfo = &((JpegState*)m_state)->cinfo;
412         JpegErrorMgr* jerr = &((JpegState*)m_state)->jerr;
413         JSAMPARRAY buffer = 0;
414 
415         if( setjmp( jerr->setjmp_buffer ) == 0 )
416         {
417 #ifdef CV_MANUAL_JPEG_STD_HUFF_TABLES
418             /* check if this is a mjpeg image format */
419             if ( cinfo->ac_huff_tbl_ptrs[0] == NULL &&
420                 cinfo->ac_huff_tbl_ptrs[1] == NULL &&
421                 cinfo->dc_huff_tbl_ptrs[0] == NULL &&
422                 cinfo->dc_huff_tbl_ptrs[1] == NULL )
423             {
424                 /* yes, this is a mjpeg image format, so load the correct
425                 huffman table */
426                 my_jpeg_load_dht( cinfo,
427                     my_jpeg_odml_dht,
428                     cinfo->ac_huff_tbl_ptrs,
429                     cinfo->dc_huff_tbl_ptrs );
430             }
431 #endif
432 
433             if( color )
434             {
435                 if( cinfo->num_components != 4 )
436                 {
437                     cinfo->out_color_space = JCS_RGB;
438                     cinfo->out_color_components = 3;
439                 }
440                 else
441                 {
442                     cinfo->out_color_space = JCS_CMYK;
443                     cinfo->out_color_components = 4;
444                 }
445             }
446             else
447             {
448                 if( cinfo->num_components != 4 )
449                 {
450                     cinfo->out_color_space = JCS_GRAYSCALE;
451                     cinfo->out_color_components = 1;
452                 }
453                 else
454                 {
455                     cinfo->out_color_space = JCS_CMYK;
456                     cinfo->out_color_components = 4;
457                 }
458             }
459 
460             // Check for Exif marker APP1
461             jpeg_saved_marker_ptr exif_marker = NULL;
462             jpeg_saved_marker_ptr cmarker = cinfo->marker_list;
463             while( cmarker && exif_marker == NULL )
464             {
465                 if (cmarker->marker == APP1)
466                     exif_marker = cmarker;
467 
468                 cmarker = cmarker->next;
469             }
470 
471             // Parse Exif data
472             if( exif_marker )
473             {
474                 const std::streamsize offsetToTiffHeader = 6; //bytes from Exif size field to the first TIFF header
475 
476                 if (exif_marker->data_length > offsetToTiffHeader)
477                 {
478                     m_exif.parseExif(exif_marker->data + offsetToTiffHeader, exif_marker->data_length - offsetToTiffHeader);
479                 }
480             }
481 
482 
483             jpeg_start_decompress( cinfo );
484 
485             buffer = (*cinfo->mem->alloc_sarray)((j_common_ptr)cinfo,
486                                               JPOOL_IMAGE, m_width*4, 1 );
487 
488             uchar* data = img.ptr();
489             for( ; m_height--; data += step )
490             {
491                 jpeg_read_scanlines( cinfo, buffer, 1 );
492                 if( color )
493                 {
494                     if( cinfo->out_color_components == 3 )
495                         icvCvt_RGB2BGR_8u_C3R( buffer[0], 0, data, 0, Size(m_width,1) );
496                     else
497                         icvCvt_CMYK2BGR_8u_C4C3R( buffer[0], 0, data, 0, Size(m_width,1) );
498                 }
499                 else
500                 {
501                     if( cinfo->out_color_components == 1 )
502                         memcpy( data, buffer[0], m_width );
503                     else
504                         icvCvt_CMYK2Gray_8u_C4C1R( buffer[0], 0, data, 0, Size(m_width,1) );
505                 }
506             }
507 
508             result = true;
509             jpeg_finish_decompress( cinfo );
510         }
511     }
512 
513     close();
514     return result;
515 }
516 
517 
518 /////////////////////// JpegEncoder ///////////////////
519 
520 struct JpegDestination
521 {
522     struct jpeg_destination_mgr pub;
523     std::vector<uchar> *buf, *dst;
524 };
525 
526 METHODDEF(void)
stub(j_compress_ptr)527 stub(j_compress_ptr)
528 {
529 }
530 
531 METHODDEF(void)
term_destination(j_compress_ptr cinfo)532 term_destination (j_compress_ptr cinfo)
533 {
534     JpegDestination* dest = (JpegDestination*)cinfo->dest;
535     size_t sz = dest->dst->size(), bufsz = dest->buf->size() - dest->pub.free_in_buffer;
536     if( bufsz > 0 )
537     {
538         dest->dst->resize(sz + bufsz);
539         memcpy( &(*dest->dst)[0] + sz, &(*dest->buf)[0], bufsz);
540     }
541 }
542 
543 METHODDEF(boolean)
empty_output_buffer(j_compress_ptr cinfo)544 empty_output_buffer (j_compress_ptr cinfo)
545 {
546     JpegDestination* dest = (JpegDestination*)cinfo->dest;
547     size_t sz = dest->dst->size(), bufsz = dest->buf->size();
548     dest->dst->resize(sz + bufsz);
549     memcpy( &(*dest->dst)[0] + sz, &(*dest->buf)[0], bufsz);
550 
551     dest->pub.next_output_byte = &(*dest->buf)[0];
552     dest->pub.free_in_buffer = bufsz;
553     return TRUE;
554 }
555 
jpeg_buffer_dest(j_compress_ptr cinfo,JpegDestination * destination)556 static void jpeg_buffer_dest(j_compress_ptr cinfo, JpegDestination* destination)
557 {
558     cinfo->dest = &destination->pub;
559 
560     destination->pub.init_destination = stub;
561     destination->pub.empty_output_buffer = empty_output_buffer;
562     destination->pub.term_destination = term_destination;
563 }
564 
565 
JpegEncoder()566 JpegEncoder::JpegEncoder()
567 {
568     m_description = "JPEG files (*.jpeg;*.jpg;*.jpe)";
569     m_buf_supported = true;
570 }
571 
572 
~JpegEncoder()573 JpegEncoder::~JpegEncoder()
574 {
575 }
576 
newEncoder() const577 ImageEncoder JpegEncoder::newEncoder() const
578 {
579     return makePtr<JpegEncoder>();
580 }
581 
write(const Mat & img,const std::vector<int> & params)582 bool JpegEncoder::write( const Mat& img, const std::vector<int>& params )
583 {
584     m_last_error.clear();
585 
586     struct fileWrapper
587     {
588         FILE* f;
589 
590         fileWrapper() : f(0) {}
591         ~fileWrapper() { if(f) fclose(f); }
592     };
593     volatile bool result = false;
594     fileWrapper fw;
595     int width = img.cols, height = img.rows;
596 
597     std::vector<uchar> out_buf(1 << 12);
598     AutoBuffer<uchar> _buffer;
599     uchar* buffer;
600 
601     struct jpeg_compress_struct cinfo;
602     JpegErrorMgr jerr;
603     JpegDestination dest;
604 
605     jpeg_create_compress(&cinfo);
606     cinfo.err = jpeg_std_error(&jerr.pub);
607     jerr.pub.error_exit = error_exit;
608 
609     if( !m_buf )
610     {
611         fw.f = fopen( m_filename.c_str(), "wb" );
612         if( !fw.f )
613             goto _exit_;
614         jpeg_stdio_dest( &cinfo, fw.f );
615     }
616     else
617     {
618         dest.dst = m_buf;
619         dest.buf = &out_buf;
620 
621         jpeg_buffer_dest( &cinfo, &dest );
622 
623         dest.pub.next_output_byte = &out_buf[0];
624         dest.pub.free_in_buffer = out_buf.size();
625     }
626 
627     if( setjmp( jerr.setjmp_buffer ) == 0 )
628     {
629         cinfo.image_width = width;
630         cinfo.image_height = height;
631 
632         int _channels = img.channels();
633         int channels = _channels > 1 ? 3 : 1;
634         cinfo.input_components = channels;
635         cinfo.in_color_space = channels > 1 ? JCS_RGB : JCS_GRAYSCALE;
636 
637         int quality = 95;
638         int progressive = 0;
639         int optimize = 0;
640         int rst_interval = 0;
641         int luma_quality = -1;
642         int chroma_quality = -1;
643 
644         for( size_t i = 0; i < params.size(); i += 2 )
645         {
646             if( params[i] == CV_IMWRITE_JPEG_QUALITY )
647             {
648                 quality = params[i+1];
649                 quality = MIN(MAX(quality, 0), 100);
650             }
651 
652             if( params[i] == CV_IMWRITE_JPEG_PROGRESSIVE )
653             {
654                 progressive = params[i+1];
655             }
656 
657             if( params[i] == CV_IMWRITE_JPEG_OPTIMIZE )
658             {
659                 optimize = params[i+1];
660             }
661 
662             if( params[i] == CV_IMWRITE_JPEG_LUMA_QUALITY )
663             {
664                 if (params[i+1] >= 0)
665                 {
666                     luma_quality = MIN(MAX(params[i+1], 0), 100);
667 
668                     quality = luma_quality;
669 
670                     if (chroma_quality < 0)
671                     {
672                         chroma_quality = luma_quality;
673                     }
674                 }
675             }
676 
677             if( params[i] == CV_IMWRITE_JPEG_CHROMA_QUALITY )
678             {
679                 if (params[i+1] >= 0)
680                 {
681                     chroma_quality = MIN(MAX(params[i+1], 0), 100);
682                 }
683             }
684 
685             if( params[i] == CV_IMWRITE_JPEG_RST_INTERVAL )
686             {
687                 rst_interval = params[i+1];
688                 rst_interval = MIN(MAX(rst_interval, 0), 65535L);
689             }
690         }
691 
692         jpeg_set_defaults( &cinfo );
693         cinfo.restart_interval = rst_interval;
694 
695         jpeg_set_quality( &cinfo, quality,
696                           TRUE /* limit to baseline-JPEG values */ );
697         if( progressive )
698             jpeg_simple_progression( &cinfo );
699         if( optimize )
700             cinfo.optimize_coding = TRUE;
701 
702 #if JPEG_LIB_VERSION >= 70
703         if (luma_quality >= 0 && chroma_quality >= 0)
704         {
705             cinfo.q_scale_factor[0] = jpeg_quality_scaling(luma_quality);
706             cinfo.q_scale_factor[1] = jpeg_quality_scaling(chroma_quality);
707             if ( luma_quality != chroma_quality )
708             {
709                 /* disable subsampling - ref. Libjpeg.txt */
710                 cinfo.comp_info[0].v_samp_factor = 1;
711                 cinfo.comp_info[0].h_samp_factor = 1;
712                 cinfo.comp_info[1].v_samp_factor = 1;
713                 cinfo.comp_info[1].h_samp_factor = 1;
714             }
715             jpeg_default_qtables( &cinfo, TRUE );
716         }
717 #endif // #if JPEG_LIB_VERSION >= 70
718 
719         jpeg_start_compress( &cinfo, TRUE );
720 
721         if( channels > 1 )
722             _buffer.allocate(width*channels);
723         buffer = _buffer.data();
724 
725         for( int y = 0; y < height; y++ )
726         {
727             uchar *data = img.data + img.step*y, *ptr = data;
728 
729             if( _channels == 3 )
730             {
731                 icvCvt_BGR2RGB_8u_C3R( data, 0, buffer, 0, Size(width,1) );
732                 ptr = buffer;
733             }
734             else if( _channels == 4 )
735             {
736                 icvCvt_BGRA2BGR_8u_C4C3R( data, 0, buffer, 0, Size(width,1), 2 );
737                 ptr = buffer;
738             }
739 
740             jpeg_write_scanlines( &cinfo, &ptr, 1 );
741         }
742 
743         jpeg_finish_compress( &cinfo );
744         result = true;
745     }
746 
747 _exit_:
748 
749     if(!result)
750     {
751         char jmsg_buf[JMSG_LENGTH_MAX];
752         jerr.pub.format_message((j_common_ptr)&cinfo, jmsg_buf);
753         m_last_error = jmsg_buf;
754     }
755 
756     jpeg_destroy_compress( &cinfo );
757 
758     return result;
759 }
760 
761 }
762 
763 #endif
764 
765 /* End of file. */
766