# Visualization Library

A lightweight C++ OpenGL middleware for 2D/3D graphics

[Home] [Tutorials] [All Classes] [Grouped Classes]

- Main Page
- Related Pages
- Namespaces
- Classes
- Files

- File List
- File Members

# D:/VL/BuildSystem/VL_DISTRO/Visualization_Library_SDK/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 v2011.09.1162 Reference Documentation
Copyright 2005-2011 Michele Bosi. All rights reserved.
Updated on Thu Jan 26 2012 00:43:30.
Permission is granted to use this page to write and publish articles regarding Visualization Library.