In a WPF usercontrol I'm writing I have 3 sliders representing RGB with values from 0 - 255. Standard stuff ! Also displayed is a color swatch
Base class is
private class SwatchPixels
{
public Point P { get; set; }
public int X { get; set; }
public int Y { get; set; }
public int R { get; set; }
public int G { get; set; }
public int B { get; set; }
public int A { get; set; }
}
private List<SwatchPixels> _points = new List<SwatchPixels>();
Now what I want to do is (what I have sorta works but no accurate enough !)
Load the List with all of the RGB values of the pixels in the color swatch and secondly find the closest pixel color to a supplied set of RGB values. I can then move an ellipse to the x,y location of that pixel. Reason I'm wanting this of course is that a color swatch generally will not contain all 16 million plus colors !
So if somebody can suggest a better method I would be most appreciative !
The swatch sits in a canvas object of the same size.
<Canvas Name="CanvasImage" Grid.Row="0" Grid.Column="0" Grid.RowSpan="3" Width="150" Height="150"
HorizontalAlignment="Center" Background="Transparent" VerticalAlignment="Top" Margin="2"
MouseMove="CanvasImage_MouseMove" MouseDown="CanvasImage_MouseDown" MouseUp="CanvasImage_MouseUp">
<Ellipse Name="EllipsePixel" Width="8" Height="8" Stroke="Black" Fill="White"
Canvas.Left="0" Canvas.Top="0"/>
</Canvas>
Method to load all of the pixel values
private List<SwatchPixels> FindAllPixelLocations()
{
// http://stackoverflow.com/questions/1176910/finding-specific-pixel-colors-of-a-bitmapimage
var img = new BitmapImage(new Uri(@"Resources/Cws.png", UriKind.RelativeOrAbsolute));
Image Ti = new Image();
Ti.Source = img;
ImageSource ims = Ti.Source;
BitmapImage bitmapImage = (BitmapImage)ims;
try
{
int stride = bitmapImage.PixelWidth * 4;
int size = bitmapImage.PixelHeight * stride; // stride
pixels = new byte[size];
bitmapImage.CopyPixels(pixels, stride, 0);
for (int y = 0; y < bitmapImage.PixelHeight; y++)
{
for (int x = 0; x < bitmapImage.PixelWidth; x++)
{
int index = y * stride + 4 * x;
byte red = pixels[index];
byte green = pixels[index + 1];
byte blue = pixels[index + 2];
byte alpha = pixels[index + 3];
var swatchPixels = new SwatchPixels
{
X = x,
Y = y,
P = new Point(x, y),
R = red,
G = green,
B = blue,
A = alpha
};
_points.Add(swatchPixels);
}
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
return _points;
}
The find a point method follows (the bit I'm not happy with !)
private const int initVariance = 40;
private const int dropPercent = 5;
private SwatchPixels FindXy(string a, string r, string g, string b)
{
var iR = 0;
var iG = 0;
var iB = 0;
if (RgbDec.IsChecked == true)
{
iR = Convert.ToByte(r);
iG = Convert.ToByte(g);
iB = Convert.ToByte(b);
}
else
{
// Number in hex format so convert to dec first
iR = Convert.ToByte(int.Parse(r, NumberStyles.HexNumber));
iG = Convert.ToByte(int.Parse(g, NumberStyles.HexNumber));
iB = Convert.ToByte(int.Parse(b, NumberStyles.HexNumber));
}
List<SwatchPixels> closepoints = new List<SwatchPixels>();
List<SwatchPixels> prevCp = new List<SwatchPixels>(closepoints);
var v = Convert.ToInt32(initVariance);
foreach (var p in _points)
{
if ((iR >= p.R - v && iR <= p.R + v) &&
(iG >= p.G - v && iG <= p.G + v) &&
(iB >= p.B - v && iB <= p.B + v))
{
closepoints.Add(p);
}
}
var c = closepoints.Count;
while (c > 10)
{
v = v - (v * dropPercent / 100);
closepoints = LoopAgain(closepoints, v, iR, iG, iB);
c = closepoints.Count;
//Variance.Text += c.ToString() + Environment.NewLine;
if (c == 0)
{
closepoints = new List<SwatchPixels>(prevCp);
break;
}
else
{
prevCp = new List<SwatchPixels>(closepoints);
}
}
if (c > 1)
return closepoints[0];
return null;
}
private List<SwatchPixels> LoopAgain(IEnumerable<SwatchPixels> cpoints, int v, int iR, int iG, int iB)
{
var closepoints = new List<SwatchPixels>();
foreach (var p in cpoints)
{
if ((iR >= p.R - v && iR <= p.R + v) &&
(iG >= p.G - v && iG <= p.G + v) &&
(iB >= p.B - v && iB <= p.B + v))
{
closepoints.Add(p);
}
}
return closepoints;
}
Here is my modified ColorCanvas. Changes include individual color rectangles for RGB, apply variances to a chosen color and use different color models for entry. Also you can copy the Hex contents to the clipboard with 1 click.