10

I'm quite new to C# and trying to do a basic image processing software. I understand this snippet extracts A,R,G,B from an ARGB int value of a WriteableBitmap pixel "current"

for(int i = 0; i < bitmapArray.Length; i++) {
    var current = bitmapArray[i];

    var alpha = (byte)(current >> 24);
    var red = (byte)(current >> 16);
    var green = (byte)(current >> 8);
    var blue = (byte)(current);
    //Some code
 }

What is ">>" doing to convert the values?

Also, If I do some calculations to the r,g and b individually, how do I convert them back to an integer ARGB value to replace the original pixel with the new one?

Thanks in advance.

Edit: thanks guys, it makes sense now.

Hosain
  • 101
  • 3
  • Its actually quite irritating that the `Color` structure in Silverlight doesn't provide a means of converting an `Int32` to `Color`. – AnthonyWJones Aug 15 '10 at 13:39

3 Answers3

16

It is the binary shift operator.

If you have a color defined by (a, r, g, b), it's binary representation would look like this (assuming a channel depth of 8 bits):

AAAAAAAA RRRRRRRR GGGGGGGG BBBBBBBB

So, shift that whole thing over 24 places and you are left with the alpha channel

AAAAAAAA

Shift by 16 and you get the alpha channel and the red channel

AAAAAAAARRRRRRRR

Now, since that is cast as a byte, only the first 8 bits are extracted

(byte)AAAAAAAARRRRRRRR == RRRRRRRR

You could also get the red channel by shifting 16 places and AND'ing with 11111111 (0xFF)

AAAAAAAARRRRRRRR &
0000000011111111
----------------
00000000RRRRRRRR
Ed S.
  • 122,712
  • 22
  • 185
  • 265
  • 1
    +1. This is a great explanation, I've always wondered about bit shifting and how it works. If you had the time, it would be great to see an example of how doing the above changes a color value and how. Like how does bit shifting change 128, 64, 256 to some other RGB value. Also, I still don't undertand `(byte)AAAAAAAARRRRRRRR == RRRRRRRR` (i.e. is it extracted from right to left?), but at least I know more than I did before visiting this answer. – Todd Main Aug 15 '10 at 01:02
  • @Otaku: Binary is read right to left, and in this case, "first 8 bits" means just that. – junkforce Aug 15 '10 at 01:22
  • If you cast (pixel & 0xff000000) to a byte, you will get a zero no matter what since the rightmost 8 bits will be 0. So I don't think your last block is correct. – Jacob Aug 15 '10 at 02:14
  • D'oh! You're right. That's what I get for trying to answer too quickly. – Ed S. Aug 15 '10 at 05:20
  • @Otaku: As junkforce said, you are just cropping the first 8 bits and stuffing that in a byte. The rest (i.e., anything > 255) is discarded. – Ed S. Aug 15 '10 at 05:23
12

It is shifting the bits of the current value to the right. In the case of this particular code snippit, it appears to be extracting each byte of color information from the selected bitmap array element into individual color bytes.

http://msdn.microsoft.com/en-us/library/xt18et0d.aspx

Assuming that your array contains ints, to get a computed value back into the array element, you would reverse the bit-shifting process and OR the results back together, like so:

int current = (alpha << 24) | (red << 16) | (green << 8) | blue; 
Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
  • I wonder ... is `BitConverter.GetBytes(current)` too complicated? Hm, maybe too slow for serious image manipulation. – Joey Aug 15 '10 at 00:39
  • @Johannes: `BitConverter` is very fast. I would imagine it would be appropriate here. – Robert Harvey Aug 15 '10 at 00:41
  • 1
    It's such a simple, obvious, and common operation that I don't see the advantage to using anything but binary operators. If you don't understand what is going on, you should learn or stay away from image processing (not 'you' in particular, just in general) – Ed S. Aug 15 '10 at 00:42
  • Robert: You'd get a `byte[]` and you probably don't want a new one for each pixel; that's the rationale behind my "perhaps too slow" edit. – Joey Aug 15 '10 at 01:14
  • 'int' is signed. If the alpha value is greater than 127 it will overflow and your code will break. – Ed S. Aug 15 '10 at 05:17
  • 1
    @Ed: No it won't. You'll just get a negative 32-bit number. Although it is a signed number, there are still 32 bits you can use. See LukeH's comment [below his answer.](http://stackoverflow.com/questions/3485701/what-does-the-operator-do-in-c/3485731#3485731) – Robert Harvey Aug 15 '10 at 05:35
  • You're right; overflow was the wrong way to put it. I'm just used to explicitly using unsigned types when appropriate. – Ed S. Aug 15 '10 at 22:39
2

Further to Robert's answer -- and to cover the second part of your question -- you can combine the separate components back to an integer using the << (left-shift) and | (bitwise OR) operators:

int combined = (alpha << 24) | (red << 16) | (green << 8) | blue;
LukeH
  • 263,068
  • 57
  • 365
  • 409
  • @Robert: The OP doesn't specify, and I suppose that philosophically it's neither - it's just a set of 4 unsigned octets. If the *storage mechanism* is an `int` then my code will work just fine (and the result will be a negative `int` if the alpha value is greater than 127). If the storage mechanism is a `uint` then some additional casting etc would be required. – LukeH Aug 15 '10 at 01:00