/indra/llimage/llimagejpeg.cpp
C++ | 648 lines | 306 code | 115 blank | 227 comment | 27 complexity | 15d5052df5ad3ec22e0b982500e96681 MD5 | raw file
Possible License(s): LGPL-2.1
1/** 2 * @file llimagejpeg.cpp 3 * 4 * $LicenseInfo:firstyear=2002&license=viewerlgpl$ 5 * Second Life Viewer Source Code 6 * Copyright (C) 2010, Linden Research, Inc. 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; 11 * version 2.1 of the License only. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with this library; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 * 22 * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA 23 * $/LicenseInfo$ 24 */ 25 26#include "linden_common.h" 27#include "stdtypes.h" 28 29#include "llimagejpeg.h" 30 31#include "llerror.h" 32 33jmp_buf LLImageJPEG::sSetjmpBuffer ; 34LLImageJPEG::LLImageJPEG(S32 quality) 35 : 36 LLImageFormatted(IMG_CODEC_JPEG), 37 mOutputBuffer( NULL ), 38 mOutputBufferSize( 0 ), 39 mEncodeQuality( quality ) // on a scale from 1 to 100 40{ 41} 42 43LLImageJPEG::~LLImageJPEG() 44{ 45 llassert( !mOutputBuffer ); // Should already be deleted at end of encode. 46 delete[] mOutputBuffer; 47} 48 49BOOL LLImageJPEG::updateData() 50{ 51 resetLastError(); 52 53 // Check to make sure that this instance has been initialized with data 54 if (!getData() || (0 == getDataSize())) 55 { 56 setLastError("Uninitialized instance of LLImageJPEG"); 57 return FALSE; 58 } 59 60 //////////////////////////////////////// 61 // Step 1: allocate and initialize JPEG decompression object 62 63 // This struct contains the JPEG decompression parameters and pointers to 64 // working space (which is allocated as needed by the JPEG library). 65 struct jpeg_decompress_struct cinfo; 66 cinfo.client_data = this; 67 68 struct jpeg_error_mgr jerr; 69 cinfo.err = jpeg_std_error(&jerr); 70 71 // Customize with our own callbacks 72 jerr.error_exit = &LLImageJPEG::errorExit; // Error exit handler: does not return to caller 73 jerr.emit_message = &LLImageJPEG::errorEmitMessage; // Conditionally emit a trace or warning message 74 jerr.output_message = &LLImageJPEG::errorOutputMessage; // Routine that actually outputs a trace or error message 75 76 // 77 //try/catch will crash on Mac and Linux if LLImageJPEG::errorExit throws an error 78 //so as instead, we use setjmp/longjmp to avoid this crash, which is the best we can get. --bao 79 // 80 if(setjmp(sSetjmpBuffer)) 81 { 82 jpeg_destroy_decompress(&cinfo); 83 return FALSE; 84 } 85 try 86 { 87 // Now we can initialize the JPEG decompression object. 88 jpeg_create_decompress(&cinfo); 89 90 //////////////////////////////////////// 91 // Step 2: specify data source 92 // (Code is modified version of jpeg_stdio_src(); 93 if (cinfo.src == NULL) 94 { 95 cinfo.src = (struct jpeg_source_mgr *) 96 (*cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_PERMANENT, 97 sizeof(struct jpeg_source_mgr)); 98 } 99 cinfo.src->init_source = &LLImageJPEG::decodeInitSource; 100 cinfo.src->fill_input_buffer = &LLImageJPEG::decodeFillInputBuffer; 101 cinfo.src->skip_input_data = &LLImageJPEG::decodeSkipInputData; 102 cinfo.src->resync_to_restart = jpeg_resync_to_restart; // For now, use default method, but we should be able to do better. 103 cinfo.src->term_source = &LLImageJPEG::decodeTermSource; 104 105 cinfo.src->bytes_in_buffer = getDataSize(); 106 cinfo.src->next_input_byte = getData(); 107 108 //////////////////////////////////////// 109 // Step 3: read file parameters with jpeg_read_header() 110 jpeg_read_header( &cinfo, TRUE ); 111 112 // Data set by jpeg_read_header 113 setSize(cinfo.image_width, cinfo.image_height, 3); // Force to 3 components (RGB) 114 115 /* 116 // More data set by jpeg_read_header 117 cinfo.num_components; 118 cinfo.jpeg_color_space; // Colorspace of image 119 cinfo.saw_JFIF_marker; // TRUE if a JFIF APP0 marker was seen 120 cinfo.JFIF_major_version; // Version information from JFIF marker 121 cinfo.JFIF_minor_version; // 122 cinfo.density_unit; // Resolution data from JFIF marker 123 cinfo.X_density; 124 cinfo.Y_density; 125 cinfo.saw_Adobe_marker; // TRUE if an Adobe APP14 marker was seen 126 cinfo.Adobe_transform; // Color transform code from Adobe marker 127 */ 128 } 129 catch (int) 130 { 131 jpeg_destroy_decompress(&cinfo); 132 133 return FALSE; 134 } 135 //////////////////////////////////////// 136 // Step 4: Release JPEG decompression object 137 jpeg_destroy_decompress(&cinfo); 138 139 return TRUE; 140} 141 142// Initialize source --- called by jpeg_read_header 143// before any data is actually read. 144void LLImageJPEG::decodeInitSource( j_decompress_ptr cinfo ) 145{ 146 // no work necessary here 147} 148 149// Fill the input buffer --- called whenever buffer is emptied. 150boolean LLImageJPEG::decodeFillInputBuffer( j_decompress_ptr cinfo ) 151{ 152// jpeg_source_mgr* src = cinfo->src; 153// LLImageJPEG* self = (LLImageJPEG*) cinfo->client_data; 154 155 // Should never get here, since we provide the entire buffer up front. 156 ERREXIT(cinfo, JERR_INPUT_EMPTY); 157 158 return TRUE; 159} 160 161// Skip data --- used to skip over a potentially large amount of 162// uninteresting data (such as an APPn marker). 163// 164// Writers of suspendable-input applications must note that skip_input_data 165// is not granted the right to give a suspension return. If the skip extends 166// beyond the data currently in the buffer, the buffer can be marked empty so 167// that the next read will cause a fill_input_buffer call that can suspend. 168// Arranging for additional bytes to be discarded before reloading the input 169// buffer is the application writer's problem. 170void LLImageJPEG::decodeSkipInputData (j_decompress_ptr cinfo, long num_bytes) 171{ 172 jpeg_source_mgr* src = cinfo->src; 173// LLImageJPEG* self = (LLImageJPEG*) cinfo->client_data; 174 175 src->next_input_byte += (size_t) num_bytes; 176 src->bytes_in_buffer -= (size_t) num_bytes; 177} 178 179void LLImageJPEG::decodeTermSource (j_decompress_ptr cinfo) 180{ 181 // no work necessary here 182} 183 184 185// Returns true when done, whether or not decode was successful. 186BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time) 187{ 188 llassert_always(raw_image); 189 190 resetLastError(); 191 192 // Check to make sure that this instance has been initialized with data 193 if (!getData() || (0 == getDataSize())) 194 { 195 setLastError("LLImageJPEG trying to decode an image with no data!"); 196 return TRUE; // done 197 } 198 199 S32 row_stride = 0; 200 U8* raw_image_data = NULL; 201 202 //////////////////////////////////////// 203 // Step 1: allocate and initialize JPEG decompression object 204 205 // This struct contains the JPEG decompression parameters and pointers to 206 // working space (which is allocated as needed by the JPEG library). 207 struct jpeg_decompress_struct cinfo; 208 209 struct jpeg_error_mgr jerr; 210 cinfo.err = jpeg_std_error(&jerr); 211 212 // Customize with our own callbacks 213 jerr.error_exit = &LLImageJPEG::errorExit; // Error exit handler: does not return to caller 214 jerr.emit_message = &LLImageJPEG::errorEmitMessage; // Conditionally emit a trace or warning message 215 jerr.output_message = &LLImageJPEG::errorOutputMessage; // Routine that actually outputs a trace or error message 216 217 // 218 //try/catch will crash on Mac and Linux if LLImageJPEG::errorExit throws an error 219 //so as instead, we use setjmp/longjmp to avoid this crash, which is the best we can get. --bao 220 // 221 if(setjmp(sSetjmpBuffer)) 222 { 223 jpeg_destroy_decompress(&cinfo); 224 return TRUE; // done 225 } 226 try 227 { 228 // Now we can initialize the JPEG decompression object. 229 jpeg_create_decompress(&cinfo); 230 231 //////////////////////////////////////// 232 // Step 2: specify data source 233 // (Code is modified version of jpeg_stdio_src(); 234 if (cinfo.src == NULL) 235 { 236 cinfo.src = (struct jpeg_source_mgr *) 237 (*cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_PERMANENT, 238 sizeof(struct jpeg_source_mgr)); 239 } 240 cinfo.src->init_source = &LLImageJPEG::decodeInitSource; 241 cinfo.src->fill_input_buffer = &LLImageJPEG::decodeFillInputBuffer; 242 cinfo.src->skip_input_data = &LLImageJPEG::decodeSkipInputData; 243 cinfo.src->resync_to_restart = jpeg_resync_to_restart; // For now, use default method, but we should be able to do better. 244 cinfo.src->term_source = &LLImageJPEG::decodeTermSource; 245 cinfo.src->bytes_in_buffer = getDataSize(); 246 cinfo.src->next_input_byte = getData(); 247 248 //////////////////////////////////////// 249 // Step 3: read file parameters with jpeg_read_header() 250 251 jpeg_read_header(&cinfo, TRUE); 252 253 // We can ignore the return value from jpeg_read_header since 254 // (a) suspension is not possible with our data source, and 255 // (b) we passed TRUE to reject a tables-only JPEG file as an error. 256 // See libjpeg.doc for more info. 257 258 setSize(cinfo.image_width, cinfo.image_height, 3); // Force to 3 components (RGB) 259 260 raw_image->resize(getWidth(), getHeight(), getComponents()); 261 raw_image_data = raw_image->getData(); 262 263 264 //////////////////////////////////////// 265 // Step 4: set parameters for decompression 266 cinfo.out_color_components = 3; 267 cinfo.out_color_space = JCS_RGB; 268 269 270 //////////////////////////////////////// 271 // Step 5: Start decompressor 272 273 jpeg_start_decompress(&cinfo); 274 // We can ignore the return value since suspension is not possible 275 // with our data source. 276 277 // We may need to do some setup of our own at this point before reading 278 // the data. After jpeg_start_decompress() we have the correct scaled 279 // output image dimensions available, as well as the output colormap 280 // if we asked for color quantization. 281 // In this example, we need to make an output work buffer of the right size. 282 283 // JSAMPLEs per row in output buffer 284 row_stride = cinfo.output_width * cinfo.output_components; 285 286 //////////////////////////////////////// 287 // Step 6: while (scan lines remain to be read) 288 // jpeg_read_scanlines(...); 289 290 // Here we use the library's state variable cinfo.output_scanline as the 291 // loop counter, so that we don't have to keep track ourselves. 292 293 // Move pointer to last line 294 raw_image_data += row_stride * (cinfo.output_height - 1); 295 296 while (cinfo.output_scanline < cinfo.output_height) 297 { 298 // jpeg_read_scanlines expects an array of pointers to scanlines. 299 // Here the array is only one element long, but you could ask for 300 // more than one scanline at a time if that's more convenient. 301 302 jpeg_read_scanlines(&cinfo, &raw_image_data, 1); 303 raw_image_data -= row_stride; // move pointer up a line 304 } 305 306 //////////////////////////////////////// 307 // Step 7: Finish decompression 308 jpeg_finish_decompress(&cinfo); 309 310 //////////////////////////////////////// 311 // Step 8: Release JPEG decompression object 312 jpeg_destroy_decompress(&cinfo); 313 } 314 315 catch (int) 316 { 317 jpeg_destroy_decompress(&cinfo); 318 return TRUE; // done 319 } 320 321 // Check to see whether any corrupt-data warnings occurred 322 if( jerr.num_warnings != 0 ) 323 { 324 // TODO: extract the warning to find out what went wrong. 325 setLastError( "Unable to decode JPEG image."); 326 return TRUE; // done 327 } 328 329 return TRUE; 330} 331 332 333// Initialize destination --- called by jpeg_start_compress before any data is actually written. 334// static 335void LLImageJPEG::encodeInitDestination ( j_compress_ptr cinfo ) 336{ 337 LLImageJPEG* self = (LLImageJPEG*) cinfo->client_data; 338 339 cinfo->dest->next_output_byte = self->mOutputBuffer; 340 cinfo->dest->free_in_buffer = self->mOutputBufferSize; 341} 342 343 344// Empty the output buffer --- called whenever buffer fills up. 345// 346// In typical applications, this should write the entire output buffer 347// (ignoring the current state of next_output_byte & free_in_buffer), 348// reset the pointer & count to the start of the buffer, and return TRUE 349// indicating that the buffer has been dumped. 350// 351// In applications that need to be able to suspend compression due to output 352// overrun, a FALSE return indicates that the buffer cannot be emptied now. 353// In this situation, the compressor will return to its caller (possibly with 354// an indication that it has not accepted all the supplied scanlines). The 355// application should resume compression after it has made more room in the 356// output buffer. Note that there are substantial restrictions on the use of 357// suspension --- see the documentation. 358// 359// When suspending, the compressor will back up to a convenient restart point 360// (typically the start of the current MCU). next_output_byte & free_in_buffer 361// indicate where the restart point will be if the current call returns FALSE. 362// Data beyond this point will be regenerated after resumption, so do not 363// write it out when emptying the buffer externally. 364 365boolean LLImageJPEG::encodeEmptyOutputBuffer( j_compress_ptr cinfo ) 366{ 367 LLImageJPEG* self = (LLImageJPEG*) cinfo->client_data; 368 369 // Should very rarely happen, since our output buffer is 370 // as large as the input to start out with. 371 372 // Double the buffer size; 373 S32 new_buffer_size = self->mOutputBufferSize * 2; 374 U8* new_buffer = new U8[ new_buffer_size ]; 375 if (!new_buffer) 376 { 377 llerrs << "Out of memory in LLImageJPEG::encodeEmptyOutputBuffer( j_compress_ptr cinfo )" << llendl; 378 return FALSE; 379 } 380 memcpy( new_buffer, self->mOutputBuffer, self->mOutputBufferSize ); /* Flawfinder: ignore */ 381 delete[] self->mOutputBuffer; 382 self->mOutputBuffer = new_buffer; 383 384 cinfo->dest->next_output_byte = self->mOutputBuffer + self->mOutputBufferSize; 385 cinfo->dest->free_in_buffer = self->mOutputBufferSize; 386 self->mOutputBufferSize = new_buffer_size; 387 388 return TRUE; 389} 390 391// Terminate destination --- called by jpeg_finish_compress 392// after all data has been written. Usually needs to flush buffer. 393// 394// NB: *not* called by jpeg_abort or jpeg_destroy; surrounding 395// application must deal with any cleanup that should happen even 396// for error exit. 397void LLImageJPEG::encodeTermDestination( j_compress_ptr cinfo ) 398{ 399 LLImageJPEG* self = (LLImageJPEG*) cinfo->client_data; 400 401 S32 file_bytes = (S32)(self->mOutputBufferSize - cinfo->dest->free_in_buffer); 402 self->allocateData(file_bytes); 403 404 memcpy( self->getData(), self->mOutputBuffer, file_bytes ); /* Flawfinder: ignore */ 405} 406 407// static 408void LLImageJPEG::errorExit( j_common_ptr cinfo ) 409{ 410 //LLImageJPEG* self = (LLImageJPEG*) cinfo->client_data; 411 412 // Always display the message 413 (*cinfo->err->output_message)(cinfo); 414 415 // Let the memory manager delete any temp files 416 jpeg_destroy(cinfo); 417 418 // Return control to the setjmp point 419 longjmp(sSetjmpBuffer, 1) ; 420} 421 422// Decide whether to emit a trace or warning message. 423// msg_level is one of: 424// -1: recoverable corrupt-data warning, may want to abort. 425// 0: important advisory messages (always display to user). 426// 1: first level of tracing detail. 427// 2,3,...: successively more detailed tracing messages. 428// An application might override this method if it wanted to abort on warnings 429// or change the policy about which messages to display. 430// static 431void LLImageJPEG::errorEmitMessage( j_common_ptr cinfo, int msg_level ) 432{ 433 struct jpeg_error_mgr * err = cinfo->err; 434 435 if (msg_level < 0) 436 { 437 // It's a warning message. Since corrupt files may generate many warnings, 438 // the policy implemented here is to show only the first warning, 439 // unless trace_level >= 3. 440 if (err->num_warnings == 0 || err->trace_level >= 3) 441 { 442 (*err->output_message) (cinfo); 443 } 444 // Always count warnings in num_warnings. 445 err->num_warnings++; 446 } 447 else 448 { 449 // It's a trace message. Show it if trace_level >= msg_level. 450 if (err->trace_level >= msg_level) 451 { 452 (*err->output_message) (cinfo); 453 } 454 } 455} 456 457// static 458void LLImageJPEG::errorOutputMessage( j_common_ptr cinfo ) 459{ 460 // Create the message 461 char buffer[JMSG_LENGTH_MAX]; /* Flawfinder: ignore */ 462 (*cinfo->err->format_message) (cinfo, buffer); 463 464 std::string error = buffer ; 465 LLImage::setLastError(error); 466 467 BOOL is_decode = (cinfo->is_decompressor != 0); 468 llwarns << "LLImageJPEG " << (is_decode ? "decode " : "encode ") << " failed: " << buffer << llendl; 469} 470 471BOOL LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time ) 472{ 473 llassert_always(raw_image); 474 475 resetLastError(); 476 477 switch( raw_image->getComponents() ) 478 { 479 case 1: 480 case 3: 481 break; 482 default: 483 setLastError("Unable to encode a JPEG image that doesn't have 1 or 3 components."); 484 return FALSE; 485 } 486 487 setSize(raw_image->getWidth(), raw_image->getHeight(), raw_image->getComponents()); 488 489 // Allocate a temporary buffer big enough to hold the entire compressed image (and then some) 490 // (Note: we make it bigger in emptyOutputBuffer() if we need to) 491 delete[] mOutputBuffer; 492 mOutputBufferSize = getWidth() * getHeight() * getComponents() + 1024; 493 mOutputBuffer = new U8[ mOutputBufferSize ]; 494 495 const U8* raw_image_data = NULL; 496 S32 row_stride = 0; 497 498 //////////////////////////////////////// 499 // Step 1: allocate and initialize JPEG compression object 500 501 // This struct contains the JPEG compression parameters and pointers to 502 // working space (which is allocated as needed by the JPEG library). 503 struct jpeg_compress_struct cinfo; 504 cinfo.client_data = this; 505 506 // We have to set up the error handler first, in case the initialization 507 // step fails. (Unlikely, but it could happen if you are out of memory.) 508 // This routine fills in the contents of struct jerr, and returns jerr's 509 // address which we place into the link field in cinfo. 510 struct jpeg_error_mgr jerr; 511 cinfo.err = jpeg_std_error(&jerr); 512 513 // Customize with our own callbacks 514 jerr.error_exit = &LLImageJPEG::errorExit; // Error exit handler: does not return to caller 515 jerr.emit_message = &LLImageJPEG::errorEmitMessage; // Conditionally emit a trace or warning message 516 jerr.output_message = &LLImageJPEG::errorOutputMessage; // Routine that actually outputs a trace or error message 517 518 // 519 //try/catch will crash on Mac and Linux if LLImageJPEG::errorExit throws an error 520 //so as instead, we use setjmp/longjmp to avoid this crash, which is the best we can get. --bao 521 // 522 if( setjmp(sSetjmpBuffer) ) 523 { 524 // If we get here, the JPEG code has signaled an error. 525 // We need to clean up the JPEG object, close the input file, and return. 526 jpeg_destroy_compress(&cinfo); 527 delete[] mOutputBuffer; 528 mOutputBuffer = NULL; 529 mOutputBufferSize = 0; 530 return FALSE; 531 } 532 533 try 534 { 535 536 // Now we can initialize the JPEG compression object. 537 jpeg_create_compress(&cinfo); 538 539 //////////////////////////////////////// 540 // Step 2: specify data destination 541 // (code is a modified form of jpeg_stdio_dest() ) 542 if( cinfo.dest == NULL) 543 { 544 cinfo.dest = (struct jpeg_destination_mgr *) 545 (*cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_PERMANENT, 546 sizeof(struct jpeg_destination_mgr)); 547 } 548 cinfo.dest->next_output_byte = mOutputBuffer; // => next byte to write in buffer 549 cinfo.dest->free_in_buffer = mOutputBufferSize; // # of byte spaces remaining in buffer 550 cinfo.dest->init_destination = &LLImageJPEG::encodeInitDestination; 551 cinfo.dest->empty_output_buffer = &LLImageJPEG::encodeEmptyOutputBuffer; 552 cinfo.dest->term_destination = &LLImageJPEG::encodeTermDestination; 553 554 //////////////////////////////////////// 555 // Step 3: set parameters for compression 556 // 557 // First we supply a description of the input image. 558 // Four fields of the cinfo struct must be filled in: 559 560 cinfo.image_width = getWidth(); // image width and height, in pixels 561 cinfo.image_height = getHeight(); 562 563 switch( getComponents() ) 564 { 565 case 1: 566 cinfo.input_components = 1; // # of color components per pixel 567 cinfo.in_color_space = JCS_GRAYSCALE; // colorspace of input image 568 break; 569 case 3: 570 cinfo.input_components = 3; // # of color components per pixel 571 cinfo.in_color_space = JCS_RGB; // colorspace of input image 572 break; 573 default: 574 setLastError("Unable to encode a JPEG image that doesn't have 1 or 3 components."); 575 return FALSE; 576 } 577 578 // Now use the library's routine to set default compression parameters. 579 // (You must set at least cinfo.in_color_space before calling this, 580 // since the defaults depend on the source color space.) 581 jpeg_set_defaults(&cinfo); 582 583 // Now you can set any non-default parameters you wish to. 584 jpeg_set_quality(&cinfo, mEncodeQuality, TRUE ); // limit to baseline-JPEG values 585 586 //////////////////////////////////////// 587 // Step 4: Start compressor 588 // 589 // TRUE ensures that we will write a complete interchange-JPEG file. 590 // Pass TRUE unless you are very sure of what you're doing. 591 592 jpeg_start_compress(&cinfo, TRUE); 593 594 //////////////////////////////////////// 595 // Step 5: while (scan lines remain to be written) 596 // jpeg_write_scanlines(...); 597 598 // Here we use the library's state variable cinfo.next_scanline as the 599 // loop counter, so that we don't have to keep track ourselves. 600 // To keep things simple, we pass one scanline per call; you can pass 601 // more if you wish, though. 602 603 row_stride = getWidth() * getComponents(); // JSAMPLEs per row in image_buffer 604 605 // NOTE: For compatibility with LLImage, we need to invert the rows. 606 raw_image_data = raw_image->getData(); 607 608 const U8* last_row_data = raw_image_data + (getHeight()-1) * row_stride; 609 610 JSAMPROW row_pointer[1]; // pointer to JSAMPLE row[s] 611 while (cinfo.next_scanline < cinfo.image_height) 612 { 613 // jpeg_write_scanlines expects an array of pointers to scanlines. 614 // Here the array is only one element long, but you could pass 615 // more than one scanline at a time if that's more convenient. 616 617 //Ugly const uncast here (jpeg_write_scanlines should take a const* but doesn't) 618 //row_pointer[0] = (JSAMPROW)(raw_image_data + (cinfo.next_scanline * row_stride)); 619 row_pointer[0] = (JSAMPROW)(last_row_data - (cinfo.next_scanline * row_stride)); 620 621 jpeg_write_scanlines(&cinfo, row_pointer, 1); 622 } 623 624 //////////////////////////////////////// 625 // Step 6: Finish compression 626 jpeg_finish_compress(&cinfo); 627 628 // After finish_compress, we can release the temp output buffer. 629 delete[] mOutputBuffer; 630 mOutputBuffer = NULL; 631 mOutputBufferSize = 0; 632 633 //////////////////////////////////////// 634 // Step 7: release JPEG compression object 635 jpeg_destroy_compress(&cinfo); 636 } 637 638 catch(int) 639 { 640 jpeg_destroy_compress(&cinfo); 641 delete[] mOutputBuffer; 642 mOutputBuffer = NULL; 643 mOutputBufferSize = 0; 644 return FALSE; 645 } 646 647 return TRUE; 648}