Hoang Huynh
Hoang Huynh

Reputation: 1403

Check if a PNG image contains (semi) transparent pixel using AS3

I want to use AS3 to check a (32-bit ARGB) PNG image to see if it contains any (semi) transparent pixel (returning true or false). What is the fastest way to do this?

Upvotes: 2

Views: 2799

Answers (2)

inhan
inhan

Reputation: 7470

A long time ago I was looking for the same thing and I tried using loops to check for each pixel. But that took a lot of time and consumed incredible amount of CPU. Luckily we have the BitmapData.compare() method, which outputs a Bitmapdata if there are any diferences in compared BitmapData objects.

Also there's the BitmapData.transparent property, which actually directly gives you the answer as a Boolean. But I have never used it directly on a loaded image myself.

import flash.display.Loader;
import flash.net.URLRequest;
import flash.events.Event;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.geom.Point;

var ldr:Loader = new Loader();
var req:URLRequest = new URLRequest('someImage.png');
ldr.contentLoaderInfo.addEventListener(Event.COMPLETE,imgLoaded);
ldr.load(req);

function imgLoaded(e:Event):void {
    var l:Loader = e.target.loader,
    bmp:Bitmap = l.content as Bitmap,
    file:String = l.contentLoaderInfo.url.match(/[^\/\\]+$/)[0];
    trace(bmp.bitmapData.transparent);
    // I think this default property should do it but
    // in case it does not, here's another approach:
    var trans:Boolean = isTransparent(bmp.bitmapData);
    trace(file,'is'+(trans ? '' : ' not'),'transparent');
}

function isTransparent(bmpD:BitmapData):Boolean {
    var dummy:BitmapData = new BitmapData(bmpD.width,bmpD.height,false,0xFF6600);
    // create a BitmapData with the size of the source BitmapData
    // painted in a color (I picked orange)
    dummy.copyPixels(bmpD,dummy.rect,new Point());
    // copy pixels of the original image onto this orange BitmapData
    var diffBmpD:BitmapData = bmpD.compare(dummy) as BitmapData;
    // this will return null if both BitmapData objects are identical
    // or a BitmapData otherwise
    return diffBmpD != null;
}

Upvotes: 5

Josh
Josh

Reputation: 8149

Only way I know of doing it is manually, unfortunately. There may be a built in way of doing it, but my guess is it would use the same method described below

var bytes:ByteArray = ( loader.content as Bitmap ).bitmapData.getPixels(); //that getter may be incorrect. I'd verify the property names are correct first
var bLength:Number = bytes.length; //you'll gain considerable speed by saving the length to memory rather than accessing it repeatedly
for ( var i:Number = 0; i < bLength; i++ ) {
    var alpha:uint = bytes[i] >> 24 & 255;
    if ( alpha > 0 && alpha < 255 ) {
        //put code in here that will run if it is semi transparent
    }
    if ( alpha == 255 ) {
        //put code in here that will run if it is entirely opaque
    }
    if ( alpha == 0 ) {
        //put code in here that will run if it is entirely transparent
    }
}

Keep in mind that the ByteArray will have 32 bits (or 4 bytes (8 bits per byte)) of data for each individual pixel. After the loop is finished, you should definitely do a bytes.clear(); for memory sake and you should also break; the loop the second you hit what you want (otherwise it will keep running until it checks each and every pixel in your image. A 256x256 image will run 65,536 times, for comparison's sake).

Just for clarity:

  • RGBA/ARGB is measured with values 0-255
  • 0 is black (0x000000), 255 is white (0xffffff)
  • The blacker the alpha byte, the more transparent it is
  • We use simple bitwise shifts to get the actual value of that byte (bits 24-32) and set it to a value between 0 and 255
  • You can also do this for RGB channels. B is >> 0 & 255, G is >> 8 & 255, and R is >> 16 & 255

Upvotes: 2

Related Questions