Click here to Skip to main content
15,889,315 members
Articles / Programming Languages / C#

Quick How to: Reduce Number of Colors Programmatically

Rate me:
Please Sign up or sign in to vote.
4.00/5 (2 votes)
2 Apr 2009Ms-PL 15.7K   5   3
How to reduce number of colors programmatically

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

Simple color matrix

First of all, you have to read a source image:

C#
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):

C#
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:

C#
img.Save(name.Replace(".png", ".bmp"), bmpEncoder, myEncoderParameters);

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

C#
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:

C#
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 a 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.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


Written By
Architect Better Place
Israel Israel
Hello! My name is Tamir Khason, and I am software architect, project manager, system analyst and [of course] programmer. In addition to writing big amount of documentation, I also write code, a lot of code. I used to work as a freelance architect, project manager, trainer, and consultant here, in Israel, but recently join the company with extremely persuasive idea - to make a world better place. I have very pretty wife and 3 charming kids, but unfortunately almost no time for them.

To be updated within articles, I publishing, visit my blog or subscribe RSS feed. Also you can follow me on Twitter to be up to date about my everyday life.

Comments and Discussions

 
Questionwhat is value of maxdistance here Pin
ravikant tiwari10-Apr-18 23:28
ravikant tiwari10-Apr-18 23:28 
AnswerRe: what is value of maxdistance here Pin
ravikant tiwari10-Apr-18 23:59
ravikant tiwari10-Apr-18 23:59 
Questionwow cool! Pin
chidexi29-May-17 11:12
chidexi29-May-17 11:12 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.