2

I have read up on bitwise operators (& | ^) and I understand that if I were to do:

alpha = 0xFF000000 >> 24 ;
blue = 0xFF0000FF & 0x000000FF;
red = 0xFFFF0000>>16 & 0x000000FF;
green = 0xFF00FF00>>8 & 0x000000FF;

then I can mask the other colors and just have red or blue(etc...) components and if I were to do

int color = alpha | blue | red | green;

then I re-construct the color again so to speak. What I am curious about is what if I wanted to create a bilinear interpolation between two colors in Java. How would I go about constructing it? I would like to start with the standard green color( 0xFF00FF00) and end with black (0xFF000000), the colors in the middle would be change from green to darker greens until it eventually gets to black. I think that I would have to do something where I create a bufferedImage which starts off as green at the top and then maybe create a for loop that would read the color of the previous pixel and then shift something until a new version of the previous color is created and so forth. Unfortunately I am not sure how to implement this because I understand bitwise operations and shifts in theory but am not sure how to apply them for this purpose. Any help would be greatly appreciated! Thank you in advance!

2 Answers2

4

As EJP noted the masks are used to filter out the values for one of the color components/channels (Red, Green, Blue). And that's usually what you do with bit shift/masking operations. Everything else you do with the values you get is arithmetics or more advanced math.

A color channel's range is 0-255, or 0x00 - 0xFF in hexadecimal values. To reconstruct it, you need to bitshift the components value back to their place. Which can be put together with simple arithmetic addition:

// Example values
int r = 255; // 0xFF
int g = 1;   // 0x01
int b = 15;  // 0x0F

// go back to original form:
                      //    A  R  G  B
int color = r << 16;  // 0x00.FF.00.00
color += g << 8;      // 0x00.FF.01.00
color += b;           // 0x00.FF.01.0F

// just add back the alpha if it is going to be full on
color = += 255 << 24; // 0xFF.FF.01.0F

If you want to do some interpolation between colors you need to do it for each color component seperately, not all of them together in one integer. In some instances it may also a good idea to change the representation from [0-255] to a decimal one [0.0f-1.0f]:

// Darken red value by 50%
int color = ...; // some color input
int mask = 0xFF;

int a = (color >> 24) & mask;
int r = (color >> 16) & mask;
int g = (color >> 8) & mask;
int b = color & mask;

// convert to decimal form:
float rDecimal = r / 255f; 
  // Let r: 0x66 = 102 => rDecimal: 0.4

// darken with 50%, basically divide it by two
rDecimal = r/2; 
  // rDecimal: 0.2

// Go back to original representation and put it back to r
r = (int)(rDecimal * 255); 
  // r: 51 = 0x33

// Put it all back in place
color = (a << 24) + (r << 16) + (g << 8) + b;

Hope this helps out.

Community
  • 1
  • 1
Spoike
  • 119,724
  • 44
  • 140
  • 158
  • If I wanted to do interpolation of a color and map it on a BufferedImage how would I go about it? – MasqueradeToday Sep 09 '12 at 17:15
  • @MasqueradeToday: What kind of interpolation do you have in mind? Have you read the [`BufferedImage`](http://docs.oracle.com/javase/1.4.2/docs/api/java/awt/image/BufferedImage.html) java api page? There are `getRBG()` and `setRBG()` methods in it if you want to start simple. You have to iterate through all pixels `for` all x and y coordinates of the picture. – Spoike Sep 09 '12 at 19:24
  • Well written and clear code. Is there any performance gain by converting the representation to decimal? – akhy Aug 22 '13 at 06:33
  • 1
    @akhyar: I do it for the sake of readability rather than performance... personally I just find it easier to debug color values in decimal form (mostly because I've studied signal processing at a college that uses this form). As with most optimizations I'd start profiling when things are getting "slow" (it's always surprising when code you think is slow end up not being the actual culprit/bottleneck). – Spoike Aug 22 '13 at 06:57
  • isn't it `<< 24` instead of 32 ? – Dzung Nguyen Mar 10 '15 at 09:01
  • Good catch @nXqd, sorry about any confusion it might have caused. – Spoike Mar 10 '15 at 11:12
2

I understand that if I were to do:

No, you don't understand at all. The result of all your bitshifting is 0xff in all four cases, which is self-evidently incorrect. The alpha mask is 0xff000000, the blue mask is 0xff, the red mask is 0xff0000, the green mask is 0xff00. These are masks, which need to be applied to the actual pixel, with the & operator, to mask out the relevant channels. You need to understand that before you can go any further.

user207421
  • 305,947
  • 44
  • 307
  • 483