Flex/Flash/Actionscript

Problem with Transparent PNGs in Flex using @Embed

This was posted to flexcoders today. Here’s the problem: we’ve got a transparent PNG that is loaded into a <mx:Image /> control. Normally this control handles PNG transparency just fine. However, someone posted an example of a problematic PNG. If you set the source of the Image control to use the URL for the PNG on the server, then the image loads fine with transparency. But if you try to embed the image using the @Embed syntax, then the transparency is ignored and an ugly background color shows up.

I don’t know really exactly where the problem lies. The Image component (which is really just a glorified SWFLoader) should load the exact same image whether it’s loading from a URL or an embedded asset. But it doesn’t, and the test case posted on flexcoders proves this. Now, whether there’s something weird about the image I have no idea. But the fact is that it should have transparency and using @Embed within an Image component breaks the transparency.

So here’s a solution. Basically what I did was extend the SWFLoader class and change part of the loadContent() method. To do this I had to make a copy of the SWFLoader class (I called it BaseSWFLoader) and change the needed methods to protected instead of private. Once I did that I was able to create a subclass that could override loadContent and act differently for embedded assets.

The approach I took was to get the ByteArray of the embedded asset, then load that ByteArray using the loadBytes method of the Loader class. When I tried loading the problematic embedded PNG using loadBytes, it magically loaded fine with the transparency.

There’s a trick here, which is to set the mimeType of the embedded asset. If you set the mimeType to application/octet-stream, then when it gets handled by the custom ByteArraySwfLoader class I created we can get access to the raw ByteArray of the embedded asset. This means we can pass the ByteArray to a Loader component, which will be able to handle it using the loadBytes() method. If you don’t set the mimeType of the embedded asset then you don’t get the ByteArray of the asset, instead you just get a Bitmap object.

The small example below shows the problematic PNG loaded using both the <Image /> control and my custom class. Both work fine if we’re loading via a URL. But if we’re loading by using the @Embed syntax then the normal Image component messes up the transparency.

View the source.

This movie requires Flash Player 9.

Standard

17 thoughts on “Problem with Transparent PNGs in Flex using @Embed

  1. That is really wierd…

    I can show you a perfect example of using transparent PNGs embedded in the source of an image tag working perfectly. http://www.ufc.com

    The media player on the home page is done in flex using transparent PNG images for almost everything, including the frame which I laid over video and images with a shadow using mx:image tags (showing that the transparency works perfectly).

    Mike.

  2. Just to be clear, I just checked the source and am definitely using the @Embed format multiple times without issue, like so:

    Sorry for the extended comment.

    Mike.

  3. Yeah, I’m certainly not saying that the <Image /> component doesn’t normally work with transparent PNGs. It usually does. I think there’s something weird about that image, and I don’t know the PNG format well enough to really figure out why that particular image might be special. But download that PNG image and try it out and it won’t work right.

    The discussion on flexcoders mostly went along the lines of: “But of course you can use transparent PNGs in the Image component!” My point was just to validate the original poster’s observation that in this particular case, with this image, it doesn’t work right.

  4. Haha, yea…I realized I hadn’t quite gotten it right when I read the entire thread you linked to. I apologize for being too quick on that.

    Sorry for the confusion haha.

    Mike.

  5. Jason says:

    I’ve posted a new response to the mailing list but wanted to make sure anyone reading this would follow along. Here’s the short version:

    I’ve put together this transparency test app:

    http://three.fsphost.com/flex2/pngbug/PNGBug.html

    (Note: that for some reason, I have problems in Firefox loading Flex apps off this host. If you run into the same problem, try IE and/or go to the srcview and run it locally)

    It’s based off this site:
    http://entropymine.com/jason/testbed/pngtrans/

    It has a whole bunch of different PNG types with non-transparent GIF showing how it should look properly. As you can see, some render properly in both the Embed/non-embed, some render correctly as a non-Embed and some render incorrectly as either. Hopefully, this will give someone a good test to run against when fixing these bugs.

    So first, there are the problems in support for PNG.

    Second, there is the discrepancy between using @Embed and not using @Embed.

  6. Pingback: FlexAbility » Blog Archive » Problems with Alpha Transparency in PNGs?

  7. Marcio says:

    I create the following function

    ———————————

    package com.cerebrum.utils {

    import mx.rpc.events.ResultEvent
    import mx.controls.Alert;

    public class Result {

    [Embed(“/assets/images/dialog-information.png”)]
    public var IconDialogInformation:Class;

    public function Result(event:ResultEvent,MyObject:Object):void {
    Alert.show(“teste”, “teste”, 4, null, null, IconDialogInformation);
    }

    }

    }

    ———————————

    I as follows

    import Result;

    Result(event, meuobjeto);

    ———————————

    Is presented in the following error flex builder

    1137: Incorrect number of arguments. Expected no more than 1.

    ———————————

    How should I inform the function that actually has 2 parameters?

  8. Wow! Doug McCune, thanks a ton for this post. My experience is that this is not related specifically to the embbed issue. I was able to get the same png to pass using but fail when generationg Image() in AS code. The workaround that we were able to do at this end was to export the png from CS3 into a new file every time. Any asset which was previously export as (jpg or other) contained corrupted transparency in the png. I hope this helps someone else, and the link to the adobe bug certainly shed some light on the issue for us and save me a significant amount of time.

  9. Fotis says:

    The problem only appears with 8-bit transparent pngs. If you save as 24bit the problem goes away… In case it helps anybody ;-)

  10. I’m having an issue with a bunch of PNG files that although will load fine locally refuse to load and display a broken link when accessed off the server via HTTP … I have a feeling it has something to do with the PNG … there used to be an issue with the way they were saved … progressive option???

  11. Sean M says:

    I’m trying to use the new classes, but I get an out of range error. Has anyone else experienced this problem?

  12. NewAge says:

    I wrote this code, but it shows me always a not transparent image…

    private var bitmap_mod:BitmapData = new BitmapData(1600, 1600);

    [Embed(source=”/assets/terrain/gamemap_t0.gif”,mimeType=”image/jpeg”)]
    private var Mountain01:Class;

    private var library:Object = {};
    var bma:BitmapAsset = new Mountain01() as BitmapAsset;
    library[0] = bma.bitmapData;

    var tile:Rectangle;
    tile = new Rectangle(0,0,140,140);

    bitmap_mod.copyPixels(library[0], tile, new Point(0, 0));

    Can Someone help me?

  13. I just encountered an issue with embedded PNG’s with transparency, created with Paint.NET . When I create a transparent gradient that extended beyond the boundary of the image, Flex 4 does not display the transparency at all. However, when the gradient ends within the image, the transparency displays properly.

Comments are closed.