//----------------------------------------------------------------------------- // Copyright (c) 2013 GarageGames, LLC // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. //----------------------------------------------------------------------------- #include "PNGImage.h" #include "math/mPoint.h" #include "graphics/gBitmap.h" #include "platform/platformGL.h" #include "platform/platform.h" #include "PNGImage_ScriptBinding.h" #define min(a,b) (a <= b ? a : b) IMPLEMENT_CONOBJECT(PNGImage); #define PNGSIGSIZE 8 PNGImage::PNGImage() : mPNGImageType(PNGTYPE_UNKNOWN) { mWidth = 0; mHeight = 0; mColorType = 0; mBitDepth = 0; mPng = 0; mInfo = 0; mRowPointers = 0; mRead = false; mWrite = false; } PNGImage::~PNGImage() { } bool PNGImage::Read(const char* filePath) { if(mRead == true || mWrite == true) CleanMemoryUsage(); /* open file and test for it being a png */ FILE *fp = fopen(filePath, "rb"); if (fp == NULL) { Con::printf("PNGImage::Read File %s could not be opened for reading.", filePath); return false; } dStrcpy(mReadFilePath, filePath); png_byte pngsig[PNGSIGSIZE]; fread((char*)pngsig, 1, PNGSIGSIZE, fp); if (png_sig_cmp(pngsig, 0, PNGSIGSIZE) != 0) { Con::printf("PNGImage::Read File %s is not recognized as a PNG file.", filePath); return false; } /* initialize stuff */ mPng = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (mPng == NULL) { Con::printf("PNGImage::Read png_create_read_struct failed."); return false; } mInfo = png_create_info_struct(mPng); if (mInfo == NULL) { png_destroy_read_struct(&mPng, NULL, NULL); Con::printf("PNGImage::Read png_create_info_struct failed."); return false; } if (setjmp(png_jmpbuf(mPng))) { png_destroy_read_struct(&mPng, NULL, NULL); Con::printf("PNGImage::Read Error during init_io."); return false; } png_init_io(mPng, fp); png_set_sig_bytes(mPng, 8); png_read_info(mPng, mInfo); // Obtain image information mWidth = png_get_image_width(mPng, mInfo); mHeight = png_get_image_height(mPng, mInfo); mColorType = png_get_color_type(mPng, mInfo); mBitDepth = png_get_bit_depth(mPng, mInfo); mRowPointers = (png_bytep*) dMalloc(sizeof(png_bytep) * mHeight); unsigned int y = 0; for (y = 0; y < mHeight; y++) mRowPointers[y] = (png_byte*) dMalloc(png_get_rowbytes(mPng,mInfo)); // Will read the actual png data into mRowPointers png_read_image(mPng, mRowPointers); fclose(fp); mRead = true; if(png_get_color_type(mPng, mInfo) == PNG_COLOR_TYPE_RGBA) mPNGImageType = PNGTYPE_RGBA; else if(png_get_color_type(mPng, mInfo) == PNG_COLOR_TYPE_RGB) mPNGImageType = PNGTYPE_RGB; else mPNGImageType = PNGTYPE_UNKNOWN; return true; } bool PNGImage::Create(U32 width, U32 height, PNGImageType imageType) { mRead = true; mHeight = height; mWidth = width; mRowPointers = (png_bytep*) dMalloc(sizeof(png_bytep) * mHeight); unsigned int y = 0; for (y = 0; y < height; y++) mRowPointers[y] = (png_byte*) dMalloc(sizeof(png_bytep) * mWidth); if(imageType == PNGTYPE_RGBA) { mColorType = PNG_COLOR_TYPE_RGBA; mPNGImageType = PNGTYPE_RGBA; } else if(imageType == PNGTYPE_RGB) { mColorType = PNG_COLOR_TYPE_RGB; mPNGImageType = PNGTYPE_RGB; } else { mPNGImageType = PNGTYPE_UNKNOWN; } mBitDepth = 8; ClearImageData(); return true; } bool PNGImage::ClearImageData() { if(mRowPointers == NULL) return false; if(mPNGImageType == PNGTYPE_RGBA) { for(U32 h = 0; h < mHeight; ++h) { png_byte* currentRow = mRowPointers[h]; for(U32 w = 0; w < mWidth; ++w) { png_byte* currentPngByte = &(currentRow[w*4]); currentPngByte[0] = 255; currentPngByte[1] = 255; currentPngByte[2] = 255; currentPngByte[3] = 255; } } } else if(mPNGImageType == PNGTYPE_RGB) { for(U32 h = 0; h < mHeight; ++h) { png_byte* currentRow = mRowPointers[h]; for(U32 w = 0; w < mWidth; ++w) { png_byte* currentPngByte = &(currentRow[w*3]); currentPngByte[0] = 255; currentPngByte[1] = 255; currentPngByte[2] = 255; } } } return true; } bool PNGImage::MergeOn(U32 x, U32 y, const PNGImage* inc) { if(x + inc->GetWidth() > mWidth || y + inc->GetHeight() > mHeight) return false; if(mPNGImageType == PNGTYPE_RGBA && inc->GetPNGImageType() == PNGTYPE_RGBA) { for(U32 h = 0; h < inc->GetHeight(); ++h) { png_byte* incRow = inc->GetRowPointers()[h]; png_byte* currentRow = mRowPointers[y + h]; for(U32 w = 0; w < inc->GetWidth(); ++w) { png_byte* incPngByte = &(incRow[w*4]); png_byte* currentPngByte = &(currentRow[(x+w)*4]); //float incAlpha = (incPngByte[3]/255.0f); //float currentAlpha = (currentPngByte[3]/255.0f); //float red = ((float)incPngByte[0]/255.0f * incAlpha) + ((float)currentPngByte[0]/255.0f * (currentAlpha - incAlpha)); //float green = ((float)incPngByte[1]/255.0f * incAlpha) + ((float)currentPngByte[1]/255.0f * (currentAlpha - incAlpha)); //float blue = ((float)incPngByte[2]/255.0f * incAlpha) + ((float)currentPngByte[2]/255.0f * (currentAlpha - incAlpha)); ////float alpha = ((float)incPngByte[3]/255.0f * incAlpha) + ((float)currentPngByte[3]/255.0f * (currentAlpha - incAlpha)); //currentPngByte[0] = (png_byte)min(red * 255.0f, 255.0f); //currentPngByte[1] = (png_byte)min(green * 255.0f, 255.0f); //currentPngByte[2] = (png_byte)min(blue * 255.0f, 255.0f); ////currentPngByte[3] = (png_byte)min(blue * 255.0f, 255.0f); currentPngByte[0] = incPngByte[0]; currentPngByte[1] = incPngByte[1]; currentPngByte[2] = incPngByte[2]; } } } else if(mPNGImageType == PNGTYPE_RGB && inc->GetPNGImageType() == PNGTYPE_RGBA) { for(U32 h = 0; h < inc->GetHeight(); ++h) { png_byte* incRow = inc->GetRowPointers()[h]; png_byte* currentRow = mRowPointers[y + h]; for(U32 w = 0; w < inc->GetWidth(); ++w) { png_byte* incPngByte = &(incRow[w*4]); png_byte* currentPngByte = &(currentRow[(x+w)*3]); float incAlpha = (incPngByte[3]/255.0f); float red = ((float)incPngByte[0]/255.0f * incAlpha) + ((float)currentPngByte[0]/255.0f * (1.0f - incAlpha)); float green = ((float)incPngByte[1]/255.0f * incAlpha) + ((float)currentPngByte[1]/255.0f * (1.0f - incAlpha)); float blue = ((float)incPngByte[2]/255.0f * incAlpha) + ((float)currentPngByte[2]/255.0f * (1.0f - incAlpha)); currentPngByte[0] = (png_byte)min(red * 255.0f, 255.0f); currentPngByte[1] = (png_byte)min(green * 255.0f, 255.0f); currentPngByte[2] = (png_byte)min(blue * 255.0f, 255.0f); } } } else if(mPNGImageType == PNGTYPE_RGBA && inc->GetPNGImageType() == PNGTYPE_RGB) { for(U32 h = 0; h < inc->GetHeight(); ++h) { png_byte* incRow = inc->GetRowPointers()[h]; png_byte* currentRow = mRowPointers[y + h]; for(U32 w = 0; w < inc->GetWidth(); ++w) { png_byte* incPngByte = &(incRow[w*3]); png_byte* currentPngByte = &(currentRow[(x+w)*4]); currentPngByte[0] = incPngByte[0]; currentPngByte[1] = incPngByte[1]; currentPngByte[2] = incPngByte[2]; } } } else if(mPNGImageType == PNGTYPE_RGB && inc->GetPNGImageType() == PNGTYPE_RGB) { for(U32 h = 0; h < inc->GetHeight(); ++h) { png_byte* incRow = inc->GetRowPointers()[h]; png_byte* currentRow = mRowPointers[y + h]; for(U32 w = 0; w < inc->GetWidth(); ++w) { png_byte* incPngByte = &(incRow[w*3]); png_byte* currentPngByte = &(currentRow[(x+w)*3]); currentPngByte[0] = incPngByte[0]; currentPngByte[1] = incPngByte[1]; currentPngByte[2] = incPngByte[2]; } } } return true; } bool PNGImage::Write(const char* filePath) { if(mRead == false) return false; if(mPng != NULL && mInfo != NULL) { png_destroy_read_struct(&mPng, &mInfo, NULL); mPng = NULL; mInfo = NULL; } else { if(mPng != NULL) { png_destroy_read_struct(&mPng, NULL, NULL); mPng = NULL; } else if(mInfo != NULL) { png_read_info(mPng, mInfo); mInfo = NULL; } } /* create file */ FILE *fp = fopen(filePath, "wb"); if (!fp) { Con::printf("PNGImage::Write File %s could not be opened for writing.", filePath); return false; } // png_destroy_read_struct(&mPng, NULL, NULL); // png_destroy_info_struct(mPng, NULL); /* initialize stuff */ mPng = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!mPng) { Con::printf("PNGImage::Write png_create_write_struct failed."); return false; } mInfo = png_create_info_struct(mPng); if (mInfo == NULL) { Con::printf("PNGImage::Write png_create_info_struct failed."); return false; } if (setjmp(png_jmpbuf(mPng))) { Con::printf("PNGImage::Write Error during init_io."); return false; } png_init_io(mPng, fp); /* write header */ if (setjmp(png_jmpbuf(mPng))) { Con::printf("PNGImage::Write Error during writing header."); return false; } png_set_IHDR(mPng, mInfo, mWidth, mHeight, mBitDepth, mColorType, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_write_info(mPng, mInfo); /* write bytes */ if (setjmp(png_jmpbuf(mPng))) { Con::printf("PNGImage::Write Error during writing bytes."); return false; } png_write_image(mPng, mRowPointers); /* end write */ if (setjmp(png_jmpbuf(mPng))) { Con::printf("PNGImage::Write Error during end of write."); return false; } png_write_end(mPng, NULL); fclose(fp); mRead = false; mWrite = true; return true; } bool PNGImage::CleanMemoryUsage() { if(mRead == true && mWrite == true) return false; if(mRead == true) { if(mPng != NULL && mInfo != NULL) { png_destroy_read_struct(&mPng, &mInfo, NULL); mPng = NULL; mInfo = NULL; } else { if(mPng != NULL) { png_destroy_read_struct(&mPng, NULL, NULL); mPng = NULL; } else if(mInfo != NULL) { png_read_info(mPng, mInfo); mInfo = NULL; } } for (unsigned int y = 0; y < mHeight; y++) dFree(mRowPointers[y]); dFree(mRowPointers); mRowPointers= NULL; } else if(mWrite == true) { if(mPng != NULL && mInfo != NULL) { png_destroy_write_struct(&mPng, &mInfo); mPng = NULL; mInfo = NULL; } else { if(mPng != NULL) { png_destroy_write_struct(&mPng, NULL); mPng = NULL; } if(mInfo != NULL) { png_read_info(mPng, mInfo); mInfo = NULL; } } for (unsigned int y = 0; y < mHeight; y++) dFree(mRowPointers[y]); dFree(mRowPointers); mRowPointers = NULL; } return true; }