core/vil/file_formats/vil_jpeg_decompressor.cxx
Go to the documentation of this file.
00001 // This is core/vil/file_formats/vil_jpeg_decompressor.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 // \author fsm
00008 // \verbatim
00009 //  Modifications
00010 //     11 Oct 2002 Ian Scott - converted to vil
00011 //\endverbatim
00012 
00013 #include "vil_jpeg_decompressor.h"
00014 #include "vil_jpeg_source_mgr.h"
00015 #include <vil/vil_stream.h>
00016 #include <vcl_iostream.h>
00017 #include <vxl_config.h>
00018 
00019 #define trace if (true) { } else vcl_cerr
00020 
00021 //: using jpeg decompressor objects :
00022 // -# supply an error manager, e.g. with jpeg_std_err().
00023 //    this \e must be done before initializing the object.
00024 // -# initialize with jpeg_create_decompress().
00025 // -# supply a data stream, e.g. with jpeg_std_source().
00026 // -# call jpeg_read_header() to start reading the data stream. this will read
00027 //    to the start of the compressed data and store various tables and parameters.
00028 //    if you just want the image parameters and not the data, it's ok to stop
00029 //    now, so long as you call jpeg_abort_decompress() or jpeg_destroy_decompress()
00030 //    to release resources.
00031 // -# call jpeg_finish_decompress() if you read all the data. if you only read
00032 //    some of the data, call jpeg_abort_decompress().
00033 // -# destruct the object with jpeg_destroy_decompress().
00034 
00035 vil_jpeg_decompressor::vil_jpeg_decompressor(vil_stream *s)
00036   : stream(s)
00037   , ready(false)
00038   , valid(false)
00039   , biffer(0)
00040 {
00041   stream->ref();
00042 
00043   // setup the standard error handler in the jpeg library
00044   jobj.err = jpeg_std_error(&jerr);
00045 
00046   // construct the decompression object :
00047   jpeg_create_decompress(&jobj);
00048 
00049   // Increase the amount of memory that can be used.
00050   // Default (1Mb) was too small.
00051 #if defined(VXL_ADDRESS_BITS) && VXL_ADDRESS_BITS == 32
00052   jobj.mem->max_memory_to_use = 300 * 1024 * 1024;
00053 #elif defined(VXL_ADDRESS_BITS) && VXL_ADDRESS_BITS == 64
00054   jobj.mem->max_memory_to_use = 1024 * 1024 * 1024;
00055 #else
00056   /* use the default memory settings */
00057 #endif
00058 
00059   // we need to read the header here, in order to get parameters such as size.
00060   //
00061   // set the data source
00062   vil_jpeg_stream_src_set(&jobj, stream);
00063 
00064   // rewind the stream
00065   vil_jpeg_stream_src_rewind(&jobj, stream);
00066 
00067   // now we may read the header.
00068   jpeg_read_header(&jobj, TRUE);
00069 
00070   // This seems to be necessary. jpeglib.h claims that one can use
00071   // jpeg_calc_output_dimensions() instead, but I never bothered to try.
00072 #if 1
00073   // bogus decompression to get image parameters.
00074   jpeg_start_decompress(&jobj);
00075 
00076   // this aborts the decompression, but doesn't destroy the object.
00077   jpeg_abort_decompress(&jobj);
00078 #endif
00079 }
00080 
00081 // read the given scanline, skipping/rewinding as required.
00082 JSAMPLE const *vil_jpeg_decompressor::read_scanline(unsigned line)
00083 {
00084   // if the client tries to read the same scanline again, it should be free.
00085   if (valid && line == jobj.output_scanline-1)
00086     return biffer;
00087 
00088   if (ready && line<jobj.output_scanline) {
00089     trace << "...aborting\n";
00090     // bah! have to restart
00091     jpeg_abort_decompress(&jobj);
00092 
00093     //
00094     ready = false;
00095     valid = false;
00096   }
00097 
00098   if (!ready) {
00099     trace << "...restarting\n";
00100 
00101     // rewind stream
00102     vil_jpeg_stream_src_rewind(&jobj, stream);
00103 
00104     // read header
00105     jpeg_read_header(&jobj, TRUE);
00106 
00107     // start decompression
00108     jpeg_start_decompress(&jobj);
00109 
00110     //
00111     ready = true;
00112     valid = false;
00113   }
00114 
00115   // allocate scanline buffer, if necessary.
00116   if (!biffer) {
00117     trace << "...allocate buffer\n";
00118     unsigned row_size = jobj.output_width * jobj.output_components;
00119     biffer = new JSAMPLE[row_size];
00120   }
00121 
00122   // 'buffer' is a pointer to a 1-element array whose 0th element is biffer.
00123 #if 0
00124   JSAMPLE *buffer[1] = { biffer };
00125 #else
00126   JSAMPARRAY buffer = &biffer;
00127 #endif
00128 
00129   // read till we've read the line we want :
00130   while (jobj.output_scanline <= line) {
00131     if (jpeg_read_scanlines(&jobj, buffer, 1) != 1) {
00132       jpeg_abort_decompress(&jobj);
00133       ready = false;
00134       valid = false;
00135       return 0;
00136     }
00137   }
00138 
00139   // end reached ?
00140   if (jobj.output_scanline >= jobj.image_height) {
00141     trace << "...reached end\n";
00142     jpeg_finish_decompress(&jobj); // this will call vil_jpeg_term_source()
00143     ready = false;
00144   }
00145 
00146   // success.
00147   valid = true; // even if we have reached the end.
00148   return biffer;
00149 }
00150 
00151 
00152 vil_jpeg_decompressor::~vil_jpeg_decompressor()
00153 {
00154   // destroy the pool associated with jobj
00155   (*jobj.mem->free_pool) ((j_common_ptr) &jobj, JPOOL_IMAGE);
00156 
00157   // destroy the decompression object
00158   jpeg_destroy_decompress(&jobj);
00159 
00160   //
00161   stream->unref();
00162   stream = 0;
00163 
00164   //
00165   if (biffer)
00166     delete [] biffer;
00167   biffer = 0;
00168 }