views:

616

answers:

5

I'm porting a software that build from 16bit color depth to 18bit color depth. How can I convert the 16-bit colors to 18-bit colors? Thanks.

+1  A: 

Without knowing the device, I can only speculate. Devices are typically Red, Green, Blue so each color would get 6 bits of variation. That means 64 variations of each color and a total of 262,144 colors.

Any bitmap can be scaled to this display. If you take each component (say, red), normalize it, then multiply by 64, you'll have the scaled version.

If you are asking something else or want more detail, please ask.

Update:
There are two 16-bit bitmap formats. One is 5-5-5 (5 bits per pixel) and the other is 5-6-5 (green gets an extra bit). I'll assume 5-5-5 for the sake of this conversion.

For each color within each pixel you need something like this:

NewColor = (oldColor/32.0)*64

This will turn the old color into a number between 0.0 and 1.0 and then scale it up to the new value range.

Steve Rowe
Hi sir thanks for the info. How can I convert from 16-bit representation of the bitmap to 18-bit representation?
sasayins
Just set the upper-most bit's to 0? :/
GMan
If the answer we're commenting on is correct, that will mean we only get 4 bits of red :(
Jeremy Smyth
That would work, kinda. All of your colors would get darker though. You need to interpolate the values (see my answer).
colithium
Actually, the colors would get darker AND slightly more green haha
colithium
GMan, that wouldn't scale the colors correctly. Everything would become less saturated.
Steve Rowe
very very nice!
sasayins
A: 

To answer the conversion question

I'm not familiar with c++ image libraries but I'm sure this code already exists somewhere. But if you'd like you can do it yourself.

Each pixel has three channels: red, green, and blue. In a 16-bit bitmap, each channel doesn't have the same number of bits per channel. Typically, green is first to get any extra bits because the human eye is most sensitive to that color.

It's probably 565 -- 5 for red, 6 for green, and 5 for blue.

For an 18-bit bitmap (as previously stated), each channel has 6 bits. So green is easy! Just copy the value over from the 16 bit format to the 18 bit format. The other two channels are slightly harder. You have to interpolate from 5 to 6:

18_Value = (16_Value / 32) * 64 //integers only of course.  You need to round properly to get best results.

And there you have it. If you aren't already familiar with the following, I'd suggest you research them:

  • Bit Shift Operators
  • Bitmap Stride
  • Pointer Math
  • Byte Alignment

--Edit-- Make sure you know how things are laid out in memory; RGB or BGR. It will mess with your head if you do anything more complicated than this and you're thinking about it backwards (since Green is in the middle it's not that important for this conversion).

colithium
wow thanks, can you give more examples of this conversion, i am fairly new to this stuff. thanks.
sasayins
Being integer division, this will clamp to an integer at each step and thus skew the numbers a lot. 63, 62, 61, and 60 all end up the same color.
Steve Rowe
Also, you can't divide by 5 and multiply by 6. That's the number of bits. You have to multiply and divide by their numeric values (32 and 64 in decimal).
Steve Rowe
Yes, I only meant it as rough pseduo-code. Values should be properly rounded. I'll add it to the answer.
colithium
wouldn't it be better to use 32 bit integers for the computation and multply before dividing? (or use doubles?)
cube
I made an edit just now that address this
colithium
A: 

You will first of all have to access each of the colour components (i.e. extract the R value, the G value, and the B value). The way to do this will depend totally on the way that the colour is stored in memory. If it is stored as RGB, with 5-6-5 bits for the components, you could use something like this:

blueComponent  = (colour & 0x1F);
greenComponent = (colour >> 5 ) & 0x3F;
redComponent   = (colour >> 11) & 0x1F;

This will extract the colour components for you, then you can use the method outlined above to convert each of the components (I presume 18-bit will use 6 bits per component):

blueComponent  = (blueComponent  / 32.0) * 64;
//greenComponent = (greenComponent / 64.0) * 64;    // not needed
redComponent   = (redComponent   / 32.0) * 64;

Note that with the above code, it is important that you use 32.0, or some other method that will ensure that your program represents the number as a floating point number. Then to combine the components into your 18-bit colour, use:

colour = (redComponent << 12) | (greenComponent << 6) | blueComponent;
a_m0d
+1  A: 

Assuming that the 16bit color is in 5-6-5 format:

// RRRRR-GGGGGG-BBBBB, 16bit -->

//RRRRR0-GGGGGG-BBBBB0, 18bit with the formula below:
Color18 = ((Color16 & 0xF800) << 2) | ((Color16 & 0x07E0) << 1) | ((Color16 & 0x1F) << 1);
Nick D
Accipitridae
@Accipitridae, I wanted to be obvious (is it?, anyway :) how I *pick* the R-G-B values and how I transform them. But probably I should had post also a shorter version of that formula. Thanks for mentioning it.
Nick D
+1  A: 

I don't see this covered in the other answers, but you want the conversion from 5 to 6 bits to be such that binary 11111 gets mapped to 111111, since both represent full on. One way to do that is to replicate the leading bit(s).

red6 = (red5 << 1) | (red5 >> 4);

If you use an arithmetic conversion, keep in mind that the maximum values are 31 and 63, not 32 and 64.

red6 = (red5 * 63 + 15) / 31; // all ints, +15 is for rounding

If you care about other intermediate values, such as if you want 16 mapped 32 either tweak the formula (e.g., change 15 to 14) or just make a table.

xan