Hi,
~ wrote:
I have been looking for information about adapting, say, the colors of a 24bpp bitmap to 16 VGA colors...
It's possibly best to start looking at
Floyd-Steinberg dithering.
The basic idea is, for each (24-bit) pixel to find the closest colour (in the 16 colour palette); then find the difference between what you want and what you can have (the error) and then distribute this error to adjacent pixels.
For an example of this, here's my test pattern:
This image was generated from a (calculated) 96-bit per pixel image (32b:32g:32r) and converted to 32-bit per pixel data with Floyd-Steinberg dithering, to be as accurate as possible.
Here's the exact same thing in 4-bits per pixel (standard VGA/CGA 16 colour mode):
Without dithering you get something called
"Posterization". For an example of this, here's my test pattern again without any dithering at all:
Attachment:
nodither.png [ 11.19 KiB | Viewed 7010 times ]
As you can see it doesn't look like the original test pattern at all, due to the low colour depth used; and even though the dithered image looks "noisy", it looks a lot better.
Also, you can't just combine 2 RGB colours (e.g. anitaliasing, interpolation, etc) and get a correct result, by doing something like "B = B1 + B2; G = G1 + G2; R = R1 + R2;". There's 2 reasons for this. First, RGB has
"gamma correction", which means you need to convert the original colour data (with gamma correction) into pure RGB (without gamma correction) then combine the colours, then add the gamma correction to the result.
Secondly, (AFAIK) even if you do take gamma correction into account you can still get colours that don't look right (wrong hue), because the human eye doesn't work in RGB and perceives colours differently. To avoid this I'd convert to
CIE XYZ format then combine the colours, then convert back to RGB.
My test pattern code (used to generate the images above) doesn't account for gamma correction or use CIE XYZ, which is probably what is causing those ugly bright greeen dots in the middle of the "green to red" horizontal bar (second horizontal bar from the top) in the "4-bit per pixel dithered" image above.
If you add all of this up, then the correct method would be:
- convert the original data from RGB with gamma correction to RGB without gamma correction
- convert the data from RGB without gamma correction to CIE XYZ
- process the data (including doing Floyd-Steinberg dithering) while it's in CIE XYZ format
- convert the data from CIE XYZ back to RGB without gamma correction
- convert the data from RGB without gamma correction to RGB with gamma correction
However, processing time may be a limiting factor here, especially if you're using floating point (or wide fixed point) to avoid precision loss during processing...
Cheers,
Brendan