Click here to Skip to main content
Rate this: bad
good
Please Sign up or sign in to vote.
See more: C# GDI+
I have an PNG image with a single-color shape on a transparent background. I want to blur the edges of the shape using the alpha channel to control opacity (so the blurred pixels will be the same color but the opacity will gradually diminish to 0).
 
I've looked around on google (and here on CodeProject), but haven't found anything that is a) fast enough to be used, or b) seems to work on the alpha channel. I found Christian Graus's 2003 article, but I don't think it does alpha channel stuff.
 
Can anyone help?
 
EDIT ================================
 
I'm still interested in something that's faster than the code below. I might try to optimize it later on, but for now, I'm simply too busy (and besides, it works as is).
Posted 26-Sep-11 1:51am
Edited 26-Sep-11 8:34am
v2

1 solution

Rate this: bad
good
Please Sign up or sign in to vote.

Solution 1

I found some code (but I can't find the source URL again). It was some german guy's code that was answering a similar question on MSDN. I'm using the sigma functions. I reformatted the code a little and added the NormalizeValue method (at the top) as well as the Blur method (at the bottom). I call the Blur method from my own code.
 
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using System.Collections;
using System.Drawing.Drawing2D;
using System.Collections.Generic;
namespace CamoPicker
{
	public static class ImageBlur
	{
		//--------------------------------------------------------------------------------
		private static int NormalizeValue(int value, int min, int max)
		{
			int result = Math.Min(Math.Max(value, min), max);
			return result;
		}
		//--------------------------------------------------------------------------------
		public static unsafe bool makeEdgesTransparentHorz(Bitmap bmp, int nWidth1, int nWidth2, int nZuwachs1, int nZuwachs2, bool bauto)
		{
			BitmapData bmData     = null;
			Bitmap     bmpOrig    = null;
			BitmapData bmDataOrig = null;
			try
			{
				ArrayList     Al        = new ArrayList();
				bmData                  = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
				System.IntPtr Scan0     = bmData.Scan0;
				byte*         p         = (byte*)(void*)Scan0;
				bmpOrig                 = (Bitmap)bmp.Clone();
				bmDataOrig              = bmpOrig.LockBits(new Rectangle(0, 0, bmpOrig.Width, bmpOrig.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
				System.IntPtr Scan0Orig = bmDataOrig.Scan0;
				byte*         pOrig     = (byte*)(void*)Scan0Orig;
				int           lp        = 0;
				for (int row = 0; row < bmp.Height; row++)
				{
					for (int col = 0; col < bmp.Width; col++)
					{
						p  = (byte*)(void*)Scan0;
						p += (row * bmp.Width * 4) + (col * 4);
						if ((p[3] > 0) && (lp == 0))
						{
							Al.Add(new Point(col, row));
						}
						lp = (int)p[3];
					}
					lp = 0;
				}
				Al.TrimToSize();
				for (int i = 0; i < Al.Count; i++)
				{
					Point pt1 = (Point)Al[i];
					p = (byte*)(void*)Scan0;
					pOrig = (byte*)(void*)Scan0Orig;
					if (pt1.X <= bmp.Width - nWidth1)
					{
						p += (pt1.Y * bmp.Width * 4) + (pt1.X * 4);
						pOrig += (pt1.Y * bmpOrig.Width * 4) + (pt1.X * 4);
						int start = 255 - (int)(nZuwachs1 * nWidth1);
						int z = nZuwachs1;
						if (bauto)
						{
							z = Math.Max(1, (int)Math.Ceiling(255.0 / nWidth1));
							start = Math.Max(0, (int)(255 - (z * nWidth1)));
						}
						for (int ii = 0; ii < nWidth1; ii++)
						{
							//int val = start;
							//if (val < 0)
							//{
							//    val = 0;
							//}
							//if (val > 255)
							//{
							//    val = 255;
							//}
							int val = NormalizeValue(start, 0, 255);
							p[3] = (byte)(((double)pOrig[3] / 255.0) * val);
							start += z;
							p += 4;
							pOrig += 4;
						}
					}
				}
				Al.Clear();
				lp = 0;
				for (int row = 0; row < bmp.Height; row++)
				{
					for (int col = bmp.Width - 1; col >= 0; col--)
					{
						p = (byte*)(void*)Scan0;
						p += (row * bmp.Width * 4) + (col * 4);
						if ((p[3] > 0) && (lp == 0))
						{
							Al.Add(new Point(col, row));
						}
						lp = (int)p[3];
					}
					lp = 0;
				}
				Al.TrimToSize();
				for (int i = 0; i < Al.Count; i++)
				{
					Point pt1 = (Point)Al[i];
					p = (byte*)(void*)Scan0;
					pOrig = (byte*)(void*)Scan0Orig;
					if (pt1.X >= (nWidth2 - 1))
					{
						//p += ((nWidth2) * -4) + (pt1.Y * bmp.Width * 4) + (pt1.X * 4);
						int start = 255 - (int)(nZuwachs2 * nWidth2);
						int z = nZuwachs2;
						if (bauto)
						{
							z = Math.Max(1, (int)Math.Ceiling(255.0 / nWidth2));
							start = Math.Max(0, (int)(255 - (z * nWidth2)));
						}
						p = (byte*)(void*)Scan0;
						p += ((nWidth2) * -4) + (pt1.Y * bmp.Width * 4) + ((pt1.X + nWidth2) * 4);
						pOrig = (byte*)(void*)Scan0Orig;
						pOrig += ((nWidth2) * -4) + (pt1.Y * bmpOrig.Width * 4) + ((pt1.X + nWidth2) * 4);
						for (int ii = 0; ii < nWidth2; ii++)
						{
							//int val = start;
							//if (val < 0)
							//    val = 0;
							//if (val > 255)
							//    val = 255;
							int val = NormalizeValue(start, 0, 255);
							p[3] = (byte)(((double)pOrig[3] / 255.0) * val);
							start += z;
							p -= 4;
							pOrig -= 4;
						}
					}
				}
				bmp.UnlockBits(bmData);
				bmpOrig.UnlockBits(bmDataOrig);
				bmpOrig.Dispose();
				bmpOrig = null;
				return true;
			}
			catch
			{
				try
				{
					bmpOrig.UnlockBits(bmDataOrig);
					bmp.UnlockBits(bmData);
				}
				catch
				{
				}
				if (bmpOrig != null)
				{
					bmpOrig.Dispose();
					bmpOrig = null;
				}
			}
			return false;
		}
		//--------------------------------------------------------------------------------
		public static unsafe bool makeEdgesTransparentVert(Bitmap bmp, int nWidth1, int nWidth2, int nZuwachs1, int nZuwachs2, bool bauto)
		{
			BitmapData bmData = null;
			Bitmap bmpOrig = null;
			BitmapData bmDataOrig = null;
			try
			{
				ArrayList Al = new ArrayList();
				bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
				System.IntPtr Scan0 = bmData.Scan0;
				byte* p = (byte*)(void*)Scan0;
				bmpOrig = (Bitmap)bmp.Clone();
				bmDataOrig = bmpOrig.LockBits(new Rectangle(0, 0, bmpOrig.Width, bmpOrig.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
				System.IntPtr Scan0Orig = bmDataOrig.Scan0;
				byte* pOrig = (byte*)(void*)Scan0Orig;
				int lp = 0;
				for (int col = 0; col < bmp.Width; col++)
				{
					for (int row = 0; row < bmp.Height; row++)
					{
						p = (byte*)(void*)Scan0;
						p += (row * bmp.Width * 4) + (col * 4);
						if ((p[3] > 0) && (lp == 0))
						{
							Al.Add(new Point(col, row));
						}
						lp = (int)p[3];
					}
					lp = 0;
				}
				Al.TrimToSize();
				for (int i = 0; i < Al.Count; i++)
				{
					Point pt1 = (Point)Al[i];
					p = (byte*)(void*)Scan0;
					pOrig = (byte*)(void*)Scan0Orig;
					if (pt1.Y <= bmp.Height - nWidth1)
					{
						p += (pt1.Y * bmp.Width * 4) + (pt1.X * 4);
						pOrig += (pt1.Y * bmpOrig.Width * 4) + (pt1.X * 4);
						int start = 255 - (int)(nZuwachs1 * nWidth1);
						int z = nZuwachs1;
						if (bauto)
						{
							z = Math.Max(1, (int)Math.Ceiling(255.0 / nWidth1));
							start = Math.Max(0, (int)(255 - (z * nWidth1)));
						}
						for (int ii = 0; ii < nWidth1; ii++)
						{
							//int val = start;
							//if (val < 0)
							//    val = 0;
							//if (val > 255)
							//    val = 255;
							int val = NormalizeValue(start, 0, 255);
							p[3] = (byte)(((double)pOrig[3] / 255.0) * val);
							start += z;
							p += (bmp.Width * 4);
							pOrig += (bmpOrig.Width * 4);
						}
					}
				}
				Al.Clear();
				lp = 0;
				for (int col = 0; col < bmp.Width; col++)
				{
					for (int row = bmp.Height - 1; row >= 0; row--)
					{
						p = (byte*)(void*)Scan0;
						p += (row * bmp.Width * 4) + (col * 4);
						if ((p[3] > 0) && (lp == 0))
						{
							Al.Add(new Point(col, row));
						}
						lp = (int)p[3];
					}
					lp = 0;
				}
				Al.TrimToSize();
				for (int i = 0; i < Al.Count; i++)
				{
					Point pt1 = (Point)Al[i];
					p = (byte*)(void*)Scan0;
					pOrig = (byte*)(void*)Scan0Orig;
					if (pt1.Y >= (nWidth2 - 1))
					{
						//p += ((nWidth2) * bmp.Width * -4) + (pt1.Y * bmp.Width * 4) + (pt1.X * 4);
						int start = 255 - (int)(nZuwachs2 * nWidth2);
						int z = nZuwachs2;
						if (bauto)
						{
							z = Math.Max(1, (int)Math.Ceiling(255.0 / nWidth2));
							start = Math.Max(0, (int)(255 - (z * nWidth2)));
						}
						p = (byte*)(void*)Scan0;
						p += ((nWidth2) * bmp.Width * -4) + ((pt1.Y + nWidth2) * bmp.Width * 4) + (pt1.X * 4);
						pOrig = (byte*)(void*)Scan0Orig;
						pOrig += ((nWidth2) * bmpOrig.Width * -4) + ((pt1.Y + nWidth2) * bmpOrig.Width * 4) + (pt1.X * 4);
						for (int ii = 0; ii < nWidth2; ii++)
						{
							//int val = start;
							//if (val < 0)
							//    val = 0;
							//if (val > 255)
							//    val = 255;
							int val = NormalizeValue(start, 0, 255);
							p[3] = (byte)(((double)pOrig[3] / 255.0) * val);
							start += z;
							p -= (bmp.Width * 4);
							pOrig -= (bmpOrig.Width * 4);
						}
					}
				}
				bmp.UnlockBits(bmData);
				bmpOrig.UnlockBits(bmDataOrig);
				bmpOrig.Dispose();
				bmpOrig = null;
				return true;
			}
			catch
			{
				try
				{
					bmpOrig.UnlockBits(bmDataOrig);
					bmp.UnlockBits(bmData);
				}
				catch
				{
				}
				if (bmpOrig != null)
				{
					bmpOrig.Dispose();
					bmpOrig = null;
				}
			}
			return false;
		}
		//--------------------------------------------------------------------------------
		public static double[] getVector(int Length)
		{
			if ((Length & 0x01) != 1)
			{
				MessageBox.Show("Length must be odd", "Hinweis", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
				return new Double[] { };
			}
			double[] KernelVector = new double[Length];
			int Radius = Length / 2;
			double a = -2.0 * Radius * Radius / Math.Log(0.01 /*Weight*/);
			double Sum = 0.0;
			for (int x = 0; x < KernelVector.Length; x++)
			{
				double dist = Math.Abs(x - Radius);
				KernelVector[x] = Math.Exp(-dist * dist / a);
				Sum += KernelVector[x];
			}
			//for (int x = 0; x < KernelVector.Length; x++)
			//{
			//    KernelVector[x] /= Sum;
			//}
			return KernelVector;
		}
		//--------------------------------------------------------------------------------
		public static unsafe bool makeEdgesTransparentHorzSigma(Bitmap bmp, int nWidth1, int nWidth2)
		{
			BitmapData bmData = null;
			Bitmap bmpOrig = null;
			BitmapData bmDataOrig = null;
			try
			{
				ArrayList Al = new ArrayList();
				bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
				System.IntPtr Scan0 = bmData.Scan0;
				byte* p = (byte*)(void*)Scan0;
				bmpOrig = (Bitmap)bmp.Clone();
				bmDataOrig = bmpOrig.LockBits(new Rectangle(0, 0, bmpOrig.Width, bmpOrig.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
				System.IntPtr Scan0Orig = bmDataOrig.Scan0;
				byte* pOrig = (byte*)(void*)Scan0Orig;
				int lp = 0;
				for (int row = 0; row < bmp.Height; row++)
				{
					for (int col = 0; col < bmp.Width; col++)
					{
						p = (byte*)(void*)Scan0;
						p += (row * bmp.Width * 4) + (col * 4);
						if ((p[3] > 0) && (lp == 0))
						{
							Al.Add(new Point(col, row));
						}
						lp = (int)p[3];
					}
					lp = 0;
				}
				Al.TrimToSize();
				double[] Values = getVector((nWidth1 * 2) + 1);
				if (Values.Length / 2 == nWidth1)
				{
					for (int i = 0; i < Al.Count; i++)
					{
						Point pt1 = (Point)Al[i];
						p = (byte*)(void*)Scan0;
						pOrig = (byte*)(void*)Scan0Orig;
						if (pt1.X <= bmp.Width - nWidth1)
						{
							p += (pt1.Y * bmp.Width * 4) + (pt1.X * 4);
							pOrig += (pt1.Y * bmpOrig.Width * 4) + (pt1.X * 4);
							for (int ii = 0; ii < nWidth1; ii++)
							{
								int val = (int)Math.Max(0, (int)(255.0 * Values[ii]));
								//if (val < 0)
								//    val = 0;
								//if (val > 255)
								//    val = 255;
								val = NormalizeValue(val, 0, 255);
								p[3] = (byte)(((double)pOrig[3] / 255.0) * val);
								p += 4;
								pOrig += 4;
							}
						}
					}
				}
				Al.Clear();
				lp = 0;
				for (int row = 0; row < bmp.Height; row++)
				{
					for (int col = bmp.Width - 1; col >= 0; col--)
					{
						p = (byte*)(void*)Scan0;
						p += (row * bmp.Width * 4) + (col * 4);
						if ((p[3] > 0) && (lp == 0))
						{
							Al.Add(new Point(col, row));
						}
						lp = (int)p[3];
					}
					lp = 0;
				}
				Al.TrimToSize();
				Values = getVector((nWidth2 * 2) + 1);
				if (Values.Length / 2 == nWidth2)
				{
					for (int i = 0; i < Al.Count; i++)
					{
						Point pt1 = (Point)Al[i];
						p = (byte*)(void*)Scan0;
						pOrig = (byte*)(void*)Scan0;
						if (pt1.X >= (nWidth2 - 1))
						{
							p = (byte*)(void*)Scan0;
							p += ((nWidth2) * -4) + (pt1.Y * bmp.Width * 4) + ((pt1.X + nWidth2) * 4);
							pOrig = (byte*)(void*)Scan0Orig;
							pOrig += ((nWidth2) * -4) + (pt1.Y * bmpOrig.Width * 4) + ((pt1.X + nWidth2) * 4);
							for (int ii = 0; ii < nWidth2; ii++)
							{
								int val = (int)Math.Max(0, (int)(255.0 * Values[ii]));
								//if (val < 0)
								//    val = 0;
								//if (val > 255)
								//    val = 255;
								val = NormalizeValue(val, 0, 255);
								p[3] = (byte)(((double)pOrig[3] / 255.0) * val);
								p -= 4;
								pOrig -= 4;
							}
						}
					}
				}
				bmp.UnlockBits(bmData);
				bmpOrig.UnlockBits(bmDataOrig);
				bmpOrig.Dispose();
				bmpOrig = null;
				return true;
			}
			catch
			{
				try
				{
					bmpOrig.UnlockBits(bmDataOrig);
					bmp.UnlockBits(bmData);
				}
				catch
				{
				}
				if (bmpOrig != null)
				{
					bmpOrig.Dispose();
					bmpOrig = null;
				}
			}
			return false;
		}
		//--------------------------------------------------------------------------------
		public static unsafe bool makeEdgesTransparentVertSigma(Bitmap bmp, int nWidth1, int nWidth2)
		{
			BitmapData bmData = null;
			Bitmap bmpOrig = null;
			BitmapData bmDataOrig = null;
			try
			{
				ArrayList Al = new ArrayList();
				bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
				System.IntPtr Scan0 = bmData.Scan0;
				byte* p = (byte*)(void*)Scan0;
				bmpOrig = (Bitmap)bmp.Clone();
				bmDataOrig = bmpOrig.LockBits(new Rectangle(0, 0, bmpOrig.Width, bmpOrig.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
				System.IntPtr Scan0Orig = bmDataOrig.Scan0;
				byte* pOrig = (byte*)(void*)Scan0Orig;
				int lp = 0;
				for (int col = 0; col < bmp.Width; col++)
				{
					for (int row = 0; row < bmp.Height; row++)
					{
						p = (byte*)(void*)Scan0;
						p += (row * bmp.Width * 4) + (col * 4);
						if ((p[3] > 0) && (lp == 0))
						{
							Al.Add(new Point(col, row));
						}
						lp = (int)p[3];
					}
					lp = 0;
				}
				Al.TrimToSize();
				double[] Values = getVector((nWidth1 * 2) + 1);
				if (Values.Length / 2 == nWidth1)
				{
					for (int i = 0; i < Al.Count; i++)
					{
						Point pt1 = (Point)Al[i];
						p = (byte*)(void*)Scan0;
						pOrig = (byte*)(void*)Scan0Orig;
						if (pt1.Y <= bmp.Height - nWidth1)
						{
							p += (pt1.Y * bmp.Width * 4) + (pt1.X * 4);
							pOrig += (pt1.Y * bmpOrig.Width * 4) + (pt1.X * 4);
							for (int ii = 0; ii < nWidth1; ii++)
							{
								int val = (int)Math.Max(0, (int)(255.0 * Values[ii]));
								//if (val < 0)
								//    val = 0;
								//if (val > 255)
								//    val = 255;
								val = NormalizeValue(val, 0, 255);
								p[3] = (byte)(((double)pOrig[3] / 255.0) * val);
								p += (bmp.Width * 4);
								pOrig += (bmpOrig.Width * 4);
							}
						}
					}
				}
				Al.Clear();
				lp = 0;
				for (int col = 0; col < bmp.Width; col++)
				{
					for (int row = bmp.Height - 1; row >= 0; row--)
					{
						p = (byte*)(void*)Scan0;
						p += (row * bmp.Width * 4) + (col * 4);
						if ((p[3] > 0) && (lp == 0))
						{
							Al.Add(new Point(col, row));
						}
						lp = (int)p[3];
					}
					lp = 0;
				}
				Al.TrimToSize();
				Values = getVector((nWidth2 * 2) + 1);
				if (Values.Length / 2 == nWidth2)
				{
					for (int i = 0; i < Al.Count; i++)
					{
						Point pt1 = (Point)Al[i];
						p = (byte*)(void*)Scan0;
						pOrig = (byte*)(void*)Scan0Orig;
						if (pt1.Y >= (nWidth2 - 1))
						{
							p = (byte*)(void*)Scan0;
							p += ((nWidth2) * bmp.Width * -4) + ((pt1.Y + nWidth2) * bmp.Width * 4) + (pt1.X * 4);
							pOrig = (byte*)(void*)Scan0Orig;
							pOrig += ((nWidth2) * bmpOrig.Width * -4) + ((pt1.Y + nWidth2) * bmpOrig.Width * 4) + (pt1.X * 4);
							for (int ii = 0; ii < nWidth2; ii++)
							{
								int val = (int)Math.Max(0, (int)(255.0 * Values[ii]));
								//if (val < 0)
								//    val = 0;
								//if (val > 255)
								//    val = 255;
								val = NormalizeValue(val, 0, 255);
								p[3] = (byte)(((double)pOrig[3] / 255.0) * val);
								p -= (bmp.Width * 4);
								pOrig -= (bmpOrig.Width * 4);
							}
						}
					}
				}
				bmp.UnlockBits(bmData);
				bmpOrig.UnlockBits(bmDataOrig);
				bmpOrig.Dispose();
				bmpOrig = null;
				return true;
			}
			catch
			{
				try
				{
					bmpOrig.UnlockBits(bmDataOrig);
					bmp.UnlockBits(bmData);
				}
				catch
				{
				}
				if (bmpOrig != null)
				{
					bmpOrig.Dispose();
					bmpOrig = null;
				}
			}
			return false;
		}
		//--------------------------------------------------------------------------------
		public static bool MergeBmp(Bitmap f, Bitmap z, Bitmap b)
		{
			BitmapData    bmData  = f.LockBits(new Rectangle(0, 0, f.Width, f.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
			BitmapData    bmData2 = z.LockBits(new Rectangle(0, 0, z.Width, z.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
			BitmapData    bmDataf = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
			int           stride  = bmData.Stride;
			System.IntPtr Scan0   = bmData.Scan0;
			System.IntPtr Scan02  = bmData2.Scan0;
			System.IntPtr Scanf   = bmDataf.Scan0;
			unsafe
			{
				byte* p       = (byte*)(void*)Scan0;
				byte* pf      = (byte*)(void*)Scan02;
				byte* pff     = (byte*)(void*)Scanf;
				int   nOffset = stride - b.Width * 4;
				int   nWidth  = b.Width;
				int   nHeight = b.Height;
				for (int y = 0; y < nHeight; y++)
				{
					for (int x = 0; x < nWidth; x++)
					{
						if (pf[3] <= pff[3])
						{
							p[3] = pf[3];
						}
						else
						{
							p[3] = pff[3];
						}
						p   += 4;
						pf  += 4;
						pff += 4;
					}
					p   += nOffset;
					pf  += nOffset;
					pff += nOffset;
				}
			}
			f.UnlockBits(bmData);
			z.UnlockBits(bmData2);
			b.UnlockBits(bmDataf);
			return true;
		}
		//--------------------------------------------------------------------------------
		public static void Blur(ref Bitmap bmp, bool useSigma, int width1, int width2, bool auto, int growth1, int growth2)
		{
			Bitmap bmp2 = null;
			Bitmap bmp3 = null;
			try
			{
				bmp2 = bmp.Clone() as Bitmap;
				bmp3 = bmp.Clone() as Bitmap;
				if (useSigma)
				{
					makeEdgesTransparentHorzSigma(bmp2, width1, width2);
					makeEdgesTransparentVertSigma(bmp3, width1, width2);
				}
				else
				{
					makeEdgesTransparentHorz(bmp2, width1, width2, growth1, growth2, auto);
					makeEdgesTransparentVert(bmp3, width1, width2, growth1, growth2, auto);
				}
				MergeBmp(bmp, bmp2, bmp3);
			}
			catch (Exception ex)
			{
				if (ex != null) {}
			}
			finally
			{
				if (bmp2 != null)
				{
					bmp2.Dispose();
				}
				if (bmp3 != null)
				{
					bmp3.Dispose();
				}
			}
		}
	}
	
}
  Permalink  

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
0 Sergey Alexandrovich Kryukov 535
1 CPallini 450
2 OriginalGriff 270
3 George Jonsson 256
4 Suvabrata Roy 229
0 OriginalGriff 4,873
1 CPallini 3,900
2 Sergey Alexandrovich Kryukov 3,474
3 George Jonsson 2,646
4 Gihan Liyanage 2,236


Advertise | Privacy | Mobile
Web03 | 2.8.140905.1 | Last Updated 26 Sep 2011
Copyright © CodeProject, 1999-2014
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100