Quick how to: Reduce number of colors programmatically

My colleague just asked me about how to reduce a number of colors in image programmatically. This is very simple task and contains of 43 :) steps:

Simple color matrix

First of all, you have to read a source image

using (var img = Image.FromFile(name)) {
var bmpEncoder = ImageCodecInfo.GetImageDecoders().FirstOrDefault(e => e.FormatID == ImageFormat.Bmp.Guid);

Then create your own encoder with certain color depth (32 bits in this case)

var myEncoder = System.Drawing.Imaging.Encoder.ColorDepth;
var myEncoderParameter = new EncoderParameter(myEncoder, 32L);
var myEncoderParameters = new EncoderParameters(1) { Param = new EncoderParameter[] { myEncoderParameter } };

Then save it

img.Save(name.Replace(“.png”, “.bmp”), bmpEncoder, myEncoderParameters);

It it enough? Not really, because if you’re going to loose colors (by reducing color depth), it makes sense to avoid letting default WIX decoder to do this, thus you have to find nearest base colors manually. How to do this? By using simple math

Color GetNearestBaseColor(Color exactColor) {
Color nearestColor = Colors.Black;
int cnt = baseColors.Count;
for (int i = 0; i < cnt; i++) {
int rRed = baseColors[i].R – exactColor.R;
int rGreen = baseColors[i].G – exactColor.G;
int rBlue = baseColors[i].B – exactColor.B;

int rDistance =
(rRed * rRed) +
(rGreen * rGreen) +
(rBlue * rBlue);
if (rDistance == 0.0) {
return baseColors[i];
} else if (rDistance < maxDistance) {
maxDistance = rDistance;
nearestColor = baseColors[i];
}
}
return nearestColor;
}

Now, you can either change colors on base image directly

unsafe {
uint* pBuffer = (uint*)hMap;
for (int iy = 0; iy < (int)ColorMapSource.PixelHeight; ++iy)
{
for (int ix = 0; ix < nWidth; ++ix)
{
Color nc = GetNearestBaseColor(pBuffer[0].FromOle());

pBuffer[0] &= (uint)((uint)nc.A << 24) | //A
(uint)(nc.R << 16 ) | //R
(uint)(nc.G << 8 ) | //G
(uint)(nc.B ); //B
++pBuffer;
}
pBuffer += nOffset;
}
}

Or, if you’re in WPF and .NET 3.5 create simple pixel shader effect to do it for you in hardware. Now, my colleague can do it himself in about 5 minutes :) . Have a nice day and be good people.

Be Sociable, Share!

You may also be interested with:

  1. RSA private key import from PEM format in C#
  2. Video encoder and metadata reading by using Windows Media Foundation

3 Responses to “Quick how to: Reduce number of colors programmatically”

  1. Boris Says:

    Not so easy:
    1. Using encoders/decoders won’t help because they ignore ColorDepth parameter (only GIF/TIFF use it and only 4bit/24bit values)
    2. For the manual version – you first need to create baseColors palette – your target X-bit palette somehow.

  2. Heartburn Home Remedy Says:

    Hey, nice tips. Perhaps I’ll buy a bottle of beer to the person from that chat who told me to go to your blog :)

  3. Rob Rasner Comedian Says:

    Thx for the marvelous post! We actually loved studying it, you are a great source We will ensure that I take a note of ones blog site and will eventually return at some point, We wish to encourage yourself to carry on your great work, enjoy your weekend Oh yeah did you hear Bahrain notable media stories… Thx … Rob Rasner Comedian

Leave a Reply

Recommended

 


Sponsor


Partners

WPF Disciples
Dreamhost
Code Project
Switched to Better Place

Together