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 ponter 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 namespace cv
79 {
80
81 #ifdef _MSC_VER
82 # pragma warning(push)
83 # pragma warning(disable:4324) //structure was padded due to __declspec(align())
84 #endif
85 struct JpegErrorMgr
86 {
87 struct jpeg_error_mgr pub;
88 jmp_buf setjmp_buffer;
89 };
90 #ifdef _MSC_VER
91 # pragma warning(pop)
92 #endif
93
94 struct JpegSource
95 {
96 struct jpeg_source_mgr pub;
97 int skip;
98 };
99
100 struct JpegState
101 {
102 jpeg_decompress_struct cinfo; // IJG JPEG codec structure
103 JpegErrorMgr jerr; // error processing manager state
104 JpegSource source; // memory buffer source
105 };
106
107 /////////////////////// Error processing /////////////////////
108
109 METHODDEF(void)
stub(j_decompress_ptr)110 stub(j_decompress_ptr)
111 {
112 }
113
114 METHODDEF(boolean)
fill_input_buffer(j_decompress_ptr)115 fill_input_buffer(j_decompress_ptr)
116 {
117 return FALSE;
118 }
119
120 // emulating memory input stream
121
122 METHODDEF(void)
skip_input_data(j_decompress_ptr cinfo,long num_bytes)123 skip_input_data(j_decompress_ptr cinfo, long num_bytes)
124 {
125 JpegSource* source = (JpegSource*) cinfo->src;
126
127 if( num_bytes > (long)source->pub.bytes_in_buffer )
128 {
129 // We need to skip more data than we have in the buffer.
130 // This will force the JPEG library to suspend decoding.
131 source->skip = (int)(num_bytes - source->pub.bytes_in_buffer);
132 source->pub.next_input_byte += source->pub.bytes_in_buffer;
133 source->pub.bytes_in_buffer = 0;
134 }
135 else
136 {
137 // Skip portion of the buffer
138 source->pub.bytes_in_buffer -= num_bytes;
139 source->pub.next_input_byte += num_bytes;
140 source->skip = 0;
141 }
142 }
143
144
jpeg_buffer_src(j_decompress_ptr cinfo,JpegSource * source)145 static void jpeg_buffer_src(j_decompress_ptr cinfo, JpegSource* source)
146 {
147 cinfo->src = &source->pub;
148
149 // Prepare for suspending reader
150 source->pub.init_source = stub;
151 source->pub.fill_input_buffer = fill_input_buffer;
152 source->pub.skip_input_data = skip_input_data;
153 source->pub.resync_to_restart = jpeg_resync_to_restart;
154 source->pub.term_source = stub;
155 source->pub.bytes_in_buffer = 0; // forces fill_input_buffer on first read
156
157 source->skip = 0;
158 }
159
160
161 METHODDEF(void)
error_exit(j_common_ptr cinfo)162 error_exit( j_common_ptr cinfo )
163 {
164 JpegErrorMgr* err_mgr = (JpegErrorMgr*)(cinfo->err);
165
166 /* Return control to the setjmp point */
167 longjmp( err_mgr->setjmp_buffer, 1 );
168 }
169
170
171 /////////////////////// JpegDecoder ///////////////////
172
173
JpegDecoder()174 JpegDecoder::JpegDecoder()
175 {
176 m_signature = "\xFF\xD8\xFF";
177 m_state = 0;
178 m_f = 0;
179 m_buf_supported = true;
180 }
181
182
~JpegDecoder()183 JpegDecoder::~JpegDecoder()
184 {
185 close();
186 }
187
188
close()189 void JpegDecoder::close()
190 {
191 if( m_state )
192 {
193 JpegState* state = (JpegState*)m_state;
194 jpeg_destroy_decompress( &state->cinfo );
195 delete state;
196 m_state = 0;
197 }
198
199 if( m_f )
200 {
201 fclose( m_f );
202 m_f = 0;
203 }
204
205 m_width = m_height = 0;
206 m_type = -1;
207 }
208
newDecoder() const209 ImageDecoder JpegDecoder::newDecoder() const
210 {
211 return makePtr<JpegDecoder>();
212 }
213
readHeader()214 bool JpegDecoder::readHeader()
215 {
216 bool result = false;
217 close();
218
219 JpegState* state = new JpegState;
220 m_state = state;
221 state->cinfo.err = jpeg_std_error(&state->jerr.pub);
222 state->jerr.pub.error_exit = error_exit;
223
224 if( setjmp( state->jerr.setjmp_buffer ) == 0 )
225 {
226 jpeg_create_decompress( &state->cinfo );
227
228 if( !m_buf.empty() )
229 {
230 jpeg_buffer_src(&state->cinfo, &state->source);
231 state->source.pub.next_input_byte = m_buf.ptr();
232 state->source.pub.bytes_in_buffer = m_buf.cols*m_buf.rows*m_buf.elemSize();
233 }
234 else
235 {
236 m_f = fopen( m_filename.c_str(), "rb" );
237 if( m_f )
238 jpeg_stdio_src( &state->cinfo, m_f );
239 }
240
241 if (state->cinfo.src != 0)
242 {
243 jpeg_read_header( &state->cinfo, TRUE );
244
245 m_width = state->cinfo.image_width;
246 m_height = state->cinfo.image_height;
247 m_type = state->cinfo.num_components > 1 ? CV_8UC3 : CV_8UC1;
248 result = true;
249 }
250 }
251
252 if( !result )
253 close();
254
255 return result;
256 }
257
258 /***************************************************************************
259 * following code is for supporting MJPEG image files
260 * based on a message of Laurent Pinchart on the video4linux mailing list
261 ***************************************************************************/
262
263 /* JPEG DHT Segment for YCrCb omitted from MJPEG data */
264 static
265 unsigned char my_jpeg_odml_dht[0x1a4] = {
266 0xff, 0xc4, 0x01, 0xa2,
267
268 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,
269 0x00, 0x00, 0x00, 0x00, 0x00,
270 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
271
272 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
273 0x00, 0x00, 0x00, 0x00, 0x00,
274 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
275
276 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04,
277 0x04, 0x00, 0x00, 0x01, 0x7d,
278 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06,
279 0x13, 0x51, 0x61, 0x07,
280 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1,
281 0x15, 0x52, 0xd1, 0xf0,
282 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a,
283 0x25, 0x26, 0x27, 0x28,
284 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,
285 0x46, 0x47, 0x48, 0x49,
286 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65,
287 0x66, 0x67, 0x68, 0x69,
288 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85,
289 0x86, 0x87, 0x88, 0x89,
290 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3,
291 0xa4, 0xa5, 0xa6, 0xa7,
292 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
293 0xc2, 0xc3, 0xc4, 0xc5,
294 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
295 0xd9, 0xda, 0xe1, 0xe2,
296 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4,
297 0xf5, 0xf6, 0xf7, 0xf8,
298 0xf9, 0xfa,
299
300 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04,
301 0x04, 0x00, 0x01, 0x02, 0x77,
302 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41,
303 0x51, 0x07, 0x61, 0x71,
304 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09,
305 0x23, 0x33, 0x52, 0xf0,
306 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17,
307 0x18, 0x19, 0x1a, 0x26,
308 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44,
309 0x45, 0x46, 0x47, 0x48,
310 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64,
311 0x65, 0x66, 0x67, 0x68,
312 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83,
313 0x84, 0x85, 0x86, 0x87,
314 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a,
315 0xa2, 0xa3, 0xa4, 0xa5,
316 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8,
317 0xb9, 0xba, 0xc2, 0xc3,
318 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
319 0xd7, 0xd8, 0xd9, 0xda,
320 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4,
321 0xf5, 0xf6, 0xf7, 0xf8,
322 0xf9, 0xfa
323 };
324
325 /*
326 * Parse the DHT table.
327 * This code comes from jpeg6b (jdmarker.c).
328 */
329 static
my_jpeg_load_dht(struct jpeg_decompress_struct * info,unsigned char * dht,JHUFF_TBL * ac_tables[],JHUFF_TBL * dc_tables[])330 int my_jpeg_load_dht (struct jpeg_decompress_struct *info, unsigned char *dht,
331 JHUFF_TBL *ac_tables[], JHUFF_TBL *dc_tables[])
332 {
333 unsigned int length = (dht[2] << 8) + dht[3] - 2;
334 unsigned int pos = 4;
335 unsigned int count, i;
336 int index;
337
338 JHUFF_TBL **hufftbl;
339 unsigned char bits[17];
340 unsigned char huffval[256];
341
342 while (length > 16)
343 {
344 bits[0] = 0;
345 index = dht[pos++];
346 count = 0;
347 for (i = 1; i <= 16; ++i)
348 {
349 bits[i] = dht[pos++];
350 count += bits[i];
351 }
352 length -= 17;
353
354 if (count > 256 || count > length)
355 return -1;
356
357 for (i = 0; i < count; ++i)
358 huffval[i] = dht[pos++];
359 length -= count;
360
361 if (index & 0x10)
362 {
363 index -= 0x10;
364 hufftbl = &ac_tables[index];
365 }
366 else
367 hufftbl = &dc_tables[index];
368
369 if (index < 0 || index >= NUM_HUFF_TBLS)
370 return -1;
371
372 if (*hufftbl == NULL)
373 *hufftbl = jpeg_alloc_huff_table ((j_common_ptr)info);
374 if (*hufftbl == NULL)
375 return -1;
376
377 memcpy ((*hufftbl)->bits, bits, sizeof (*hufftbl)->bits);
378 memcpy ((*hufftbl)->huffval, huffval, sizeof (*hufftbl)->huffval);
379 }
380
381 if (length != 0)
382 return -1;
383
384 return 0;
385 }
386
387 /***************************************************************************
388 * end of code for supportting MJPEG image files
389 * based on a message of Laurent Pinchart on the video4linux mailing list
390 ***************************************************************************/
391
readData(Mat & img)392 bool JpegDecoder::readData( Mat& img )
393 {
394 bool result = false;
395 int step = (int)img.step;
396 bool color = img.channels() > 1;
397
398 if( m_state && m_width && m_height )
399 {
400 jpeg_decompress_struct* cinfo = &((JpegState*)m_state)->cinfo;
401 JpegErrorMgr* jerr = &((JpegState*)m_state)->jerr;
402 JSAMPARRAY buffer = 0;
403
404 if( setjmp( jerr->setjmp_buffer ) == 0 )
405 {
406 /* check if this is a mjpeg image format */
407 if ( cinfo->ac_huff_tbl_ptrs[0] == NULL &&
408 cinfo->ac_huff_tbl_ptrs[1] == NULL &&
409 cinfo->dc_huff_tbl_ptrs[0] == NULL &&
410 cinfo->dc_huff_tbl_ptrs[1] == NULL )
411 {
412 /* yes, this is a mjpeg image format, so load the correct
413 huffman table */
414 my_jpeg_load_dht( cinfo,
415 my_jpeg_odml_dht,
416 cinfo->ac_huff_tbl_ptrs,
417 cinfo->dc_huff_tbl_ptrs );
418 }
419
420 if( color )
421 {
422 if( cinfo->num_components != 4 )
423 {
424 cinfo->out_color_space = JCS_RGB;
425 cinfo->out_color_components = 3;
426 }
427 else
428 {
429 cinfo->out_color_space = JCS_CMYK;
430 cinfo->out_color_components = 4;
431 }
432 }
433 else
434 {
435 if( cinfo->num_components != 4 )
436 {
437 cinfo->out_color_space = JCS_GRAYSCALE;
438 cinfo->out_color_components = 1;
439 }
440 else
441 {
442 cinfo->out_color_space = JCS_CMYK;
443 cinfo->out_color_components = 4;
444 }
445 }
446
447 jpeg_start_decompress( cinfo );
448
449 buffer = (*cinfo->mem->alloc_sarray)((j_common_ptr)cinfo,
450 JPOOL_IMAGE, m_width*4, 1 );
451
452 uchar* data = img.ptr();
453 for( ; m_height--; data += step )
454 {
455 jpeg_read_scanlines( cinfo, buffer, 1 );
456 if( color )
457 {
458 if( cinfo->out_color_components == 3 )
459 icvCvt_RGB2BGR_8u_C3R( buffer[0], 0, data, 0, cvSize(m_width,1) );
460 else
461 icvCvt_CMYK2BGR_8u_C4C3R( buffer[0], 0, data, 0, cvSize(m_width,1) );
462 }
463 else
464 {
465 if( cinfo->out_color_components == 1 )
466 memcpy( data, buffer[0], m_width );
467 else
468 icvCvt_CMYK2Gray_8u_C4C1R( buffer[0], 0, data, 0, cvSize(m_width,1) );
469 }
470 }
471 result = true;
472 jpeg_finish_decompress( cinfo );
473 }
474 }
475
476 close();
477 return result;
478 }
479
480
481 /////////////////////// JpegEncoder ///////////////////
482
483 struct JpegDestination
484 {
485 struct jpeg_destination_mgr pub;
486 std::vector<uchar> *buf, *dst;
487 };
488
489 METHODDEF(void)
stub(j_compress_ptr)490 stub(j_compress_ptr)
491 {
492 }
493
494 METHODDEF(void)
term_destination(j_compress_ptr cinfo)495 term_destination (j_compress_ptr cinfo)
496 {
497 JpegDestination* dest = (JpegDestination*)cinfo->dest;
498 size_t sz = dest->dst->size(), bufsz = dest->buf->size() - dest->pub.free_in_buffer;
499 if( bufsz > 0 )
500 {
501 dest->dst->resize(sz + bufsz);
502 memcpy( &(*dest->dst)[0] + sz, &(*dest->buf)[0], bufsz);
503 }
504 }
505
506 METHODDEF(boolean)
empty_output_buffer(j_compress_ptr cinfo)507 empty_output_buffer (j_compress_ptr cinfo)
508 {
509 JpegDestination* dest = (JpegDestination*)cinfo->dest;
510 size_t sz = dest->dst->size(), bufsz = dest->buf->size();
511 dest->dst->resize(sz + bufsz);
512 memcpy( &(*dest->dst)[0] + sz, &(*dest->buf)[0], bufsz);
513
514 dest->pub.next_output_byte = &(*dest->buf)[0];
515 dest->pub.free_in_buffer = bufsz;
516 return TRUE;
517 }
518
jpeg_buffer_dest(j_compress_ptr cinfo,JpegDestination * destination)519 static void jpeg_buffer_dest(j_compress_ptr cinfo, JpegDestination* destination)
520 {
521 cinfo->dest = &destination->pub;
522
523 destination->pub.init_destination = stub;
524 destination->pub.empty_output_buffer = empty_output_buffer;
525 destination->pub.term_destination = term_destination;
526 }
527
528
JpegEncoder()529 JpegEncoder::JpegEncoder()
530 {
531 m_description = "JPEG files (*.jpeg;*.jpg;*.jpe)";
532 m_buf_supported = true;
533 }
534
535
~JpegEncoder()536 JpegEncoder::~JpegEncoder()
537 {
538 }
539
newEncoder() const540 ImageEncoder JpegEncoder::newEncoder() const
541 {
542 return makePtr<JpegEncoder>();
543 }
544
write(const Mat & img,const std::vector<int> & params)545 bool JpegEncoder::write( const Mat& img, const std::vector<int>& params )
546 {
547 m_last_error.clear();
548
549 struct fileWrapper
550 {
551 FILE* f;
552
553 fileWrapper() : f(0) {}
554 ~fileWrapper() { if(f) fclose(f); }
555 };
556 bool result = false;
557 fileWrapper fw;
558 int width = img.cols, height = img.rows;
559
560 std::vector<uchar> out_buf(1 << 12);
561 AutoBuffer<uchar> _buffer;
562 uchar* buffer;
563
564 struct jpeg_compress_struct cinfo;
565 JpegErrorMgr jerr;
566 JpegDestination dest;
567
568 jpeg_create_compress(&cinfo);
569 cinfo.err = jpeg_std_error(&jerr.pub);
570 jerr.pub.error_exit = error_exit;
571
572 if( !m_buf )
573 {
574 fw.f = fopen( m_filename.c_str(), "wb" );
575 if( !fw.f )
576 goto _exit_;
577 jpeg_stdio_dest( &cinfo, fw.f );
578 }
579 else
580 {
581 dest.dst = m_buf;
582 dest.buf = &out_buf;
583
584 jpeg_buffer_dest( &cinfo, &dest );
585
586 dest.pub.next_output_byte = &out_buf[0];
587 dest.pub.free_in_buffer = out_buf.size();
588 }
589
590 if( setjmp( jerr.setjmp_buffer ) == 0 )
591 {
592 cinfo.image_width = width;
593 cinfo.image_height = height;
594
595 int _channels = img.channels();
596 int channels = _channels > 1 ? 3 : 1;
597 cinfo.input_components = channels;
598 cinfo.in_color_space = channels > 1 ? JCS_RGB : JCS_GRAYSCALE;
599
600 int quality = 95;
601 int progressive = 0;
602 int optimize = 0;
603 int rst_interval = 0;
604 int luma_quality = -1;
605 int chroma_quality = -1;
606
607 for( size_t i = 0; i < params.size(); i += 2 )
608 {
609 if( params[i] == CV_IMWRITE_JPEG_QUALITY )
610 {
611 quality = params[i+1];
612 quality = MIN(MAX(quality, 0), 100);
613 }
614
615 if( params[i] == CV_IMWRITE_JPEG_PROGRESSIVE )
616 {
617 progressive = params[i+1];
618 }
619
620 if( params[i] == CV_IMWRITE_JPEG_OPTIMIZE )
621 {
622 optimize = params[i+1];
623 }
624
625 if( params[i] == CV_IMWRITE_JPEG_LUMA_QUALITY )
626 {
627 if (params[i+1] >= 0)
628 {
629 luma_quality = MIN(MAX(params[i+1], 0), 100);
630
631 quality = luma_quality;
632
633 if (chroma_quality < 0)
634 {
635 chroma_quality = luma_quality;
636 }
637 }
638 }
639
640 if( params[i] == CV_IMWRITE_JPEG_CHROMA_QUALITY )
641 {
642 if (params[i+1] >= 0)
643 {
644 chroma_quality = MIN(MAX(params[i+1], 0), 100);
645 }
646 }
647
648 if( params[i] == CV_IMWRITE_JPEG_RST_INTERVAL )
649 {
650 rst_interval = params[i+1];
651 rst_interval = MIN(MAX(rst_interval, 0), 65535L);
652 }
653 }
654
655 jpeg_set_defaults( &cinfo );
656 cinfo.restart_interval = rst_interval;
657
658 jpeg_set_quality( &cinfo, quality,
659 TRUE /* limit to baseline-JPEG values */ );
660 if( progressive )
661 jpeg_simple_progression( &cinfo );
662 if( optimize )
663 cinfo.optimize_coding = TRUE;
664
665 #if JPEG_LIB_VERSION >= 70
666 if (luma_quality >= 0 && chroma_quality >= 0)
667 {
668 cinfo.q_scale_factor[0] = jpeg_quality_scaling(luma_quality);
669 cinfo.q_scale_factor[1] = jpeg_quality_scaling(chroma_quality);
670 if ( luma_quality != chroma_quality )
671 {
672 /* disable subsampling - ref. Libjpeg.txt */
673 cinfo.comp_info[0].v_samp_factor = 1;
674 cinfo.comp_info[0].h_samp_factor = 1;
675 cinfo.comp_info[1].v_samp_factor = 1;
676 cinfo.comp_info[1].h_samp_factor = 1;
677 }
678 jpeg_default_qtables( &cinfo, TRUE );
679 }
680 #endif // #if JPEG_LIB_VERSION >= 70
681
682 jpeg_start_compress( &cinfo, TRUE );
683
684 if( channels > 1 )
685 _buffer.allocate(width*channels);
686 buffer = _buffer;
687
688 for( int y = 0; y < height; y++ )
689 {
690 uchar *data = img.data + img.step*y, *ptr = data;
691
692 if( _channels == 3 )
693 {
694 icvCvt_BGR2RGB_8u_C3R( data, 0, buffer, 0, cvSize(width,1) );
695 ptr = buffer;
696 }
697 else if( _channels == 4 )
698 {
699 icvCvt_BGRA2BGR_8u_C4C3R( data, 0, buffer, 0, cvSize(width,1), 2 );
700 ptr = buffer;
701 }
702
703 jpeg_write_scanlines( &cinfo, &ptr, 1 );
704 }
705
706 jpeg_finish_compress( &cinfo );
707 result = true;
708 }
709
710 _exit_:
711
712 if(!result)
713 {
714 char jmsg_buf[JMSG_LENGTH_MAX];
715 jerr.pub.format_message((j_common_ptr)&cinfo, jmsg_buf);
716 m_last_error = jmsg_buf;
717 }
718
719 jpeg_destroy_compress( &cinfo );
720
721 return result;
722 }
723
724 }
725
726 #endif
727
728 /* End of file. */
729