corona
1.0.2
|
00001 #include <stdio.h> // needed by jpeglib.h 00002 #include <memory> 00003 #include <setjmp.h> 00004 extern "C" { // stupid JPEG library 00005 #include <jpeglib.h> 00006 #include <jerror.h> 00007 } 00008 #include "Debug.h" 00009 #include "Save.h" 00010 #include "Utility.h" 00011 00012 namespace corona { 00013 00014 static const int JPEG_BUFFER_SIZE = 4096; 00015 void JPEG_init_destination(j_compress_ptr cinfo); 00016 boolean JPEG_empty_output_buffer(j_compress_ptr cinfo); 00017 void JPEG_term_destination(j_compress_ptr cinfo); 00018 00019 // From OpenJPEG.cpp 00020 extern void JPEG_error_exit(j_common_ptr cinfo); 00021 00022 struct iwrite_mgr { 00023 jpeg_destination_mgr pub; 00024 JOCTET* buffer; 00025 boolean bah; 00026 }; 00027 00028 struct InternalStruct { 00029 struct { 00030 jpeg_error_mgr mgr; 00031 jmp_buf setjmp_buffer; 00032 } error_mgr; 00033 00034 File* file; 00035 byte buffer[JPEG_BUFFER_SIZE]; 00036 }; 00037 00038 bool SaveJPEG(File* file, Image* source) { 00039 COR_GUARD("SaveJPG"); 00040 00041 std::auto_ptr<Image> image(CloneImage(source, PF_R8G8B8)); 00042 if (!image.get()) { 00043 return false; 00044 } 00045 const int width = image->getWidth(); 00046 00047 jpeg_compress_struct JpegInfo; 00048 JSAMPROW row_pointer[1]; 00049 int Type = 0; 00050 00051 // Now we can initialize the JPEG compression object. 00052 jpeg_create_compress(&JpegInfo); 00053 InternalStruct is; 00054 is.file = file; 00055 JpegInfo.client_data = &is; 00056 00057 JpegInfo.err = jpeg_std_error(&is.error_mgr.mgr); 00058 is.error_mgr.mgr.error_exit = JPEG_error_exit; 00059 00060 if (setjmp(is.error_mgr.setjmp_buffer)) { 00061 jpeg_destroy_compress(&JpegInfo); 00062 return false; 00063 } 00064 00065 JpegInfo.dest = (struct jpeg_destination_mgr *) 00066 (JpegInfo.mem->alloc_small) ((j_common_ptr) &JpegInfo, JPOOL_PERMANENT, 00067 sizeof(struct jpeg_destination_mgr)); 00068 { 00069 iwrite_mgr* dest = (iwrite_mgr*)JpegInfo.dest; 00070 dest->pub.init_destination = JPEG_init_destination; 00071 dest->pub.empty_output_buffer = JPEG_empty_output_buffer; 00072 dest->pub.term_destination = JPEG_term_destination; 00073 } 00074 00075 // image width and height, in pixels 00076 JpegInfo.image_width = image->getWidth(); 00077 JpegInfo.image_height = image->getHeight(); 00078 JpegInfo.input_components = 3; // # of color components per pixel 00079 JpegInfo.in_color_space = JCS_RGB; 00080 00081 jpeg_set_defaults(&JpegInfo); 00082 Type = Type; 00083 JpegInfo.write_JFIF_header = TRUE; 00084 00085 jpeg_set_quality(&JpegInfo, 85, TRUE); // TODO: find way of setting quality 00086 00087 jpeg_start_compress(&JpegInfo, TRUE); 00088 00089 unsigned char * data = (unsigned char*)image->getPixels(); 00090 while (JpegInfo.next_scanline < JpegInfo.image_height) { 00091 // jpeg_write_scanlines expects an array of pointers to scanlines. 00092 // Here the array is only one element long, but you could pass 00093 // more than one scanline at a time if that's more convenient. 00094 row_pointer[0] = &data[JpegInfo.next_scanline * (width * 3)]; 00095 jpeg_write_scanlines(&JpegInfo, row_pointer, 1); 00096 } 00097 00098 // Step 6: Finish compression 00099 jpeg_finish_compress(&JpegInfo); 00100 00101 // Step 7: release JPEG compression object 00102 00103 // This is an important step since it will release a good deal of memory. 00104 jpeg_destroy_compress(&JpegInfo); 00105 00106 return true; 00107 } 00108 00109 void JPEG_init_destination(j_compress_ptr cinfo) { 00110 iwrite_mgr* dest = (iwrite_mgr*) cinfo->dest; 00111 00112 /* Allocate the output buffer --- it will be released when done with image */ 00113 dest->buffer = (JOCTET *) 00114 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, 00115 JPEG_BUFFER_SIZE * sizeof(JOCTET)); 00116 00117 dest->pub.next_output_byte = dest->buffer; 00118 dest->pub.free_in_buffer = JPEG_BUFFER_SIZE; 00119 } 00120 00121 boolean JPEG_empty_output_buffer(j_compress_ptr cinfo) { 00122 iwrite_mgr* dest = (iwrite_mgr*) cinfo->dest; 00123 00124 InternalStruct *is = (InternalStruct*)cinfo->client_data; 00125 if(is->file->write(dest->buffer,JPEG_BUFFER_SIZE) != JPEG_BUFFER_SIZE) 00126 ERREXIT(cinfo, JERR_FILE_WRITE); 00127 00128 dest->pub.next_output_byte = dest->buffer; 00129 dest->pub.free_in_buffer = JPEG_BUFFER_SIZE; 00130 00131 return TRUE; 00132 } 00133 00134 void JPEG_term_destination(j_compress_ptr cinfo) { 00135 iwrite_mgr* dest = (iwrite_mgr*) cinfo->dest; 00136 size_t datacount = JPEG_BUFFER_SIZE - dest->pub.free_in_buffer; 00137 InternalStruct *is = (InternalStruct*)cinfo->client_data; 00138 00139 /* Write any data remaining in the buffer */ 00140 if (datacount > 0) { 00141 if(is->file->write(dest->buffer,datacount) != int(datacount)) 00142 ERREXIT(cinfo, JERR_FILE_WRITE); 00143 } 00144 } 00145 }