0

I have each pixel that has a structure as below:

...........PIXEL............
[red | green | blue | alpha]
<-8--><--8---><--8--><--8-->  

I need to do the following:
1. Extract RGBA values
2. Perform some calculations on RGB values and not A values.
3. Assemble them back together to form a pixel with new value.

Here is how I am doing it:

for(int i = 0;i < img.pixels.length;i++){
  int pixel = img.pixels[i];

  int red = (pixel & 0xFF000000) >>> 24;
  int green = (pixel & 0x00FF0000) >>> 16;
  int blue = (pixel & 0x0000FF00) >>> 8;
  int alpha = (pixel & 0x000000FF);

  println("Red: " + red + " Green: " + green + " Blue: " + blue + " Alpha: " + alpha);

  /*
   * Luminosity Method.
   */
  red = (int) (red * 0.21);
  green = (int) (green * 0.71);
  blue = (int) (blue * 0.07);

  /*
   * Assemble them back again
   */
  red = red << 24;
  green = green << 16;
  blue = blue << 8;

  println("AvgRed : " + red + " AvgGreen: " + green + " AvgBlue: " + blue);
  pixel= red | green | blue | alpha;

  img.pixels[i] = pixel;
 }
 updatePixels(); 

But it seems that something is wrong with my shifting their positions again to assemble them.
I have values in the console as follows:

Red: 255 Green: 83 Blue: 100 Alpha: 82 // actual values
AvgRed : 889192448 AvgGreen: 3801088 AvgBlue: 1792 // new values after calculation and shifting

which indicate that something is wrong.

How do I properly assemble them back?

An SO User
  • 24,612
  • 35
  • 133
  • 221

3 Answers3

2

The Color class is very helpful for this sort of operations, It has many constructors - one that takes the bytecode of the colour which then r,g,b values can be taken from easily, once you have separated the values you can use the other constructor to build it back into a colour or bytecode.
For example:

import java.awt.Color;

public class ColourTest {

    public static void main(String[] args) {
        Color   usingfloats = new Color(1f,0f,1f),
                preset = Color.cyan,
                usingbytecode = new Color(-16711681);

            int
            red = preset.getRed(),
            green = preset.getGreen(),
            blue = preset.getBlue();

            Color usingints = new Color(red, green, blue);
            System.out.println(usingints.getRGB());
        }
}
Lee Fogg
  • 775
  • 6
  • 22
  • Yeah sorry, corrected. First ever answer so I rushed. I love to share the simplicity. – Lee Fogg Jun 14 '13 at 22:32
  • Quite a nice class, but how does it deal with an alpha channel if there is one? – fge Jun 14 '13 at 22:41
  • the Color class contains all the methods required, such as getAlpha() which returns the int (0-255) of the alpha channel of the colour. As for the constructor itself, it also has a version with 4 floats and one also with 4 ints which will contribute to the alpha of the colour, as you can see - it is optional, it will otherwise default to 0. – Lee Fogg Jun 14 '13 at 23:36
1

Make your life easier; use a ByteBuffer:

// Byte order of a ByteBuffer is MSB by default, ie big endian
// change with the .order() method
final ByteBuffer buf = ByteBuffer.allocate(4); // size of an int

// put an integer; order of bytes dependent on buffer byte order!
buf.putInt(pixel);
buf.rewind();

// get three bytes in succession (autocast to int here)
int red = buf.get();
int green = buf.get();
int blue = buf.get();
buf.rewind();

// do calculations on red, green, blue

// put the modified bytes again; put methods all return "this"
buf.put((byte) (red & 0xff))
    .put((byte) (green & 0xff))
    .put((byte) (blue & 0xff));
    .rewind();

// use buf.getInt() to get back the modified int

Note that you can allocate the buffer out of the for loop; in this case do .rewind() on it after you .getInt() the transformed pixel.

fge
  • 119,121
  • 33
  • 254
  • 329
0

You are doing it right, it is just that print is in the wrong place.

Imagine RGBA of 0x05 00 00 00

You successfully extract R as 5 and print it as the first value

Then you multiply by 0.21 and store as an int (1)

THEN YOU SHIFT AGAIN, red becomes 0x01 00 00 00

You print this latter value, not the 1 that you expect.

That is why R value is more changed while B is less. Divide each of them by 256^n (the position) and you find the value you expect.

SJuan76
  • 24,532
  • 6
  • 47
  • 87