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.
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:
converting a hex string to an int
converting a alpha percentage (0-100) to a 0-255 int
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));
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);
}
Related
I have a few Color lookup tables that looks like this. Is there a guide that i can use to program an image filter using color lookup table in Nokia Imaging SDK. I am switching to Nokia Imaging SDK because i have been told that it is more optimized and accurate.
currently the code looks like this.
public WriteableBitmap Process()
{
int width = inputimage.PixelWidth;
int height = inputimage.PixelHeight;
int[] pixelArray = this.inputimage.Pixels;
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
// Extract color components
var c = inputimage.GetPixel(i,j);
var b = c.B;
var g = c.G;
var r = c.R;
var a = c.A;
int blockBlue = b / 4;
int blockGreen = g / 4;
int blockRed = r / 4;
int right = blockBlue % 8;
int down = blockBlue / 8;
int px = right * 64 + blockRed;
int py = down * 64 + blockGreen;
Color clr = LookUpTable.GetPixel(px, py);
// Set result color
inputimage.SetPixel(i, j, clr);
}
}
return wBmp;
}
The CustomFilterBase or CustomEffectBase base classes will let you translate this loop almost directly.
I'm not sure if you'll get any better performance or accuracy for this RGB LUT alone, as it is already pretty simple. The main things I see are the GetPixel/SetPixel which you really should change to direct array accesses instead. Also avoid the Color class. Ideally read and write 32 bit uint values, mask and shift out the parts.
The second improvement would be if you can constrain the function stored in the LUT.
If it can be expressed as individual red, green and blue LUTs, you can use the CurvesFilter class in the Imaging SDK. Even without the SDK this will speed things up as those tables can live closer to the CPU in the L1 or L2 cache.
Edit: The final version of Nokia Imaging SDK 1.2 (soon to be released) has some precision improvements that may be relevant as well, btw.
Edit 2: You should be able to access Pixels with something like the following. (Haven't tested the casts fully. C# is picky about signed-ness.)
// in for loop..
var uintColor = (uint)wb.Pixels[i];
var a = (byte)((uintColor >> 24) & 255);
var r = (byte)((uintColor >> 16) & 255);
var g = (byte)((uintColor >> 8) & 255);
var b = (byte)((uintColor) & 255);
// ..do something..
wb.Pixels[i] = (int)(b | (g << 8) | (r << 16) | (a << 24));
Im using a very big BitmapData as a pathing map for my platformer game, however I only use pixels for 4 particular values, instead of, well 4294967295.
Would converting this Bitmapdata as 2 2D Vectors of Boolean save me some memory ?
And if it does, what about performance, would it be faster or slower to do something like:
MapGetPixel(x:int, y:int):int
{
return MapBoolFirst[x][y] + MapBoolSecond[x][y]*2;
}
instead of the bitmapdata class getPixel32(x:int, y:int):uint ?
In short im looking for a way to reduce the size and/or optimize my 4 colors bitmapdata.
Edit :
Using my boolean method apparently consumes 2 times more memory than the bitmapdata one.
I guess a boolean takes more than one bit in memory, else that would be too easy. So im thinking about bitshifting ints and thus have an int store the value for several pixels, but im not sure about this…
Edit 2 :
Using int bitshifts I can manage the data of 16 pixels into a single int, this trick should work to save some memory, even if it'll probably hit performance a bit.
Bitshifting will be the most memory-optimized way of handling it. Performance wise, that shouldn't be too big of an issue unless you need to poll a lot of asks each frame. The issue with AS is that booleans are 4bits :(
As I see it you can handle it in different cases:
1) Create a lower res texture for the hit detections, usually it is okay to shrink it 4 times (256x256 --> 64x64)
2) Use some kind of technique of saving that data into some kind of storage (bool is easiest, but if that is too big, then you need to find another solution for it)
3) Do the integer-solution (I haven't worked with bit-shifting before, so I thought it would be a fun challenge, here's the result of that)
And that solution is way smaller than the one used for boolean, and also way harder to understand :/
public class Foobar extends MovieClip {
const MAX_X:int = 32;
const MAX_Y:int = 16;
var _itemPixels:Vector.<int> = new Vector.<int>(Math.ceil(MAX_X * MAX_Y / 32));
public function Foobar() {
var pre:Number = System.totalMemory;
init();
trace("size=" + _itemPixels.length);
for (var i = 0; i < MAX_Y; ++i) {
for (var j = 0; j < MAX_X; ++j) {
trace("item=" + (i*MAX_X+j) + "=" + isWalkablePixel(j, i));
}
}
trace("memory preInit=" + pre);
trace("memory postInit=" + System.totalMemory);
}
public function init() {
var MAX_SIZE:int = MAX_X * MAX_Y;
var id:int = 0;
var val:int = 0;
var b:Number = 0;
for(var y=0; y < MAX_Y; ++y) {
for (var x = 0; x < MAX_X; ++x) {
b = Math.round(Math.random()); //lookup the pixel from some kind of texture or however you expose the items
if (b == 1) {
id = Math.floor((y * MAX_X + x) / 32);
val = _itemPixels[id];
var it:uint = (y * MAX_X + x) % 32;
b = b << it;
val |= b;
_itemPixels[id] = val;
}
}
}
}
public function isWalkablePixel(x, y):Boolean {
var val:int = _itemPixels[Math.floor((y * MAX_X + x) / 32)];
var it:uint = 1 << (y * MAX_X + x) % 32;
return (val & it) != 0;
}
}
One simple improvement is to use a ByteArray instead of BitmapData. That means each "pixel" only takes up 1 byte instead of 4. This is still a bit wasteful since you're only needing 2 bits per pixel and not 8, but it's a lot less than using BitmapData. It also gives you some "room to grow" without having to change anything significant later if you need to store more than 4 values per pixel.
ByteArray.readByte()/ByteArray.writeByte() works with integers, so it's really convenient to use. Of course, only the low 8 bits of the integer is written when calling writeByte().
You set ByteArray.position to the point (0-based index) where you want the next read or write to start from.
To sum up: Think of the ByteArray as a one dimensional Array of integers valued 0-255.
Here are the results, I was using an imported 8 bit colored .png by the way, not sure if it changes anything when he gets converted into a
BitmapData.
Memory usage :
BitmapData : 100%
Double Boolean vectors : 200%
Int Bitshifting : 12%
So int bitshifting win hands down, it works pretty much the same way as hexadecimal color components, however in that case I store 16 components (pixel values in 2 bits) not the 4 ARGB:
var pixels:int = -1;// in binary full of 1
for (var i:int = 0; i < 16; i++)
trace("pixel " + (i + 1) +" value : " + (pixels >> i * 2 & 3));
outputs as expected :
"pixel i value : 3"
I know it was asked a thousand times before, but I still can't find a solution.
Searching SO, I indeed found the algorithm for it, but lacking the mathematical knowledge required to truly understand it, I am helplessly lost!
To start with the beginning, my goal is to compute an entire spectrogram and save it to an image in order to use it for a visualizer.
I tried using Sound.computeSpectrum, but this requires to play the sound and wait for it to end, I want to compute the spectrogram in a way shorter time than that will require to listen all the song. And I have 2 hours long mp3s.
What I am doing now is to read the bytes from a Sound object, the separate into two Vectors(.); Then using a timer, at each 100 ms I call a function (step1) where I have the implementation of the algorithm, as follows:
for each vector (each for a channel) I apply the hann function to the elements;
for each vector I nullify the imaginary part (I have a secondary vector for that)
for each vector I apply FFT
for each vector I find the magnitude for the first N / 2 elements
for each vector I convert squared magnitude to dB scale
end.
But I get only negative values, and only 30 percent of the results might be useful (in the way that the rest are identical)
I will post the code for only one channel to get rid off the "for each vector" part.
private var N:Number = 512;
private function step1() : void
{
var xReLeft:Vector.<Number> = new Vector.<Number>(N);
var xImLeft:Vector.<Number> = new Vector.<Number>(N);
var leftA:Vector.<Number> = new Vector.<Number>(N);
// getting sample range
leftA = this.channels.left.slice(step * N, step * (N) + (N));
if (leftA.length < N)
{
stepper.removeEventListener(TimerEvent.TIMER, getFreq100ms);
return;
}
else if (leftA.length == 0)
{
stepper.removeEventListener(TimerEvent.TIMER, getFreq100ms);
return;
}
var i:int;
// hann window function init
m_win = new Vector.<Number>(N);
for ( var i:int = 0; i < N; i++ )
m_win[i] = (4.0 / N) * 0.5 * (1 - Math.cos(2 * Math.PI * i / N));
// applying hann window function
for ( i = 0; i < N; i++ )
{
xReLeft[i] = m_win[i]*leftA[i];
//xReRight[i] = m_win[i]*rightA[i];
}
// nullify the imaginary part
for ( i = 0; i < N; i++ )
{
xImLeft[i] = 0.0;
//xImRight[i] = 0.0;
}
var magnitutel:Vector.<Number> = new Vector.<Number>(N);
fftl.run( xReLeft, xImLeft );
current = xReLeft;
currf = xImLeft;
for ( i = 0; i < N / 2; i++ )
{
var re:Number = xReLeft[i];
var im:Number = xImLeft[i];
magnitutel[i] = Math.sqrt(re * re + im * im);
}
const SCALE:Number = 20 / Math.LN10;
var l:uint = this.total.length;
for ( i = 0; i < N / 2; i++ )
{
magnitutel[i] = SCALE * Math.log( magnitutel[i] + Number.MIN_VALUE );
}
var bufferl:Vector.<Number> = new Vector.<Number>();
for (i = 0; i < N / 2 ; i++)
{
bufferl[i] = magnitutel[i];
}
var complete:Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>();
complete[0] = bufferl;
this.total[step] = complete;
this.step++;
}
This function is executed in the event dispatched by the timer (stepper).
Obviously I do something wrong, as I said I have only negative values and further more values range between 1 and 7000 (at least).
I want to thank you in advance for any help.
With respect,
Paul
Negative dB values are OK. Just add a constant (representing your volume control) until the number of points you want to color become positive. The remaining values that stay negative are usually just displayed or colored as black in a spectrogram. No matter how negative (as they might just be the FFT's numerical noise, which can be a huge negative dB number or even NaN or -Inf for log(0)).
I have a number array and I'd like to calculate the median.
When the array is odd, the calculation is OK, when it's even strange number comes up.
private var numbers:String = "2,5,3,4,6,1";
private var array:Array = numbers.split(",");
private function getMedian(array:Array):Number {
var sortnums:Array = array.sort(Array.NUMERIC);
var length:Number = sortnums.length;
var mid1:Number; var mid2:Number; var median:Number;
if(length % 2 == 0){
mid1 = length / 2; trace("mid1: "+mid1);
mid2= ((length - 1) / 2)-0.5; trace("mid2: "+mid2);
trace ("mid1: "+sortnums[mid1]+", mid2: "+sortnums[mid2]);
median = (sortnums[mid1] + sortnums[mid2]) / 2;
}else{
mid1 = (length / 2)-0.5
median = sortnums[mid1]
}
trace (median);
return median;
}
The result is 21.5, but should be 3.5
mid1 and mid2 are a position in the array.
Could somebody help?
Try this (for tidyness):
function getMedian(plug:Array):Number
{
// Even length.
if(plug.length % 2 == 0)
{
var a:Number = plug[int(plug.length / 2) - 1];
var b:Number = plug[int(plug.length / 2)];
return (a + b) / 2;
}
// Odd length.
return plug[int(plug.length / 2)];
}
// Tests.
trace(getMedian([2,5,3,4,6,1])); // 3.5
trace(getMedian([2,5,3,4,6])); // 3
By the way, I'm fairly certain your code is working fine, the problem is that you're doing this as a string concatenation rather than a number sum here:
median = (sortnums[mid1] + sortnums[mid2]) / 2;
Meaning you're literally adding the string 1.5 onto 2 and getting 21.5 rather than 3.5.
Try amending your code so it reads like so:
median = (Number(sortnums[mid1]) + Number(sortnums[mid2])) / 2;
I am a bit new to using blitting for graphics. But I have worked up a few demos myself, and I have been reading a lot of information on the methods used.
One common theme I have been seeing though is that all of them brute force rendering; drawing the farthest back object first and stepping through all other objects. even drawing objects that are going to be completely overlapped.
The reason all of them say this is that any kind of testing to see what should be drawn actually takes more time than just drawing everything with no checks.
Is there any kind of way to detect what should be drawn, that will run faster than just drawing everything?
It is hard to actually tell whether it is faster to check for what should be drawn or drawing stuff. You could maybe use both like If there is more than 5 images, use draw check, if not, draw them all. ...
So - the draw them all method is very obvious, and about the draw check it is like:
// drawCheck
var w:int = 300;
var h:int = 200;
var result:Bitmap = new Bitmap(w, h);
for (var x:int = 0; x < w; x++){
for (var y:int = 0; y < h; y++){
result.bitmapData.setPixel32(x, y, 0x00FFFFFF);
for (var iid:int = 0; iid < images.length; iid++){
var resC:uint = result.bitmapData.getPixel32(x, y);
var resA:uint = resC >>> 24;
var resR:uint = resC >>> 16 & 0xFF;
var resG:uint = resC >>> 8 & 0xFF;
var resB:uint = resC & 0xFF;
if (resA == 0xFF){
break;
}
var oriC:uint = images[iid].bitmapData.getPixel32(x, y);
var oriA:uint = oriC >>> 24 &;
var oriR:uint = oriC >>> 16 & 0xFF;
var oriG:uint = oriC >>> 8 & 0xFF;
var oriB:uint = oriC & 0xFF;
var newA:uint = resA + oriA;
var newR:uint = (256 / resA) * resR + (256 / oriA) * oriR;
var newG:uint = (256 / resA) * resR + (256 / oriA) * oriG;
var newB:uint = (256 / resA) * resR + (256 / oriA) * oriB;
var newC:uint = newA << 24 | newR << 16 | newG << 8 | newB;
result.bitmapData.setPixel32(x, y, newC);
}
}
}
Basically, MAYBE the drawing could be faster, but I am not sure - bitwise operations... Anyways - you should get the idea - this loops through X and Y coordinates and finally through the images.
Note: The images are stored like: 0 = front, images.length - 1 = back
It checks (HERE) if the resulting bitmap is already fully drawn by checking the alpha (if it equals 0xFF, there is no use of drawing), and if it is not, it merges the colours and adds the alpha.
You should do some performance tests so we know what is faster and when...