renderTexture->saveToFile() bugged for image alpha values

Take any image that has transparent pixels in it and try to save it as a png using renderTexture. The transparent pixels will get added with the background color of the renderTexture despite setting the background’s alpha channel to zero with clear(0,0,0,0). Below is the code I used:

auto sprite = Sprite::create("original.png");
auto renderTexture = RenderTexture::create(64, 64, Texture2D::PixelFormat::RGBA8888);
renderTexture->clear(0,0,0,0);
renderTexture->begin();
sprite->setAnchorPoint(Vec2(0, 0));
sprite->setPosition(Vec2(0,0));
sprite->visit();
renderTexture->end();
renderTexture->saveToFile("rendertexture.png", Image::Format::PNG);

So in the above case because I cleared with rgba(0,0,0,0), my transparent pixels will end up being darker. One would assume that having an alpha of zero shouldn’t change the image at all.

Here is an example of the effect. The first image is my original, a square with the light green color rbga(55,255,0,100). The second image is the renderTexture image I get after running the above code. You can see it is now a dark green color rgba(21,100,0,100).

Original:
original
RenderTexture:
rendertexture

This error was also reproduced by @anon98020523 so I have opened a github issue here:
https://github.com/cocos2d/cocos2d-x/issues/18193


@zhangxm Are you here? Active on forum?

No updates?

@zhangxm any news? A lot of time passed but this issue hasn’t’ been fixed.
renderTexture->saveToFile() bugged for image alpha values · Issue #18193 · cocos2d/cocos2d-x · GitHub

Post by 26 September:

@hotcoco maybe you found how to fix this?

@zhangxm
Just want to assume this bug and add something.

For image:
1

Use code:

auto sprite = Sprite::create("1.png");
sprite->setPosition(Vec2(visibleSize.width * 0.5, visibleSize.height * 0.5));
addChild(sprite);
    
auto render = RenderTexture::create(visibleSize.width, visibleSize.height);
render->begin();
visit();
render->end();
render->saveToFile("rendered.png");

I have this scene:

sceme

Result rendered image of this scene:

rendered

Take a closer look:

Notice that not only transparent image but text has some artefacts.

Even more:

Add this code on top of code posted before:

auto gradient = LayerGradient::create(Color4B(100, 250, 100, 255.0), Color4B(5, 5, 5, 0.0));
gradient->setContentSize(visibleSize);
addChild(gradient);

Result of rendered image compare to actual scene with gradient:

Left - rendered. Right - actual scene.

Notice - rendered gradient is different than actual saved file.

It’s like has some transparency where it should’t have. Top of gradient isn’t transparent, but on rendered image - it’s transparent:

screen shot

Hello @hotcoco @anon98020523 @zhangxm
@drelaptop
I have that same issue with your engine.

Here is image I’m using:

rect_1

Here is the code:

Sprite *img = Sprite::createWithSpriteFrameName("Objects/rect_1.png");
img->setAnchorPoint(Vec2(0, 0));
img->setBlendFunc(BlendFunc::DISABLE);

LayerColor *stencilNode = LayerColor::create(Color4B(0, 0, 0, 255), 50, 50);
ClippingNode *clippingNode = ClippingNode::create();
clippingNode->setStencil(stencilNode);
clippingNode->setInverted(false);
clippingNode->setAlphaThreshold(0.1);
clippingNode->addChild(img);

addChild(clippingNode);

RenderTexture *render = RenderTexture::create(img->getContentSize().width,
                                             img->getContentSize().height,
                                              Texture2D::PixelFormat::RGBA8888,
                                              GL_DEPTH24_STENCIL8);

render->beginWithClear(0, 0, 0, 0);
clippingNode->cocos2d::Node::visit();
render->end();
render->saveToFile("result.png");

Reading comments from renderTexture->saveToFile() bugged for image alpha values · Issue #18193 · cocos2d/cocos2d-x · GitHub I used:

img->setBlendFunc(BlendFunc::DISABLE); as you see.

But anyway result is(notice left side and bottom with some grayscale line):

result

So, I’m trying to slice a sprite and get new part as file.

As it was reported - some kind of grayscale pixels around rendered image. It’s not should be there. It’s a bug. Can someone from cocos2d-x developers comment this and help me? Thank you in advance.

Anyone? It’s like urgent. My team has problems with this and it’s really like a bug, we tried everything to avoid this, but no success.

You are using 3.17 and this still occurs? The original bug report references 3.15.1.

We always using latest.

My workaround: do not use ClippingNode and RenderTexture (bugs, performance issues). Use some image library (opencv in my case), keep image in memory, transform in memory. Use Texture2D::initWithData to display

Thats looks like very complicated. I hope they fix this bug.

Hello? Anyone? It seems that only after @slackmoehrle asks someone like @zhangxm or @drelaptop who as I now understand a cocos2d-x developers, only after that they arrive here. Otherwise not response at all. Thats sad for me, I’m developing my game with this engine, but now I realize that there are not help. Is this will be changed? Please.

Sorry, we are busy for creator 2.0 releasing. It will be better after the releasing.

For anyone facing this issue, I’ve just created a pull request with changes to Cocos2d-x to allow users to save files with non-premultiplied alpha. It works by reversing the PMA, so it’ll be pretty close to the original image, but there’s no way to actually get perfect RGB values since some information is lost in the initial PMA process.

The new method is RenderTexture::saveToFileAsNonPMA().

There will be no strange artifacts in a transparent image, like the grey borders usually seen in PMA output.

For more info, see this github issue.