2010-01-01 254 views
14

System.Drawing.Color转换为类似System.ConsoleColor的最佳方法是什么?将颜色转换为ConsoleColor?

+1

我建议看看http://stackoverflow.com/questions/28211009,而不是遵循这里提供的任何(所有错误)答案> _> – mafu 2015-01-29 09:47:58

回答

12

不幸的是,尽管Windows控制台可以支持RGB颜色,但Console类只公开了ConsoleColor枚举,这大大限制了您可以使用的可能颜色。如果你想要一个Color结构映射到“最接近的”ConsoleColor,那将是棘手的。

但是如果你想指定的颜色,以配合相应的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); 

编辑:这里有一个question about finding color "closeness"的链接。

+0

是否可能没有Console类? – 2010-01-01 15:22:33

+0

不会出现。 SetConsoleTextAttribute Win32 API仅为R,G,B和亮度位定义了4 x 1位标志。这只会支持ConsoleColor枚举所支持的16种颜色。 – Josh 2010-01-01 15:35:36

+1

但是你说Windows控制台支持任何RGB颜色...... – 2010-01-01 15:42:40

2

在Vista和更高版本上,请参阅SetConsoleScreenBufferInfoEx API函数。

有关使用示例,请参阅my answer与另一个非常类似的StackOverflow问题。 (感谢Hans Passant提供的原始答案)。

22

以下是由.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位显示为零。所有其他的Alpha通道都有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)); 
     } 
    } 
} 

输出(局部的)...

test output

+0

上面的DarkYellow十六进制代码(帖子的开头)是错误的。它说#000000,但它应该是#d7c32a(如此处所述=> http://rgb.to/color/6990/dark-yellow) – SuperJMN 2017-01-18 19:00:18

+0

@SuperJMN请注意我在原始文章中的评论:“正如您可以看到,DarkYellow的报告存在问题。“ – 2017-01-19 05:27:39

+0

哦,好的!我没有读到它是一个程序输出。我将这个十六进制值用于我的算法版本,并在向字典中添加值时发现问题:)对不起! – SuperJMN 2017-01-19 09:36:50

1

一种简单而有效的方法可以通过使用Color类的​​,GetBrightnessGetSaturation方法来实现。

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; 
    } 
} 

请注意,控制台的颜色名称与众所周知的颜色不匹配。所以如果你测试一个颜色映射方案,你必须记住(例如)在众所周知的颜色中,灰色是深灰色,浅灰色是灰色,绿色是深绿色,石灰是纯绿色,而橄榄色是黑暗的黄色。

2

您可以使用反射。

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; 
    } 
} 
17
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位颜色,通过忽略alpha通道)转换为具有亮度分量的基本3位颜色。在这种情况下,如果任何System.Drawing.Color的红色,绿色或蓝色字节大于128,则设置'亮度'位,如果等效源字节大于64,则设置红色,绿色和蓝色位