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

SavePNG.cpp

Go to the documentation of this file.
00001 #include <memory>
00002 #include <png.h>
00003 #include "Debug.h"
00004 #include "Save.h"
00005 #include "Types.h"
00006 
00007 
00008 namespace corona {
00009 
00010   void PNG_write(png_structp png_ptr, png_bytep data, png_size_t length) {
00011     File* file = (File*)png_get_io_ptr(png_ptr);
00012     if (file->write(data, length) != int(length)) {
00013       png_error(png_ptr, "Write error");
00014     }
00015   }
00016 
00017   void PNG_flush(png_structp png_ptr) {
00018     // assume that files always flush
00019   }
00020 
00021   bool SavePNG(File* file, Image* image) {
00022     COR_GUARD("SavePNG");
00023 
00024     if (!image) {
00025       return false;
00026     }
00027 
00028     // If the image format isn't supported directly by this function,
00029     // clone to a supported format and try to save with that.
00030     switch (image->getFormat()) {
00031       case PF_R8G8B8A8:
00032       case PF_R8G8B8:
00033       case PF_I8:
00034         break;
00035       default: {
00036         COR_LOG("Unsupported pixel format... cloning");
00037         std::auto_ptr<Image> cloned(CloneImage(image, PF_R8G8B8A8));
00038         return SavePNG(file, cloned.get());
00039       }
00040     }
00041 
00042     // create write struct
00043     png_structp png_ptr = png_create_write_struct(
00044       PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
00045     if (!png_ptr) {
00046       return false;
00047     }
00048 
00049     // error handling!
00050     if (setjmp(png_jmpbuf(png_ptr))) {
00051       png_destroy_write_struct(&png_ptr, NULL);
00052       return false;
00053     }
00054 
00055     // create info struct
00056     png_infop info_ptr = png_create_info_struct(png_ptr);
00057     if (!info_ptr) {
00058       png_destroy_write_struct(&png_ptr, NULL);
00059       return false;
00060     }
00061 
00062     int width  = image->getWidth();
00063     int height = image->getHeight();
00064 
00065     // set image characteristics
00066     png_set_write_fn(png_ptr, file, PNG_write, PNG_flush);
00067 
00068     int color_format = 0; // png output format
00069     int color_format_bpp = 0; // png bytes per pixel
00070     bool color_format_paletted = false; // png palette needed flag
00071 
00072     // figure out output format
00073     switch (image->getFormat()) {
00074       case PF_R8G8B8A8:
00075         color_format = PNG_COLOR_TYPE_RGB_ALPHA;
00076         color_format_bpp = 4;
00077         break;
00078       case PF_R8G8B8:
00079         color_format = PNG_COLOR_TYPE_RGB;
00080         color_format_bpp = 3;
00081         break;
00082       case PF_I8:
00083         color_format = PNG_COLOR_TYPE_PALETTE;
00084         color_format_bpp = 1;
00085         color_format_paletted = true;
00086         break;
00087       default:
00088         // Unsupported format.  This should already be taken care of
00089         // by the test at the beginning of this function.
00090         png_destroy_write_struct(&png_ptr, &info_ptr);
00091         return false;
00092     }
00093 
00094     png_set_IHDR(
00095       png_ptr, info_ptr,
00096       width, height,
00097       8,
00098       color_format,
00099       PNG_INTERLACE_NONE,
00100       PNG_COMPRESSION_TYPE_DEFAULT,
00101       PNG_FILTER_TYPE_DEFAULT);
00102 
00103     png_color* png_palette = 0;
00104     if (color_format_paletted) {
00105       COR_LOG("Saving palettized image...");
00106 
00107       int image_palette_format = image->getPaletteFormat(); // palette format
00108       int image_palette_size = image->getPaletteSize(); // palette size
00109 
00110       // allocate png palette and get pointer to image palette
00111       png_palette = (png_color*)png_malloc(
00112         png_ptr, sizeof(png_color) * image_palette_size);
00113       byte* image_palette = (byte*)image->getPalette();
00114 
00115 
00116       if (image_palette_format == PF_R8G8B8) {
00117         // 24 bit source palette
00118         for (int i = 0; i < image_palette_size; i++) {
00119           // copy entry directly
00120           png_palette[i].red   = *image_palette++;
00121           png_palette[i].green = *image_palette++;
00122           png_palette[i].blue  = *image_palette++;
00123         }
00124       } else if (image_palette_format == PF_R8G8B8A8) {
00125         // 32 bit source palette
00126         for (int i = 0; i < image_palette_size; i++) {
00127           // copy entry, skip alpha
00128           png_palette[i].red   = *image_palette++;
00129           png_palette[i].green = *image_palette++;
00130           png_palette[i].blue  = *image_palette++;
00131           image_palette++;
00132         }
00133       }
00134       // write palette
00135       png_set_PLTE(png_ptr, info_ptr, png_palette, image_palette_size);
00136     }
00137 
00138     byte* pixels = (byte*)image->getPixels();
00139 
00140     // build rows
00141     void** rows = (void**)png_malloc(png_ptr, sizeof(void*) * height);
00142     for (int i = 0; i < height; ++i) {
00143       rows[i] = png_malloc(png_ptr, color_format_bpp * width);
00144       memcpy(rows[i], pixels, color_format_bpp * width);
00145       pixels += width * color_format_bpp;      
00146     }
00147     png_set_rows(png_ptr, info_ptr, (png_bytepp)rows);
00148     info_ptr->valid |= PNG_INFO_IDAT;
00149 
00150     // actually write the image
00151     png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
00152 
00153     // clean up memory
00154     for (int i = 0; i < height; ++i) {
00155       png_free(png_ptr, rows[i]);
00156     }
00157     png_free(png_ptr, rows);
00158 
00159     if (png_palette) {
00160       png_free(png_ptr, png_palette);
00161     }
00162 
00163     png_destroy_write_struct(&png_ptr, &info_ptr);
00164 
00165     return true;
00166   }
00167 
00168 }

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