tried this:
in the List<Color>
colors there are many different colors over 39,000
and the first item for example is:
{Name = ffcecece, ARGB = (255, 206, 206, 206)}
and now I want to convert the ARGB to KnownColor
name for example if it was Blue or Red or any color name.
the problem is that the method GetKnownColorName
return only "Unknown"
.
private void label1_Click(object sender, EventArgs e)
{
if(colorsAdded)
{
for(int i =0; i < colors.Count; i++)
{
colorsNames.Add(GetKnownColorName(colors[i]));
}
}
}
Then the conversion:
private string GetKnownColorName(Color color)
{
foreach (KnownColor knownColor in Enum.GetValues(typeof(KnownColor)))
{
Color knownColorValue = Color.FromKnownColor(knownColor);
if (knownColorValue.ToArgb() == color.ToArgb())
{
return knownColor.ToString();
}
}
return "Unknown";
}
Full Code:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
namespace Colors_Scanner
{
public partial class Form1 : Form
{
private Bitmap imageBitmap;
private Bitmap imageBitmapComparison;
private Color currentColor;
private List<string> colorsNames = new List<string>();
private List<Color> colors = new List<Color>();
private Bitmap bmp;
private bool colorsAdded = false; // Flag to track if colors have been added
public Form1()
{
InitializeComponent();
// Load images into PictureBox controls
LoadImages();
// Initialize the bitmap for pictureBox2
bmp = new Bitmap(pictureBox2.Image);
}
private void LoadImages()
{
// Load an image into the PictureBox control
imageBitmap = new Bitmap(@"D:\Ffmpeg Capture\radar1.jpg"); // Replace with your image
pictureBox1.Size = imageBitmap.Size;
pictureBox1.Image = imageBitmap;
imageBitmapComparison = new Bitmap(@"D:\Ffmpeg Capture\colorslevels1.jpg"); // Replace with your ruler image
pictureBox2.Size = imageBitmapComparison.Size;
pictureBox2.Image = imageBitmapComparison;
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (IsMouseWithinPictureBoxBounds(e.Location, pictureBox1))
{
UpdateColorLabel(e.Location);
currentColor = GetColorAtCursor(e.Location, imageBitmap);
pictureBox2.Invalidate();
}
}
private void pictureBox2_Paint(object sender, PaintEventArgs e)
{
Pen pen = new Pen(currentColor);
e.Graphics.DrawRectangle(pen, new Rectangle(0, 0, 3, 3));
if (!colorsAdded)
{
// Add colors from pictureBox2 only once
AddColorsFromPictureBox2();
colorsAdded = true; // Set the flag to true after adding colors
}
}
private List<Color> AddColorsFromPictureBox2()
{
if (bmp != null)
{
for (int i = 0; i < bmp.Width; i++)
{
if (i == bmp.Width - 1)
{
break;
}
for (int j = 0; j < bmp.Height; j++)
{
Color c = bmp.GetPixel(i, j);
// You can add the color to your list here
colors.Add(c);
}
}
}
return colors;
}
private void UpdateColorLabel(Point location)
{
Color color = GetColorAtCursor(location, imageBitmap);
label1.Text = $"RGB: ({color.R}, {color.G}, {color.B})";
label1.BackColor = color;
}
private Color GetColorAtCursor(Point location, Bitmap bitmap)
{
int x = location.X;
int y = location.Y;
if (IsMouseWithinPictureBoxBounds(location, pictureBox1))
{
BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadOnly, bitmap.PixelFormat);
try
{
int bytesPerPixel = Bitmap.GetPixelFormatSize(bitmap.PixelFormat) / 8;
IntPtr ptr = bmpData.Scan0;
int pixelOffset = y * bmpData.Stride + x * bytesPerPixel;
byte b = System.Runtime.InteropServices.Marshal.ReadByte(ptr, pixelOffset);
byte g = System.Runtime.InteropServices.Marshal.ReadByte(ptr, pixelOffset + 1);
byte r = System.Runtime.InteropServices.Marshal.ReadByte(ptr, pixelOffset + 2);
return Color.FromArgb(r, g, b);
}
finally
{
bitmap.UnlockBits(bmpData);
}
}
return Color.Black; // Default color if outside of PictureBox bounds
}
private bool IsMouseWithinPictureBoxBounds(Point location, PictureBox pictureBox)
{
return location.X >= 0 && location.X < pictureBox.Width && location.Y >= 0 && location.Y < pictureBox.Height;
}
private void label1_Click(object sender, EventArgs e)
{
if(colorsAdded)
{
for(int i =0; i < colors.Count; i++)
{
colorsNames.Add(GetKnownColorName(colors[i]));
}
}
}
private string GetKnownColorName(Color color)
{
foreach (KnownColor knownColor in Enum.GetValues(typeof(KnownColor)))
{
Color knownColorValue = Color.FromKnownColor(knownColor);
if (knownColorValue.ToArgb() == color.ToArgb())
{
return knownColor.ToString();
}
}
return "Unknown";
}
}
}
If you want to get closest KnownColor
for an arbitrary Color
you have to define some Distance
method and then you can query for known color with minimum distance from originalColor
:
using System.Linq;
...
Color originColor = Color.FromArgb(255, 206, 206, 206);
// Simplest, but not necessary the best one
static int Distance(Color left, Color right) =>
Math.Abs(left.R - right.R) +
Math.Abs(left.G - right.G) +
Math.Abs(left.B - right.B) +
Math.Abs(left.A - right.A);
var result = Enum
.GetValues<KnownColor>()
.MinBy(color => Distance(Color.FromKnownColor(color), originColor));
Console.Write(result);
Outcome (note, that LightGray
is {255, 211, 211, 211}
):
LightGray
If you have custom collection of known colors, you can organize it as a Dictionary<Color, string>
, e. g.
private static readonly Dictionary<Color, string> KnownColors = new() {
{ Color.FromArgb(255, 255, 255, 255), "Black Color"},
{ Color.FromArgb(255, 206, 206, 206), "Light Gray Color"},
// etc.
};
Then
if (KnownColors.TryGetValue(originColor, out string name)) {
// originColor is known under "name" name
Console.Write(name);
}
Edit: You can exclude SystemColors
such as ActiveBorder
if you like:
private static HashSet<string> SystemColorsNames() => typeof(SystemColors)
.GetProperties(BindingFlags.Public | BindingFlags.Static)
.Where(prop => prop.CanRead && prop.PropertyType == typeof(Color))
.Select(prop => prop.Name)
.ToHashSet();
...
var exclude = SystemColorsNames();
var result = Enum
.GetValues<KnownColor>()
.Where(color => !exclude.Contains(Enum.GetName(color)))
.MinBy(color => Distance(Color.FromKnownColor(color), originColor));