Visualization Library

A lightweight C++ OpenGL middleware for 2D/3D graphics
[Home] [Tutorials] [All Classes] [Grouped Classes]

X:/dropbox/visualizationlibrary/src/vlCore/plugins/ioJPG.cpp

Go to the documentation of this file.
00001 /**************************************************************************************/
00002 /*                                                                                    */
00003 /*  Visualization Library                                                             */
00004 /*  http://www.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 //-----------------------------------------------------------------------------

Visualization Library 2011.09.1160 Reference Documentation
Copyright 2005-2011 Michele Bosi. All rights reserved.
Updated on Thu May 2 2013 13:40:30.
Permission is granted to use this page to write and publish articles regarding Visualization Library.