fixed #630 To realize the buffer-saving function in CCRenderTexture

This commit is contained in:
RongHong 2011-07-27 16:55:04 +08:00
parent fb1132bbf8
commit a253909030
4 changed files with 370 additions and 31 deletions

View File

@ -91,6 +91,9 @@ public:
/* get buffer as UIImage, can only save a render buffer which has a RGBA8888 pixel format */
CCData *getUIImageAsDataFromBuffer(int format);
bool getUIImageFromBuffer(CCImage *pImage);
protected:
GLuint m_uFBO;
GLint m_nOldFBO;

View File

@ -29,7 +29,7 @@ THE SOFTWARE.
#include "platform/platform.h"
#include "CCImage.h"
#include "support/ccUtils.h"
#include "CCFileUtils.h"
#include "CCGL.h"
namespace cocos2d {
@ -172,13 +172,13 @@ void CCRenderTexture::begin()
glGetIntegerv(CC_GL_FRAMEBUFFER_BINDING, &m_nOldFBO);
ccglBindFramebuffer(CC_GL_FRAMEBUFFER, m_uFBO);//Will direct drawing to the frame buffer created above
// Issue #1145
// There is no need to enable the default GL states here
// but since CCRenderTexture is mostly used outside the "render" loop
// these states needs to be enabled.
// Since this bug was discovered in API-freeze (very close of 1.0 release)
// This bug won't be fixed to prevent incompatibilities with code.
//
// Issue #1145
// There is no need to enable the default GL states here
// but since CCRenderTexture is mostly used outside the "render" loop
// these states needs to be enabled.
// Since this bug was discovered in API-freeze (very close of 1.0 release)
// This bug won't be fixed to prevent incompatibilities with code.
//
// If you understand the above mentioned message, then you can comment the following line
// and enable the gl states manually, in case you need them.
@ -222,25 +222,70 @@ bool CCRenderTexture::saveBuffer(const char *name)
}
bool CCRenderTexture::saveBuffer(const char *fileName, int format)
{
CC_UNUSED_PARAM(fileName);
CC_UNUSED_PARAM(format);
bool bRet = false;
//@ todo CCRenderTexture::saveBuffer
// UIImage *myImage = this->getUIImageFromBuffer(format);
// CCMutableArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
// CCString *documentsDirectory = [paths objectAtIndex:0];
// CCString *fullPath = [documentsDirectory stringByAppendingPathComponent:fileName];
// CCData * data = this->getUIImageAsDataFromBuffer(format);
// if (data)
// {
// bRet = data->writeToFile(path, true);
// delete data;
// bRet = true;
// }
bool bRet = false;
CCAssert(format == kCCImageFormatJPG || format == kCCImageFormatPNG,
@"the image can only be saved as JPG or PNG format");
CCImage *pImage = new CCImage();
if (pImage != NULL && getUIImageFromBuffer(pImage))
{
std::string fullpath = CCFileUtils::getWriteablePath() + fileName;
if (kCCImageFormatPNG == format)
{
fullpath += ".png";
}
else
{
fullpath += ".jpg";
}
bRet = pImage->saveToFile(fullpath.c_str());
}
CC_SAFE_DELETE(pImage);
return bRet;
}
/* get buffer as UIImage */
bool CCRenderTexture::getUIImageFromBuffer(CCImage *pImage)
{
if (NULL == pImage)
{
return false;
}
GLubyte * pBuffer = NULL;
bool bRet = false;
do
{
CCAssert(m_ePixelFormat == kCCTexture2DPixelFormat_RGBA8888,@"only RGBA8888 can be saved as image");
CCSize s = m_pTexture->getContentSizeInPixels();
int tx = (int)s.width;
int ty = (int)s.height;
CC_BREAK_IF(! (pBuffer = new GLubyte[tx * ty * 4]));
this->begin();
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(0,0,tx,ty,GL_RGBA,GL_UNSIGNED_BYTE, pBuffer);
this->end();
pImage->initWithImageData(pBuffer, tx * ty * 4, CCImage::kFmtRawData, tx, ty, 8);
bRet = true;
} while (0);
CC_SAFE_DELETE_ARRAY(pBuffer);
return bRet;
}
CCData * CCRenderTexture::getUIImageAsDataFromBuffer(int format)
{
CC_UNUSED_PARAM(format);

View File

@ -94,7 +94,12 @@ bool CCImage::initWithImageFile(const char * strPath, EImageFormat eImgFmt/* = e
return initWithImageData(data.getBuffer(), data.getSize(), eImgFmt);
}
bool CCImage::initWithImageData(void * pData, int nDataLen, EImageFormat eFmt/* = eSrcFmtPng*/)
bool CCImage::initWithImageData(void * pData,
int nDataLen,
EImageFormat eFmt/* = eSrcFmtPng*/,
int nWidth/* = 0*/,
int nHeight/* = 0*/,
int nBitsPerComponent/* = 8*/)
{
bool bRet = false;
do
@ -111,6 +116,11 @@ bool CCImage::initWithImageData(void * pData, int nDataLen, EImageFormat eFmt/*
bRet = _initWithJpgData(pData, nDataLen);
break;
}
else if (kFmtRawData == eFmt)
{
bRet = _initWithRawData(pData, nDataLen, nWidth, nHeight, nBitsPerComponent);
break;
}
} while (0);
return bRet;
}
@ -287,6 +297,272 @@ bool CCImage::_initWithPngData(void * pData, int nDatalen)
return bRet;
}
bool CCImage::_initWithRawData(void * pData, int nDatalen, int nWidth, int nHeight, int nBitsPerComponent)
{
bool bRet = false;
do
{
CC_BREAK_IF(0 == nWidth || 0 == nHeight);
m_nBitsPerComponent = nBitsPerComponent;
m_nHeight = (short)nHeight;
m_nWidth = (short)nWidth;
m_bHasAlpha = true;
// only RGBA8888 surported
int nBytesPerComponent = 4;
int nSize = nHeight * nWidth * nBytesPerComponent;
m_pData = new unsigned char[nSize];
CC_BREAK_IF(! m_pData);
memcpy(m_pData, pData, nSize);
bRet = true;
} while (0);
return bRet;
}
bool CCImage::saveToFile(const char *pszFilePath, bool bIsToRGB)
{
bool bRet = false;
do
{
CC_BREAK_IF(NULL == pszFilePath);
std::string strFilePath(pszFilePath);
CC_BREAK_IF(strFilePath.size() <= 4);
std::string strLowerCasePath(strFilePath);
for (unsigned int i = 0; i < strLowerCasePath.length(); ++i)
{
strLowerCasePath[i] = tolower(strFilePath[i]);
}
if (std::string::npos != strLowerCasePath.find(".png"))
{
CC_BREAK_IF(!_saveImageToPNG(pszFilePath, bIsToRGB));
}
else if (std::string::npos != strLowerCasePath.find(".jpg"))
{
CC_BREAK_IF(!_saveImageToJPG(pszFilePath));
}
else
{
break;
}
bRet = true;
} while (0);
return bRet;
}
bool CCImage::_saveImageToPNG(const char * pszFilePath, bool bIsToRGB)
{
bool bRet = false;
do
{
CC_BREAK_IF(NULL == pszFilePath);
FILE *fp;
png_structp png_ptr;
png_infop info_ptr;
png_colorp palette;
png_bytep *row_pointers;
fp = fopen(pszFilePath, "wb");
CC_BREAK_IF(NULL == fp);
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL)
{
fclose(fp);
break;
}
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL)
{
fclose(fp);
png_destroy_write_struct(&png_ptr, NULL);
break;
}
if (setjmp(png_jmpbuf(png_ptr)))
{
fclose(fp);
png_destroy_write_struct(&png_ptr, &info_ptr);
break;
}
png_init_io(png_ptr, fp);
if (!bIsToRGB && m_bHasAlpha)
{
png_set_IHDR(png_ptr, info_ptr, m_nWidth, m_nHeight, 8, PNG_COLOR_TYPE_RGB_ALPHA,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
}
else
{
png_set_IHDR(png_ptr, info_ptr, m_nWidth, m_nHeight, 8, PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
}
palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * sizeof (png_color));
png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH);
png_write_info(png_ptr, info_ptr);
png_set_packing(png_ptr);
row_pointers = (png_bytep *)malloc(m_nHeight * sizeof(png_bytep));
if(row_pointers == NULL)
{
fclose(fp);
png_destroy_write_struct(&png_ptr, &info_ptr);
break;
}
if (!m_bHasAlpha)
{
for (int i = 0; i < (int)m_nHeight; i++)
{
row_pointers[i] = (png_bytep)m_pData + i * m_nWidth * 3;
}
png_write_image(png_ptr, row_pointers);
free(row_pointers);
row_pointers = NULL;
}
else
{
if (bIsToRGB)
{
unsigned char *pTempData = new unsigned char[m_nWidth * m_nHeight * 3];
CC_BREAK_IF(NULL == pTempData);
for (int i = 0; i < m_nHeight; ++i)
{
for (int j = 0; j < m_nWidth; ++j)
{
pTempData[(i * m_nWidth + j) * 3] = m_pData[(i * m_nWidth + j) * 4];
pTempData[(i * m_nWidth + j) * 3 + 1] = m_pData[(i * m_nWidth + j) * 4 + 1];
pTempData[(i * m_nWidth + j) * 3 + 2] = m_pData[(i * m_nWidth + j) * 4 + 2];
}
}
for (int i = 0; i < (int)m_nHeight; i++)
{
row_pointers[i] = (png_bytep)pTempData + i * m_nWidth * 3;
}
png_write_image(png_ptr, row_pointers);
free(row_pointers);
row_pointers = NULL;
CC_SAFE_DELETE_ARRAY(pTempData);
}
else
{
for (int i = 0; i < (int)m_nHeight; i++)
{
row_pointers[i] = (png_bytep)m_pData + i * m_nWidth * 4;
}
png_write_image(png_ptr, row_pointers);
free(row_pointers);
row_pointers = NULL;
}
}
png_write_end(png_ptr, info_ptr);
png_free(png_ptr, palette);
palette = NULL;
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(fp);
bRet = true;
} while (0);
return bRet;
}
bool CCImage::_saveImageToJPG(const char * pszFilePath)
{
bool bRet = false;
do
{
CC_BREAK_IF(NULL == pszFilePath);
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE * outfile; /* target file */
JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
int row_stride; /* physical row width in image buffer */
cinfo.err = jpeg_std_error(&jerr);
/* Now we can initialize the JPEG compression object. */
jpeg_create_compress(&cinfo);
CC_BREAK_IF((outfile = fopen(pszFilePath, "wb")) == NULL);
jpeg_stdio_dest(&cinfo, outfile);
cinfo.image_width = m_nWidth; /* image width and height, in pixels */
cinfo.image_height = m_nHeight;
cinfo.input_components = 3; /* # of color components per pixel */
cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
jpeg_set_defaults(&cinfo);
jpeg_start_compress(&cinfo, TRUE);
row_stride = m_nWidth * 3; /* JSAMPLEs per row in image_buffer */
if (m_bHasAlpha)
{
unsigned char *pTempData = new unsigned char[m_nWidth * m_nHeight * 3];
CC_BREAK_IF(NULL == pTempData);
for (int i = 0; i < m_nHeight; ++i)
{
for (int j = 0; j < m_nWidth; ++j)
{
pTempData[(i * m_nWidth + j) * 3] = m_pData[(i * m_nWidth + j) * 4];
pTempData[(i * m_nWidth + j) * 3 + 1] = m_pData[(i * m_nWidth + j) * 4 + 1];
pTempData[(i * m_nWidth + j) * 3 + 2] = m_pData[(i * m_nWidth + j) * 4 + 2];
}
}
while (cinfo.next_scanline < cinfo.image_height) {
row_pointer[0] = & pTempData[cinfo.next_scanline * row_stride];
(void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
CC_SAFE_DELETE_ARRAY(pTempData);
}
else
{
while (cinfo.next_scanline < cinfo.image_height) {
row_pointer[0] = & m_pData[cinfo.next_scanline * row_stride];
(void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
}
jpeg_finish_compress(&cinfo);
fclose(outfile);
jpeg_destroy_compress(&cinfo);
bRet = true;
} while (0);
return bRet;
}
NS_CC_END;
#endif // (CC_TARGET_PLATFORM != TARGET_OS_IPHONE)

View File

@ -39,6 +39,7 @@ public:
{
kFmtJpg = 0,
kFmtPng,
kFmtRawData,
}EImageFormat;
typedef enum
@ -65,12 +66,18 @@ public:
/**
@brief Load image from stream buffer.
@warning Only support png data now.
@warning kFmtRawData only support RGBA8888
@param pBuffer stream buffer that hold the image data
@param nLength the length of data(managed in byte)
@param nWidth, nHeight, nBitsPerComponent are used for kFmtRawData
@return true if load correctly
*/
bool initWithImageData(void * pData, int nDataLen, EImageFormat eFmt = kFmtPng);
bool initWithImageData(void * pData,
int nDataLen,
EImageFormat eFmt = kFmtPng,
int nWidth = 0,
int nHeight = 0,
int nBitsPerComponent = 8);
/**
@brief Create image with specified string.
@ -99,18 +106,26 @@ public:
/**
@brief Save the CCImage data to specified file with specified format.
@param pszFilePath the file's absolute path, including file subfix
@param bIsToRGB if the image is saved as RGB format
*/
bool saveToFile(const char * pszFilePath) { CC_UNUSED_PARAM(pszFilePath);return false; }
bool saveToFile(const char *pszFilePath, bool bIsToRGB = true);
CC_SYNTHESIZE_READONLY(short, m_nWidth, Width);
CC_SYNTHESIZE_READONLY(short, m_nHeight, Height);
CC_SYNTHESIZE_READONLY(int, m_nBitsPerComponent, BitsPerComponent);
CC_SYNTHESIZE_READONLY(int, m_nBitsPerComponent, BitsPerComponent);
protected:
bool _initWithJpgData(void * pData, int nDatalen);
bool _initWithPngData(void * pData, int nDatalen);
bool _initWithJpgData(void *pData, int nDatalen);
bool _initWithPngData(void *pData, int nDatalen);
unsigned char * m_pData;
// @warning kFmtRawData only support RGBA8888
bool _initWithRawData(void *pData, int nDatalen, int nWidth, int nHeight, int nBitsPerComponent);
bool _saveImageToPNG(const char *pszFilePath, bool bIsToRGB = true);
bool _saveImageToJPG(const char *pszFilePath);
unsigned char *m_pData;
bool m_bHasAlpha;
bool m_bPreMulti;