Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert 16bit colour to 32bit

Tags:

c++

c

iphone

I've got an 16bit bitmap image with each colour represented as a single short (2 bytes), I need to display this in a 32bit bitmap context. How can I convert a 2 byte colour to a 4 byte colour in C++?

The input format contains each colour in a single short (2 bytes).

The output format is 32bit RGB. This means each pixel has 3 bytes I believe?

I need to convert the short value into RGB colours.

Excuse my lack of knowledge of colours, this is my first adventure into the world of graphics programming.

like image 327
JWood Avatar asked Nov 19 '25 09:11

JWood


2 Answers

Normally a 16-bit pixel is 5 bits of red, 6 bits of green, and 5 bits of blue data. The minimum-error solution (that is, for which the output color is guaranteed to be as close a match to the input colour) is:

red8bit   = (red5bit << 3) | (red5bit >> 2);
green8bit = (green6bit << 2) | (green6bit >> 4);
blue8bit  = (blue5bit << 3) | (blue5bit >> 2);

To see why this solution works, let's look at at a red pixel. Our 5-bit red is some fraction fivebit/31. We want to translate that into a new fraction eightbit/255. Some simple arithmetic:

     fivebit   eightbit
     ------- = --------
        31        255

Yields:

     eightbit = fivebit * 8.226

Or closely (note the squiggly ≈):

     eightbit ≈ (fivebit * 8) + (fivebit * 0.25)

That operation is a multiply by 8 and a divide by 4. Owch - both operations that might take forever on your hardware. Lucky thing they're both powers of two and can be converted to shift operations:

     eightbit = (fivebit << 3) | (fivebit >> 2);

The same steps work for green, which has six bits per pixel, but you get an accordingly different answer, of course! The quick way to remember the solution is that you're taking the top bits off of the "short" pixel and adding them on at the bottom to make the "long" pixel. This method works equally well for any data set you need to map up into a higher resolution space. A couple of quick examples:

    five bit space         eight bit space        error
    00000                  00000000                 0%
    11111                  11111111                 0%
    10101                  10101010                0.02%
    00111                  00111001               -1.01%
like image 96
Carl Norum Avatar answered Nov 21 '25 21:11

Carl Norum


Common formats include BGR0, RGB0, 0RGB, 0BGR. In the code below I have assumed 0RGB. Changing this is easy, just modify the shift amounts in the last line.

unsigned long rgb16_to_rgb32(unsigned short a)
{
/* 1. Extract the red, green and blue values */

/* from rrrr rggg gggb bbbb */
unsigned long r = (a & 0xF800) >11;
unsigned long g = (a & 0x07E0) >5;
unsigned long b = (a & 0x001F);

/* 2. Convert them to 0-255 range:
There is more than one way. You can just shift them left:
to 00000000 rrrrr000 gggggg00 bbbbb000
r <<= 3;
g <<= 2;
b <<= 3;
But that means your image will be slightly dark and
off-colour as white 0xFFFF will convert to F8,FC,F8
So instead you can scale by multiply and divide: */

r = r * 255 / 31;
g = g * 255 / 63;
b = b * 255 / 31;
/* This ensures 31/31 converts to 255/255 */

/* 3. Construct your 32-bit format (this is 0RGB): */
return (r << 16) | (g << 8) | b;

/* Or for BGR0:
return (r << 8) | (g << 16) | (b << 24);
*/
}
like image 41
Software_Designer Avatar answered Nov 21 '25 21:11

Software_Designer



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!