corona  1.0.2
SaveJPEG.cpp
Go to the documentation of this file.
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 }