47

I am trying to understand the code below where b is a given integer and image is an image.

I understand that if the RGB value at given point i,j is greater than b then set that pixel to white else set to black. so would convert the image into black and white.

However I am lost to what (& 0xff) actually does, I am guessing its a kind of binary shift?

if ((image.getRGB(i, j) & 0xff) > b) {
    image.setRGB(i, j, 0xffffff) ;
} else {
    image.setRGB(i, j, 0x000000);
}
Lunar
  • 4,663
  • 7
  • 43
  • 51

5 Answers5

52

It's a so-called mask. The thing is, you get the RGB value all in one integer, with one byte for each component. Something like 0xAARRGGBB (alpha, red, green, blue). By performing a bitwise-and with 0xFF, you keep just the last part, which is blue. For other channels, you'd use:

int alpha = (rgb >>> 24) & 0xFF;
int red   = (rgb >>> 16) & 0xFF;
int green = (rgb >>>  8) & 0xFF;
int blue  = (rgb >>>  0) & 0xFF;

In the alpha case, you can skip & 0xFF, because it doesn't do anything; same for shifting by 0 in the blue case.

xs0
  • 2,990
  • 17
  • 25
  • Excellent, i see your point, are there other ways of getting the same values? i have other examples such as: blue = ( rgb & 0 x f f ) ; green = ( rgb & 0 x f f0 0 ) >> 8; red = ( rgb & 0xf f0000 ) >> 16; OR blue = ( rgb & 0xff ) ; green = ( rgb & 0 xf800 ); red = ( rgb & 0xf80000 ); – Lunar May 25 '11 at 15:06
  • Sure, you can use the mask first, and shift later, same thing happens - the mask ensures all other bits are zero, the shift moves the value so it's in the rightmost byte of the integer, hence in range 0-255.. 0xF8 on the other hand would just keep the topmost 5 bits of the 8, so I'm not sure where you'd find that useful.. – xs0 May 25 '11 at 15:29
  • The answer to, for example, int `red = (rgb >>> 16) & 0xFF;` would still need to be left-shifted by 16 to be used as a red value. Otherwise, it will look like `0x00000023` which is blue. – mcgyver5 Apr 23 '19 at 17:37
  • so, writing `int red = rgb & (0xFF << 16)` seems clearer. – mcgyver5 Apr 23 '19 at 17:45
  • @mcgyver5 - `rgb & (0xFF << 16)` is the same as `rgb & 0xFF0000`, which has the effect of isolating red from the color (i.e. sets the green and blue channels to 0). Could be useful if that's what you need, but it doesn't give you a value in the normal range 0..255 that is typically much easier to manipulate. Of course, if you shift the bits right when you start, you then need to shift them back left to their original position when you're done, just like you said. – xs0 Apr 25 '19 at 09:34
12

Color representation

The RGB value is an integer so it is represented in memory by 4 bytes (or equivalently 32 bits).

Example:

00000001 00000010 00000011 00000100

Each byte represents one component of the color :

  • 1st byte: alpha value (00000001 in the example) which corresponds to the opacity
  • 2nd byte: red value (00000010 in the example)
  • 3rd byte: green value (00000011 in the example)
  • 4th byte: blue value (00000100 in the example)

0xff and 0xffffff symbols

0xff represents the hexadecimal value FF which is equal to the integer 255. Its binary representation is:

00000000 00000000 00000000 11111111

Similarly 0xffffff is represented by:

00000000 11111111 11111111 11111111

It corresponds to the color white (red, green and blue equal to 255).

& operator

The binary operator and "&" is applied on two integers i1 and i2 (i1 & i2). It returns an integer with all its bits equal to 0 except the ones which are equal to 1 in both i1 and i2. For example, if we apply & on my first example and on 0xff, we obtain:

00000000 00000000 00000000 00000100

As a consequence, (& 0xff) enables to only keep the values of the last byte (i.e., the value of the blue component of the color).

// If the blue component of image.getRGB(i, j) is greater than b
if ((image.getRGB(i, j) & 0xff) > b) {
    // Set the image to white
    image.setRGB(i, j, 0xffffff) ;
} else {
    // Set the image to black
    image.setRGB(i, j, 0x000000);
}
Zach
  • 600
  • 5
  • 16
12

The

& 0xFF

is getting one of the color components (either red or blue, I forget which).

If the color mask is not performed, consider RGB (0, 127, 0), and the threshold 63. The getRGB(...) call would return

(0 * 256 * 256) + (127 * 256) + 0 = 32512

Which is clearly more than the threshold 63. But the intent was to ignore the other two color channels. The bitmask gets only the lowest 8 bits, with is zero.

The

> b

is checking if the color is brighter than a particular threshold, 'b'.

If the threshold is exceeded, the pixel is colored white, using

image.setRGB(i,j,0xffffff)

... otherwise it is colored black, using

image.setRGB(i,j,0x000000)

So it is a conversion to black and white based on a simple pixel-by-pixel threshold on a single color channel.

Dilum Ranatunga
  • 13,254
  • 3
  • 41
  • 52
4

It is probably because there is some conversion to or from ARGB. This is a really good blog post about why to do bit-wise operations for colors.

Joseph Hansen
  • 12,665
  • 8
  • 50
  • 68
0

& 0xff is a bitwise AND

(image.getRGB(i,j)&0xff) gets the blue value of the rgb encoded int returned by getRGB the > b part check whether it's larger than some threshold

ratchet freak
  • 47,288
  • 5
  • 68
  • 106