View comments | RSS feed

paletteMap (BitmapData.paletteMap method)

public paletteMap(sourceBitmap:BitmapData, sourceRect:Rectangle, destPoint:Point, [redArray:Array], [greenArray:Array], [blueArray:Array], [alphaArray:Array]) : Void

Remaps the color channel values in an image that has up to four arrays of color palette data, one for each channel.

Flash Player uses the following formula to generate the resulting image.

After the red, green, blue, and alpha values are computed, they are added together using standard 32-bit-integer arithmetic. The red, green, blue, and alpha channel values of each pixel are is extracted into a separate 0 to 255 value. These values are used to look up new color values in the appropriate array: redArray, greenArray, blueArray, and alphaArray. Each of these four arrays should contain 256 values. After all four of the new channel values are retrieved, they are combined into a standard ARGB value, which is applied to the pixel.

Cross-channel effects can be supported with this method. Each input array can contain full 32-bit values, and there is no shifting when the values are added together. This routine does not support per-channel clamping.

If no array is specified for a channel, the color channel is simply copied from the source image to the destination image.

You can use this method for a variety of effects such as general palette mapping (taking one channel and converting it to a false color image). You can also use this method for a variety of advanced color manipulation algorithms, such as gamma, curves, levels, and quantizing.

Availability: ActionScript 1.0; Flash Player 8

Parameters

sourceBitmap:flash.display.BitmapData - The input bitmap image to use. The source image can be a different BitmapData object, or it can refer to the current BitmapData object.

sourceRect:flash.geom.Rectangle - A rectangle that defines the area of the source image to use as input.

destPoint:flash.geom.Point - The point within the destination image (the current BitmapData object) that corresponds to upper-left corner of the source rectangle.

redArray:Array [optional] - If redArray is not null, red = redArray[source red value] else red = source rect value.

greenArray:Array [optional] - If greenArray is not null, green = greenArray[source green value] else green = source green value.

blueArray:Array [optional] - If blueArray is not null, blue = blueArray[source blue value] else blue = source blue value.

alphaArray:Array [optional] - If alphaArray is not null, alpha = alphaArray[source alpha value] else alpha = source alpha value.

Example

The following example shows how to use a palette map to convert solid red to green, and solid green to red in a single BitmapData object.

import flash.display.BitmapData;
import flash.geom.Rectangle;
import flash.geom.Point;

var myBitmapData:BitmapData = new BitmapData(100, 80, false, 0x00FF0000);

var mc:MovieClip = this.createEmptyMovieClip("mc", this.getNextHighestDepth()); mc.attachBitmap(myBitmapData, this.getNextHighestDepth());

myBitmapData.fillRect(new Rectangle(51, 0, 50, 80), 0x0000FF00);

mc.onPress = function() {
    var redArray:Array = new Array(256);
    var greenArray:Array = new Array(256);

    for(var i = 0; i < 255; i++) {
        redArray[i] = 0x00000000;
        greenArray[i] = 0x00000000;
    }

    redArray[0xFF] = 0x0000FF00;
    greenArray[0xFF] = 0x00FF0000;

    myBitmapData.paletteMap(myBitmapData, new Rectangle(0, 0, 100, 40), new Point(0, 0), redArray, greenArray, null, null);
}

Version 8

Comments


Roks-1 said on Sep 25, 2005 at 8:36 PM :
What does the for loop in this code do? When you take it out the code still works the same.
pan69 said on Oct 9, 2005 at 12:10 AM :
>> After the red, green, blue, and alpha values are computed, they...

Where do these values come from? Can the help be more specific about this ?
Mario Klingemann said on Mar 19, 2006 at 5:34 AM :
After several tests of paletteMap I must say that there seems to be a serious flaw in this function. At least it does not behave like the documentation says. It looks to me like internally something like this happens:

- the blue channel is extracted first and the value of the blue lookup array is written into the target bitmap
- now the green channel is extracted - BUT - not from the source image but from the already changed target bitmap. Then the value from the green lookup array is added to the target bitmap. This addition has very strange effect when the sum is > 255.
- the same procedure follows with red and alpha

The problem here is that I don't think that this is how it was intended to work. In my opinion the results of the single channel transformations should be combined at the very end - otherwise the results are almost impredictable.

But there is also some results that I don't understand at all. Here is some example code - if I have understood paletteMap correctly the input and the output of this code should be equal because I replace each channel with the same value that is already in there. But the results are very weird for channel values below 113. Here are some traces:

[...]
Input: 9/9/9/9 Output: 9/0/0/0
Input: 10/10/10/10 Output: 10/0/0/0
Input: 11/11/11/11 Output: 11/0/0/0
Input: 12/12/12/12 Output: 12/21/21/21
Input: 13/13/13/13 Output: 13/20/20/20
Input: 14/14/14/14 Output: 14/18/18/18
[...]
Input: 26/26/26/26 Output: 26/29/29/29
Input: 27/27/27/27 Output: 27/28/28/28
Input: 28/28/28/28 Output: 28/27/27/27
Input: 29/29/29/29 Output: 29/26/26/26
[...]
Input: 109/109/109/109 Output: 109/110/110/110
Input: 110/110/110/110 Output: 110/109/109/109
Input: 111/111/111/111 Output: 111/110/110/110
Input: 112/112/112/112 Output: 112/111/111/111
Input: 113/113/113/113 Output: 113/113/113/113
Input: 114/114/114/114 Output: 114/114/114/114
Input: 115/115/115/115 Output: 115/115/115/115
Input: 116/116/116/116 Output: 116/116/116/116



import flash.display.BitmapData;
import flash.geom.*

var zero:Point = new Point();

var test:BitmapData = new BitmapData(1,1,true,0);

var a:Array = new Array();
var r:Array = new Array();
var g:Array = new Array();
var b:Array = new Array();

for (var i:Number =0;i<256;i++){
a[i] = i<<24;
r[i] = i<<16;
g[i] = i<<8;
b[i] = i;
}

for (var i:Number=0;i<256;i++){

// this creates a pixel value in the format 0x01010101 / 0x02020202 / ... / 0xffffffff
var p:Number=i;
for(j:Number=0;j<3;j++){
p<<=8;
p|=i;
}


test.fillRect(test.rectangle,p)
test.paletteMap( test, test.rectangle, zero,r,g,b,a);
showPixelValue(p,test.getPixel32(0,0));
}

function showPixelValue(pin,pout)
{
trace("Input: "+((pin>>24)&0xff)+"/"+((pin>>16)&0xff)+"/"+((pin>>8)&0xff)+"/"+(pin&0xff)+" Output: "+((pout>>24)&0xff)+"/"+((pout>>16)&0xff)+"/"+((pout>>8)&0xff)+"/"+(pout&0xff));
}
Dan Zen said on Nov 4, 2006 at 10:21 PM :
Sorry - in that last comment to you I left out the = in <=.

This technique will help - note the assignment of the color arrays

Dan Zen
http://www.danzen.com
http://imm.sheridanc.on.ca



import flash.display.BitmapData;
import flash.geom.*;

// assuming you have a picture on the stage in a clip called pic
bm = new BitmapData(pic._width, pic._height, false);
myM = new Matrix();
bm.draw(pic,myM,null);

var redArray:Array = new Array(256);
var greenArray:Array = new Array(256);
var blueArray:Array = new Array(256);

// this converts the picture to some number of colors
colors = 16; perChannel = colors / 3; divider = 256 / perChannel;
for(var i = 0; i <= 255; i++) {
blueArray[i] = Math.floor(i/divider)*divider;
greenArray[i] = blueArray[i] << 8;
redArray[i] = greenArray[i] << 8;
}

/* this is unity
for(var i = 0; i <= 255; i++) {
blueArray[i] = i;
greenArray[i] = blueArray[i] << 8;
redArray[i] = greenArray[i] << 8;
}
*/

/* this would invert the picture
for(var i = 0; i <= 255; i++) {
blueArray[i] = (255-i);
greenArray[i] = blueArray[i] << 8;
redArray[i] = greenArray[i] << 8;
}
*/

bm.paletteMap(bm, new Rectangle(0, 0, pic._width, pic._height), new Point(0, 0), redArray, greenArray, blueArray, null);

//view the bitmap
this.createEmptyMovieClip("output", this.getNextHighestDepth());
output.attachBitmap(bm,this.getNextHighestDepth());
output._x = pic._x; //+ pic._width + 20;
output._y = pic._y;

// this makes a nice edge on the posterizing effect of the pallete
import flash.filters.BlurFilter;
bf = new BlurFilter(2,2,2);
bm.applyFilter(bm,bm.rectangle,null,bf);
motorro said on Nov 21, 2006 at 12:28 AM :
Hello!
As I guess paletteMap doesn't do a bit shift when calculating the result color. I mean that resulting value is (RArray[index] | GArray[index] | BArray[index] | AlfaArray[index]). Thus the color arrays generation should look like this:

for (i:Number = 0; i < 256; i++) {
var R:Number = someFunction1(i);
var G:Number = someFunction2(i);
var B:Number = someFunction3(i);
lutR[i] = R << 16;
lutG[i] = G << 8;
lutB[i] = B;
}

Works fine for me...

 

RSS feed | Send me an e-mail when comments are added to this page | Comment Report

Current page: http://livedocs.adobe.com/flash/8/main/00001962.html