corona
1.0.2
|
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 }