I'm looking for an efficient way to filter a specific color from a bitmapData object in ActionScript 3. Currently I use a loop with readByte32(). This takes about a second to process which is unacceptable. I have been trying to get paletteMap() to work but so far haven't been able to grasp its API (any truly useful links? Google has failed me...).
Here's my current logic, which I want to improve:
var n:int = bitmapData.width;
for (var i:int = 0; i < n; i++) {
var m:int = bitmapData.height;
for (var j:int = 0; j < m; j++) {
var color:int = bitmapData.getPixel(i, j);
if (color == 0xCACACA) {
bitma开发者_JS百科pData.setPixel32(i, j, 0x00000000);
}
}
}
I can get slightly better performance from using Vectors but it's only marginally better...
var v:Vector.<uint> = bitmapData.getVector(bitmapData.rect);
var n:int = bitmapData.width * bitmapData.height;
for (var i:int = 0; i < n; i++) {
var color:uint = v[i];
v[i] = color == 0xFFCACACA ? 0x00000000 : color;
}
bitmapData.setVector(bitmapData.rect, v);
I really think there must be a better way to do this that only takes a few 100 milliseconds. If anyone can unlock the mysteries of bitmapData for me, you will be the new leader of my people.
PS I am using bitmapData.lock() and unlock(); I just didn't post the boilerplate stuff.
An easy way is using the threshold method. It's a bit cumbersome at first, but it's pretty fast (as fast as you'll get, I think)
This will change every red pixel (considering red only a pixel whose value is exactly 0xffff0000) to blue (0xff0000ff).
var colorToReplace:uint = 0xffff0000;
var newColor:uint = 0xff0000ff;
var maskToUse:uint = 0xffffffff;
var rect:Rectangle = new Rectangle(0,0,bitmapData.width,bitmapData.height);
var p:Point = new Point(0,0);
bitmapData.threshold(bitmapData, rect, p, "==", colorToReplace,
newColor, maskToUse, true);
Flash has an API to a shader like language called pixel bender that may be of use to you in this case. Here is a tutorial from adobe on how to apply a pixel bender filter to an image in flash.
Otherwise you could processes rows at a time. (Note a slight error in your code was to re-get the height on each iteration of width):
private var currentRow:Number = 0;
private var timer:Timer;
public function processImage(event:Event=null):void
{
var m:int = bitmapData.height;
for (var j:int = 0; j < m; j++)
{
if (bitmapData.getPixel(currentRow, j) == 0xCACACA)
{
bitmapData.setPixel32(currentRow, j, 0x00000000);
}
}
currentRow++;
if(currentRow < bitmapData.width)
{
timer = new Timer(1, 500);
timer.addEventListener(TimerEvent.COMPLETE, processImage);
timer.start();
}
}
The processing will take a bit longer but at least your display won't be blocked.
精彩评论