Bitshift Operators in RGB values?

I’ve been trying to figure this out for a while, I’ve come to terms with a lot of things thanks to this forum and I always do a good google search before I ask here but they seem to be quiet hard to understand hence asking so if someone could please explain why the bitshift operators are needed in this random pixel generator:

BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
			
		File f = null;
		for(int y = 0; y < height; y++) {
			for(int x = 0; x < width; x++) {
				
				int a = (int)(Math.random()*256); //alpha
				int r = (int)(Math.random()*256); //red
				int g = (int)(Math.random()*256); //green
				int b = (int)(Math.random()*256); //blue

				
				int p = (a<<24) | (r<<16) | (g<<8) | b;  //<<<------HERE
				
				img.setRGB(x, y, p);
				
			}
		}

I notice this ususage with a lot of tutorials and its where I’d normally get confused with, what is its purpose? When I took away the operators it was giving me an image of some kind. I know that if the value is 40 in binary it shifts by 1,2,3,4,5,6 along the 010101000(i.e ?40) if this makes sense but what is the purpose here for these RGB values? Thanks

4 8-bit values packed into a 32-bit package.

Hence the name of the type: INT_ARGB

Each int contains the A, R, G, and B color channels. (8 bits for each)

And how does that work? Please be more specific if possible, How can it be packed if it has the bitwise OR | ? Thanks

To store a value of 255, you need 8 bits size. The purpose of this, is to simply package them into a single 32 bit package. (java int is 4bytes, giving you 4*8=32 bits). The idea is to represent every 8-bit value in 32-bits and simply, or them.

Let’s take an example. We have a color in ARGB format as (100, 255, 50, 158) and you need to package them into a single ARGB integer. First, we see the bit versions of those integers.


   A: 0000 0000 0000 0000 0000 0000 0110 0100
   R: 0000 0000 0000 0000 0000 0000 1111 1111
   G: 0000 0000 0000 0000 0000 0000 0011 0010
   B: 0000 0000 0000 0000 0000 0000 1001 1110

So, now if you OR them, the contents will be damaged and cannot be retrieved. So we shift the bits, in-order to place all them in the same single 32-bit package. First, we shift A by 24 bits to make it the first in the package. We shift R by 16 bits to make it second, G by 8 bits to make it third. We don’t shift B since it is already in place. After doing that, the values look like this.


   A: 0110 0100 0000 0000 0000 0000 0000 0000
   R: 0000 0000 1111 1111 0000 0000 0000 0000
   G: 0000 0000 0000 0000 0011 0010 0000 0000
   B: 0000 0000 0000 0000 0000 0000 1001 1110

Finally, you OR them together to package them into a 32-bit ARGB integer. So the ARGB looks like this.


ARGB: 0110 0100 1111 1111 0011 0010 1001 1110

That’s the ARGB integer. This is the way you follow to pack the integers. Instead of just applying this, pay an attention to the pixel format, in this case, it is ARGB. There are also other formats like ABGR, RGBA, BGRA, etc., The shift to be done depends on the pixel format you are packing into. By the way, the value of that integer in decimal system is (1694446238)10 very large, isn’t it?

Hope this helps.

Just to add to what SHC posted, the bitwise OR operator will look at two numbers and combine them based on the rule that for the same bit position in any two numbers, if one or both of the numbers contain a one at the position, the output number will contain a 1 at that position, otherwise it will contain a 0.

It probably wouldn’t hurt to look into bitwise operations to get a better grasp of the overall general concepts. You may not find yourself using the information on a daily basis, but there are some neat tricks that can be performed at the bitwise level in certain situations.

One other note, the code you posted has a small bug in it. The maximum value for an 8 bit number is 255, not 256, so the code should be changed to:


int a = (int)(Math.random()*255); //alpha
int r = (int)(Math.random()*255); //red
int g = (int)(Math.random()*255); //green
int b = (int)(Math.random()*255); //blue

Other thoughts:

Sometimes you’ll instead see code which uses a utility class like AWT Color, which lets you get and set the 4 components individually rather than messing with bits in this undignified way :smiley:

You may also see this kind of code using multiplication or division instead of bit shifting. E.g. r*65536 is mathematically the same thing as r<<16 and will almost certainly be compiled the same way.

Accessing subparts of a larger numeric type is more elegant in other languages like C++ (go C++!) which allow you to manipulate, say, the 3rd chunk of 8 bits as an 8 bit number in place rather than having to shift it to and from the low position first.

@CodeHead Math.random() returns a value less than 1, so it does need to be multiplied by 256 to produce values in the range 0…255.99999, which then give equal probability of 0…255 when cast (truncated) to int.

Got it thanks a lot.

I never knew it’d be that technical, I’ve done some ASM on 6502, not much but knowing ‘some’ made me understand this.

Technical as in tweaking the value like that with an integer, in Java. I only really know:

int a = 1;
int b = 2;
int c = a + b;

So in reality, its tweaking values of the binary values at its address (kind of… stack isnt it?)

The | OR still confuses me, I’d of thought you would use & to join the numbers together into one int…

@CodeHead - as Richierich says, is why I added 256

An excellent tutorial for understanding all things (I joke, if only) bitwise. http://www.wildbunny.co.uk/blog/2012/11/07/understanding-binary/ for future reference and future readers of this post.

The definition of OR is simply Either this or this. If any of the two inputs to an OR gate is 1, then the output is 1. So, this truth table should help you understand.

[tr]
[td]
[icode]

P Q Y
0 0 0
0 1 1
1 0 1
1 1 1

[/icode]
[h2]Logical OR[/h2]
[/td]
[td]
[icode]

P Q Y
0 0 0
0 1 0
1 0 0
1 1 1

[/icode]
[h2]Logical AND[/h2]
[/td]
[/tr]

The difference between those two is really simple, OR requires at least one to be 1 while AND requires both to be 1 for the output to be 1.

And bitwise OR (or any operation) on 32 bit operands runs the truth table on each of the respective 32 bits of each operand to generate the 32 bit result. 1st bit of each operand yields the 1st bit of the result, 2nd of each yields 2nd result bit, 3rd, etc. So you can see how ORing the shifted values “collapses” them into a single value.

(Also, SHC, you have a typo: “java int’s are 4kb each” :P)

They came up with confusing terminology really. AND is equivalent to multiplication in boolean algebra, not addition. OR is addition. (As you can see from SHC’s truth tables).

The code you posted could (almost) be written using arithmetic addition (+) instead of OR and work exactly the same. It can’t though for the same reason all this is necessary in the first place - i.e. a lack of variety of integer data types in Java. We have to do everything with 32 bit signed values. >:( If we used addition here the sign bit would get in the way.

Yep! Fixed that. Thanks for pointing it out.

Quite correct. I blame it on not having my morning caffeine fix when I typed that. I was forgetting a type cast to an int functioned more like a floor than a round. My apologies. :slight_smile:

I seem to drink a lot more coffee and energy drinks since I got bang into programming, they go well together.

@quew8 – Thanks very much for that link you posted, I’ve bookmarked it. And I’d suggest anyone reading this for future reference to read SHC post:

Explains visually how they are shifted which is where I got stuck on, I couldn’t quiet visualize this which led me to confusion. The + | OR’s are a bit confusing but I guess thats how its rolls as Richie explained.

Think the Topic has been cracked :slight_smile: