black borders around sprites

There have been some posts about problems with black borders around sprites with cocos2d-x-3.0 and I have seen them for myself. The same sprite textures do not have black borders in cocos2d-x-2.x.x. I discovered the problem is that in cocos2d-x-3.0, when a PNG file is loaded in, alpha is not pre-multiplied. However, in cocos2d-x-2.x.x, there is code to pre-mulitply the alpha.

I believe BlendFunc::ALPHA_NON_PREMULTIPLIED is blending properly, but that when it blends properly, it adds the black borders. What we really want is to pre-multiply the alpha, and then use BlendFunc::ALPHA_PREMULTIPLIED, which does not add the black borders. (I am not 100% certain about this, but I think it is true)

Is this a bug or a feature? Was it intentional in cocos2d-x-3.0 to not pre-multiply the alpha when loading a PNG, or was this a mistake that was overlooked?

Here is how I fixed the problem in cocos2d-x-3.0rc1:

In the file CCImage.cpp (CCImageCommon_cpp.h for earlier versions of cocos2d-x-3.0), in the method initWithPngData(), right after the call to png_read_end(), replace this code:

_preMulti = false;

with this (which is what was done in cocos2d-x-2.x.x with variable names changed appropriately):

png_uint_32 channel = rowbytes/_width;
if (channel == 4)
{
    _hasPremultipliedAlpha = true;
    unsigned int *tmp = (unsigned int *)_data;
    for(unsigned short i = 0; i < _height; i++)
    {
        for(unsigned int j = 0; j < rowbytes; j += 4)
        {
            *tmp++ = CC_RGB_PREMULTIPLY_ALPHA( row_pointers[i][j], row_pointers[i][j + 1], 
                                               row_pointers[i][j + 2], row_pointers[i][j + 3] );
        }
    }
            
    _preMulti = true;
}

For my test case to illustrate the problem, I added this code to HelloWorldScene.cpp:

auto s1 = Sprite::create("circle.png");
s1->setPosition(75, 100);
this->addChild(s1);

auto s2 = Sprite::create("circle.png");
s2->setPosition(100, 100);
this->addChild(s2);

I have seen the black borders on windows and android, but I’m guessing it affects all platforms.


black_border_example.png (131.7 KB)


circle.png (0.5 KB)

Hey guy, if the image is pre-multiplied, and you need to call setBlendFunc(BlendFunc::ALPHA_PREMULTIPLIED) as following:

auto s2 = Sprite::create("circle.png");
s2->setPosition(100, 100);
s2->setBlendFunc(BlendFunc::ALPHA_PREMULTIPLIED);
this->addChild(s2);

I hope this helps.

Ryeeeeee, thank you for responding. I apologize, because my post was not clear. My images are not pre-multiplied. However, the example I gave using “circle.png” behaves as if it were pre-multiplied. Let me show you the problem with a different image. “circle2.png” is another white circle with a transparent background.

This code is used in each example:

auto s1 = Sprite::create("circle2.png");
s1->setPosition(75, 100);
this->addChild(s1);

auto s2 = Sprite::create("circle2.png");
s2->setPosition(100, 100);
this->addChild(s2);

###Example A
Using unmodified CCImage.cpp, sprites created in HelloWorldScene.cpp.
Result A: Dark borders around sprite images.

###Example B
Using unmodified CCImage.cpp, sprites created in HelloWorldScene.cpp with additional code to use pre-multiplied alpha BlendFunc

s1->setBlendFunc(BlendFunc::ALPHA_PREMULTIPLIED);
s2->setBlendFunc(BlendFunc::ALPHA_PREMULTIPLIED);

Result B: Transparent image background turned white!

###Example C
Using my adjustment to CCImage.cpp (in original post), sprites created in HelloWorldScene.cpp, without setting the BlendFunc.

Result C: Everything looks good, no dark borders, no transparent background turning white!

###The Moral of the Story
My mod to CCImage.cpp came from the cocos2d-x-2.2.3 codebase. It will convert a non-pre-multiplied PNG image into pre-multiplied after the data has been read, and prevent the “dark border” problem and other alpha-related artifacts. I don’t understand why this functionality was not put into 3.0.

Waiting for next Upgrade for this issue…
:frowning:

Just Updated to 3.0RC2, seems the white border problem still presented…
It likes a Alpha Blending a bug, a Pixel with small Alpha value blending to BG will get a wrong Value, shows a unsuitable edge…
Waiting for Upgrade…

@JohnnyLee

Hi! Can you share your Modified cpp file?
Thanks alot!

Thank you !!! You have resolved my problem !

When I add sprite before I have an alpha and my sprite not display correctly. With your solution my problem is resolved !

(sorry for my english).

is this applied cocos2dx engine?