So I wish to build an ASCII Renderer, that takes an image and converts each pixel to a character. However, I thought it would be cool if I could also get Color values as well, not just white characters. However I ran into a problem: the image format I'm using (PPM, for convenience) uses RGB values, and the C# console only has 16 colors, so I'd need to estimate the color. The problem came, however, that nothing i've tried works.
Here's the snippet I tried:
static ConsoleColor FindClosestConsoleColor(int r, int g, int b)
{
ConsoleColor closest = ConsoleColor.Black;
double closestDist = double.MaxValue;
foreach (ConsoleColor consoleColor in Enum.GetValues(typeof(ConsoleColor)))
{
if (consoleColor == ConsoleColor.Black || consoleColor == ConsoleColor.DarkBlue || consoleColor == ConsoleColor.DarkCyan ||
consoleColor == ConsoleColor.DarkGreen || consoleColor == ConsoleColor.DarkMagenta || consoleColor == ConsoleColor.DarkRed ||
consoleColor == ConsoleColor.DarkYellow || consoleColor == ConsoleColor.Gray || consoleColor == ConsoleColor.DarkGray ||
consoleColor == ConsoleColor.Blue || consoleColor == ConsoleColor.Cyan || consoleColor == ConsoleColor.Green ||
consoleColor == ConsoleColor.Magenta || consoleColor == ConsoleColor.Red || consoleColor == ConsoleColor.Yellow ||
consoleColor == ConsoleColor.White)
{
int consoleColorValue = (int)consoleColor;
int consoleRed = (consoleColorValue & 0xFF0000) >> 16;
int consoleGreen = (consoleColorValue & 0x00FF00) >> 8;
int consoleBlue = consoleColorValue & 0x0000FF;
// Calculate the Euclidean distance between the two colors
double distance = Math.Sqrt(Math.Pow(consoleRed - r, 2) + Math.Pow(consoleGreen - g, 2) + Math.Pow(consoleBlue - b, 2));
// Check if this ConsoleColor is closer to the given RGB values
if (distance < closestDist)
{
closestDist = distance;
closest = consoleColor;
}
}
}
return closest;
}
However this snippet only returned the color black, even when I fed it just straight red. (255, 0, 0)
I also tried reading this StackOverflow article, but that was for the System.Drawing.Color
namespace. I'm looking to just convert raw RGB values to a ConsoleColor.
Any help would be appreciated! Thanks, TheGame12
I figured it out! For those wondering, here's what I did.
// First, I defined a list of the ConsoleColor's RGB values as an array of int tuples
private static readonly (int, int, int)[] colorValuesInt = new (int, int, int)[] {
(0, 0, 255), (0, 255, 255), (0, 0, 128), (0, 139, 139), (169, 169, 169), (0, 100, 0), (139, 0, 139), (139, 0, 0), (139, 139, 0), (128, 128, 128), (0, 128, 0), (255, 0, 255), (255, 0, 0), (255, 255, 255), (255, 255, 0)
};
// Then used this function
public static Color RGBToConsoleColor(int r, int g, int b) {
// Make a lamda square function
Func<int, int> square = (int x) => x * x;
Color[] consoleColors = new[] {
Color.Blue, Color.Cyan, Color.DarkBlue, Color.DarkCyan, Color.DarkGray, Color.DarkGreen, Color.DarkMagenta, Color.DarkRed, Color.DarkYellow, Color.Gray, Color.Green, Color.Magenta, Color.Red, Color.White, Color.Yellow
};
Color best = Color.Black;
int bestSquareDistance = Int32.MaxValue;
for (int i = 0; i < consoleColors.Length; i++) {
Color c = consoleColors[i];
(int, int, int) colorValues = colorValuesInt[i];
int squareDistance = square(r - colorValues.Item1) + square(g - colorValues.Item2) + square(b - colorValues.Item3);
if (squareDistance < bestSquareDistance) {
best = c;
bestSquareDistance = squareDistance;
}
}
return best;
}
Thanks so much to @Serg, they provided articles that helped me figure it out :D