I'm working in an application, that uses a rather strange format for it's colours. It's using a variation of ARGB, by using a float to store all the data. The colours themselves are hardcoded into the classes, and are decoded by this operation:
float alpha = (float)(color >> 24 & 255) / 255.0F;
float red = (float)(color >> 16 & 255) / 255.0F;
float blue = (float)(color >> 8 & 255) / 255.0F;
float green = (float)(color & 255) / 255.0F;
The 32 bits of the float are used to extract four 8-Bit Integers by Bit-Shifting them out, and converting them to a float between 0 and 1. This way they are processed further with a graphics library.
I wrote a class to represent colours, since I really don't want to work with all these magical float's. I need a method to reverse the process, but I'm clueless to how this reversal would work. I started by converting my float's to integers between 0 and 1, but that's about as far as I get. How can I take these values and "glue" them together in the same order as the original values?
public int toARGB() {
System.out.println(fromARGB(1615855616)); // gives Color{red=0.3137255, green=0.0, blue=0.0, alpha=0.3764706}
System.out.println(fromARGB(-2130706433)); // gives Color{red=1.0, green=1.0, blue=1.0, alpha=0.5019608}
int closeAlpha = (int) (alpha*255.0F);
int closeRed = (int) (red*255.0F);
int closeGreen = (int) (green*255.0F);
int closeBlue = (int) (blue*255.0F);
//How do I proceed here?
return null;
}
Related
I'm working on drawing semi-transparent images on top of other images for a small 2d game. To currently blend the images I'm using the formula found here: https://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending
My implementation of this is as follows;
private static int blend(int source, int dest, int trans)
{
double alpha = ((double) trans / 255.0);
int sourceRed = (source >> 16 & 0xff);
int sourceGreen = (source >> 8 & 0xff);
int sourceBlue = (source & 0xff);
int destRed = (dest >> 16 & 0xff);
int destGreen = (dest >> 8 & 0xff);
int destBlue = (dest & 0xff);
int blendedRed = (int) (alpha * sourceRed + (1.0 - alpha) * destRed);
int blendedGreen = (int) (alpha * sourceGreen + (1.0 - alpha) * destGreen);
int blendedBlue = (int) (alpha * sourceBlue + (1.0 - alpha) * destBlue);
return (blendedRed << 16) + (blendedGreen << 8) + blendedBlue;
}
Now, it works fine, but it has a pretty high overhead since it's being called for every single pixel every single frame. I get a performance drop of around 30% FPS as opposed to simply rendering the image without blending.
I just wanted to know if anyone can think of a better way to optimise this code as I'm probably doing too many bit operations.
not a java coder (so read with prejudice) but you are doing some things really wrong (from mine C++ and low level gfx perspective):
mixing integers and floating point
that requires conversions which are sometimes really costly... Its much better to use integer weights (alpha) in range <0..255> and then just divide by 255 or bitshift by 8. That would be most likely much faster.
bitshifting/masking to obtain bytes
yes its fine but there are simpler and faster methods simply by using
enum{
_b=0, // db
_g=1,
_r=2,
_a=3,
};
union color
{
DWORD dd; // 1x32 bit unsigned int
BYTE db[4]; // 4x8 bit unsigned int
};
color col;
col.dd=some_rgba_color;
r = col.dd[_r]; // get red channel
col.dd[_b]=5; // set blue channel
decent compilers could optimize some parts of your code to this internally on its own but I doubt it can do it everywhere...
You can also use pointers instead of union in the same way...
function overhead
you got function blending single pixel. That means it will be called a lot. its usually much faster to blend region (rectangle) per single call than call stuff on per pixel basis. Because you trash the stack this way. To limit this you can try these (for functions that are called massively):
Recode your app so you can blend regions instead of pixels causing much less function calls.
Lower the stack trashing by lowering operands, return values and internal variables of called function to limit the amount of RAM being allocated/freed/overwritten/copied each call... For example by using static or global variables for example the Alpha will most likely not be changing much. Or you can use alpha encoded in the color directly instead of having alpha as operand.
use inline or macros like #define to place the source code directly to code instead of function call.
For starters I would try to recode your function body to something like this:
enum{
_b=0, // db
_g=1,
_r=2,
_a=3,
};
union color
{
unsigned int dd; // 1x32 bit unsigned int
unsigned char db[4]; // 4x8 bit unsigned int
};
private static unsigned int blend(unsigned int src, unsigned int dst, unsigned int alpha)
{
unsigned int i,a,_alpha=255-alpha;
color s,d;
s.dd=src;
d.dd=dst;
for (i=0;i<3;i++)
{
a=(((unsigned int)(s.db[i]))*alpha) + (((unsigned int)(d.db[i]))*_alpha);
a>>=8;
d.db[i]=a;
}
return d.dd;
}
However if you want true speed use GPU (OpenGL Blending).
I am getting data from bluetooth and want to convert byte value to int and show result into float for that I have written following code
String prob1Str = manufactureData.substring(20, 24); // prob1Str = FE70
float prob1Temp = (Integer.parseInt(prob1Str,16)&0xffff); // Here I am getting prob1Tem = 65136.0 instead of -400.0
model.setProb1Temp(prob1Temp);
From above code I am getting prob1Tem = 65136.0 instead of -400.0
can anybody help me how to resolve this
thanks
Just cast your result to short!
float prob1Temp = (short)Integer.parseInt(prob1Str, 16);
int is 32 bits, so 0x0000FE70 = 65136, it is a positive value!
Short is 16 bits, 0xFE70 = -400, you will recast it to int or float after.
Look at that explanation for more details.
Integer.parseInt("FE70", 16) << 16 >> 16
will correctly extend sign bit. or same less tricky and not bound to Integer size:
int i = Integer.parseInt("FE70", 16);
if (i >= 0x8000) i -= 0x10000;
My particular case of summing digits deals with colors represented as integer. Java function BufferedImage.getRGB returns image in 0x00RRGGBB format. I'm making a function that gives you grayscale (color independent) sum of colors on the image. Currently, my operation looks very naive:
//Just a pseudocode
int sum = 0;
for(x->width) {
for(y->height) {
int pixel = image.getRGB(x,y);
sum+=(pixel&0x00FF0000)+(pixel&0x0000FF00)+(pixel&0x000000FF);
}
}
//The average value for any color then equals:
float avg = sum/(width*height*3);
I was wondering if I could do it even faster with some bit-shifting logic. And I am mostly asking this question to learn more about bit-shifting as I doubt any answer will speed up the program really significantly.
R, G and B do not attribute equally to the perceived intensity. A better way to sum things up than this:
sum+=(pixel&0x00FF0000)+(pixel&0x0000FF00)+(pixel&0x000000FF);
Would be, with the necessary bitshifting and weighing (assuming 00RRGGBB):
sum+= ((pixel&0x00FF0000)>>16) * .30 / 255
+ ((pixel&0x0000FF00)>> 8) * .59 / 255
+ (pixel&0x000000FF) * .11 / 255;
You might want to leave the /255 part out here and replace the floating point numbers with scaled-up integer numbers (like 30, 59 and 11), bearing in mind that you'll need a long sum to prevent overflow to a reasonable degree.
I'm in JNI hell with typeconversions out the wazoo:
Here's the general flow of things:
read a file and it returns me with a
1D array of floats.
convert these
floats[] to shorts[] (*4095, I want a
12 bit number)
pass these shorts[] to
C, which duplicates them in an
unsigned short array
flip bits around
to make big-endian java bits
little-endian for image processing
convert these new numbers to a
double[] (/4095)
pass the double[] to the
image processing function
convert processed double[] back to short[] (*4095)
flip bits in short[] back to
big-endian
convert short[] back to float (/4095), pass back to java
pass float[] to int
conversion which arranges the bits to
ARGB_8888 format
There has GOT to be a better way to do this.
On top of all that crap, it's not working. I'm getting back all noise, which I feel might be a result of the unsigned short arrays in C (useful for bit-switching) and the signed short arrays in C. This is a major problem.
So I guess my general question is, how can I improve this so that I'm not dealing with all of these problems converting between types, including signed/unsigned issues.
Anything you can suggest will be appreciated..
I don't see the benefit of having an intermediate short representation, since the Java code works with floats and the C code works with doubles. I would do something like this:
float[] floats = readFile();
// Convert to little-endian doubles
ByteBuffer bb = ByteBuffer.allocateDirect(4 * floats.length);
bb.order(ByteOrder.LITTLE_ENDIAN);
DoubleBuffer db = bb.asDoubleBuffer();
for (int i = 0; i < floats.length; ++ i) {
db.put(i, floats[i]);
}
doImageProcessing(bb); // Native method
// Convert double values to ARGB
int j = 0;
int[] argb = new int[floats.length / 4];
for (int i = 0; i < floats.length; i += 4) {
int a = Math.max(0, Math.min((int) (db.get(i) * 256.0), 255));
int r = Math.max(0, Math.min((int) (db.get(i+1) * 256.0), 255));
int g = Math.max(0, Math.min((int) (db.get(i+2) * 256.0), 255));
int b = Math.max(0, Math.min((int) (db.get(i+3) * 256.0), 255));
argb[j++] = (a<<24)|(r<<16)|(g<<8)|b;
}
How can I create the opposite of a hexadecimal color? For example, I'd like to convert 0x000000 (black) into 0xFFFFFF (white), or 0xFF0000 (red) into 0x00FFFF (cyan). Those are rather basic colors, while variants of colors can have more complex hexadecimal values, such as 0x21B813 (greenish).
Are bitwise operators required for this? Maybe a loop of each digit to calculate it's mirror from 0 to 15, or 0 to F (0 become F, 6 becomes 9, etc.)
I'm using ActionScript, so I'm almost certain that this would be done the same way in Java.
As Spidey says just use 0xFFFFFF - COLOR.
In ActionScript you would do something like:
public static function pad(str:String, minLength:uint, pad:String):String {
while (str.length < minLength) str = pad + str;
return str;
}
var color:Number=0x002233;
var hexColorStr:String = "#" + pad((0xFFFFFF-color).toString(16), 6, "0");
In Java:
int color = 0x002233;
String hex = String.format("06X", (0xFFFFFF - color));
In C#:
int color = 0x002233;
string hex = (0xFFFFFF - color).ToString("X").PadLeft(6, '0');
Just do 0xFFFFFF - COLOR.