Преобразование цвета в ConsoleColor?
-
22-09-2019 - |
Вопрос
Каков наилучший способ преобразовать System.Drawing.Color
к подобному System.ConsoleColor
?
Решение
К сожалению, несмотря на то, что консоль Windows может поддерживать цвета RGB, класс Console предоставляет только перечисление ConsoleColor, что значительно ограничивает возможные цвета, которые вы можете использовать.Если вы хотите, чтобы Цветовая структура была сопоставлена с "ближайшим" цветом консоли, это будет непросто.
Но если вы хотите, чтобы названный Цвет соответствовал соответствующему цвету консоли, вы можете создать такую карту, как:
var map = new Dictionary<Color, ConsoleColor>();
map[Color.Red] = ConsoleColor.Red;
map[Color.Blue] = ConsoleColor.Blue;
etc...
Или, если производительность не так важна, вы можете использовать строку в оба конца.(Работает только для названные цвета)
var color = Enum.Parse(typeof(ConsoleColor), color.Name);
Редактировать:Вот ссылка на вопрос о поиске цветовой "близости".
Другие советы
Вот шестнадцатеричные значения цвета консоли, преобразованные .NET 4.5.Сначала программа:
using System;
using System.Drawing;
class Program
{
static void Main(string[] args)
{
foreach (var n in Enum.GetNames(typeof(ConsoleColor)))
Console.WriteLine("{0,-12} #{1:X6}", n, Color.FromName(n).ToArgb() & 0xFFFFFF);
}
}
И вот результат.Как вы можете видеть, существует проблема с отчетностью для DarkYellow
.Полные 32 бита этого элемента отображаются как ноль.Все остальные имеют 0xFF для альфа-канала.
Black #000000
DarkBlue #00008B
DarkGreen #006400
DarkCyan #008B8B
DarkRed #8B0000
DarkMagenta #8B008B
DarkYellow #000000 <-- see comments
Gray #808080
DarkGray #A9A9A9
Blue #0000FF
Green #008000
Cyan #00FFFF
Red #FF0000
Magenta #FF00FF
Yellow #FFFF00
White #FFFFFF
Редактировать:Только что я немного увлекся, так что вот конвертер из RGB
к ближайшему ConsoleColor
ценность.Обратите внимание , что зависимость от System.Windows.Media
предназначен только для демонстрации ремня безопасности;сама фактическая функция ссылается только System.Drawing
.
using System;
using System.Windows.Media;
class NearestConsoleColor
{
static ConsoleColor ClosestConsoleColor(byte r, byte g, byte b)
{
ConsoleColor ret = 0;
double rr = r, gg = g, bb = b, delta = double.MaxValue;
foreach (ConsoleColor cc in Enum.GetValues(typeof(ConsoleColor)))
{
var n = Enum.GetName(typeof(ConsoleColor), cc);
var c = System.Drawing.Color.FromName(n == "DarkYellow" ? "Orange" : n); // bug fix
var t = Math.Pow(c.R - rr, 2.0) + Math.Pow(c.G - gg, 2.0) + Math.Pow(c.B - bb, 2.0);
if (t == 0.0)
return cc;
if (t < delta)
{
delta = t;
ret = cc;
}
}
return ret;
}
static void Main()
{
foreach (var pi in typeof(Colors).GetProperties())
{
var c = (Color)ColorConverter.ConvertFromString(pi.Name);
var cc = ClosestConsoleColor(c.R, c.G, c.B);
Console.ForegroundColor = cc;
Console.WriteLine("{0,-20} {1} {2}", pi.Name, c, Enum.GetName(typeof(ConsoleColor), cc));
}
}
}
Результат (частичный)...
public static System.ConsoleColor FromColor(System.Drawing.Color c) {
int index = (c.R > 128 | c.G > 128 | c.B > 128) ? 8 : 0; // Bright bit
index |= (c.R > 64) ? 4 : 0; // Red bit
index |= (c.G > 64) ? 2 : 0; // Green bit
index |= (c.B > 64) ? 1 : 0; // Blue bit
return (System.ConsoleColor)index;
}
Перечисление ConsoleColors, по-видимому, использует порядок палитры в стиле EGA, который:
index Brgb
0 0000 dark black
1 0001 dark blue
2 0010 dark green
3 0011 dark cyan
4 0100 dark red
5 0101 dark purple
6 0110 dark yellow (brown)
7 0111 dark white (light grey)
8 1000 bright black (dark grey)
9 1001 bright blue
10 1010 bright green
11 1011 bright cyan
12 1100 bright red
13 1101 bright purple
14 1110 bright yellow
15 1111 bright white
Вы можете грубо сопоставить 24-битный цвет (или 32-битный цвет, игнорируя альфа-канал) с тем, что по сути является 3-битным цветом с компонентом яркости.В этом случае устанавливается бит 'яркость', если таковой имеется в системе.Рисование.Красные, зеленые или синие байты цвета больше 128, а красные, зеленые, синие биты устанавливаются, если эквивалентные исходные байты больше 64.
В Vista и более поздних версиях смотрите SetConsoleScreenBufferInfoEx Установить Функция API.
Пример использования приведен на мой ответ к другому очень похожему вопросу StackOverflow.(Спасибо Хансу Пассанту за оригинальный ответ).
Вы можете использовать отражение.
public static class ColorHelpers
{
public static bool TryGetConsoleColor(Color color, out ConsoleColor consoleColor)
{
foreach (PropertyInfo property in typeof (Color).GetProperties())
{
Color c = (Color) property.GetValue(null);
if (color == c)
{
int index = Array.IndexOf(Enum.GetNames(typeof (ConsoleColor)), property.Name);
if (index != -1)
{
consoleColor = (ConsoleColor) Enum.GetValues(typeof (ConsoleColor)).GetValue(index);
return true;
}
}
}
consoleColor = default (ConsoleColor);
return false;
}
}
Использование:
private static void Main()
{
ConsoleColor c;
if (ColorHelpers.TryGetConsoleColor(Color.Red, out c))
{
Console.ForegroundColor = c;
}
}
Простой и эффективный подход может быть реализован с помощью GetHue
, GetBrightness
и GetSaturation
методы проведения Color
класс.
public static ConsoleColor GetConsoleColor(this Color color) {
if (color.GetSaturation() < 0.5) {
// we have a grayish color
switch ((int)(color.GetBrightness()*3.5)) {
case 0: return ConsoleColor.Black;
case 1: return ConsoleColor.DarkGray;
case 2: return ConsoleColor.Gray;
default: return ConsoleColor.White;
}
}
int hue = (int)Math.Round(color.GetHue()/60, MidpointRounding.AwayFromZero);
if (color.GetBrightness() < 0.4) {
// dark color
switch (hue) {
case 1: return ConsoleColor.DarkYellow;
case 2: return ConsoleColor.DarkGreen;
case 3: return ConsoleColor.DarkCyan;
case 4: return ConsoleColor.DarkBlue;
case 5: return ConsoleColor.DarkMagenta;
default: return ConsoleColor.DarkRed;
}
}
// bright color
switch (hue) {
case 1: return ConsoleColor.Yellow;
case 2: return ConsoleColor.Green;
case 3: return ConsoleColor.Cyan;
case 4: return ConsoleColor.Blue;
case 5: return ConsoleColor.Magenta;
default: return ConsoleColor.Red;
}
}
Обратите внимание, что названия цветов консоли не соответствуют хорошо известным цветам.Поэтому, если вы тестируете схему цветового отображения, вы должны иметь в виду, что (например) в хорошо известных цветах серый - темно-серый, Светло-серый - серый, Зеленый - темно-зеленый, лайм - чисто-зеленый, а оливковый - темно-желтый.
Самый простой...
Public Shared Function ColorToConsoleColor(cColor As Color) As ConsoleColor
Dim cc As ConsoleColor
If Not System.Enum.TryParse(Of ConsoleColor)(cColor.Name, cc) Then
Dim intensity = If(Color.Gray.GetBrightness() < cColor.GetBrightness(), 8, 0)
Dim r = If(cColor.R >= &H80, 4, 0)
Dim g = If(cColor.G >= &H80, 2, 0)
Dim b = If(cColor.B >= &H80, 1, 0)
cc = CType(intensity + r + g + b, ConsoleColor)
End If
Return cc
End Function
Отличный от стандартного "бело-синий" цвет PowerShell.exe до версии 6 (и любого окна ConsoleWindowClass) на самом деле Темно-желтый на ДаркМагента если вы проверите $Host.UI.RawUI
.Это происходит потому, что ConsoleColor
значения enum - это просто индексы в таблице цветов консоли, которая настраивается (см. этот ответ о DarkYellow).
Вот шестнадцатеричные значения RGB для таблицы цветов консоли по умолчанию:
Value Hex RGB Name
0 #000000 Black
1 #000080 DarkBlue
2 #008000 DarkGreen
3 #008080 DarkCyan
4 #800000 DarkRed
5 #012456 DarkMagenta
6 #EEEDF0 DarkYellow
7 #C0C0C0 Gray
8 #808080 DarkGray
9 #0000FF Blue
10 #00FF00 Green
11 #00FFFF Cyan
12 #FF0000 Red
13 #FF00FF Magenta
14 #FFFF00 Yellow
15 #FFFFFF White