mirror of https://github.com/axmolengine/axmol.git
fixed #630 To realize the buffer-saving function in CCRenderTexture
This commit is contained in:
parent
fb1132bbf8
commit
a253909030
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue