web-dev-qa-db-ja.com

C#で色のグラデーションを生成する

ここでの私の質問は、C#で作業していることを除いて、- ここでの質問 に似ています。

2色あり、事前定義の手順があります。 2つの間の勾配であるColorsのリストを取得する方法は?

これは私が試したアプローチですが、うまくいきませんでした:

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

上記のコードを試してみると、argbの漸進的な増加は、視覚的な漸進的な色の増加に対応していないことがわかります。

これについて何か考えはありますか?

27
Graviton

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));
}
28
David M

オリバーの答えは非常に近かった...しかし私の場合、私のステッパー数のいくつかは負である必要がありました。ステッパー値を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));
    }
}
12
jocull

たぶん、この機能は次のことに役立ちます。

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));
    }
}
10
Oliver
    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;
    }
7
Steinwolfe

Intの代わりにdoubleを使用します。

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

そして:

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));
5
DjCzermino

this answer と他のいくつかの回答のアイデアを組み合わせて浮動小数点ステップを使用する場合、浮動小数点でステップ実行するための完全なメソッドスニペットを次に示します。 (整数ステッピングでは、青から赤への16色のグラデーションで非対称のグラデーションカラーが表示されていました。)

このバージョンの重要な違い:メソッドの実装内で実行するステップの数ではなく、返されるグラデーションシーケンスで必要な色の総数を渡します。

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