Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

OpenJPEG.cpp

Go to the documentation of this file.
00001 #include <stdio.h>  // needed by jpeglib.h
00002 #include <string.h>
00003 #include <setjmp.h>
00004 extern "C" {  // stupid JPEG library
00005   #include <jpeglib.h>
00006 }
00007 #include "Open.h"
00008 #include "SimpleImage.h"
00009 
00010 
00011 namespace corona {
00012 
00013   static const int JPEG_BUFFER_SIZE = 4096;
00014 
00015 
00016   void    JPEG_init_source(j_decompress_ptr cinfo);
00017   boolean JPEG_fill_input_buffer(j_decompress_ptr cinfo);
00018   void    JPEG_skip_input_data(j_decompress_ptr cinfo, long num_bytes);
00019   void    JPEG_term_source(j_decompress_ptr cinfo);
00020   void    JPEG_error_exit(j_common_ptr cinfo);
00021   void    JPEG_emit_message(j_common_ptr cinfo, int msg_level);
00022 
00023 
00024   struct InternalStruct {
00025     struct {
00026       jpeg_error_mgr mgr;
00027       jmp_buf setjmp_buffer;
00028     } error_mgr;
00029 
00030     File* file;
00031     byte buffer[JPEG_BUFFER_SIZE];
00032   };
00033 
00035 
00036   Image* OpenJPEG(File* file) {
00037 
00038     // set up internal information
00039     InternalStruct is;
00040     is.file = file;
00041 
00042     // initialize the source manager
00043     jpeg_source_mgr mgr;
00044     mgr.bytes_in_buffer = 0;
00045     mgr.next_input_byte = NULL;
00046     mgr.init_source       = JPEG_init_source;
00047     mgr.fill_input_buffer = JPEG_fill_input_buffer;
00048     mgr.skip_input_data   = JPEG_skip_input_data;
00049     mgr.resync_to_restart = jpeg_resync_to_restart;  // use default
00050     mgr.term_source       = JPEG_term_source;
00051     
00052     // initialize decompressor
00053     jpeg_decompress_struct cinfo;
00054     jpeg_create_decompress(&cinfo);
00055     cinfo.client_data = &is;
00056 
00057     cinfo.err = jpeg_std_error(&is.error_mgr.mgr);
00058     is.error_mgr.mgr.error_exit = JPEG_error_exit;
00059 
00060     SimpleImage* image = 0;
00061     
00062     if (setjmp(is.error_mgr.setjmp_buffer)) {
00063       delete image;
00064       jpeg_destroy_decompress(&cinfo);
00065       return 0;
00066     }
00067 
00068     cinfo.src = &mgr;
00069     jpeg_read_header(&cinfo, TRUE);
00070     jpeg_start_decompress(&cinfo);
00071 
00072     // do we support the number of color components?
00073     if (cinfo.output_components != 1 && cinfo.output_components != 3) {
00074       jpeg_finish_decompress(&cinfo);
00075       jpeg_destroy_decompress(&cinfo);
00076       return 0;
00077     }
00078 
00079     // make a one-row-high sample array that will go away when done with image
00080     int row_stride = cinfo.output_width * cinfo.output_components;
00081     JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray)(
00082       (j_common_ptr)&cinfo,
00083       JPOOL_IMAGE,
00084       row_stride,
00085       1);
00086 
00087     // allocate image
00088     unsigned width  = cinfo.output_width;
00089     unsigned height = cinfo.output_height;
00090     byte* pixels = new byte[width * height * 3];
00091     memset(pixels, 0, width * height * 3);
00092 
00093     // create the image object now, so that if the error handler is called,
00094     // the longjmp code will know what to free
00095     image = new SimpleImage(width, height, PF_R8G8B8, pixels);
00096 
00097     // read the scanlines
00098     bool finished = true;
00099     while (cinfo.output_scanline < height) {
00100       int num_rows = jpeg_read_scanlines(&cinfo, buffer, 1);
00101       if (num_rows == 0) {
00102         finished = false;
00103         break;
00104       }
00105 
00106       // copy scanline into pixel buffer
00107       if (cinfo.output_components == 1) {        // greyscale
00108         byte* in = (byte*)(*buffer);
00109         for (unsigned i = 0; i < width * num_rows; ++i) {
00110           *pixels++ = *in; // red
00111           *pixels++ = *in; // green
00112           *pixels++ = *in; // blue
00113           ++in;
00114         }
00115       } else if (cinfo.output_components == 3) { // RGB
00116         memcpy(pixels, (*buffer), num_rows * width * 3);
00117         pixels += num_rows * width * 3;
00118       }
00119     }
00120 
00121     // finish up
00122     if (finished) {
00123       jpeg_finish_decompress(&cinfo);
00124     }
00125     jpeg_destroy_decompress(&cinfo);
00126 
00127     return image;
00128   }
00129 
00131 
00132   void JPEG_init_source(j_decompress_ptr cinfo) {
00133     // no initialization required
00134   }
00135 
00137 
00138   boolean JPEG_fill_input_buffer(j_decompress_ptr cinfo) {
00139     // more or less copied from jdatasrc.c
00140 
00141     InternalStruct* is = (InternalStruct*)(cinfo->client_data);
00142 
00143     int nbytes = is->file->read(is->buffer, JPEG_BUFFER_SIZE);
00144     if (nbytes <= 0) {
00145       /* Insert a fake EOI marker */
00146       is->buffer[0] = (JOCTET)0xFF;
00147       is->buffer[1] = (JOCTET)JPEG_EOI;
00148       nbytes = 2;
00149     }
00150 
00151     cinfo->src->bytes_in_buffer = nbytes;
00152     cinfo->src->next_input_byte = is->buffer;
00153     return TRUE;
00154   }
00155 
00157 
00158   void JPEG_skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
00159     //InternalStruct* is = (InternalStruct*)(cinfo->client_data);
00160     if (num_bytes > 0) {
00161       while (num_bytes > (long)cinfo->src->bytes_in_buffer) {
00162         num_bytes -= (long)cinfo->src->bytes_in_buffer;
00163         JPEG_fill_input_buffer(cinfo);
00164       }
00165       cinfo->src->next_input_byte += (size_t)num_bytes;
00166       cinfo->src->bytes_in_buffer -= (size_t)num_bytes;
00167     }
00168   }
00169 
00171 
00172   void JPEG_term_source(j_decompress_ptr cinfo) {
00173     // nothing to do here...
00174   }
00175 
00177 
00178   void JPEG_error_exit(j_common_ptr cinfo) {
00179     InternalStruct* is = (InternalStruct*)(cinfo->client_data);
00180     longjmp(is->error_mgr.setjmp_buffer, 1);
00181   }
00182 
00184 
00185   void JPEG_emit_message(j_common_ptr /*cinfo*/, int /*msg_level*/) {
00186     // ignore error messages
00187   }
00188 
00190 
00191 }

Generated on Thu Oct 2 12:59:31 2003 for corona by doxygen1.3-rc1