WPF Цветовая интерполяция - PullRequest
2 голосов
/ 26 апреля 2009

Я пытаюсь нарисовать фон элемента управления WPF на основе палитры, в которой каждому цвету назначены значения (например, Red = 0, DarkGreen = 10, Green = 20, LightGreen = 30) и выбранное пользователем значение (например, 25) это дало бы результирующий цвет. Я хотел бы, чтобы результирующий цвет был интерполяцией между двумя ближайшими значениями цвета (например, для значения 25 он должен давать цвет между зеленым и светло-зеленым)

Для этого я подумываю использовать существующий LinearGradientBrush в WPF; установить GradientStops, смещения и получить цвет по указанному значению. Есть ли способ сделать это или я должен реализовать свою собственную функцию интерполяции цвета?

Спасибо.

Ответы [ 5 ]

5 голосов
/ 26 апреля 2009

Использование LinearGradientBrush звучит так, как будто это немного перегружено. Никаких знаний, хотя. Функцию цветовой интерполяции не так сложно написать.

Я предполагаю, что ваши палитры имеют значения, которые делятся на 10 для простоты.

public static Color GetColor(int value)
{
    int startIndex = (value/10)*10;
    int endIndex = startIndex + 10;

    Color startColor = Palette[startIndex];
    Color endColor = Palette[endIndex];

    float weight = (value - startIndex)/(float)(endIndex - startIndex);

    return Color.FromArgb(
        (int)Math.Round(startColor.R * (1 - weight) + endColor.R * weight),
        (int)Math.Round(startColor.G * (1 - weight) + endColor.G * weight),
        (int)Math.Round(startColor.B * (1 - weight) + endColor.B * weight));

}

Если определенные цвета не делятся на 10, логика поиска начального и конечного цветов будет немного сложнее.

1 голос
/ 11 января 2013

Я не уверен, что так было тогда, но в .NET 4.0 можно получить цвет из LinearGradientBrush.

private Color GetColor(double ratio)
{
    if (ratio < 0) ratio = 0;
    else if (ratio > 1) ratio = 1;

    //Find gradient stops that surround the input value
    GradientStop gs0 = ColorScale.GradientStops.Where(n => n.Offset <= ratio).OrderBy(n => n.Offset).Last();
    GradientStop gs1 = ColorScale.GradientStops.Where(n => n.Offset >= ratio).OrderBy(n => n.Offset).First();

    float y = 0f;
    if (gs0.Offset != gs1.Offset)
    {
        y = (float)((ratio - gs0.Offset) / (gs1.Offset - gs0.Offset));
    }

    //Interpolate color channels
    Color cx = new Color();
    if (ColorScale.ColorInterpolationMode == ColorInterpolationMode.ScRgbLinearInterpolation)
    {
        float aVal = (gs1.Color.ScA - gs0.Color.ScA) * y + gs0.Color.ScA;
        float rVal = (gs1.Color.ScR - gs0.Color.ScR) * y + gs0.Color.ScR;
        float gVal = (gs1.Color.ScG - gs0.Color.ScG) * y + gs0.Color.ScG;
        float bVal = (gs1.Color.ScB - gs0.Color.ScB) * y + gs0.Color.ScB;
        cx = Color.FromScRgb(aVal, rVal, gVal, bVal);
    }
    else
    {
        byte aVal = (byte)((gs1.Color.A - gs0.Color.A) * y + gs0.Color.A);
        byte rVal = (byte)((gs1.Color.R - gs0.Color.R) * y + gs0.Color.R);
        byte gVal = (byte)((gs1.Color.G - gs0.Color.G) * y + gs0.Color.G);
        byte bVal = (byte)((gs1.Color.B - gs0.Color.B) * y + gs0.Color.B);
        cx = Color.FromArgb(aVal, rVal, gVal, bVal);
    }
    return cx;
}

Это будет работать с кистью, настроенной следующим образом (например):

var brush = new LinearGradientBrush();
brush.StartPoint = new Point(0, 0);
brush.EndPoint = new Point(1, 0);

//Set brush colors
brush.GradientStops.Add(new GradientStop() { Color = Color.FromRgb(102, 40, 0), Offset = 0 });
brush.GradientStops.Add(new GradientStop() { Color = Color.FromRgb(254, 167, 80), Offset = 0.25 });
brush.GradientStops.Add(new GradientStop() { Color = Color.FromRgb(0, 153, 51), Offset = 0.5 });
brush.GradientStops.Add(new GradientStop() { Color = Color.FromRgb(232, 165, 255), Offset = 0.75 });
brush.GradientStops.Add(new GradientStop() { Color = Color.FromRgb(66, 0, 89), Offset = 1 });

Источник: http://dotupdate.wordpress.com/2008/01/28/find-the-color-of-a-point-in-a-lineargradientbrush/

1 голос
/ 26 апреля 2009

Спасибо за все ответы, ребята. Кажется, нет способа получить "значение" GradientBrush в указанной точке. Я надеюсь, что это исправлено в более поздней версии фреймворка. Поэтому я думаю, что пока единственной возможностью является реализация алгоритма интерполяции, как предложил Микко.

1 голос
/ 26 апреля 2009

Я думаю, вам лучше использовать преобразователь значений, просто возьмите одну из функций интерполяции, предложенных в других ответах, и вставьте в преобразователь значений, используйте этот преобразователь, чтобы связать свойство фона со значением, и готово.

1 голос
/ 26 апреля 2009

Где вы нашли значения 10/20/30 для ваших темно-зеленых / зеленых / светло-зеленых цветов.

Вам понадобится какая-то таблица корреляции между назначенными значениями палитры и действительными числовыми представлениями цветов ... например,

Color             Pal-Code     RGB            HSL
Red               0            255,0,0        0,240,120
Dark Green        10           0,128,0        80,240,60
Green             20           0,255,0        80,240,120
Light Green       30           128,255,128    80,240,180

Из этой корреляционной таблицы вы можете взять любой пользовательский «код палитры», найти пару закрытых пар кодов палитры из таблицы выше и найти в ней диапазон наилучшего соответствия. например если кто-то введет 25 (давайте для удобства воспользуемся HSL), тогда формула будет ...

Green             20           0,255,0        80,240,120
Light Green       30           128,255,128    80,240,180

25 находится на полпути между обоими кодами, поэтому

Palette Code     Hue        Sat      Luminence
20               80         240      120
30               80         240      180
-------------------------------------------------
25               80         240      150 

Если бы они выбрали 6, вам нужно найти 0,6 из диапазона цветов между каждым значением.

Red               0            255,0,0        0,240,120
Dark Green        10           0,128,0        80,240,60

Palette Code     Hue        Sat      Luminence
0                0          240      120
10               80         240      60
-------------------------------------------------
6                48         240      84

0->80      = +80 * 60%   = +48    So 0+48   = 48
240->240   =   0 * 60%   = 0      So 240+0  = 240
120->60    = -60 * 60%   = -36    So 120-36 = 84
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...