2

Say I have the following setup in my AS code:

var color:String = "#0000FF"; //blue
var alpha:Number = 42; //42% or 42/100

How would I combine those into a #RRGGBBAA hex color? I've been Googling around and trying to figure out hexadecimal conversion and notation without luck.

mattsven
  • 22,305
  • 11
  • 68
  • 104

2 Answers2

8

There are two ways you could do this. One is a bit hacky using int's toString() method and passing 16 as the radix/base:

var rgb:int = (int)("#0000FF".replace("#","0x"));//convert the string to a int (note you can type hex ints starting with 0x (e.g. 0x0000FF)
var a:int = 42;
var rgba:int = int("0x"+rgb.toString(16) + a.toString(16));

or the less hacky and probably faster computationally method using bitwise operators:

var rgb:uint = (uint)("#0000FF".replace("#","0x"));
//extract components using bit shifting (>>) and masking (0xFF)
var r:uint = rgb >> 16 & 0xFF;
var g:uint = rgb >>  8 & 0xFF;
var b:uint = rgb >>  0 & 0xFF;//same as rgb >> 0xFF, just added >> 0 to make the shift obvious
var a:uint = 42;
var rgba:uint = r << 24 | g << 16 | b << 8 | a;
var argb:uint = a << 24 | r << 16 | g << 8 | b;
//test
trace(rgba.toString(16));
trace(argb.toString(16));

Note that using toString(16) in the trace above is to make it useful to us humans, you'd use the actual uint value when working with hex color values.

Also note that you might want to use ARGB in as3 sometimes, for example when working with BitmapData:

addChild(new BitmapData(100,100,true,0x2a0000ff));//add a 42% transparent blue box (100x100 px)

UPDATE

The above bitshift code snippet actually explains rgb extraction in detail which helps understand things better, but you already have rgb, so it's a matter of adding the alpha component. Also you mentioned 42% which is not the same as on a 0 to 255 scale. Therefore bellow lies your answer:

var rgb:uint = (uint)("#0000FF".replace("#","0x"));
var   a:uint = (uint)((42 * .01) * 255);//map 42 from 0<>100 to 0<>255 ( *.01 is the same as / 100 but faster
var rgba:uint = rgb << 8 | a;
var argb:uint = a << 24 | rgb;

Regarding speed, if I run the two different conversion methods a million times here are execution times:

using strings (var rgba:int = int("0x"+rgb.toString(16) + a.toString(16));) takes 851 ms 
using bitwise ops (var rgba:uint = rgb << 8| a;) takes 3 ms

As you can the bitwise version is much faster and for your case even less verbose than the string version. Also, now that you understand bitwise operators probably it's easier to read/understand.

In conclusion:

var color:String = "#0000FF"; //blue
var alpha:Number = 42; //42% or 42/100
var rgb:uint = (uint)(color.replace("#","0x"));
var   a:uint = (uint)((alpha * .01) * 255);
var rgba:uint = rgb << 8 | a;
trace("hex: #",rgba.toString(16),"test",0x0000ff6b.toString(16));

Also, it's funny you mentioned Google, because you can use the search to convert to hex.

Update: There seems to be a bit of confusion so I've split the 3 steps into functions:

  1. converting a hex string to an int
  2. converting a alpha percentage (0-100) to a 0-255 int
  3. concatenating the above

Which would be:

function getHex(hexStr:String):uint{
    return (uint)(hexStr.replace("#","0x"));
}
function getHexAlpha(alpha:uint):uint{
    return (uint)((alpha * .01) * 255);
}
function rgbaConcat(rgb:uint,a:uint):uint{
    return rgb << 8 | a;
}
trace("test",rgbaConcat(getHex("#FF9900"),getHexAlpha(50)).toString(16));

or all in one go:

function rgbaConcat(hexStr:String,alpha:uint):uint{
    var rgb:uint = (uint)(hexStr.replace("#","0x"));
    var a:uint = (uint)((alpha * .01) * 255);
    return (rgb << 8 | a);
}
trace("test",rgbaConcat("#123456",100).toString(16));
George Profenza
  • 50,687
  • 19
  • 144
  • 218
  • How much faster? Because the first one is shorter and makes my brain hurt less. Also thanks! – mattsven Oct 18 '12 at 04:11
  • You're forgetting one thing; the alpha value in rgba is not specified as a percentage, but as a [0-255] integer value. Nice mention of the `toString` with radix, didn't know about that one. – wich Oct 18 '12 at 04:51
  • @coderkid I've updated my answer which includes the "easy answer", but on the long run it believes it pays off to make the brain hurt every once in a while :) Feel free to vote/mark this if you find it acceptable. wich, thank you, I've just noticed that myself when I was typing the update. Well spoted ! – George Profenza Oct 18 '12 at 04:59
  • Actually, I just noticed - it hiccups on #000000 (black) and other darker hex. For example, `#001a66` gave me `#1a6691`? – mattsven Oct 18 '12 at 17:50
  • That's using the conclusion version, btw. – mattsven Oct 18 '12 at 18:54
  • If I set `var color:String = "#000000";` and print `trace("hex: #",rgba.toString(16),"test",0x0000006b.toString(16));` I get `hex: # 6b test 6b ` and for `var color:String = "#001a66";` and `trace("hex: #",rgba.toString(16),"test",0x001a666b.toString(16));` I get this which looks correct: `hex: # 1a666b test 1a666b `. 1a666b as in 0x001a666b. I've updated the answer – George Profenza Oct 20 '12 at 10:23
  • This is the best thing I've ever seen. Thanks for this! I'll test it. – mattsven Oct 27 '12 at 18:40
2

I'm not sure if sprintf or something similar is available in action script, but you would use something like:

var alpha_2:int = Math.round(255*alpha/100);
var rgba:String = sprintf("%s%2x", color, alpha_2);

By the way, be sure to check whether it is supposed to be #RRGGBBAA or #AARRGGBB

So apparently sprintf is not available, you can use some substitute as mentioned in Is there something like printf in Action Script 3?

If you do not like to use a printf like function you can use:

function hex_char(value:int) {
  if (value < 0)
    return "X";
  if (value < 10)
    return String.fromCharCode("0".charCodeAt(0)+value);
  if (value < 16)
    return String.fromCharCode("A".charCodeAt(0)+value-10);
  return "X";
}

var alpha_2:int = Math.round(255*alpha/100);
var rgba:String = color + hex_char(alpha_2/16) + hex_char(alpha_2%16);

alternatively you coulde use the following definition for hex_char which (I assume) will give you an exception/error for any value under 0 or over 15 instead of "X"

function hex_char(value:int) {
  return "0123456789ABCDEF".charAt(value);
}
Community
  • 1
  • 1
wich
  • 16,709
  • 6
  • 47
  • 72