Visualization Library v1.0.3A lightweight C++ OpenGL middleware for 2D/3D graphics |
[Download] [Tutorials] [All Classes] [Grouped Classes] |
00001 /**************************************************************************************/ 00002 /* */ 00003 /* Visualization Library */ 00004 /* http://visualizationlibrary.org */ 00005 /* */ 00006 /* Copyright (c) 2005-2010, Michele Bosi */ 00007 /* All rights reserved. */ 00008 /* */ 00009 /* Redistribution and use in source and binary forms, with or without modification, */ 00010 /* are permitted provided that the following conditions are met: */ 00011 /* */ 00012 /* - Redistributions of source code must retain the above copyright notice, this */ 00013 /* list of conditions and the following disclaimer. */ 00014 /* */ 00015 /* - Redistributions in binary form must reproduce the above copyright notice, this */ 00016 /* list of conditions and the following disclaimer in the documentation and/or */ 00017 /* other materials provided with the distribution. */ 00018 /* */ 00019 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */ 00020 /* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */ 00021 /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */ 00022 /* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */ 00023 /* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */ 00024 /* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */ 00025 /* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */ 00026 /* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ 00027 /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */ 00028 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 00029 /* */ 00030 /**************************************************************************************/ 00031 00032 #include "ioJPG.hpp" 00033 #include <vlCore/VisualizationLibrary.hpp> 00034 #include <vlCore/FileSystem.hpp> 00035 #include <vlCore/VirtualFile.hpp> 00036 #include <vlCore/Image.hpp> 00037 #include <vlCore/LoadWriterManager.hpp> 00038 00039 extern "C" 00040 { 00041 #include "jpeglib.h" 00042 #include "jconfig.h" 00043 #include "jerror.h" 00044 #include "jmorecfg.h" 00045 } 00046 #include <setjmp.h> 00047 #include <cstdio> 00048 00049 using namespace vl; 00050 00051 namespace 00052 { 00053 /* 00054 * Some of the code below has been adapted to VL from the IJG jpeg library. 00055 */ 00056 00057 /* Expanded data source object for stdio input */ 00058 00059 typedef struct 00060 { 00061 struct jpeg_source_mgr pub; 00062 VirtualFile * infile; /* source stream */ 00063 JOCTET * buffer; /* start of buffer */ 00064 boolean start_of_file; /* have we gotten any data yet? */ 00065 } my_source_mgr; 00066 00067 typedef my_source_mgr * my_src_ptr; 00068 00069 #define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */ 00070 00071 /* 00072 * Initialize source --- called by jpeg_read_header 00073 * before any data is actually read. 00074 */ 00075 00076 METHODDEF(void) 00077 init_source (j_decompress_ptr cinfo) 00078 { 00079 my_src_ptr src = (my_src_ptr) cinfo->src; 00080 00081 /* We reset the empty-input-file flag for each image, 00082 * but we don't clear the input buffer. 00083 * This is correct behavior for reading a series of images from one source. 00084 */ 00085 src->start_of_file = TRUE; 00086 } 00087 00088 /* 00089 * Fill the input buffer --- called whenever buffer is emptied. 00090 * 00091 * In typical applications, this should read fresh data into the buffer 00092 * (ignoring the current state of next_input_byte & bytes_in_buffer), 00093 * reset the pointer & count to the start of the buffer, and return TRUE 00094 * indicating that the buffer has been reloaded. It is not necessary to 00095 * fill the buffer entirely, only to obtain at least one more byte. 00096 * 00097 * There is no such thing as an EOF return. If the end of the file has been 00098 * reached, the routine has a choice of ERREXIT() or inserting fake data into 00099 * the buffer. In most cases, generating a warning message and inserting a 00100 * fake EOI marker is the best course of action --- this will allow the 00101 * decompressor to output however much of the image is there. However, 00102 * the resulting error message is misleading if the real problem is an empty 00103 * input file, so we handle that case specially. 00104 * 00105 * In applications that need to be able to suspend compression due to input 00106 * not being available yet, a FALSE return indicates that no more data can be 00107 * obtained right now, but more may be forthcoming later. In this situation, 00108 * the decompressor will return to its caller (with an indication of the 00109 * number of scanlines it has read, if any). The application should resume 00110 * decompression after it has loaded more data into the input buffer. Note 00111 * that there are substantial restrictions on the use of suspension --- see 00112 * the documentation. 00113 * 00114 * When suspending, the decompressor will back up to a convenient restart point 00115 * (typically the start of the current MCU). next_input_byte & bytes_in_buffer 00116 * indicate where the restart point will be if the current call returns FALSE. 00117 * Data beyond this point must be rescanned after resumption, so move it to 00118 * the front of the buffer rather than discarding it. 00119 */ 00120 00121 METHODDEF(boolean) 00122 fill_input_buffer (j_decompress_ptr cinfo) 00123 { 00124 my_src_ptr src = (my_src_ptr) cinfo->src; 00125 size_t nbytes; 00126 00127 nbytes = (size_t)src->infile->read(src->buffer, INPUT_BUF_SIZE); 00128 00129 if (nbytes <= 0) { 00130 if (src->start_of_file) /* Treat empty input file as fatal error */ 00131 ERREXIT(cinfo, JERR_INPUT_EMPTY); 00132 WARNMS(cinfo, JWRN_JPEG_EOF); 00133 /* Insert a fake EOI marker */ 00134 src->buffer[0] = (JOCTET) 0xFF; 00135 src->buffer[1] = (JOCTET) JPEG_EOI; 00136 nbytes = 2; 00137 } 00138 00139 src->pub.next_input_byte = src->buffer; 00140 src->pub.bytes_in_buffer = nbytes; 00141 src->start_of_file = FALSE; 00142 00143 return TRUE; 00144 } 00145 00146 /* 00147 * Skip data --- used to skip over a potentially large amount of 00148 * uninteresting data (such as an APPn marker). 00149 * 00150 * Writers of suspendable-input applications must note that skip_input_data 00151 * is not granted the right to give a suspension return. If the skip extends 00152 * beyond the data currently in the buffer, the buffer can be marked empty so 00153 * that the next read will cause a fill_input_buffer call that can suspend. 00154 * Arranging for additional bytes to be discarded before reloading the input 00155 * buffer is the application writer's problem. 00156 */ 00157 00158 METHODDEF(void) 00159 skip_input_data (j_decompress_ptr cinfo, long num_bytes) 00160 { 00161 my_src_ptr src = (my_src_ptr) cinfo->src; 00162 00163 /* Just a dumb implementation for now. Could use fseek() except 00164 * it doesn't work on pipes. Not clear that being smart is worth 00165 * any trouble anyway --- large skips are infrequent. 00166 */ 00167 if (num_bytes > 0) { 00168 while (num_bytes > (long) src->pub.bytes_in_buffer) { 00169 num_bytes -= (long) src->pub.bytes_in_buffer; 00170 fill_input_buffer(cinfo); 00171 /* note we assume that fill_input_buffer will never return FALSE, 00172 * so suspension need not be handled. 00173 */ 00174 } 00175 src->pub.next_input_byte += (size_t) num_bytes; 00176 src->pub.bytes_in_buffer -= (size_t) num_bytes; 00177 } 00178 } 00179 00180 /* 00181 * An additional method that can be provided by data source modules is the 00182 * resync_to_restart method for error recovery in the presence of RST markers. 00183 * For the moment, this source module just uses the default resync method 00184 * provided by the JPEG library. That method assumes that no backtracking 00185 * is possible. 00186 */ 00187 00188 /* 00189 * Terminate source --- called by jpeg_finish_decompress 00190 * after all data has been read. Often a no-op. 00191 * 00192 * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding 00193 * application must deal with any cleanup that should happen even 00194 * for error exit. 00195 */ 00196 00197 METHODDEF(void) 00198 term_source (j_decompress_ptr /*cinfo*/) 00199 { 00200 /* no work necessary here */ 00201 } 00202 00203 /* 00204 * Prepare for input from a stdio stream. 00205 * The caller must have already opened the stream, and is responsible 00206 * for closing it after finishing decompression. 00207 */ 00208 00209 GLOBAL(void) 00210 jpeg_vl_src (j_decompress_ptr cinfo, VirtualFile* infile) 00211 { 00212 my_src_ptr src; 00213 00214 /* The source object and input buffer are made permanent so that a series 00215 * of JPEG images can be read from the same file by calling jpeg_stdio_src 00216 * only before the first one. (If we discarded the buffer at the end of 00217 * one image, we'd likely lose the start of the next one.) 00218 * This makes it unsafe to use this manager and a different source 00219 * manager serially with the same JPEG object. Caveat programmer. 00220 */ 00221 if (cinfo->src == NULL) { /* first time for this JPEG object? */ 00222 cinfo->src = (struct jpeg_source_mgr *) 00223 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(my_source_mgr)); 00224 src = (my_src_ptr) cinfo->src; 00225 src->buffer = (JOCTET *) 00226 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, 00227 INPUT_BUF_SIZE * sizeof(JOCTET)); 00228 } 00229 00230 src = (my_src_ptr) cinfo->src; 00231 src->pub.init_source = init_source; 00232 src->pub.fill_input_buffer = fill_input_buffer; 00233 src->pub.skip_input_data = skip_input_data; 00234 src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ 00235 src->pub.term_source = term_source; 00236 src->infile = infile; 00237 src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ 00238 src->pub.next_input_byte = NULL; /* until buffer loaded */ 00239 } 00240 //----------------------------------------------------------------------------- 00241 struct my_error_mgr { 00242 struct jpeg_error_mgr pub; /* "public" fields */ 00243 jmp_buf setjmp_buffer; /* for return to caller */ 00244 }; 00245 00246 typedef struct my_error_mgr * my_error_ptr; 00247 00248 /* 00249 * Here's the routine that will replace the standard error_exit method: 00250 */ 00251 00252 METHODDEF(void) 00253 my_error_exit (j_common_ptr cinfo) 00254 { 00255 /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ 00256 my_error_ptr myerr = (my_error_ptr) cinfo->err; 00257 00258 /* Always display the message. */ 00259 /* We could postpone this until after returning, if we chose. */ 00260 (*cinfo->err->output_message) (cinfo); 00261 00262 /* Return control to the setjmp point */ 00263 longjmp(myerr->setjmp_buffer, 1); 00264 } 00265 00266 //----------------------------------------------------------------------------- 00267 00268 /* Expanded data destination object for stdio output */ 00269 00270 typedef struct { 00271 struct jpeg_destination_mgr pub; /* public fields */ 00272 00273 VirtualFile * outfile; /* target stream */ 00274 JOCTET * buffer; /* start of buffer */ 00275 } my_destination_mgr; 00276 00277 typedef my_destination_mgr * my_dest_ptr; 00278 00279 #define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */ 00280 00281 /* 00282 * Initialize destination --- called by jpeg_start_compress 00283 * before any data is actually written. 00284 */ 00285 00286 METHODDEF(void) 00287 init_destination (j_compress_ptr cinfo) 00288 { 00289 my_dest_ptr dest = (my_dest_ptr) cinfo->dest; 00290 00291 /* Allocate the output buffer --- it will be released when done with image */ 00292 dest->buffer = (JOCTET *) 00293 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, 00294 OUTPUT_BUF_SIZE * sizeof(JOCTET)); 00295 00296 dest->pub.next_output_byte = dest->buffer; 00297 dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; 00298 } 00299 00300 /* 00301 * Empty the output buffer --- called whenever buffer fills up. 00302 * 00303 * In typical applications, this should write the entire output buffer 00304 * (ignoring the current state of next_output_byte & free_in_buffer), 00305 * reset the pointer & count to the start of the buffer, and return TRUE 00306 * indicating that the buffer has been dumped. 00307 * 00308 * In applications that need to be able to suspend compression due to output 00309 * overrun, a FALSE return indicates that the buffer cannot be emptied now. 00310 * In this situation, the compressor will return to its caller (possibly with 00311 * an indication that it has not accepted all the supplied scanlines). The 00312 * application should resume compression after it has made more room in the 00313 * output buffer. Note that there are substantial restrictions on the use of 00314 * suspension --- see the documentation. 00315 * 00316 * When suspending, the compressor will back up to a convenient restart point 00317 * (typically the start of the current MCU). next_output_byte & free_in_buffer 00318 * indicate where the restart point will be if the current call returns FALSE. 00319 * Data beyond this point will be regenerated after resumption, so do not 00320 * write it out when emptying the buffer externally. 00321 */ 00322 00323 METHODDEF(boolean) 00324 empty_output_buffer (j_compress_ptr cinfo) 00325 { 00326 my_dest_ptr dest = (my_dest_ptr) cinfo->dest; 00327 00328 // if (JFWRITE(dest->outfile, dest->buffer, OUTPUT_BUF_SIZE) != (size_t) OUTPUT_BUF_SIZE) 00329 if (dest->outfile->write(dest->buffer, OUTPUT_BUF_SIZE) != (size_t) OUTPUT_BUF_SIZE) 00330 ERREXIT(cinfo, JERR_FILE_WRITE); 00331 00332 dest->pub.next_output_byte = dest->buffer; 00333 dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; 00334 00335 return TRUE; 00336 } 00337 00338 /* 00339 * Terminate destination --- called by jpeg_finish_compress 00340 * after all data has been written. Usually needs to flush buffer. 00341 * 00342 * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding 00343 * application must deal with any cleanup that should happen even 00344 * for error exit. 00345 */ 00346 00347 METHODDEF(void) 00348 term_destination (j_compress_ptr cinfo) 00349 { 00350 my_dest_ptr dest = (my_dest_ptr)cinfo->dest; 00351 size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; 00352 00353 /* Write any data remaining in the buffer */ 00354 if (datacount > 0) { 00355 if (dest->outfile->write(dest->buffer, datacount) != (long long)datacount) 00356 ERREXIT(cinfo, JERR_FILE_WRITE); 00357 } 00358 // fixme? 00359 //fflush(dest->outfile); 00361 //if (ferror(dest->outfile)) 00362 // ERREXIT(cinfo, JERR_FILE_WRITE); 00363 } 00364 00365 /* 00366 * Prepare for output to a stdio stream. 00367 * The caller must have already opened the stream, and is responsible 00368 * for closing it after finishing compression. 00369 */ 00370 00371 GLOBAL(void) 00372 jpeg_vl_dest (j_compress_ptr cinfo, VirtualFile * outfile) 00373 { 00374 my_dest_ptr dest; 00375 00376 /* The destination object is made permanent so that multiple JPEG images 00377 * can be written to the same file without re-executing jpeg_stdio_dest. 00378 * This makes it dangerous to use this manager and a different destination 00379 * manager serially with the same JPEG object, because their private object 00380 * sizes may be different. Caveat programmer. 00381 */ 00382 if (cinfo->dest == NULL) { /* first time for this JPEG object? */ 00383 cinfo->dest = (struct jpeg_destination_mgr *) 00384 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, 00385 sizeof(my_destination_mgr)); 00386 } 00387 00388 dest = (my_dest_ptr) cinfo->dest; 00389 dest->pub.init_destination = init_destination; 00390 dest->pub.empty_output_buffer = empty_output_buffer; 00391 dest->pub.term_destination = term_destination; 00392 dest->outfile = outfile; 00393 } 00394 } 00395 //----------------------------------------------------------------------------- 00396 ref<Image> vl::loadJPG(VirtualFile* file) 00397 { 00398 if ( !file->open(OM_ReadOnly) ) 00399 { 00400 Log::error( Say("loadJPG: cannot open file '%s'\n") << file->path() ); 00401 return NULL; 00402 } 00403 00404 ref<Image> img = new Image; 00405 img->setObjectName(file->path().toStdString().c_str()); 00406 00407 struct jpeg_decompress_struct cinfo; 00408 00409 struct my_error_mgr jerr; 00410 00411 JSAMPARRAY buffer; /* Output row buffer */ 00412 int row_stride; /* physical row width in output buffer */ 00413 00414 /* Step 1: allocate and initialize JPEG decompression object */ 00415 00416 /* We set up the normal JPEG error routines, then override error_exit. */ 00417 cinfo.err = jpeg_std_error(&jerr.pub); 00418 jerr.pub.error_exit = my_error_exit; 00419 00420 // fixme? "warning C4611: interaction between '_setjmp' and C++ object destruction is non-portable" 00421 00422 #if 0 00423 /* Establish the setjmp return context for my_error_exit to use. */ 00424 if (setjmp(jerr.setjmp_buffer)) { 00425 /* If we get here, the JPEG code has signaled an error. 00426 * We need to clean up the JPEG object, close the input file, and return. */ 00427 jpeg_destroy_decompress(&cinfo); 00428 file->close(); 00429 return 0; 00430 } 00431 #endif 00432 00433 /* Now we can initialize the JPEG decompression object. */ 00434 jpeg_create_decompress(&cinfo); 00435 00436 /* Step 2: specify data source (eg, a file) */ 00437 00438 jpeg_vl_src(&cinfo, file); 00439 00440 /* Step 3: read file parameters with jpeg_read_header() */ 00441 00442 jpeg_read_header(&cinfo, TRUE); 00443 00444 if (cinfo.jpeg_color_space == JCS_GRAYSCALE) 00445 { 00446 VL_CHECK(cinfo.out_color_space == JCS_GRAYSCALE) 00447 img->allocate2D(cinfo.image_width, cinfo.image_height, 1, IF_LUMINANCE, IT_UNSIGNED_BYTE); 00448 } 00449 else // JCS_RGB 00450 { 00451 VL_CHECK(cinfo.out_color_space == JCS_RGB) 00452 img->allocate2D(cinfo.image_width, cinfo.image_height, 1, IF_RGB, IT_UNSIGNED_BYTE); 00453 } 00454 00455 /* Step 4: set parameters for decompression */ 00456 00457 // Use defaults set by jpeg_read_header() 00458 00459 /* Step 5: Start decompressor */ 00460 00461 jpeg_start_decompress(&cinfo); 00462 00463 /* JSAMPLEs per row in output buffer */ 00464 row_stride = cinfo.output_width * cinfo.output_components; 00465 /* Make a one-row-high sample array that will go away when done with image */ 00466 buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, 1); 00467 00468 /* Step 6: read scanlines */ 00469 00470 /* Here we use the library's state variable cinfo.output_scanline as the 00471 * loop counter, so that we don't have to keep track ourselves. 00472 */ 00473 while (cinfo.output_scanline < cinfo.output_height) 00474 { 00475 /* jpeg_read_scanlines expects an array of pointers to scanlines. 00476 * Here the array is only one element long, but you could ask for 00477 * more than one scanline at a time if that's more convenient. 00478 */ 00479 jpeg_read_scanlines(&cinfo, buffer, 1); 00480 00481 memcpy(img->pixels() + img->pitch()*(img->height() - cinfo.output_scanline), buffer[0], row_stride); 00482 } 00483 00484 /* Step 7: Finish decompression */ 00485 00486 jpeg_finish_decompress(&cinfo); 00487 00488 /* Step 8: Release JPEG decompression object */ 00489 00490 /* This is an important step since it will release a good deal of memory. */ 00491 jpeg_destroy_decompress(&cinfo); 00492 00493 /* After finish_decompress, we can close the input file. 00494 * Here we postpone it until after no more JPEG errors are possible, 00495 * so as to simplify the setjmp error logic above. (Actually, I don't 00496 * think that jpeg_destroy can do an error exit, but why assume anything...) 00497 */ 00498 file->close(); 00499 00500 return img; 00501 } 00502 //----------------------------------------------------------------------------- 00503 ref<Image> vl::loadJPG(const String& path) 00504 { 00505 ref<VirtualFile> file = defFileSystem()->locateFile(path); 00506 if ( !file ) 00507 { 00508 Log::error( Say("File '%s' not found.\n") << path ); 00509 return NULL; 00510 } 00511 else 00512 return loadJPG(file.get()); 00513 } 00514 //----------------------------------------------------------------------------- 00515 bool vl::isJPG(VirtualFile* file) 00516 { 00517 file->open(OM_ReadOnly); 00518 unsigned char sig1[] = { 0xFF, 0xD8, 0xFF, 0xE0 }; 00519 unsigned char sig2[] = { 0xFF, 0xD8, 0xFF, 0xE1 }; 00520 unsigned char signature[4]; 00521 file->read(signature,4); 00522 file->close(); 00523 bool sig_ok = memcmp(sig1,signature,4) == 0 || memcmp(sig2,signature,4) == 0; 00524 return sig_ok || (file->path().toLowerCase().endsWith(".jpg") || file->path().toLowerCase().endsWith(".jpeg")); 00525 } 00526 //----------------------------------------------------------------------------- 00527 bool vl::saveJPG(const Image* src, const String& path, int quality) 00528 { 00529 ref<DiskFile> file = new DiskFile(path); 00530 return saveJPG(src, file.get(), quality); 00531 } 00532 //----------------------------------------------------------------------------- 00533 bool vl::saveJPG(const Image* src, VirtualFile* fout, int quality) 00534 { 00535 //if (src->dimension() != ID_2D ) 00536 //{ 00537 // Log::error( Say("saveJPG('%s'): can save only 2D images.\n") << fout->path() ); 00538 // return false; 00539 //} 00540 00541 int w = src->width(); 00542 int h = src->height(); 00543 int d = src->depth(); 00544 if (h == 0) h=1; 00545 if (d == 0) d=1; 00546 if (src->isCubemap()) d=6; 00547 h = h*d; 00548 00549 // convert src to IT_UNSIGNED_BYTE / IF_RGB 00550 ref<Image> cimg; 00551 if (src->type() != IT_UNSIGNED_BYTE) 00552 { 00553 cimg = src->convertType(IT_UNSIGNED_BYTE); 00554 src = cimg.get(); 00555 if (!cimg) 00556 { 00557 Log::error( Say("saveJPG('%s'): could not convert image to IT_UNSIGNED_BYTE.\n") << fout->path() ); 00558 return false; 00559 } 00560 } 00561 if (src->format() != IF_RGB) 00562 { 00563 cimg = src->convertFormat(IF_RGB); 00564 src = cimg.get(); 00565 if (!cimg) 00566 { 00567 Log::error( Say("saveJPG('%s'): could not convert image to IF_RGB.\n") << fout->path() ); 00568 return false; 00569 } 00570 } 00571 00572 if(!fout->open(OM_WriteOnly)) 00573 { 00574 Log::error( Say("JPG: could not write to '%s'.\n") << fout->path() ); 00575 return false; 00576 } 00577 00578 /* This struct contains the JPEG compression parameters and pointers to 00579 * working space (which is allocated as needed by the JPEG library). 00580 * It is possible to have several such structures, representing multiple 00581 * compression/decompression processes, in existence at once. We refer 00582 * to any one struct (and its associated working data) as a "JPEG object". 00583 */ 00584 struct jpeg_compress_struct cinfo; 00585 00586 /* This struct represents a JPEG error handler. It is declared separately 00587 * because applications often want to supply a specialized error handler 00588 * (see the second half of this file for an example). But here we just 00589 * take the easy way out and use the standard error handler, which will 00590 * print a message on stderr and call exit() if compression fails. 00591 * Note that this struct must live as long as the main JPEG parameter 00592 * struct, to avoid dangling-pointer problems. 00593 */ 00594 struct jpeg_error_mgr jerr; 00595 00596 JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ 00597 int row_stride; /* physical row width in image buffer */ 00598 00599 /* Step 1: allocate and initialize JPEG compression object */ 00600 00601 /* We have to set up the error handler first, in case the initialization 00602 * step fails. (Unlikely, but it could happen if you are out of memory.) 00603 * This routine fills in the contents of struct jerr, and returns jerr's 00604 * address which we place into the link field in cinfo. 00605 */ 00606 cinfo.err = jpeg_std_error(&jerr); 00607 00608 /* Now we can initialize the JPEG compression object. */ 00609 jpeg_create_compress(&cinfo); 00610 00611 /* Step 2: specify data destination (eg, a file) */ 00612 /* Note: steps 2 and 3 can be done in either order. */ 00613 00615 // * stdio stream. You can also write your own code to do something else. 00616 // * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that 00617 // * requires it in order to write binary files. 00618 // */ 00619 //if ((outfile = fopen(filename, "wb")) == NULL) { 00620 // fprintf(stderr, "can't open %s\n", filename); 00621 // exit(1); 00622 //} 00623 //jpeg_stdio_dest(&cinfo, outfile); 00624 jpeg_vl_dest(&cinfo, fout); 00625 00626 /* Step 3: set parameters for compression */ 00627 00628 /* First we supply a description of the input image. 00629 * Four fields of the cinfo struct must be filled in: 00630 */ 00631 cinfo.image_width = w; /* image width and height, in pixels */ 00632 cinfo.image_height = h; 00633 cinfo.input_components = 3; /* # of color components per pixel */ 00634 cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ 00635 00636 /* Now use the library's routine to set default compression parameters. 00637 * (You must set at least cinfo.in_color_space before calling this, 00638 * since the defaults depend on the source color space.) 00639 */ 00640 jpeg_set_defaults(&cinfo); 00641 00642 /* Now you can set any non-default parameters you wish to. 00643 * Here we just illustrate the use of quality (quantization table) scaling: */ 00644 jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); 00645 00646 /* Step 4: Start compressor */ 00647 00648 /* TRUE ensures that we will write a complete interchange-JPEG file. 00649 * Pass TRUE unless you are very sure of what you're doing. 00650 */ 00651 jpeg_start_compress(&cinfo, TRUE); 00652 00653 /* Step 5: while (scan lines remain to be written) */ 00654 /* jpeg_write_scanlines(...); */ 00655 00656 /* Here we use the library's state variable cinfo.next_scanline as the 00657 * loop counter, so that we don't have to keep track ourselves. 00658 * To keep things simple, we pass one scanline per call; you can pass 00659 * more if you wish, though. 00660 */ 00661 row_stride = w * 3; /* JSAMPLEs per row in image_buffer */ 00662 00663 while (cinfo.next_scanline < cinfo.image_height) 00664 { 00665 /* jpeg_write_scanlines expects an array of pointers to scanlines. 00666 * Here the array is only one element long, but you could pass 00667 * more than one scanline at a time if that's more convenient. 00668 */ 00669 row_pointer[0] = (JSAMPROW)(src->pixels() + (h - 1 - cinfo.next_scanline) * row_stride); 00670 jpeg_write_scanlines(&cinfo, row_pointer, 1); 00671 } 00672 00673 /* Step 6: Finish compression */ 00674 00675 jpeg_finish_compress(&cinfo); 00676 00677 /* Step 7: release JPEG compression object */ 00678 00679 /* This is an important step since it will release a good deal of memory. */ 00680 jpeg_destroy_compress(&cinfo); 00681 00682 /* And we're done! */ 00683 00684 fout->close(); 00685 return true; 00686 } 00687 //-----------------------------------------------------------------------------