C# 将颜色转换为 ConsoleColor?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1988833/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 22:26:59  来源:igfitidea点击:

Converting Color to ConsoleColor?

c#consolecolorssystem.drawing.color

提问by Alon Gubkin

What is the best way to convert a System.Drawing.Colorto a similar System.ConsoleColor?

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

采纳答案by Josh

Unfortunately, even though the Windows console can support RGB colors, the Console class only exposes the ConsoleColor enumeration which greatly limits the possible colors you can use. If you want a Color structure to be mapped to the "closest" ConsoleColor, that will be tricky.

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

But if you want the named Color to match a corresponding ConsoleColor you can make a map such as:

但是,如果您希望命名的 Color 与相应的 ConsoleColor 匹配,您可以制作一个地图,例如:

var map = new Dictionary<Color, ConsoleColor>();
map[Color.Red] = ConsoleColor.Red;
map[Color.Blue] = ConsoleColor.Blue;
etc...

Or if performance is not that important, you can round trip through String. (Only works for named colors)

或者,如果性能不是那么重要,您可以通过 String 进行往返。(仅适用于命名颜色

var color = Enum.Parse(typeof(ConsoleColor), color.Name);

EDIT: Here's a link to a question about finding color "closeness".

编辑:这是一个关于寻找颜色“接近度”问题的链接。

回答by Ash

On Vista and later see the SetConsoleScreenBufferInfoExAPI function.

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

For an example of usage refer to my answerto another very similar StackOverflow question. (Thanks Hans Passant for original answer).

有关使用示例,请参阅对另一个非常相似的 StackOverflow 问题的回答。(感谢 Hans Passant 的原始答案)。

回答by Glenn Slayden

Here are the console color hex values, as converted by .NET 4.5. First the program:

以下是由 .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);
    }
}

And here's the output. As you can see, there's a problem with the reporting for DarkYellow. The full 32-bits of that one show up as zero. All the others have 0xFF for the alpha channel.

这是输出。如您所见,报告存在问题DarkYellow。该 1 的完整 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

edit: I got a little more carried away just now, so here's a converter from RGBto the nearest ConsoleColorvalue. Note that the dependency on System.Windows.Mediais only for the demonstration harness; the actual function itself only references System.Drawing.

编辑:我刚才有点不知所措,所以这里有一个从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));
        }
    }
}

The output (partial)...

输出(部分)...

test output

测试输出

回答by Lucero

A simple and effective approach can be implemented by using the GetHue, GetBrightnessand GetSaturationmethods of the Colorclass.

使用类的GetHue,GetBrightnessGetSaturation方法可以实现一种简单有效的方法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;
    }
}

Note that the color names of the console do not match the well known colors. So if you test a color mapping scheme, you have to keep in mind that (for instance) in the well known colors, Gray is dark gray, Light Gray is gray, Green is dark green, Lime is pure green, and Olive is dark yellow.

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

回答by Raz Megrelidze

You can use reflection.

您可以使用反射。

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

Usage:

用法:

private static void Main()
{
    ConsoleColor c;
    if (ColorHelpers.TryGetConsoleColor(Color.Red, out c))
    {
        Console.ForegroundColor = c;
    }
}

回答by Malwyn

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

The ConsoleColors enumeration seems to use the EGA style palette ordering, which is:

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

You can roughly map a 24-bit colour (or 32-bit colour, by ignoring the alpha channel) to what is essentially 3-bit colour with a brightness component. In this case, the 'brightness' bit is set if any of the System.Drawing.Color's red, green or blue bytes are greater than 128, and the red, green, blue bits are set if the equivalent source bytes are higher than 64.

您可以粗略地将 24 位颜色(或 32 位颜色,通过忽略 alpha 通道)映射到本质上是具有亮度分量的 3 位颜色。在这种情况下,如果 System.Drawing.Color 的任何红色、绿色或蓝色字节大于 128,则设置“亮度”位,如果等效源字节大于 64,则设置红色、绿色、蓝色位.

回答by Jens

Easy one...

简单的...

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

回答by brianary

The distinct default "white-on-blue" color of PowerShell.exe before version 6 (and any ConsoleWindowClass window) is actually DarkYellowon DarkMagentaif you check $Host.UI.RawUI. This is because the ConsoleColorenum values are just indices into the console color table, which is configurable (see this answer about DarkYellow).

在不同的默认的“白色蓝底”第6版(以及任何ConsoleWindowClass窗口)前PowerShell.exe的颜色实际上是DarkYellow深洋红,如果您检查$Host.UI.RawUI。这是因为ConsoleColor枚举值只是控制台颜色表的索引,这是可配置的(请参阅有关 DarkYellow 的答案)。

Here are the hex RGB values for the default console color table:

以下是默认控制台颜色表的十六进制 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