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