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