Problem when saving transparent PNG image from CCRenderTexture on Android - [FIXED]

Hi everyone,

Here is the example code for this situation.

I have a drawing layer which contain the brushes.(CCSprite with the blendFunc) (This function is for setting up the color of the brush)

mSprite->setBlendFunc((ccBlendFunc){CC_BLEND_SRC, CC_BLEND_DST}); mDrawingLayer->addChild(mSprite);

Then, I want to save the PNG file for only the mSprite, so I use the CCRenderTexture.

CCRenderTexture *render = CCRenderTexture::create(mCanvasRect.size.width, mCanvasRect.size.height,kCCTexture2DPixelFormat_RGBA8888); render->getSprite()->setAnchorPoint(CCPointZero); render->beginWithClear(0, 0, 0, 0); mDrawingLayer->visit(); render->end(); // ********************************** // // Saving PNG file with Transparent // ********************************** // CCImage *image = render->newCCImage(); string filePath = CCFileUtils::sharedFileUtils()->getWriteablePath() + "test.png"; if (image->saveToFile(filePath.c_str(),false)) { CCLog("Succeed!"); } else { CCLog("Fail!"); } // ********************************** // // Loading PNG file with Transparent // ********************************** // string loadPath = CCFileUtils::sharedFileUtils()->getWriteablePath() + "test.png"; CCSprite *sprite = CCSprite::create(loadPath.c_str()); this->addChild(sprite);

I can save the file on Android without any problem. However, the problem is when I load the file and add it to the scene again.
I got the black glow like the image below.

And here is the image that I expected.

NOTE: This is only happen on Android devices. (I’ve tested (All Amazon Kindle, NOOK HD & HD+, HTC)
Thanks!

Jate

P.S. I also found that when I use the newCCImage() from CCRenderTexture.
The color from the background get added to the image’s pixel where the alpha value isn’t 0 or 1 even though the alpha value of the background already set to 0.

if (image->saveToFile(filePath.c_str(),false))
Try true.

Thanks for the answer,

I tried.
Also, if I use “true”. It won’t be transparent.
I need it to be transparent because this will be placed on top of the background layer.

OK, I found the way to solve this problem.

PROBLEM:

Basically, when using CCRenderTexture the background need to be created using “beginWithClear(0, 0, 0, 0)” or begin().
Then, the background will get premultiply with any image you applied in between begin() and end() even though you set the alpha to 0.
When you use newCCImage() to copy the pixel out and save to png file. The image data will also have the premultiply.
On the iOS works because the UIImage seems to divide the premultiply alpha for you.

ANSWER:

So, I just get the raw image data then divide the color of each pixel with the result alpha. I’ve created a class derive from CCRenderTexture and create
The new function to divide the color pixel by the alpha.

Here is the equation for getting the original color without premultiply alpha.
result = ColorResult/(Alpha1 + (Alpha2 * (1 - Alpha1);

In the CCRenderTexture function newCCImage() - Added this code between this->end() and if ( flipImage )

// HACKED Divide the alpha from color pixel

for (int i = 0; i < nSavedBufferHeight; i)
{
for
{
GLfloat As = * 4
3])/255.0;
if
{
GLfloat Rs = * 4])/255.0;
GLfloat Gs = * 4
1])/255.0;
GLfloat Bs = (GLfloat)(pTempData[(i * nSavedBufferWidth + j) * 4 + 2])/255.0;

GLfloat Rd = Rs/As + (this->mBackgroundAlpha * (1-As));
GLfloat Gd = Gs/As + (this->mBackgroundAlpha * (1-As));
GLfloat Bd = Bs/As + (this->mBackgroundAlpha * (1-As));

GLubyte nRd = (GLubyte)(Rd * 255.0);
GLubyte nGd = (GLubyte)(Gd * 255.0);
GLubyte nBd = (GLubyte)(Bd * 255.0);

pTempData[(i * nSavedBufferWidth + j) * 4] = nRd;
pTempData[(i * nSavedBufferWidth + j) * 4 + 1] = nGd;
pTempData[(i * nSavedBufferWidth + j) * 4 + 2] = nBd;
}
}
}

Can you tell please, on which devices you seen this issue and on which devices you’ve tested fix?

Hi Sergey,

I believe this problem seems to happen on all android devices as I’ve searched through.
It seems like when you trying to save and load the transparent PNG using CCImage, the image always get premultiply.
So, those will solution will do the trick if you don’t want premultiply image.

However, I only have tested it on Kindle Fire, Kindle HD 7, Kindle HD 9, Nook HD, Nook HD+, HTC One, and Mortola Tablet.

How can i save this image to the gallery ?

Hi Jate Wit, this is my exact problem.

I’m happy you have fixed, but I’m not able to use your code.

there is a variable: mBackgroundAlpha, that I not find.

I use cocos 2.1.5, what does this variable mean?

can you help me, thanks.
Don

wow, that’s great.

I used 0 as mBackgroundAlpha and the black border is disappeared.

thanks a lot
Don

The problem still exists in 3.3 but can be fixed the same way as jatewit did.

Use this patched class for v3.3: http://pastebin.com/cbM3MJCW

Big thanks!

Using the fix posted by creiser, it isn’t working properly when an image contains a transparent color with yellow- yellow gets rendered to blue, peach colors are getting rendered with cyan, and oranges are getting rendered green. It’s really weird. It might have something to do with the GPU, but I haven’t been able to test on anything else than this Arduno. Anyone else have any funny resutls?

Remove the folder containing the resource if any other than “Resources” or inside “Resources” folder. Now add the folder of assets again, wait, make sure to select right target in “option” menu on Bottom left of selection window before you go for “Add” menu.

What was the Problem…?? even though the folder was available in project but the same was not logically available in you currently working target.

Thanks.