Bit shifting and masking, bitwise operators in AS 3. Getting Alpha channel out of the color.
In this article I'm going to show how to extract color channels out from the color value and how to create new colors using bitwise operators in Action Script. First there is some theory with examples and then practising with coding.
First some theory about the colors:
ARGB colors as 32 bit variables are specified by 4 groups of 8 bits each / or 2 hex each:
In binary:
AAAAAAAA RRRRRRRR GGGGGGGG BBBBBBBB
In hex:
AA RR GG BB
where each group defines intensity of each of the colors channels, A is alpha, R is red, G is green, B is blue.
FF is full intensity (255), 00 is no color in the channel (0).
White (full intensity on all channels) is in hex: 0xFFFFFFFF.
Black (no color in any of the Red, Green, and Blue channels) is in hex: 0xFF000000.
Full intensity on the alpha channel means no alpha (FF) and no intensity (00) means full alpha. So a transparent pixel color value is 0x00rrggbb.
Everybody use hex as that's the one, which is easiest to read (use 0x where declaring variables in hex, ie: var myColor:int = 0xAABBCCDD). Although binary representation is very long, we use it to understand how things work behind the scenes. In decimal the range for each channel is 0 - 255.
Some theory about the bit operators:
& - bitwise AND operator, used often for masking, works the way that 1 AND 1 gives 1, 0 AND 0 gives 0, 1 AND 0 or 0 AND 1 gives 0.
Below example:| 1010 | |
| AND | 0111 |
| gives | 0010 |
Let's code it:
1 |
var a:int = 10; |
Traced results:
a: 1010 (bin) | 10 (dec)
b: 111 (bin) | 7 (dec)
c = a & b: 10 (bin) | 2 (dec)
| - bitwise OR operator, works as follows, 0 OR 0 gives 0, 0 OR 1 or 1 OR 0 gives 1, 1 OR 1 gives 1
Below example:| 1010 | |
| OR | 0111 |
| gives | 1111 |
Let's code it:
1 |
var a:int = 10; |
Traced results:
a: 1010 (bin) | 10 (dec)
b: 111 (bin) | 7 (dec)
c = a | b: 1111 (bin) | 15 (dec)
>>n or <<n - right or left shift by n-bits
>>>n - unsigned right shifting by n-bits
Example:
1011 (11 in dec) >> 2 gives 0010 (2 in dec)
1011 (11 in dec) << 2 gives 101100 (44 in dec)
Right shifting:
1 |
var a:int = 11; |
Traced results:
a: 1011 (bin) | 11 (dec)
b = a >> 2: 10 (bin) | 2 (dec)
Left shifting:
1 |
var a:int = 11; |
Traced results:
a: 1011 (bin) | 11 (dec)
b = a << 2: 101100 (bin) | 44 (dec)
Now time for practicing - replacing alpha channel with AND and OR
So now let's try to use what we've just learned to replace the Alpha part of our color with Alpha from different color.
Let's say I have color named "my color", that I want to apply the alpha part from the "other color". I'm going to do that in three steps.
First I mask out the Alpha part from "my color". In the second step I mask out the color parts from the "other color" leaving only the alpha part. At the last step I will "merge" two variables creating new color.
"My color" is: 0xEEDDEEEE (hex), the "other color" is: 0xABCCDDEE (hex).
Let's change representaion to binary to see how the whole operation looks like.
First let's get rid of the alpha part from "my color". To mask it out, we use AND operator and 32 bit value that has the first part (first byte - 8 leading bits) only "0"s
our color: 11101110 11011101 11101110 11101110 (bin) 0xEEDDEEEE (hex)
mask: 00000000 11111111 11111111 11111111 (bin) 0x00FFFFFF (hex)
result of AND: 00000000 11011101 11101110 11101110 (bin) 0x00DDEEEE (hex)
Now similar thing with the "other color", we mask out everything except the Alpha part:
other color: 10101011 11001100 11011101 11101110 (bin) 0xABCCDDEE (hex)
mask: 11111111 00000000 00000000 00000000 (bin) 0xFF000000 (hex)
result of AND: 10101011 00000000 00000000 00000000 (bin) 0xAB000000 (hex)
Now let's combine both results using OR operator:
masked our color: 00000000 11011101 11101110 11101110 (bin) 0x00DDEEEE (hex)
masked other color: 10101011 00000000 00000000 00000000 (bin) 0xAB000000 (hex)
result of OR: 10101011 11011101 11101110 11101110 (bin) 0xABDDEEEE (hex)
OK, let's code it:
1 |
var myColor:Number = 0xEEDDEEEE; |
And here are traced result:
myColor: 11101110 11011101 11101110 11101110 (bin) | eeddeeee (hex)
newAlphaColor: 10101011 11001100 11011101 11101110 (bin) | abccddee (hex)
resultColor: -1010100 00100010 00010001 00010010 (bin) | -54221112 (hex)
Looking at the results, we notice that this is not what we actually expected... It looks like negative value. Why?
Let's amend last line in the code to trace results as unsigned int:
1 |
trace("resultColor: " + uint(resultColor).toString(2) + " (bin) | " + uint(resultColor).toString(16) + " (hex)");
|
and now the result is correct:
resultColor: 10101011 11011101 11101110 11101110 (bin) | abddeeee (hex)
Action Script data types like int or Number are stored the way that the first bit (the leading bit) indicates whether value is positive or negative. To read more about negative int please click here. There are no negative values in the colors, so we actually should be using unsigned int (uint) rather than int (or Number - actually this data type should be rather used for values bigger than 32 bits due to the performance reasons).
Extracting individual channels with bit shifting
We can use bit shifting as a method of extracting individual color channels: first by moving necessary bits to the right and then masking out unnecessary values if there are any.
Let's code it:
1 |
var myColor:uint = 0xABCCDDEE; |
And the result is:
myColor: 10101011 11001100 11011101 11101110 (bin) | abccddee (hex)
Alpha: 11111111 11111111 11111111 10101011 (bin) | ffffffab (hex)
Red: 11001100 (bin) | cc (hex)
Green: 11011101 (bin) | dd (hex)
Blue: 11101110 (bin) | ee (hex)
Hmm, the red, green, blue are as expected but what has happened to our Alpha channel, we are expecting just AB and we got series of "1" in front of AB. This is again related to the way how the data types are stored in Action Script. This will happen every time when you will try to right-shift 32 bit values. It will be fine for 24 bit (RGB). First hex digit of our color is A which is 1010 in binary. The first bit is "1" what means this is a negative value. You may think, ok but we are using unsigned int... Well there is another way of right-shifting bits: >>>n shifts n bits to the right without caring about sign. It's called unsigned right shift.
So remember:
>> - pads with 1 or 0, if negative or positive respectively
>>> - pads with 0 no matter what
Let's see a difference on example below:
This was positive value, missing bits on the left were replaced with zeros.
01010101 00000000 00000000 00000000 >> 2 = 00010101
This was negative value, missing bits on the left were replaced with ones. This is again the way how Flash works with signed values. Read more here.
10101010 00000000 00000000 00000000 >> 2 = 11101010
01010101 00000000 00000000 00000000 >>> 2 = 00010101
No matter what is the leading bit, one or zero, unsigned right shifting replace missing bits with zeros.
10101010 00000000 00000000 00000000 >>> 2 = 00101010
So let's modify our code and see what we will get:
1 |
var myColor:uint = 0xABCCDDEE; |
This time results are fine:
myColor: 10101011 11001100 11011101 11101110 (bin) | abccddee (hex)
Alpha: 10101011 (bin) | ab (hex)
Red: 11001100 (bin) | cc (hex)
Green: 11011101 (bin) | dd (hex)
Blue: 11101110 (bin) | ee (hex)
How is negative integer "stored" in memory?
You won't find much literature explaining how the data typs including negative integer are stored in memory. I had troubles understanding what's going on when shifting bits right in 32 bit variables. I got some help from Lordofduct on actionscript.org, who has shed some more light on that subject (link to that thread at the end of this article).
I'm going to quote him from the thread on the forum:
~ - NOT - this is not with only one value. A 1 is placed where a zero is, a 0 where a one is. This is called the 'binary inverse' of the value. The binary inverse of N bits in length of a value is the same number that needs to be subtracted from (2^N) - 1 to make the negative value of said value. That is why a negative int is just the NOT form of the positive value. You can try it, take a uint, NOT it, and then cast it as an int and you'll have that value negative - 1.
trace( uint( ~3 ) );//you get -4... -(3 + 1)
or as such:
trace( uint.MAX_VALUE - uint(~3) );//you get 3
I bring this up because this is how negative integers are stored. It's 1 followed by the 31 bits that represent the inverse of the absolute value. Anways so you can see the operand in action:
~1010 == 0101
The NOT of any positive value equals the -(value+1)
Example: What is NOT of 15?
0000 1111 (bin) == 15 (dec)
1111 0000 (bin) == -16 (dec)
1 |
var pos:int = 15; |
Gives as a result:
Positive value: 15 is in binary: 1111
Negative value: -16 is in binary: 11111111 11111111 11111111 11110000
So now you know how negative integers are stored in memory... but if you still wonder - why...well it makes sense? For further explanation visit a thread with discussion http://www.actionscript.org/forums/showthread.php3?t=190086 and read the explanation with examples from Lordofduct.

