Introduction
This article describes about image bit depth conversion from 32 bit to 8 bit. There are several methods for conversion. In this article, Indexed color and palette are used.
32 Bit to 8 Bit Conversion
There are several methods to convert to indexed color. Some methods are Dithering, Nearest Color, Adaptive or Optimized or Perceptual Palette, Standard Web Browser Palette etc. Here I am describing about Standard Web Browser Palette.
The Standard Palette (often called Web palette) always contains the same colors for any image. It is sometimes called 6-6-6, because it contains six standard evenly spaced colors for each of Red, Green, and Blue. Those 6x6x6 color combinations create 6x6x6 = 216 standard color combinations, which are used for any image.
The Standard Palette always contains combinations of the following 6 tones for each of the Red, Green, Blue primaries:

The 216 combinations of these 18 colors above (six shades of the three RGB colors, 6x6x6 = 216) produce the Standard web-safe palette. This Standard web-safe palette color shades are shown below:

First, we define a standard color table using those 6 colors.
const DWORD STANDARD_PALETTE[] = {00,51,102,153,204,255}
const INT STANDARD_COLOR_SIZE = 6;
const INT STANDARD_PALETTE_VAL_DIF = 51;
For 8 bit conversion, we must create a color table which is called as Palette color map. All possible combinations of Standard palette colors are entries in this table. Palette color map creation is shown below:
DWORD dwColorMapTable[216] = {0};
int nColorMapIdx = 0;
for (int nBlueIdx = 0; nBlueIdx < STANDARD_COLOR_SIZE; ++nBlueIdx)
{
for(int nGreenIdx = 0; nGreenIdx < STANDARD_COLOR_SIZE; ++nGreenIdx)
{
for(int nRedIdx = 0; nRedIdx < STANDARD_COLOR_SIZE; ++nRedIdx)
{
RGBQUAD objColor;
objColor.rgbRed = STANDARD_PALETTE[nRedIdx];
objColor.rgbGreen = STANDARD_PALETTE[nGreenIdx];
objColor.rgbBlue = STANDARD_PALETTE[nBlueIdx];
objColor.rgbReserved = 0;
memcpy(&dwColorMapTable[nColorMapIdx],&objColor,sizeof(RGBQUAD));
++nColorMapIdx;
}
}
}
After that, we can convert a 32 bit image file to 8 bit image file. For conversion, read each pixel data from input image data. Get Red, Green and Blue values from pixel. With these RGB values, calculate suitable color from STANDARD_PALETTE
. Find suitable color from the Palette color map table. Set table map entry index to the output pixel value.
Cstring csInputFileName = "c:\\32BitImage.bmp";
Bitmap InputImage(csInputFileName,FALSE);
INT nImageHeight = InputImage .GetHeight();
INT nImageWidth = InputImage .GetWidth();
INT nPixelSize = nImageHeight * nImageWidth;
BYTE byBitsPerPixel = 32;
BYTE pixels = new BYTE[nPixelSize];
for(UINT nRow = 0; nRow < nImageHeight; ++nRow)
{
for(UINT nCol = 0; nCol < nImageWidth; ++nCol)
{
Color objColorData;
UINT i8bppPixel = nRow * nImageWidth + nCol;
if(Ok != InputImage GetPixel(nCol,nRow,&objColorData))
{
printf("Get Image Pixel Failed.\n")
}
int nRed = objColorData.GetRed();
int nGreen = objColorData.GetGreen();
int nBlue = objColorData.GetBlue();
UINT uRedValue = GetPixelValue(objColorData.GetRed());
UINT uGreenValue = GetPixelValue(objColorData.GetGreen());
UINT uBlueValue = GetPixelValue(objColorData.GetBlue());
UINT uPalettePos = uBlueValue*36+uGreenValue*6+uRedValue;
pixels[i8bppPixel] =(BYTE)uPalettePos;
}
}
GetPixelValue()
returns appropriate pixel index value in the Standard Palette table. Implementation is shown below:
UINT GetPixelValue(UINT uPixelValue_i)
{
UINT uRetValue = 0;
UINT uPos = uPixelValue_i / PALETTE_VAL_DIF;
if(0 == uPixelValue_i % PALETTE_VAL_DIF)
{
uRetValue = uPixelValue_i/PALETTE_VAL_DIF;
}
else
{
if(abs(uPixelValue_i - STANDARD_PALETTE [uPos]) >
abs(uPixelValue_i - STANDARD_PALETTE [uPos+1]))
{
uRetValue = uPos+1;
}
else
{
uRetValue = uPos;
}
}
return uRetValue;
}
For viewing converted image:
- Create an output file.
- Write Bitmap header to the output file.
- Write pixel data to the output file.
- Close output file.
Good luck!