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) 110 stub(j_decompress_ptr) 111 { 112 } 113 114 METHODDEF(boolean) 115 fill_input_buffer(j_decompress_ptr) 116 { 117 return FALSE; 118 } 119 120 // emulating memory input stream 121 122 METHODDEF(void) 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 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) 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 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 183 JpegDecoder::~JpegDecoder() 184 { 185 close(); 186 } 187 188 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 209 ImageDecoder JpegDecoder::newDecoder() const 210 { 211 return makePtr<JpegDecoder>(); 212 } 213 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 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 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) 490 stub(j_compress_ptr) 491 { 492 } 493 494 METHODDEF(void) 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) 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 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 529 JpegEncoder::JpegEncoder() 530 { 531 m_description = "JPEG files (*.jpeg;*.jpg;*.jpe)"; 532 m_buf_supported = true; 533 } 534 535 536 JpegEncoder::~JpegEncoder() 537 { 538 } 539 540 ImageEncoder JpegEncoder::newEncoder() const 541 { 542 return makePtr<JpegEncoder>(); 543 } 544 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