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.
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.
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).
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;
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);
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.