代码之家  ›  专栏  ›  技术社区  ›  Alon Gubkin

将颜色转换为控制台颜色?

  •  17
  • Alon Gubkin  · 技术社区  · 15 年前

    转换 System.Drawing.Color 类似 System.ConsoleColor ?

    8 回复  |  直到 6 年前
        1
  •  14
  •   Community CDub    8 年前

    不幸的是,尽管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);
    

    编辑:这里有一个链接指向 question about finding color "closeness" .

        2
  •  29
  •   Glenn Slayden    8 年前

    下面是由.NET 4.5转换的控制台颜色十六进制值。首先是程序:

    使用系统;
    使用系统、图纸;
    
    类程序
    {
    静态void main(string[]args)
    {
    foreach(enum.getnames中的var n(typeof(consolecolor)))
    console.writeline(“0,-12 1:x6”,n,color.fromname(n).toargb()&0xffffff);
    }
    }
    < /代码> 
    
    

    这里是输出。如您所见,报告darkyellow时出现问题。其中完整的32位显示为零。所有其他频道的alpha频道都有0xFF。

    black 000000
    深蓝色00008b
    深绿色006400
    深青色008B8b
    暗红色8亿
    深洋红8B008B
    深黄色000000<——见注释
    灰色808080
    深灰色A9A9A9
    蓝色0000FF
    绿色008000
    青色00ffff
    红色ff0000
    洋红ff00ff
    黄色ffff00
    白色ffffff
    < /代码> 
    
    

    编辑:我刚才有点激动,所以这里有一个转换器,从rgb到最近的consolecolorvalue。请注意,对system.windows.media的依赖性仅适用于演示线束;实际功能本身仅引用system.drawing。

    使用系统;
    使用system.windows.media;
    
    类NearestConsoleColor
    {
    静态控制台颜色关闭控制台颜色(字节R、字节G、字节B)
    {
    控制台颜色ret=0;
    double r r=r,g g=g,b b=b,delta=double.maxvalue;
    
    foreach(enum.getvalues中的consolecolor cc(typeof(consolecolor)))
    {
    var n=enum.getname(typeof(consolecolor),cc);
    var c=system.drawing.color.fromname(n=“深黄色”?)橙色“:n);//错误修复
    var t=数学.pow(c.r-r r,2.0)+数学.pow(c.g-g g,2.0)+数学.pow(c.b-b b,2.0);
    如果(t=0)
    返回CC;
    如果(t<delta)
    {
    δ=t;
    RT=CC;
    }
    }
    返回RET;
    }
    
    静态void main()
    {
    foreach(var pi,typeof(colors).getproperties())
    {
    var c=(color)colorconverter.convertFromString(pi.name);
    var c c=关闭控制台颜色(C.R、C.G、C.B);
    
    console.foregroundcolor=cc;
    console.writeline(“0,-20 1 2”,pi.name,c,enum.getname(typeof(consolecolor),c c));
    }
    }
    }
    

    输出(部分)……

    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

        3
  •  21
  •   Malwyn    10 年前
    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,则设置红色、绿色、蓝色位。

        4
  •  2
  •   Community CDub    8 年前

    在Vista上,稍后查看 SetConsoleScreenBufferInfoEx API函数。

    有关用法示例,请参阅 my answer 到另一个非常类似的stackoverflow问题。(感谢Hans Passant给出的原始答案)。

        5
  •  2
  •   Rezo Megrelidze    10 年前

    你可以使用反射。

    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;
        }
    }
    
        6
  •  1
  •   Lucero    10 年前

    通过使用 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;
        }
    }
    

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

        7
  •  1
  •   Nigel Thorne    6 年前

    简单的一个…

    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
    
        8
  •  0
  •   brianary    6 年前

    在版本6(以及任何控制台窗口类窗口)之前,PowerShell.exe的独特默认“蓝底白字”颜色实际上是 暗黄色 暗红色 如果你检查 $Host.UI.RawUI .这是因为 ConsoleColor 枚举值只是控制台颜色表的索引,可配置(请参见 this answer about 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