简体   繁体   English

从颜色列表中,如何获得同时在每种颜色上可见的浅色或深色?

[英]From a list of colors, how can I get a light or dark color that is visible over each color simultaneously?

In my app, I allow the user to choose up to three colors to use as a 'theme color'. 在我的应用程序中,我允许用户最多选择三种颜色用作“主题颜色”。 These colors are displayed as a LinearGradientBrush (or SolidColorBrush if one color is chosen) under the status bar. 这些颜色在状态栏下显示为LinearGradientBrush (如果选择一种颜色,则显示为SolidColorBrush )。 I need a light or dark color (not necessarily only black or white) for the status bar foreground color. 我需要状态栏前景色为浅色或深色(不一定只有黑色或白色)。 This will be more complex than just determining if white or black should be used, but including colors like dark gray (IE if a user chooses white and black for their theme, my current algorithm chooses black as the foreground which can't be seen over the black they chose). 这将比仅确定应使用白色还是黑色要复杂得多,但是要包括深灰色(例如,如果用户选择主题使用白色和黑色,即是我目前的算法选择黑色作为前景,这是不可见的)之类的颜色。他们选择的黑色)。 Also, the StatusBar.ForegroundColor ignores the alpha channel, so I can't just change the opacity. 另外, StatusBar.ForegroundColor忽略Alpha通道,因此我不能只更改不透明度。 How can I do this? 我怎样才能做到这一点?

Thanks 谢谢

Contrast color can be determine by the opposite of HSB color 对比色可以通过HSB颜色的色来确定

For black and white only, you can just use 仅适用于黑白,您可以使用

ForeColor = BackColor.GetBrightness() > 0.4 ? Color.Black : Color.White;

You can calculate the brightness of a Color from it's R, G, and B values then pick a brush based on that. 您可以根据颜色的R,G和B值计算颜色的亮度,然后根据该值选择画笔。 I've used the following converter to pick a Foreground color that contrasts with the bound Background color. 我使用以下转换器选择与绑定的背景色形成对比的前景色。

public class ColorConverter : IValueConverter
{

    public object Convert(object value, Type targetType, object parameter, string language)
    {
        Color c = (Color)value;
        int brightness = (int)(c.R * 0.30 + c.G * 0.59 + c.B * 0.11);
        if (brightness < 127)
            return App.Current.Resources["LightBrush"];
        else
            return App.Current.Resources["DarkBrush"];
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}

I used this for a color picker bound to all of the named colors in the Colors class. 我将其用于绑定到Colors类中所有已命名颜色的颜色选择器。 If you target only a few theme colors then you could hand-craft a table of tinted colors that still maintain contrast rather than forcing everything to black and white. 如果您仅针对几种主题色,则可以手工制作一张仍保持对比度的有色表,而不是将所有内容强制设置为黑白。

For more colors you could try converting from RGB to HSL, modifying the luminosity while keeping the Hue, and then converting back, but that may be more trouble than it's worth and you can run out of gamut while round tripping and get poor results. 对于更多颜色,您可以尝试从RGB转换为HSL,在保持色相的同时修改亮度,然后再转换回去,但这可能比它值得的麻烦更多,并且在往返旅行时可能会用尽色域并获得较差的结果。

A couple of years ago I created something for a similar problem such that given a color it would return the color that is opposite it on the color wheel . 几年前, 为类似的问题创建了一些东西 ,例如给定一种颜色,它将返回与色轮相反的颜色

I used it to create a second, or complimentary, color brush for use in apps where I wanted more than just the single, user selected, system wide accent color but wanted to ensure that the colors would work together and not clash. 我用它来创建第二个或互补的彩色笔刷,以用于应用程序中,在这些应用程序中,我不仅需要单一的,用户选择的,系统范围内的强调色,还希望确保这些颜色能够一起使用而不发生冲突。

Maybe you could extend this idea to three colors. 也许您可以将此想法扩展为三种颜色。

The code is on GitHub: https://github.com/mrlacey/WPMisc/blob/master/AccentComplimentBrush.cs 该代码在GitHub上: https : //github.com/mrlacey/WPMisc/blob/master/AccentComplimentBrush.cs

I did some playing around and I think I got a method that work perfectly. 我玩了一些游戏,我认为我有一个完美的方法。 I started with one algorithm from this question , and mixed it with similar code from Matt Lacey's and Rob Caplan's answers, cleaned it up and modified it to work with a list of colors. 我从这个问题开始使用一种算法,然后将其与Matt Lacey和Rob Caplan的答案中的类似代码混合,将其清理并修改为可使用的颜色列表。 I think it works just fine. 我认为效果很好。

private static Color DetermineForegroundColor(List<Color> colors) {
            double r = 0, g = 0, b = 0;
            foreach (Color color in colors) {
                r += color.R;
                g += color.G;
                b += color.B;
            }
            if (r > g && r > b) {
                Debug.WriteLine("First condition matched ({0}, {1}, {2})", (byte)r, (byte)g, (byte)b);
                return new Color() {
                    R = (byte)r,
                    G = (byte)r,
                    B = (byte)r
                };
            }
            else if (g > r && g > b) {
                Debug.WriteLine("Second condition matched ({0}, {1}, {2})", (byte)r, (byte)g, (byte)b);
                return new Color() {
                    R = (byte)g,
                    G = (byte)g,
                    B = (byte)g
                };
            }
            else if (b > r && b > g) {
                Debug.WriteLine("Third condition matched ({0}, {1}, {2})", (byte)r, (byte)g, (byte)b);
                return new Color() {
                    R = (byte)b,
                    G = (byte)b,
                    B = (byte)b
                };
            }
            else if (r == g) {
                Debug.WriteLine("Fourth condition matched ({0}, {1}, {2})", (byte)r, (byte)g, (byte)b);
                return new Color() {
                    R = (byte)b,
                    G = (byte)b,
                    B = (byte)b
                };
            }
            else if (r == b) {
                Debug.WriteLine("Fifth condition matched ({0}, {1}, {2})", (byte)r, (byte)g, (byte)b);
                return new Color() {
                    R = (byte)g,
                    G = (byte)g,
                    B = (byte)g
                };
            }
            else if (g == b) {
                Debug.WriteLine("Sixth condition matched ({0}, {1}, {2})", (byte)r, (byte)g, (byte)b);
                return new Color() {
                    R = (byte)r,
                    G = (byte)r,
                    B = (byte)r
                };
            }
            else {
                Debug.WriteLine("No condition matched ({0}, {1}, {2})", (byte)r, (byte)g, (byte)b);
                return new Color() {
                    R = 255,
                    G = 255,
                    B = 255
                };
            }
        }

I might replace the large if/else-if/else blocks with a switch/case block in the future to make it less bulky. 将来,我可能会用switch/case块替换较大的if/else-if/else块,以减少体积。

Try either: 尝试以下任一方法:

  • Invert each RGB value, and then possibly adjust to a closest colour from a set of predefined colours. 反转每个RGB值,然后可能将其调整为一组预定义颜色中最接近的颜色。

OR 要么

  • OR Multiple each value of the RGB by a given amount (say .25 - .5). 或将RGB的每个值乘以给定的数量(例如.25-.5)。 If > 128 multiply and then subtract the difference twice, and if < 128 just multiple. 如果> 128,则相乘,然后相减两次;如果<128,则相乘。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM