在 C# 中生成颜色渐变

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2011832/
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:38:53  来源:igfitidea点击:

Generate Color Gradient in C#

c#.netcolorssystem.drawing.color

提问by Graviton

My question here is similar to the question here, except that I am working with C#.

我在这里的问题类似于这里的问题,除了我正在使用 C#。

I have two colors, and I have a predefine steps. How to retrieve a list of Colors that are the gradients between the two?

我有两种颜色,我有一个预定义的步骤。如何检索作为Color两者之间梯度的s列表?

This is an approach that I tried, which didn't work:

这是我尝试过的一种方法,但不起作用:

int argbMax = Color.Chocolate.ToArgb();
int argbMin = Color.Blue.ToArgb();
var colorList = new List<Color>();

for(int i=0; i<size; i++)
{
    var colorAverage= argbMin + (int)((argbMax - argbMin) *i/size);
    colorList.Add(Color.FromArgb(colorAverage));
}

If you try the above code, you will find that a gradual increase in argbdoesn't correspond to a visual gradual increase in the color.

如果你尝试上面的代码,你会发现argb颜色的逐渐增加并不对应于颜色的视觉逐渐增加。

Any idea on this?

对此有什么想法吗?

采纳答案by David M

You will have to extract the R, G, B components and perform the same linear interpolation on each of them individually, then recombine.

您必须提取 R、G、B 分量并对它们中的每一个单独执行相同的线性插值,然后重新组合。

int rMax = Color.Chocolate.R;
int rMin = Color.Blue.R;
// ... and for B, G
var colorList = new List<Color>();
for(int i=0; i<size; i++)
{
    var rAverage = rMin + (int)((rMax - rMin) * i / size);
    var gAverage = gMin + (int)((gMax - gMin) * i / size);
    var bAverage = bMin + (int)((bMax - bMin) * i / size);
    colorList.Add(Color.FromArgb(rAverage, gAverage, bAverage));
}

回答by Oliver

Maybe this function can help:

也许这个功能可以帮助:

public IEnumerable<Color> GetGradients(Color start, Color end, int steps)
{
    Color stepper = Color.FromArgb((byte)((end.A - start.A) / (steps - 1)),
                                   (byte)((end.R - start.R) / (steps - 1)),
                                   (byte)((end.G - start.G) / (steps - 1)),
                                   (byte)((end.B - start.B) / (steps - 1)));

    for (int i = 0; i < steps; i++)
    {
        yield return Color.FromArgb(start.A + (stepper.A * i),
                                    start.R + (stepper.R * i),
                                    start.G + (stepper.G * i),
                                    start.B + (stepper.B * i));
    }
}

回答by Steinwolfe

    public static List<Color> GetGradientColors(Color start, Color end, int steps)
    {
        return GetGradientColors(start, end, steps, 0, steps - 1);
    }

    public static List<Color> GetGradientColors(Color start, Color end, int steps, int firstStep, int lastStep)
    {
        var colorList = new List<Color>();
        if (steps <= 0 || firstStep < 0 || lastStep > steps - 1)
            return colorList;

        double aStep = (end.A - start.A) / steps;
        double rStep = (end.R - start.R) / steps;
        double gStep = (end.G - start.G) / steps;
        double bStep = (end.B - start.B) / steps;

        for (int i = firstStep; i < lastStep; i++)
        {
            var a = start.A + (int)(aStep * i);
            var r = start.R + (int)(rStep * i);
            var g = start.G + (int)(gStep * i);
            var b = start.B + (int)(bStep * i);
            colorList.Add(Color.FromArgb(a, r, g, b));
        }

        return colorList;
    }

回答by jocull

Oliver's answer was very close... but in my case some of my stepper numbers needed to be negative. When converting the stepper values into a Colorstruct my values were going from negative to the higher values e.g. -1 becomes something like 254. I setup my step values individually to fix this.

Oliver 的回答非常接近......但就我而言,我的一些步进器数字需要为负数。将步进值转换为Color结构体时,我的值从负值变为较高值,例如 -1 变为 254 之类的值。我单独设置了步长值以解决此问题。

public static IEnumerable<Color> GetGradients(Color start, Color end, int steps)
{
    int stepA = ((end.A - start.A) / (steps - 1));
    int stepR = ((end.R - start.R) / (steps - 1));
    int stepG = ((end.G - start.G) / (steps - 1));
    int stepB = ((end.B - start.B) / (steps - 1));

    for (int i = 0; i < steps; i++)
    {
        yield return Color.FromArgb(start.A + (stepA * i),
                                    start.R + (stepR * i),
                                    start.G + (stepG * i),
                                    start.B + (stepB * i));
    }
}

回答by MartinCermak

Use double instead of int:

使用 double 代替 int:

double stepA = ((end.A - start.A) / (double)(steps - 1));
double stepR = ((end.R - start.R) / (double)(steps - 1));
double stepG = ((end.G - start.G) / (double)(steps - 1));
double stepB = ((end.B - start.B) / (double)(steps - 1));

and:

和:

yield return Color.FromArgb((int)start.A + (int)(stepA * step),
                                            (int)start.R + (int)(stepR * step),
                                            (int)start.G + (int)(stepG * step),
                                            (int)start.B + (int)(stepB * step));

回答by William

Combining this answerwith the idea from several other answers to use floating-point steps, here's a complete method snippet for stepping with floating point. (With integer stepping, I had been getting asymmetrical gradient colors in a 16-color gradient from blue to red.)

将此答案与其他几个使用浮点步骤的答案的想法相结合,这是一个使用浮点步进的完整方法片段。(通过整数步进,我得到了从蓝色到红色的 16 色渐变中的不对称渐变颜色。)

Important difference in this version: you pass the total number of colors you want in the returned gradient sequence, not the number of steps to take within the method implementation.

此版本的重要区别:您在返回的渐变序列中传递所需的颜色总数,而不是方法实现中要采取的步骤数。

public static IEnumerable<Color> GetColorGradient(Color from, Color to, int totalNumberOfColors)
{
    if (totalNumberOfColors < 2)
    {
        throw new ArgumentException("Gradient cannot have less than two colors.", nameof(totalNumberOfColors));
    }

    double diffA = to.A - from.A;
    double diffR = to.R - from.R;
    double diffG = to.G - from.G;
    double diffB = to.B - from.B;

    var steps = totalNumberOfColors - 1;

    var stepA = diffA / steps;
    var stepR = diffR / steps;
    var stepG = diffG / steps;
    var stepB = diffB / steps;

    yield return from;

    for (var i = 1; i < steps; ++i)
    {
        yield return Color.FromArgb(
            c(from.A, stepA),
            c(from.R, stepR),
            c(from.G, stepG),
            c(from.B, stepB));

        int c(int fromC, double stepC)
        {
            return (int)Math.Round(fromC + stepC * i);
        }
    }

    yield return to;
}