WPF调色盘(1):绘制三色轮

发布于:2023-01-04 ⋅ 阅读:(676) ⋅ 点赞:(0)

        计算机对颜色的表示,有很多种方式。如RGB模式、HSB(HSV)模式、CMYK模式等。这里重点讲如何用C#语言,生成一个RGB模式的调色盘。

先看效果图:

        在计算机中,一个像素点的颜色,由三种颜色构成:红色(R),蓝色(B)和绿色(G)构成。每种颜色的最大值为255,最亮,最小值为0,最暗。因此,构建一张这样的图片,重点就在于三种颜色如何进行混合。

        因为有三种颜色,首先很容易想到,将一个圆,三等份,每一份表示一种颜色,其颜色值为255,这就构成了基本的调试盘。例如在-60°~60°这个区间内,所有像素的颜色值,R = 255, G =0, B =0。如下图所示:

        有了这一个调色盘之后,就需要将各种颜色,向相邻的区域进行扩散。如何扩散,是调色盘绘制的关键。

        颜色的扩散,有两个方向:

  1. 圆周扩散:从一个颜色的边缘,沿着圆周向相邻区域扩散;
  2. 径向扩散:从圆的中心点,向圆周扩散。

        那么扩散的范围呢?通常的做法如下:

  1. 圆周的扩散范围是60°。例如红色,在60°~120°、-120°~-60°的区间内,圆周上各像素点的R值,从255按比例减少至0。在120°~180°、-180°~-120°区间内,圆周上各像素点的R值,均为0;
  2. 径向扩散的范围是120度。例如红色,在60°~180°、-180°~-60°的区间内,沿着半径的方向,各像素点的R值,从255按比例减少至圆周像素点的R值。

如下图所示:

 

有了这两条规则,就可以计算出每一个点的颜色值。

核心代码如下:

public Color GetColor(int x, int y,int radius)
{

    // radius为圆的半径
    // 已圆心为坐标原点,水平向右为起始向量
    Vector o = new Vector(radius, 0);

    // r,g,b为三个原色分量
    byte r, g, b;

    // 点(x,y)到圆心的距离
    double distance = Math.Sqrt(Math.Pow(x - radius, 2) + Math.Pow(y - radius, 2));

    // 距离大于半径,说明点在圆的外面,不用计算器颜色
    if (distance > radius) return new Color() { A = 0 }

    // 将(x,y)换算成已圆心为坐标原点的坐标,并计算向量(x1,y1)与起始向量的夹角
    Vector v1 = new Vector(x - radius, radius - y);
    double angel = Vector.AngleBetween(o, v1);

    if (angel <= -60)
    {
        // 落在蓝色区间
        r = CalculateSpread(distance, -angel - 60);
        g = CalculateSpread(distance, 180 + angel);
        b = 255;
    }
    else if (angel <= 60)
    {
        // 落在红色区间
        r = 255;
        g = CalculateSpread(distance, 60 - angel);
        b = CalculateSpread(distance, 60 + angel);
    }
    else
    {
        // 落在绿色区间
        r = CalculateSpread(distance, angel - 60);
        g = 255;
        b = CalculateSpread(distance, 180 - angel);
    }
    return new Color() { R = r, G = g, B = b, A = 255 };
}


// 计算某个颜色的分量。
// distance为点到圆心的距离;
// angel为点与圆心的连线,与颜色的边界之间的夹角
private byte CalculateSpread1(double distance, double angel, int radius)
{
    // 计算圆周分量:如果两个向量的夹角大于60度,则圆周分量为0;否则,计算比例递减
    double circum = angel > 60 ? 0 : circum = 255 - (angel / 60 * 255);
    return (byte)(255 - distance / radius * (255 - circum));
}

关于控件的制作,下回讲解


网站公告

今日签到

点亮在社区的每一天
去签到

热门文章