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