Loading PNG's automatically premultiplies the alpha

Loading PNG's automatically premultiplies the alpha
0.0 0


I’m currently writing a rendering node that has a fragment shader that uses the alpha channel in a non-standard way. It doesn’t use it for blending. It uses it for other things.
Anyhow, normally there’d be no problem with this, but what I’m finding is that the PNG loader makes a lot of assumptions about how you’re going to use your image. Specifically, in CCImageCommon_cpp.h, I see this code:

            for(unsigned short i = 0; i < m_nHeight; 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] );

The problem here is that this is blowing away the information in my color channels. I need the image to stay non-pre-multiplied. I just want the raw color and alpha channels with no modification.
On a related note, I do have some images I’m rendering out of Maya that has premultiplied alpha already. If I put it in a PNG, I think it’s premultiplying it again, double-darkening those edges.
This is in version 2.1.4. It sounds like this might be already addressed in 3.0? Ideally there’d be some sort of flag we could set which would turn this premultiplying on or off. In my case I really don’t want this functionality for my specific use case.
Short of modifying the cocos2d code locally, is there any sort of workaround that anyone could suggest in the meantime? I’ve tried saving out a TIFF and loading that, and it actually does the right thing, but unfortunately pops up an annoying warning dialog on load in Windows (my usual development platform). Perhaps PVR would work, but I don’t want the compression. I really just want the raw texture data, unmodified.


So, I’ve locally added a flag to cocos2d on my build to allow turning off premultiplying of alpha when loading PNG files. This seems to be working for me for now, but I’d love to know what the plans are for 3.0, and if there’s any thought to add a flag for 2.x which allows disabling of this premultiply step.
On a related note, it turns out that indeed my art from Maya is being rendered onto a black background so it also effectively has premultiplied alpha built into it, so cocos2d isn’t doing me any favors by premultiplying it again. I’m sure I could fix that in my art pipeline somehow, so it’s not the end of the world, but once again, all would be a lot easier if the image loader wouldn’t munge my data and just allow me to render the image correctly by setting my blend functions appropriately for the image.


I’ve ran into this problem too: I have a fragment shader which uses 4 channels as separate raw data, and I don’t need the premultiplied alpha. At first I thought that my toolset does not save PNGs properly and I decided that I’ll be fine with 3 channels, so I used RGB only. But now it appears that I require the alpha channel too. Thanks to Alan for confirming that Cocos2d-x does premultiplication by itself. Now at least I can make some local patches to control this behaviour.
It’s too bad that no one from development team has answered. I have started several threads which I consinder to be quite important for other developers as well. Unfortunately they stayed unanswered too.


As an update to this, here’s what I’ve discovered and how I deal with the problem:

  • This forced premultiplication of alpha is only done explicitly on Windows. In iOS, the premultiplication happens as a result of using UIImage to load PNG images. It seems that UIImage does premultiplication and you can’t turn it off. So I understand now why the Windows code forces premultiplication on you: It’s to match the behaviour under iOS.
  • Since it was so easy to turn off premultiplication when loading via libpng, as is done under Windows, I decided it was time to bring that over to the iOS side of things. So I pulled in libpng in my iOS app, and wrote a wrapper around it with my own code to load a PNG and spit back out a CCTexture2D. Internally, I load the PNG using libpng, then create a new CCImage, initialize it with pImage~~>initWithImageData, and then create a new CCTexture2D, and initialize that with pTexture~~>initWithImage(pImage). You can then release the pImage and return the CCTexture2D. This is basically how it’s done internally in cocos2d, but simplified since it doesn’t bother with the shared texture cache.
    If you really need alpha, hopefully this will get you on the right track. If you need any more specific info, I’d be happy to help.


Thanks for such a great detailed answer! I haven’t thought that Cocos2dx uses different ways to load images on different platform, and now I’m a little bit confused. Probably I’ll stay with default premultiplied PNGs and use an additional texture (I hope my performance budget allows doing that).