Alexanus
Alexanus

Reputation: 689

Java increase brigthness of int color with bit shifting

I would like to increase the brightness of a color. The color is saved as an integer ARGB. The opacity should stay the same. Is it possible to increase the brightness by multiplying each color(RGB) by 2? So when my color is: 0xFF010000 how would I bit-shift it to get: 0xff020000?

Upvotes: 0

Views: 693

Answers (3)

user555045
user555045

Reputation: 64933

Colours can be brightened-with-desaturation with a nice bithack:

pixel = ~((~pixel >> 1) & 0x7F7F7F7F);

Works by subtracting every channel from 0xFF (with ~pixel), dividing by 2 (>> 1) cleaning out the bits that shifted out of their channel (& 0x7F7F7F7F, has the upper bit of every byte reset) and then subtracting every channel from 0xFF again with the first ~. Since it halves the distance between the channel value and 0xFF, you could say it "slows down" at the value goes up - so they tend to equalize, which causes the desaturation.

Looks like this: enter image description here

You could also use scale-and-saturate, to brighten without desaturation but the flipside is that any channel that is 0 will be stuck there (black cannot be brightened this way; yellow, cyan and magenta won't move towards white),

uint saturate = ((p & 0x80808080) >> 7) * 255;
p = ((p & 0x7F7F7F7F) << 1) | saturate;

This works by first computing which channels would overflow, which is when their top bit (0x80808080) is set. A mask making that whole channel 255 is calculated, called saturate. Then every channel is multiplied by two without overflows and the saturation is applied. Since this doubles the distance from the channel value to zero, it "speeds up" as the value grows, there is not much desaturation (only when values are clipped at the top by saturation).

Looks like this: enter image description here

A minor variant allows brightening channels that are zero slightly,

uint saturate = ((p & 0x80808080) >> 7) * 255;
p = ((p & 0x7F7F7F7F) << 1) | saturate | 0x01010101;

Looks the same as the previous one when applies once, but the difference becomes clear when doing it multiple times.

I modified Alpha too because whatever. You can leave that out by changing the masks.

Upvotes: 3

Sanket Makani
Sanket Makani

Reputation: 2489

You can extract the corresponding values of colors and then multiply it by 2 and then again form the color with new values.

int color = 0xff040200;

int blue = color & 0xff;           //last 8 bits value
color = color>>8;                  //We have stored last 8 bits so shift it.
int green = color & 0xff;          
color = color>>8;                  
int red = color & 0xff;            
color = color>>8;                
int alpha = color;                  //now color has only first 8 bits value.


//Make changes in the color;

blue = Math.max( blue<<1 , 255 ); 
green = Math.max( green<<1 , 255 ); 
red = Math.max( red<<1 , 255 ); 

//Now we need to form a new color
//reverse the steps of extraction of color from integer

int new_color = 0;

new_color = new_color | alpha;     //setting up the last 8 bits
new_color = new_color<<8;          //we have set last 8 bits so shift it.
new_color = new_color | red;     
new_color = new_color<<8;          
new_color = new_color | green;     
new_color = new_color<<8;          
new_color = new_color | blue; 

Upvotes: 2

Neil
Neil

Reputation: 5780

The maximum value for each color is 255, so multiplying a color by 2 (through bit-shifting or otherwise) is probably not what you want. You probably should separate each component into its own int, apply brightness to all or several components, then recombine.

Separating each component is simply a matter of applying a mask, then bit shifting as necessary.

int red = (color & 0xff000000) >>> 24;
int green = (color & 0x00ff0000) >>> 16;
int blue = (color & 0x0000ff00) >>> 8;

Applying then the brightness, rather than double each color component, you'd only halve the distance betwen the color and the max (255), so:

red = ((red - 255)/2 + 255);
green = ((green - 255)/2 + 255);
blue = ((blue - 255)/2 + 255);

Once you've accomplished this, you only have to reassemble the color (note, alpha value readded from original value):

color = (red << 24) + (green << 16) + (blue << 8) + (color & 0x000000ff);

I hope that's what you were looking for. Let me know how that works for you.

Upvotes: 2

Related Questions