fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
  SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation)  

Fl_JPEG_Image.cxx

Go to the documentation of this file.
00001 //
00002 // "$Id: Fl_JPEG_Image.cxx 7903 2010-11-28 21:06:39Z matt $"
00003 //
00004 // Fl_JPEG_Image routines.
00005 //
00006 // Copyright 1997-2010 by Easy Software Products.
00007 // Image support by Matthias Melcher, Copyright 2000-2009.
00008 //
00009 // This library is free software; you can redistribute it and/or
00010 // modify it under the terms of the GNU Library General Public
00011 // License as published by the Free Software Foundation; either
00012 // version 2 of the License, or (at your option) any later version.
00013 //
00014 // This library is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017 // Library General Public License for more details.
00018 //
00019 // You should have received a copy of the GNU Library General Public
00020 // License along with this library; if not, write to the Free Software
00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00022 // USA.
00023 //
00024 // Please report all bugs and problems on the following page:
00025 //
00026 //     http://www.fltk.org/str.php
00027 //
00028 // Contents:
00029 //
00030 //   Fl_JPEG_Image::Fl_JPEG_Image() - Load a JPEG image file.
00031 //
00032 
00033 //
00034 // Include necessary header files...
00035 //
00036 
00037 #include <FL/Fl_JPEG_Image.H>
00038 #include <FL/fl_utf8.h>
00039 #include <config.h>
00040 #include <stdio.h>
00041 #include <stdlib.h>
00042 #include <setjmp.h>
00043 
00044 
00045 // Some releases of the Cygwin JPEG libraries don't have a correctly
00046 // updated header file for the INT32 data type; the following define
00047 // from Shane Hill seems to be a usable workaround...
00048 
00049 #if defined(WIN32) && defined(__CYGWIN__)
00050 #  define XMD_H
00051 #endif // WIN32 && __CYGWIN__
00052 
00053 
00054 extern "C"
00055 {
00056 #ifdef HAVE_LIBJPEG
00057 #  include <jpeglib.h>
00058 #endif // HAVE_LIBJPEG
00059 }
00060 
00061 
00062 //
00063 // Custom JPEG error handling structure...
00064 //
00065 
00066 #ifdef HAVE_LIBJPEG
00067 struct fl_jpeg_error_mgr {
00068   jpeg_error_mgr        pub_;           // Destination manager...
00069   jmp_buf               errhand_;       // Error handler
00070 };
00071 #endif // HAVE_LIBJPEG
00072 
00073 
00074 //
00075 // Error handler for JPEG files...
00076 //
00077 
00078 #ifdef HAVE_LIBJPEG
00079 extern "C" {
00080   static void
00081   fl_jpeg_error_handler(j_common_ptr dinfo) {   // I - Decompressor info
00082     longjmp(((fl_jpeg_error_mgr *)(dinfo->err))->errhand_, 1);
00083   }
00084 
00085   static void
00086   fl_jpeg_output_handler(j_common_ptr) {        // I - Decompressor info (not used)
00087   }
00088 }
00089 #endif // HAVE_LIBJPEG
00090 
00091 
00103 Fl_JPEG_Image::Fl_JPEG_Image(const char *filename)      // I - File to load
00104 : Fl_RGB_Image(0,0,0) {
00105 #ifdef HAVE_LIBJPEG
00106   FILE                          *fp;    // File pointer
00107   jpeg_decompress_struct        dinfo;  // Decompressor info
00108   fl_jpeg_error_mgr             jerr;   // Error handler info
00109   JSAMPROW                      row;    // Sample row pointer
00110   
00111   // the following variables are pointers allocating some private space that
00112   // is not reset by 'setjmp()'
00113   char* max_finish_decompress_err;      // count errors and give up afer a while
00114   char* max_destroy_decompress_err;     // to avoid recusion and deadlock
00115   
00116   // Clear data...
00117   alloc_array = 0;
00118   array = (uchar *)0;
00119   
00120   // Open the image file...
00121   if ((fp = fl_fopen(filename, "rb")) == NULL) return;
00122   
00123   // Setup the decompressor info and read the header...
00124   dinfo.err                = jpeg_std_error((jpeg_error_mgr *)&jerr);
00125   jerr.pub_.error_exit     = fl_jpeg_error_handler;
00126   jerr.pub_.output_message = fl_jpeg_output_handler;
00127   
00128   // Setup error loop variables
00129   max_finish_decompress_err = (char*)malloc(1);   // allocate space on the frame for error counters
00130   max_destroy_decompress_err = (char*)malloc(1);  // otherwise, the variables are reset on the longjmp
00131   *max_finish_decompress_err=10;
00132   *max_destroy_decompress_err=10;
00133   
00134   if (setjmp(jerr.errhand_))
00135   {
00136     // JPEG error handling...
00137     // if any of the cleanup routines hits another error, we would end up 
00138     // in a loop. So instead, we decrement max_err for some upper cleanup limit.
00139     if ( ((*max_finish_decompress_err)-- > 0) && array)
00140       jpeg_finish_decompress(&dinfo);
00141     if ( (*max_destroy_decompress_err)-- > 0)
00142       jpeg_destroy_decompress(&dinfo);
00143     
00144     fclose(fp);
00145     
00146     w(0);
00147     h(0);
00148     d(0);
00149     
00150     if (array) {
00151       delete[] (uchar *)array;
00152       array = 0;
00153       alloc_array = 0;
00154     }
00155     
00156     free(max_destroy_decompress_err);
00157     free(max_finish_decompress_err);
00158     
00159     return;
00160   }
00161   
00162   jpeg_create_decompress(&dinfo);
00163   jpeg_stdio_src(&dinfo, fp);
00164   jpeg_read_header(&dinfo, 1);
00165   
00166   dinfo.quantize_colors      = (boolean)FALSE;
00167   dinfo.out_color_space      = JCS_RGB;
00168   dinfo.out_color_components = 3;
00169   dinfo.output_components    = 3;
00170   
00171   jpeg_calc_output_dimensions(&dinfo);
00172   
00173   w(dinfo.output_width); 
00174   h(dinfo.output_height);
00175   d(dinfo.output_components);
00176   
00177   array = new uchar[w() * h() * d()];
00178   alloc_array = 1;
00179   
00180   jpeg_start_decompress(&dinfo);
00181   
00182   while (dinfo.output_scanline < dinfo.output_height) {
00183     row = (JSAMPROW)(array +
00184                      dinfo.output_scanline * dinfo.output_width *
00185                      dinfo.output_components);
00186     jpeg_read_scanlines(&dinfo, &row, (JDIMENSION)1);
00187   }
00188   
00189   jpeg_finish_decompress(&dinfo);
00190   jpeg_destroy_decompress(&dinfo);
00191   
00192   free(max_destroy_decompress_err);
00193   free(max_finish_decompress_err);
00194   
00195   fclose(fp);
00196 #endif // HAVE_LIBJPEG
00197 }
00198 
00199 
00200 // data source manager for reading jpegs from memory
00201 // init_source (j_decompress_ptr cinfo)
00202 // fill_input_buffer (j_decompress_ptr cinfo)
00203 // skip_input_data (j_decompress_ptr cinfo, long num_bytes)
00204 // resync_to_restart (j_decompress_ptr cinfo, int desired)
00205 // term_source (j_decompress_ptr cinfo)
00206 //         JOCTET * next_output_byte;  /* => next byte to write in buffer */
00207 //         size_t free_in_buffer;      /* # of byte spaces remaining in buffer */
00208 
00209 #ifdef HAVE_LIBJPEG
00210 typedef struct {
00211   struct jpeg_source_mgr pub;
00212   const unsigned char *data, *s;
00213   // JOCTET * buffer;              /* start of buffer */
00214   // boolean start_of_file;        /* have we gotten any data yet? */
00215 } my_source_mgr;
00216 
00217 typedef my_source_mgr *my_src_ptr;
00218 
00219 
00220 void init_source (j_decompress_ptr cinfo) {
00221   my_src_ptr src = (my_src_ptr)cinfo->src;
00222   src->s = src->data;
00223 }
00224 
00225 boolean fill_input_buffer(j_decompress_ptr cinfo) {
00226   my_src_ptr src = (my_src_ptr)cinfo->src;
00227   size_t nbytes = 4096;
00228   src->pub.next_input_byte = src->s;
00229   src->pub.bytes_in_buffer = nbytes;
00230   src->s += nbytes;
00231   return TRUE;
00232 }
00233 
00234 void term_source(j_decompress_ptr cinfo)
00235 {
00236 }
00237 
00238 void skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
00239   my_src_ptr src = (my_src_ptr)cinfo->src;
00240   if (num_bytes > 0) {
00241     while (num_bytes > (long)src->pub.bytes_in_buffer) {
00242       num_bytes -= (long)src->pub.bytes_in_buffer;
00243       fill_input_buffer(cinfo);
00244     }
00245     src->pub.next_input_byte += (size_t) num_bytes;
00246     src->pub.bytes_in_buffer -= (size_t) num_bytes;
00247   }
00248 }
00249 
00250 static void jpeg_mem_src(j_decompress_ptr cinfo, const unsigned char *data)
00251 {
00252   my_src_ptr src;
00253   cinfo->src = (struct jpeg_source_mgr *)malloc(sizeof(my_source_mgr));
00254   src = (my_src_ptr)cinfo->src;
00255   src->pub.init_source = init_source;
00256   src->pub.fill_input_buffer = fill_input_buffer;
00257   src->pub.skip_input_data = skip_input_data;
00258   src->pub.resync_to_restart = jpeg_resync_to_restart;
00259   src->pub.term_source = term_source;
00260   src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
00261   src->pub.next_input_byte = NULL; /* until buffer loaded */
00262   src->data = data;
00263   src->s = data;
00264 }
00265 #endif // HAVE_LIBJPEG
00266 
00267 
00280 Fl_JPEG_Image::Fl_JPEG_Image(const char *name, const unsigned char *data)
00281 : Fl_RGB_Image(0,0,0) {
00282 #ifdef HAVE_LIBJPEG
00283   jpeg_decompress_struct        dinfo;  // Decompressor info
00284   fl_jpeg_error_mgr             jerr;   // Error handler info
00285   JSAMPROW                      row;    // Sample row pointer
00286   
00287   // the following variables are pointers allocating some private space that
00288   // is not reset by 'setjmp()'
00289   char* max_finish_decompress_err;      // count errors and give up afer a while
00290   char* max_destroy_decompress_err;     // to avoid recusion and deadlock
00291   
00292   // Clear data...
00293   alloc_array = 0;
00294   array = (uchar *)0;
00295   
00296   // Setup the decompressor info and read the header...
00297   dinfo.err                = jpeg_std_error((jpeg_error_mgr *)&jerr);
00298   jerr.pub_.error_exit     = fl_jpeg_error_handler;
00299   jerr.pub_.output_message = fl_jpeg_output_handler;
00300   
00301   // Setup error loop variables
00302   max_finish_decompress_err = (char*)malloc(1);   // allocate space on the frame for error counters
00303   max_destroy_decompress_err = (char*)malloc(1);  // otherwise, the variables are reset on the longjmp
00304   *max_finish_decompress_err=10;
00305   *max_destroy_decompress_err=10;
00306   
00307   if (setjmp(jerr.errhand_))
00308   {
00309     // JPEG error handling...
00310     // if any of the cleanup routines hits another error, we would end up 
00311     // in a loop. So instead, we decrement max_err for some upper cleanup limit.
00312     if ( ((*max_finish_decompress_err)-- > 0) && array)
00313       jpeg_finish_decompress(&dinfo);
00314     if ( (*max_destroy_decompress_err)-- > 0)
00315       jpeg_destroy_decompress(&dinfo);
00316     
00317     w(0);
00318     h(0);
00319     d(0);
00320     
00321     if (array) {
00322       delete[] (uchar *)array;
00323       array = 0;
00324       alloc_array = 0;
00325     }
00326     
00327     free(max_destroy_decompress_err);
00328     free(max_finish_decompress_err);
00329     
00330     return;
00331   }
00332   
00333   jpeg_create_decompress(&dinfo);
00334   jpeg_mem_src(&dinfo, data);
00335   jpeg_read_header(&dinfo, 1);
00336   
00337   dinfo.quantize_colors      = (boolean)FALSE;
00338   dinfo.out_color_space      = JCS_RGB;
00339   dinfo.out_color_components = 3;
00340   dinfo.output_components    = 3;
00341   
00342   jpeg_calc_output_dimensions(&dinfo);
00343   
00344   w(dinfo.output_width); 
00345   h(dinfo.output_height);
00346   d(dinfo.output_components);
00347   
00348   array = new uchar[w() * h() * d()];
00349   alloc_array = 1;
00350   
00351   jpeg_start_decompress(&dinfo);
00352   
00353   while (dinfo.output_scanline < dinfo.output_height) {
00354     row = (JSAMPROW)(array +
00355                      dinfo.output_scanline * dinfo.output_width *
00356                      dinfo.output_components);
00357     jpeg_read_scanlines(&dinfo, &row, (JDIMENSION)1);
00358   }
00359   
00360   jpeg_finish_decompress(&dinfo);
00361   jpeg_destroy_decompress(&dinfo);
00362   
00363   free(max_destroy_decompress_err);
00364   free(max_finish_decompress_err);
00365 #endif // HAVE_LIBJPEG
00366 }
00367 
00368 //
00369 // End of "$Id: Fl_JPEG_Image.cxx 7903 2010-11-28 21:06:39Z matt $".
00370 //