JPEGUtil.C

00001 #include "Image/JPEGUtil.H"
00002 
00003 
00004 #include <vector>
00005 #include <math.h>
00006 
00007 #define INPUT_BUF_SIZE  4096LU
00008 //The output buffer size... I believe this should be as large as possible
00009 //so that empty_output_buffer will never need to be called as an intermediary
00010 //step, and we can just rely on term_destination to write all of our data
00011 #define OUTPUT_BUF_SIZE  100000
00012 
00013 
00014 namespace IIDC_NS
00015 {
00016   typedef struct
00017   {
00018     //The public fields common to source managers
00019     struct jpeg_source_mgr pub;
00020 
00021     //The compressed image source base pointer
00022     std::vector<unsigned char>* src_vec;
00023     int curr_src_pos;
00024 
00025     //The output buffer pointer
00026     JOCTET* buffer;
00027 
00028   } buff_src_mgr;
00029 
00030 
00031   ////////////////////////////////////////////////////////////////
00032   // Initialize the source -- called by jpeg_read_header before
00033   // any data is actually read
00034   ////////////////////////////////////////////////////////////////
00035   METHODDEF(void)
00036     init_source (j_decompress_ptr cinfo)
00037     {
00038       buff_src_mgr* src = (buff_src_mgr*) cinfo->src;
00039       src->curr_src_pos = 0;
00040     }
00041 
00042   ////////////////////////////////////////////////////////////////
00043   // Fill the input buffer -- called whenever bytes_in_buffer is 0
00044   ////////////////////////////////////////////////////////////////
00045   METHODDEF(boolean)
00046     fill_input_buffer (j_decompress_ptr cinfo)
00047     {
00048 
00049       buff_src_mgr* src = (buff_src_mgr*) cinfo->src;
00050 
00051       size_t nbytes;
00052 
00053       nbytes = std::min(INPUT_BUF_SIZE, (long unsigned int)(src->src_vec->size() - src->curr_src_pos));
00054       unsigned char* src_base = &((*(src->src_vec))[0]);
00055 
00056 
00057       src->pub.next_input_byte =  src_base + src->curr_src_pos;
00058       src->pub.bytes_in_buffer = nbytes;
00059       src->curr_src_pos += nbytes;
00060 
00061       return TRUE;
00062     }
00063 
00064   ////////////////////////////////////////////////////////////////
00065   // Skip input data -- Skips num_bytes worth of data without
00066   // putting it into the buffer
00067   ////////////////////////////////////////////////////////////////
00068   METHODDEF(void)
00069     skip_input_data (j_decompress_ptr cinfo, long num_bytes)
00070     {
00071       buff_src_mgr* src = (buff_src_mgr*) cinfo->src;
00072 
00073       src->curr_src_pos += num_bytes;
00074 
00075       src->pub.next_input_byte += (size_t) num_bytes;
00076       src->pub.bytes_in_buffer -= (size_t) num_bytes;
00077     }
00078 
00079   ////////////////////////////////////////////////////////////////
00080   // Terminate source -- Nothing to do here
00081   ////////////////////////////////////////////////////////////////
00082   METHODDEF(void)
00083     term_source (j_decompress_ptr cinfo)
00084     {
00085       /* no work necessary here */
00086     }
00087 
00088 }
00089 
00090 namespace IIC_NS
00091 {
00092   typedef struct {
00093     //The public fields common to destination managers
00094     struct jpeg_destination_mgr pub;
00095 
00096     //The input buffer pointer
00097     JOCTET* in_buffer;
00098 
00099     //The destination queue of
00100     std::vector<unsigned char>* out_buffer;
00101 
00102   } buff_dest_mgr;
00103 
00104   ////////////////////////////////////////////////////////////////
00105   // Initialize destination --- called by jpeg_start_compress
00106   // before any data is actually written.
00107   ////////////////////////////////////////////////////////////////
00108   METHODDEF(void) init_destination(j_compress_ptr cinfo)
00109   {
00110     //Get the pointer to our cinfo's destination manager
00111     buff_dest_mgr* dest = (buff_dest_mgr*) cinfo->dest;
00112 
00113     //Allocate the input buffer --- it will be released when done with image
00114     dest->in_buffer = (JOCTET *)
00115       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
00116           OUTPUT_BUF_SIZE * sizeof(JOCTET));
00117 
00118     //Reset the input buffer
00119     dest->pub.next_output_byte = dest->in_buffer;
00120     dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
00121   }
00122 
00123   ////////////////////////////////////////////////////////////////
00124   // Empty the output buffer --- called whenever buffer fills up.
00125   ////////////////////////////////////////////////////////////////
00126   METHODDEF(boolean) empty_output_buffer (j_compress_ptr cinfo)
00127   {
00128     //Get the pointer to our cinfo's destination manager
00129     buff_dest_mgr* dest = (buff_dest_mgr*) cinfo->dest;
00130 
00131     //Copy the rest of the input buffer onto the end of our output buffer
00132     dest->out_buffer->insert(dest->out_buffer->end(),
00133         dest->in_buffer,
00134         dest->in_buffer+OUTPUT_BUF_SIZE);
00135 
00136     //Reset the input buffer
00137     dest->pub.next_output_byte = dest->in_buffer;
00138     dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
00139 
00140     return TRUE;
00141   }
00142 
00143   ////////////////////////////////////////////////////////////////
00144   // Terminate destination --- called by jpeg_finish_compress
00145   // after all data has been written.  Usually needs to flush buffer.
00146   ////////////////////////////////////////////////////////////////
00147   METHODDEF(void) term_destination (j_compress_ptr cinfo)
00148   {
00149     //Get the pointer to our cinfo's destination manager
00150     buff_dest_mgr* dest = (buff_dest_mgr*) cinfo->dest;
00151 
00152     //Calculate the number of bytes left to be written
00153     size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
00154 
00155     //Copy the rest of the input buffer onto the end of our output buffer
00156     dest->out_buffer->insert(dest->out_buffer->end(),
00157         dest->in_buffer,
00158         dest->in_buffer+datacount);
00159   }
00160 
00161 
00162 }
00163 
00164 ///////////////////////////////////////////////////////////////////////////////
00165 
00166 // constuctor does nothing, maybe that needs FIXME
00167 JPEGDecompressor::JPEGDecompressor()
00168 { }
00169 
00170 ////////////////////////////////////////////////////////////////
00171 // Decompress an Image -- Pass this function an std::vector
00172 // filled with data from a compressed jpeg image, and it will
00173 // return to you an uncompressed Image< PixRGB<byte> >
00174 ////////////////////////////////////////////////////////////////
00175 Image<PixRGB<byte> > JPEGDecompressor::DecompressImage(std::vector<unsigned char> &source_buffer)
00176 {
00177   //Initialize our jpeg error handler to the default
00178   //(spit out non-fatal error messages on cerr, and
00179   // exit() on fatal errors)
00180   cinfo.err = jpeg_std_error(&jerr);
00181 
00182   //Create our jpeg decompression object
00183   jpeg_create_decompress(&cinfo);
00184 
00185   InitImageSource(&source_buffer);
00186 
00187   int ret =  jpeg_read_header(&cinfo, TRUE);
00188   if (ret != JPEG_HEADER_OK)
00189     return Image<PixRGB<byte> >();
00190 
00191   (void) jpeg_start_decompress(&cinfo);
00192 
00193 
00194   assert(cinfo.output_components == 3);
00195   Image<PixRGB<byte> > outputImg(cinfo.output_width, cinfo.output_height, NO_INIT);
00196   JSAMPLE* img_ptr = reinterpret_cast<JSAMPLE*>(outputImg.getArrayPtr());
00197 
00198   int row_stride = cinfo.output_width * cinfo.output_components;
00199 
00200   JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray)
00201     ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
00202 
00203   while(cinfo.output_scanline < cinfo.output_height)
00204   {
00205     (void) jpeg_read_scanlines(&cinfo, buffer, 1);
00206     std::memcpy(img_ptr, *buffer, row_stride);
00207     img_ptr+=row_stride;
00208   }
00209 
00210 
00211   (void) jpeg_finish_decompress(&cinfo);
00212   jpeg_destroy_decompress(&cinfo);
00213 
00214   return outputImg;
00215 }
00216 
00217 
00218 ////////////////////////////////////////////////////////////////
00219 // Initialize image source -- Just set up some variables and
00220 // allocate some buffer space (if necessary) for the
00221 // decompressor
00222 ////////////////////////////////////////////////////////////////
00223 GLOBAL(void) JPEGDecompressor::InitImageSource(std::vector<unsigned char>* source_buffer)
00224 {
00225   IIDC_NS::buff_src_mgr* src;
00226 
00227   //Allocate the source buffer
00228   if (cinfo.src == NULL)
00229   {        /* first time for this JPEG object? */
00230 
00231     cinfo.src = (struct jpeg_source_mgr *)
00232       (*cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_PERMANENT,
00233           sizeof(IIDC_NS::buff_src_mgr));
00234 
00235     src = (IIDC_NS::buff_src_mgr*) cinfo.src;
00236 
00237     src->buffer = (JOCTET *)
00238       (*cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_PERMANENT,
00239           INPUT_BUF_SIZE * sizeof(JOCTET));
00240   }
00241 
00242 
00243   src = (IIDC_NS::buff_src_mgr*) cinfo.src;
00244   src->pub.init_source = IIDC_NS::init_source;
00245   src->pub.fill_input_buffer = IIDC_NS::fill_input_buffer;
00246   src->pub.skip_input_data = IIDC_NS::skip_input_data;
00247   src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
00248   src->pub.term_source = IIDC_NS::term_source;
00249   src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
00250   src->pub.next_input_byte = NULL; /* until buffer loaded */
00251 
00252   src->src_vec      = source_buffer;
00253   src->curr_src_pos = 0;
00254 
00255 }
00256 ///////////////////////////////////////////////////////////////////////////////
00257 
00258 JPEGCompressor::JPEGCompressor()
00259 {
00260 
00261         //Initialize our jpeg error handler to the default
00262   //(spit out non-fatal error messages on cerr, and
00263   // exit() on fatal errors)
00264   cinfo.err = jpeg_std_error(&jerr);
00265 
00266   //Create our jpeg compression object
00267   jpeg_create_compress(&cinfo);
00268 
00269 }
00270 
00271 std::vector<unsigned char> JPEGCompressor::compressImage(Image<PixRGB<byte> >& input)
00272 {
00273         std::vector<unsigned char> jpeg_buffer;
00274 
00275   //Initialize our data destination
00276   InitImageDest(&jpeg_buffer);
00277 
00278   //Set our image and compression parameters
00279   cinfo.image_width   = input.getWidth();
00280   cinfo.image_height  = input.getHeight();
00281   cinfo.input_components = 3;
00282   cinfo.in_color_space = JCS_RGB;
00283   jpeg_set_defaults(&cinfo);
00284 
00285   //Begin the compression
00286   jpeg_start_compress(&cinfo, TRUE);
00287 
00288   //Get a pointer to the start of the image's raw data array. This assumes that
00289   //all of the image data is layed out as R G B R G B, with each element as a
00290   //byte in contiguous memory. This should be a valid assumption for any
00291   //Image<PixRGB<byte> >
00292   JSAMPLE* p_start = reinterpret_cast<JSAMPLE*>(input.getArrayPtr());
00293 
00294   //Pass a pointer to each row of the image to the jpeg compressor.  It would
00295   //be nice to do this all in one shot, but libjpeg segfaults when I try.
00296   for(int row_idx=0; row_idx<input.getHeight(); row_idx++)
00297   {
00298     JSAMPLE* p = (p_start + (row_idx * input.getWidth()*3) );
00299     jpeg_write_scanlines(&cinfo, &p, 1);
00300   }
00301 
00302   //Clean up the compression, and finish writing all bytes to the output buffer
00303   jpeg_finish_compress(&cinfo);
00304 
00305   return jpeg_buffer;
00306 
00307 }
00308 
00309 GLOBAL(void) JPEGCompressor::InitImageDest(std::vector<unsigned char>* destination_buffer)
00310 {
00311 
00312  IIC_NS::buff_dest_mgr* dest;
00313 
00314   if(cinfo.dest == NULL)
00315   {
00316     //Allocate some memory space for our destination manager.
00317     cinfo.dest = (struct jpeg_destination_mgr *)
00318       (*(cinfo.mem->alloc_small)) ((j_common_ptr) &cinfo, JPOOL_PERMANENT, sizeof(IIC_NS::buff_dest_mgr));
00319   }
00320 
00321   //Initialize our destination manager by filling in all of the appropriate
00322   //function pointers, and assigning the output buffer.
00323   dest = (IIC_NS::buff_dest_mgr*) cinfo.dest;
00324   dest->pub.init_destination    = IIC_NS::init_destination;
00325   dest->pub.empty_output_buffer = IIC_NS::empty_output_buffer;
00326   dest->pub.term_destination    = IIC_NS::term_destination;
00327   dest->out_buffer              = destination_buffer;
00328 
00329 }
00330 
00331 
00332 
Generated on Sun May 8 08:05:12 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3