Color transformation
by ericlin

Color transformation is a very powerful function. I will discuss this in more details. The structure of transform data contains ra, rb, ga, gb, ba, bb  to transform R, G and B elements. It also contains aa and ab which control _alpha transform. Usually, we control the _alpha directly without bothering the transform function. So, I would like to discuss them separatively.

_alpha

Let's start from the _alpha first.

Before everything, I would give you a quiz and hope that would make you interested in this article.

Quiz:

I have a MovieClipl containing various background and one child movieClip. I know I can make the whole clip invisible by setting its _alpha value. I can make that child clip invisible by setting the _alpha of that child clip. But, can I make everything in the background invisible except the child clip ?

The answer is quite simple. Yes, just manipulate the _alpha values.

Here is the swf.

You see, I have set _alpha value to be 200 in some occasion and set _alpha=-100 in some occasion.

_alpha=200 and _alpha=-100

What is it about when the _alpha value is greater than 100 or less than 0 ?

If you are not a newbie, you must have known that the basic unit of _alpha value is 100/256, that is 0.390625 not 1; I am not going to discuss this here.

If you are not a newbie, you might have heard that the maximum value of _alpha is 12800 and the minimum value for _alpha is -12800; If an _alpha goes bigger than 12800 then it turns negative. Vis versa.

Well, pratically when _alpha=100, it is fully visible and when _alpha=0 it is invisible. Value between these two extremes will be displayed with some color mixing semi-transparency. But when and who needs an _alpha value less than 0 or greater than 100 ? Why macromedia supports an _alpha between 12800~-12800 ?

The nested _alpha

Quiz:

If we set child clip _alpha=50 and the parent _alpha=80, then what will be the _alpha value the child clip finally looks like ?

The answer: it looks like _alpha 40. The calculation is a multiplication. Not addition. So, if we set _alpha for parent clip, then the nested child clip becomes even more transparent.

Becareful, I am talking about "nested" clips. Not overlap or stacked _alpha.

So, lets go back to the first quiz. If I set the parent _alpha=50, then everything is semi-transparent. However, I set the child._alpha=200, so for the child clip, the resulting _alpha apperance is 200%*50%, that is 100% opaque. While other background stuffs are still remained in the semi-transparent state.

Now how to make background invisible ?

If we set parent._alpha=0, any number multiplied with 0 will be zero. So, we have no way to increase the child._alpha value.

Here is a trick. I set parent._alpha=-100; So, everything is invisible. Then I set child._alpha=-100; The resulting _alpha apperarnce of the child is -100%*-100%=100%. So we get everything invisible but the child is 100% opaque.

The resulting color by _alpha

We put a blue (0xFF) clip over a  red (0xFF0000) background; If we set the blue clip clip._alpha=50, what color will it be displayed ?

The color will be half blue and half red. That is purple, a dark purple. The color is the same as we put a semi-transparent red clip on a blue background.

Yes, I can guess it is some kind of "purple". But, what is the accurate "value" ?

End Red value: (R of upper clip)*opacity+(R of lower clip)*(1-opacity);

Same for the G and B value.

Lets try make a blue clip with _alpha=40 over a red background;

endR=0x00*(40/100)+0xFF*(60/100);

endG=0x00*(40/100)+0x00*(60/100);

endB=0xFF*(40/100)+0x00*(60/100);

If there is another semi-tranparent clip get stacked over it, then the endR, endG and endB will be used as the color value for further calculation with the opacity.

Note that, stacked _alpha value can be calculated from bottom up, layer by layer.

Here is fla demopnstration the calculations. Please check the fla in the zip, not the swf.

Transform the RGB

In the property panel, advanced setting, we can drag the ra, ga and ba value from -100% to 100%. We can drag the rb, gb and bb value from -255 to 255. If we input directly bypass the dragging, the panel accepts ra, ga and ba value up to -1000 to 1000; And by input directly, it accepts rb, gb and bb value up to -512 to 512. If we supply transform data by script, then it would accept "Integer" beyond this limit. The limit is simuilar to _alpha. For ra, ga and ba it is 12800, that means (-12799 ~+12799). For rb, gb and bb, it is 32768, that is ( -32767~+32767);

So, what is color transform ?

A pixel may have original RGB value, defined with R, G, B in the range of (0~0xFF); However, we can control how it is "shown" on the screen by setting transform. The resulted end R, end G, endB values shown onto the screen are not limited in the range of (0~0xFF);

endR=R*ra/100+rb;

endG=G*ga/100+gb;

endB=B*ba/100+bb;

If original color is red (0xFF0000), and we set transform ra=1000, rb=500; Then the end result R value is 255*1000/100+500=3050; Well, this R value is much higher than the number 0xFF; If it is going to be displayed on to the screen, it is the same as 0xFF; Also, if we make ra=-1000, then the end R value will be less than 0 and it is displayed as if it is 0x00. Remember that, it is displayed "as if", the value is still what it is. We will see the effect when we discuss the nested transform.

Do not combine these endR, endG, endB value to an integer to represent color value. We can not do colorValue=((endR<<16)+(endG<<8)+endB); Because the endR, endG and endB value are not an integer in the range of 0~255. In other words, these values are not a 16 bits integer.

Nested color transform and the true R value:

What will it look like if we transform the child ra=1000 and transform the parent ra=10 ?

We have a movieClip containing a child clip. The child clip is a red square with color value of 0xFF0000; We first transform the child clip by setting ra=500; So, as calculation, the endR value for the child clip pixels will be 255*1000/100=2550; Well, nothing happens. It is still displayed as a fully saturated bright red square as if it is a red of 255;

Now let's transform the parent. We transform the parent by setting ra=20;

According to the equation, endR=orgR*ra/100+rb; Shall we supply the transformed value 2550 or the maximum red 255 as the orgR ? The answer is : the transformed value: 2550;

According to the calculation, the endR of the pixels in the parent will be 2550*10/100=255;  The  transformed Red value is transformed back to original 255; The square still shows fully satureated bright red.

Do you feel strange ?

If we had supply the maximum red value 255 for parent transformation , then the endR in parent would be 255*10/100=25.5; It should be displayed as a dark red square with R value to be 25 not 255.

By this, we proove that, the R value for displaying is not a 16 bits value. We must accept that, we are handling a Red value of something like 2550 or even -3000. Although it is displayed the same brightness as 255, its value is 2550; Although it is displayed as the same dark as 0, the value is -3000;

Transform the parent but preserve the child

Here is a quiz:

I have a movieClip containing various background and one child movieClip. Can I setRGB to all the background but preserve the original color of the child ?

We know that, if we setRGB, all content in the movieClip will be affected. Is there anyway to make the clip resistant to be transformed or can we change it back ?

The solution is: what get decreased by parent transform, we add it back. What get increased by the parent transform, we reduce it off.

Lets check the Math:

Original R value passes through the child transform ra,rb and the results endR can be calculated by the formula : orgR*ra/100+rb;

This endR value then passes through the parent transform ra2, rb2 and results in another endR value by the same formula. So, we get  (orgR*ra/100+rb)*ra2/100+rb2;

We want the final endR back to the original R, so here is the equation:

(R*ra/100+rb)*ra2/100+rb2=R;

R*(ra/100)*(ra2/100)+rb*ra2/100+rb2=R;

R*(ra*ra2*10000-1)+(rb*ra2/100+rb2)=0;

For this equation, if we want it appliable to any R, then (ra*ra2*10000-1) must be zero; So,we get:

ra=10000/ra2;

Back to the equation, we get

rb= -(100)*rb2/ra2;

This equation implies that, we can cancel the effect done by the parent transform ra2, rb2 by transforming the child with a transform data ra, rb calculated through that equation.

However, we should notice that, if ra2==0, then the calculated ra and rb will be infinity. Unfortunately, the effect done by setRGB is through setting ra=ga=ba=0;

Before discussing the setRGB, I would solve this quiz first. Instead of setRGB, we can setTransform by supplying ra=1, ga=1, ba=1. The effect is to remove original color. Well, on my screen, I did not notice any difference. The effect is similar to setRGB but by avoiding ra=0, we can solve our quiz and rescue the color of child clip.

Here is the movie:

setRGB and getRGB

If we use setRGB to set an RGB color, then every pixel color is masked out, leaving the whole clip homogenously colored by single color, the RGB color. If we peek the transform data through getTransform, it shows ra:0,ga:0,ba:0 and the rb:R, gb:G, bb:B.

The effect of setRGB is understandable through the equation: endR=R*ra/100+rb. Since ra is set to 0, original R data is masked out and whatever the original R is , the resulted endR is rb.

If we setTransform then the method getRGB returns a value of (rb<<16)+(gb<<8)+bb; Becareful, getRGB only returns the combination of "B" part (rb, gb, bb). It does not necessarily represent the color we see. For any color object before transformation, the getRGB always return 0, because rb=0, gb=0 and bb=0; We do not expect it appears "Black" - 0x000000.

To display a colored box, it is a common implementation that we create a "Black" box and then setRGB to colorize the black box. For black color, the ra, ga, ba part can be dropped because R, G, and B are all zero. The transformation equation will be simplified as endR=rb; endG=gb; endB=bb; And, getRGB/setRGB can be used inter-changeably with setTransform/getTransform.

Here is a trick. The function getRGB/setRGB handles an integer representing the RGB color values. While setTransform/getTransform handles R, G, and B separatively.

We can write a function with repeated 8 bit shift and "biwise AND" operation to retrieve R, G and B elements from a RGB integer value. We can combine R, G and B elements into a RGB integer value by  rgbInteger=(rb<<16)+(gb<<8)+bb;

For a Black box, the conversion is straight-forward without the need of above functions.

If we want it colored to purple, then we do setRGB(0xFF00FF); If we want to retrieve the R, G and B elements separatively, we just do getTransform. If we want the purple more "greenish", then we increase gb value and then setTransform. If we want to get the color integer value to draw something, then we just getRGB(). Thus, we completely do not need those retriving and conversion functions.

You even can create one off stage black box to serve as RGB retrieving and conversion engine so that you don't need those complex functions.

You must know that there is a trap. That trick only works when rb, gb, bb are integer between 0~255 (0x00~0xFF); If we give a transform {rb:0,gb:0,bb:-1}, the color shown is still black, but the getRGB return a value of -1. The binary representation of -1 is 0xFFFFFF, So, the color is "White"; If we give it a transform {rb:0, gb:0, bb:512}, the color turns "Blue". However, the getRGB return a value of 512. The binary representation of 512 is 0x000200, so, it is a color of "nearly Black".

Manipulation of colors like photoshop.

The ra, ga, ba in transform data, control the "window". In other word, it control the contrast. The rb, gb and bb control the "level". In other word, it is the brightness.

I wont show the effect in this page. I just include the fla in the zip file. You can find them in the zip file.

We can set {ra:-100,ga:-100,ba:-100, rb:255, gb:255, bb:255} to get a color-invert images. We can isolate R chanel by setting ga=0,ba=0. The same for G chanel and B chanel.

However, tranformation is lineal. For single R element, the equation endR=R*ra+rb is just like "Y=aX+b"; If we plot X, Y on 2D plane, then display is the Y, original value is X. Nothing mysterious.

Questions:

Can I do "de-Saturation" effect by setTransform ? Can I convert a color clip into Gray-Scale one by setTransform ?

No. I dont think we can. The transformation is a lineal formula, we give it two constant the slop a and shift b. We can never turn a R elements into B or G elements. Maybe we can turn R element into GB (yellow) element, but in fact, that is just a negative-R (-R) elements.

Flash does not support "pixel RGB" manipulation. We can not get the R, G, B values for specific pixels. So, we can not calculate the R, G, B data for one single specific pixels. Not to mention "Set pixel RGB". So, I dont think we can turn color clip into a Gray-scale one.

Transform the textbox

Questions:

Could we make a textbox with Red text on Blue color but the selected text shows Yellow color on Purple background ?

The Bladk/White color for selected text is a fixed setting and can only be modified by Color transformation.

We have 3 weapons. One is setTransform, the second is to set textColor, the third is to set backgroundColor. Lets try it.

Black         (0,0,0)      ---->Purple     (255,0,255)

textColor     (?,?,?)     ---->Red         (255,0,0)

bgColor         (?,?,?)   ---->Blue         (0,0,255)

White (255,255,255)   --->Yellow     (255,255,0)

Transformation is a lineal equation, so, the slope (a) and shift (b) can be calculated from the Black->Purple and White->Yellowlast pairs.

Lets see the range of colors. Before transformation, at the left extreme , it is Black. At the right extreme, it is White. After our transformation, the left extreme is Purple and the right extreme is Yellow.

If we pick the R elements, before transformation, the left extreme is 0x00 and right extreme is 0xFF. After our transform, the left extreme is 255 (red value of Purple) and right extreme is 255 (red value of Yellow).  Any original R value picked between left and right extreme  will also falls between the new left and new right extreme after transformation. So, we can check whether this request is doable.

The Blue color has its endR value to be 0. This falls out of the range of endR which is (255~255); So, the original R value for the bgColor before transformation is picked from outside of the range (0~255); This means, we can not get a reasonable original R value for bgColor if we want it to be transformed to Blue.

What about White color (255,255,255) instead of Blue ? OK, to make transformed bgColor to White color is doable. Because the transformed R, G , B: endR=0, endG=255, endB=255  are all fall between the range of endR (255~255), endG(0~255), endB(255~0);

If we set selection color as Green/Purple , then the range of R, G, B are all (0~255), basically it coverers all possible colors. We can assign any textColor and backgroundColor in such condition.