Fawkes API Fawkes Development Version

jpeg_compressor.cpp

00001 
00002 /***************************************************************************
00003  *  jpeg.cpp - JPEG image compressor
00004  *
00005  *  Generated: Sat Aug 12 13:42:39 2006 (in LFI of Central Medical Library
00006  *                                       of Germany, Cologne)
00007  *  Copyright  2005-2007  Tim Niemueller [www.niemueller.de]
00008  *
00009  ****************************************************************************/
00010 
00011 /*  This program is free software; you can redistribute it and/or modify
00012  *  it under the terms of the GNU General Public License as published by
00013  *  the Free Software Foundation; either version 2 of the License, or
00014  *  (at your option) any later version. A runtime exception applies to
00015  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00016  *
00017  *  This program is distributed in the hope that it will be useful,
00018  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020  *  GNU Library General Public License for more details.
00021  *
00022  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00023  */
00024 
00025 
00026 #include <fvutils/compression/jpeg_compressor.h>
00027 #include <fvutils/color/yuvrgb.h>
00028 #include <fvutils/color/rgbyuv.h>
00029 
00030 #include <core/exception.h>
00031 
00032 #include <cstdio>
00033 #include <cstring>
00034 #include <cstdlib>
00035 #include <setjmp.h>
00036 extern "C" {
00037 #include <jpeglib.h>
00038 #include <jerror.h>
00039 }
00040 
00041 namespace firevision {
00042 #if 0 /* just to make Emacs auto-indent happy */
00043 }
00044 #endif
00045 
00046 ///@cond INTERNALS
00047 
00048 /** JPEG error manager type. */
00049 typedef struct {
00050   struct jpeg_error_mgr pub;    /**< manager */
00051   jmp_buf setjmp_buffer;        /**< jmp buffer */
00052 } fv_jpeg_error_mgr_t;
00053 
00054 
00055 /** Defines a new destination manager to store images in memory
00056  * derived by jdatadst.c
00057  */
00058 typedef struct {
00059   struct jpeg_destination_mgr pub;      /**< public fields */
00060   JOCTET *buffer;                       /**< start of buffer */
00061   int bufsize;                          /**< buffer size */
00062   int datacount;                        /**< final data size */
00063 } fv_jpeg_memory_destination_mgr_t;
00064 
00065 
00066 /** Initialize destination
00067  * called by jpeg_start_compress before any data is actually written.
00068  * @param cinfo compression info
00069  */
00070 METHODDEF(void)
00071 fv_jpeg_init_destination (j_compress_ptr cinfo)
00072 {
00073   fv_jpeg_memory_destination_mgr_t *dest = (fv_jpeg_memory_destination_mgr_t *) cinfo->dest;
00074   dest->pub.next_output_byte = dest->buffer;
00075   dest->pub.free_in_buffer = dest->bufsize;
00076   dest->datacount=0;
00077 }
00078 
00079 /** Empty the output buffer
00080  * called whenever buffer fills up.
00081  * @param cinfo compression info
00082  */
00083 METHODDEF(boolean)
00084 fv_jpeg_empty_output_buffer (j_compress_ptr cinfo)
00085 {
00086   fv_jpeg_memory_destination_mgr_t *dest = (fv_jpeg_memory_destination_mgr_t *) cinfo->dest;
00087   dest->pub.next_output_byte = dest->buffer;
00088   dest->pub.free_in_buffer = dest->bufsize;
00089 
00090   return TRUE;
00091 }
00092 
00093 /** Terminate destination
00094  * called by jpeg_finish_compress after all data has been written.
00095  * Usually needs to flush buffer.
00096  * @param cinfo compression info
00097  */
00098 METHODDEF(void)
00099 fv_jpeg_term_destination (j_compress_ptr cinfo)
00100 {
00101   /* expose the finale compressed image size */
00102 
00103   fv_jpeg_memory_destination_mgr_t *dest = (fv_jpeg_memory_destination_mgr_t *) cinfo->dest;
00104   dest->datacount = dest->bufsize - dest->pub.free_in_buffer;
00105 }
00106 
00107 /** Setup memory destination.
00108  * @param cinfo compression info
00109  * @param buffer buffer
00110  * @param bufsize buffer size
00111  */
00112 GLOBAL(void)
00113 fv_jpeg_memory_destination_setup(j_compress_ptr cinfo, JOCTET *buffer,int bufsize)
00114 {
00115   fv_jpeg_memory_destination_mgr_t *dest;
00116   if ( cinfo->dest == NULL ) {
00117     cinfo->dest = (struct jpeg_destination_mgr *)
00118       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
00119                                   sizeof(fv_jpeg_memory_destination_mgr_t));
00120     
00121   }
00122 
00123   dest = (fv_jpeg_memory_destination_mgr_t *) cinfo->dest;
00124   dest->bufsize = bufsize;
00125   dest->buffer = buffer;
00126   dest->pub.init_destination = fv_jpeg_init_destination;
00127   dest->pub.empty_output_buffer = fv_jpeg_empty_output_buffer;
00128   dest->pub.term_destination = fv_jpeg_term_destination;
00129 }
00130 
00131 METHODDEF(void)
00132 init_source(j_decompress_ptr cinfo)
00133 {
00134   /* nothing to do */
00135 }
00136 
00137 METHODDEF(boolean)
00138 fill_input_buffer(j_decompress_ptr cinfo)
00139 {
00140   /* can't fill */
00141   return FALSE; 
00142 }
00143 
00144 METHODDEF(void)
00145 skip_input_data(j_decompress_ptr cinfo, long num_bytes)
00146 {
00147   if ((size_t)num_bytes > cinfo->src->bytes_in_buffer) {
00148     cinfo->src->next_input_byte = NULL;
00149     cinfo->src->bytes_in_buffer = 0;
00150   } else {
00151     cinfo->src->next_input_byte += (size_t) num_bytes;
00152     cinfo->src->bytes_in_buffer -= (size_t) num_bytes;
00153   }
00154 }
00155 
00156 METHODDEF(void)
00157 term_source(j_decompress_ptr cinfo)
00158 {
00159   /* nothing to do */
00160 }
00161 
00162 
00163 /**
00164  * set momory-jpeg image to JPEG lib Info struct
00165  * @param cinfo  JPEG lib decompress infomation structure
00166  * @param ptr    JPEG image 
00167  * @param size   JPEG image size
00168  */
00169 GLOBAL(void)
00170 fv_jpeg_memory_source_setup(j_decompress_ptr cinfo, unsigned char *ptr, size_t size)
00171 {
00172     struct jpeg_source_mgr *src;
00173     src = cinfo->src = (struct jpeg_source_mgr *)
00174       (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, 
00175                                   JPOOL_PERMANENT,
00176                                   sizeof(*src));
00177     src->init_source       = init_source;
00178     src->fill_input_buffer = fill_input_buffer;
00179     src->skip_input_data   = skip_input_data;
00180     src->resync_to_restart = jpeg_resync_to_restart;
00181     src->term_source       = term_source;
00182     src->next_input_byte   = ptr;
00183     src->bytes_in_buffer   = size;
00184 }
00185 
00186 /// @endcond
00187 
00188 /** @class JpegImageCompressor <fvutils/compression/jpeg_compressor.h>
00189  * Jpeg image compressor.
00190  */
00191 
00192 
00193 /** Constructor.
00194  * @param quality JPEG quality in percent
00195  * @param jcs Jpeg colorspace
00196  */
00197 JpegImageCompressor::JpegImageCompressor(unsigned int quality, JpegColorspace jcs)
00198 {
00199   this->quality = quality;
00200   jpeg_cs = jcs;
00201 }
00202 
00203 /** Destructor. */
00204 JpegImageCompressor::~JpegImageCompressor()
00205 {
00206 }
00207 
00208 
00209 void
00210 JpegImageCompressor::compress()
00211 {
00212   struct jpeg_compress_struct cinfo;
00213   struct jpeg_error_mgr jerr;
00214   unsigned int row_stride;
00215   unsigned char *row_buffer;
00216 
00217   // mem destination specific
00218   fv_jpeg_memory_destination_mgr_t *dest;
00219 
00220   // file destination specific
00221   FILE *outfile = NULL;
00222 
00223   /* zero out the compression info structure and
00224      allocate a new compressor handle */
00225   memset (&cinfo, 0, sizeof(cinfo));
00226   cinfo.err = jpeg_std_error(&jerr);
00227   jpeg_create_compress(&cinfo);
00228  
00229   /* Setup JPEG datastructures */
00230   cinfo.image_width = width;      /* image width and height, in pixels */
00231   cinfo.image_height = height;
00232   cinfo.input_components = 3;     /* # of color components per pixel=3 RGB */
00233   if ( jpeg_cs == JPEG_CS_RGB ) {
00234     cinfo.in_color_space = JCS_RGB;
00235   } else {
00236     cinfo.in_color_space = JCS_YCbCr;
00237   }
00238 
00239   row_stride = cinfo.image_width * cinfo.input_components;
00240 
00241   if ( compdest == COMP_DEST_MEM ) {
00242     // mem
00243     fv_jpeg_memory_destination_setup(&cinfo, (JOCTET *)jpeg_buffer, jpeg_buffer_size);
00244   } else {
00245     outfile = fopen(filename, "wb");
00246     if (outfile == NULL) {
00247       throw fawkes::Exception("JpegImageCompressor: cannot open %s\n", filename);
00248     }
00249     jpeg_stdio_dest( &cinfo, outfile );
00250   }
00251   /* Setup compression */
00252   jpeg_set_defaults(&cinfo);
00253   jpeg_set_quality (&cinfo, quality, true /* limit to baseline-JPEG values */);
00254   jpeg_start_compress(&cinfo, true);
00255 
00256   /* compress each scanline one-at-a-time */
00257   row_buffer = (unsigned char *)malloc( row_stride );
00258 
00259 
00260   if ( jpeg_cs == JPEG_CS_RGB ) {
00261     while (cinfo.next_scanline < cinfo.image_height) {
00262       convert_line_yuv422planar_to_rgb( buffer, row_buffer,
00263                                         cinfo.image_width, cinfo.image_height,
00264                                         cinfo.next_scanline, 0 );
00265       jpeg_write_scanlines(&cinfo, &row_buffer, 1);
00266     }
00267   } else {
00268     while (cinfo.next_scanline < cinfo.image_height) {
00269       convert_line_yuv422planar_to_yuv444packed( buffer, row_buffer,
00270                                                  cinfo.image_width, cinfo.image_height,
00271                                                  cinfo.next_scanline, 0 );
00272       jpeg_write_scanlines(&cinfo, &row_buffer, 1);
00273     }
00274   }
00275 
00276   free(row_buffer);
00277   jpeg_finish_compress(&cinfo);
00278 
00279   if ( compdest == COMP_DEST_MEM ) {
00280     /* Now extract the size of the compressed buffer */
00281     dest=(fv_jpeg_memory_destination_mgr_t *)cinfo.dest;
00282     jpeg_bytes = dest->datacount; /* the actual compressed datasize */
00283   } else {
00284     fclose( outfile );
00285   }
00286 
00287   /* destroy the compressor handle */
00288   jpeg_destroy_compress(&cinfo);
00289 
00290 }
00291 
00292 
00293 void
00294 JpegImageCompressor::set_image_dimensions(unsigned int width, unsigned int height)
00295 {
00296   this->width = width;
00297   this->height = height;
00298 }
00299 
00300 
00301 void
00302 JpegImageCompressor::set_image_buffer(colorspace_t cspace, unsigned char *buffer)
00303 {
00304   if ( cspace == YUV422_PLANAR ) {
00305     this->buffer = buffer;
00306   }
00307 }
00308 
00309 
00310 void
00311 JpegImageCompressor::set_compression_destination(ImageCompressor::CompressionDestination cd)
00312 {
00313   compdest = cd;
00314 }
00315 
00316 
00317 bool
00318 JpegImageCompressor::supports_compression_destination(ImageCompressor::CompressionDestination cd)
00319 {
00320   return true;
00321 }
00322 
00323 
00324 void
00325 JpegImageCompressor::set_destination_buffer(unsigned char *buf, unsigned int buf_size)
00326 {
00327   jpeg_buffer = buf;
00328   jpeg_buffer_size = buf_size;
00329 }
00330 
00331 
00332 size_t
00333 JpegImageCompressor::compressed_size()
00334 {
00335   return jpeg_bytes;
00336 }
00337 
00338 size_t
00339 JpegImageCompressor::recommended_compressed_buffer_size()
00340 {
00341   return width * height / 5;
00342 }
00343 
00344 
00345 void
00346 JpegImageCompressor::set_filename(const char *filename)
00347 {
00348   this->filename = filename;
00349 }
00350 
00351 } // end namespace firevision
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends