Converting 24-Bit Numbers to 8-Bit Numbers
QUESTION: I have a 24-bit number, 14772545, which represents a royal blue color. But in my particular application, I need to decomposed this into three 8-bit numbers representing the RBG values buried in the number. How can I recover these RGB values in IDL?
ANSWER: Let's consider a royal blue color, which is represented by the RGB triple (65, 105, 225) where the red value is 65, the green value is 105, and the blue value is 225. In IDL, we can create a 24-bit value from these numbers like this:
IDL> num24 = 65 + (105 * 2L^8) + (225 * 2L^16) IDL> Print, num24 14772545
What you are asking to do is to go in the reverse direction. To see how this can be done, it might be useful to see a binary representation of the 24-bit number. We can use BINARY to do so, like this:
IDL> Print, Binary(num24, /COLOR, /SEPARATE) 1 1 1 0 0 0 0 1 0 1 1 0 1 0 0 1 0 1 0 0 0 0 0 1
In this representation, the 8 bits that make up the blue color are on the left, and the 8 bits that make up the red color are on the right. What we wish to know, essentially, is what number (byte value) is associated with each of these three separate bit patterns. In other words, which number is associated with the bit pattern 1 1 1 0 0 0 0 1 and represents a blue color?
To solve the problem, we need a way of separating these three bits patterns out of the 24-bit number. The bitwise operator AND will be of some use to us, if we can determine which number to AND against. Since each bit represents a power of two, if we wanted to find a number to AND with our color, we want a number that has bits 17 through 24 set. In other words, we want this number:
1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Since,
1 1 1 0 0 0 0 1 0 1 1 0 1 0 0 1 0 1 0 0 0 0 0 1 AND 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 EQUALS 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
We can find this number in IDL like this:
IDL> numberToAndBlue = Long(Total(2L^(Lindgen(8)+16))) IDL> Print, numberToAndBlue 16711680 IDL> Print, Binary(numberToAndBlue, /COLOR, /SEPARATE) 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
(Another way to find this number, if you remember back to your hexadecimal days, is like this: numberToAndBlue = 'FF0000'xL.)
And, so:
IDL> blueBits = num24 AND numberToAndBlue IDL> Print, Binary(blueBits, /COLOR, /SEPARATE) 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IDL> Print, bluebits 14745600
Now, of course, that is not exactly what we want. We have the blue bits separated out, but we want to know what 8-bit value (byte value) is represented by those bits. Another way of saying this is we need to shift that bit pattern 16 bits to the right, and then determine what the number is. We can do this with the ISHFT command in IDL.
IDL> blue = ISHFT(bluebits, -16) IDL> Print, Binary(blue, /COLOR, /SEPARATE) 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 IDL> Print, blue 225
Perfect!
So, a general algorithm for converting a 24-bit number to three eight bit numbers would look something like this.
IDL> num24 = 14772545L IDL> numberToAndBlue = Long(Total(2L^(Lindgen(8)+16))) IDL> numberToAndGreen = Long(Total(2L^(Lindgen(8)+8))) IDL> numberToAndRed = Long(Total(2L^(Lindgen(8)))) IDL> blue = ISHFT(num24 AND numberToAndBlue, -16) IDL> green = ISHFT(num24 AND numberToAndGreen, -8) IDL> red = num24 AND numberToAndRed IDL> Print, red, green, blue 65 105 225
Or, in a shorter version.
IDL> num24 = 14772545L IDL> blue = ISHFT(num24 AND 'FF0000'xL, -16) IDL> green = ISHFT(num24 AND '00FF00'xL, -8) IDL> red = num24 AND '0000FF'xL IDL> Print, red, green, blue 65 105 225
Or (as Med Bennett points out to me), in the shortest version yet. (Which, I confess, I don't completely understand.)
IDL> num24 = 14772545L IDL> Print, [num24 MOD 2L^8, (num24 MOD 2L^16)/2L^8, num24/2L^16] 65 105 225
I'll leave it as an exercise for the reader to write a Convert24to8 function.
Copyright © 2007 David W. Fanning
Last Updated 10 November 2007