/// <summary> /// Linearly interpolates between two color values. /// </summary> /// <param name="from">The color value that represents 0 on the lerp number line.</param> /// <param name="to">The color value that represents 1 on the lerp number line.</param> /// <param name="frac">A value in the range [0, 1].</param> /// <remarks> /// This method does a simple lerp on each color value and on the alpha channel. It does /// not properly take into account the alpha channel's effect on color blending. /// </remarks> public static ColorBgra Lerp(ColorBgra from, ColorBgra to, double frac) { return FromBgraClamped( (((double)@from.B).Lerp(to.B, frac)), (((double)@from.G).Lerp(to.G, frac)), (((double)@from.R).Lerp(to.R, frac)), (((double)@from.A).Lerp(to.A, frac))); }
private static SaveFormats.LinearColor BgraToLinearColor(ColorBgra bgra) { return new SaveFormats.LinearColor( (float)bgra.R / 255, (float)bgra.G / 255, (float)bgra.B / 255, (float)bgra.A / 255); }
/// <summary> /// Blends the colors based on the given weight values. /// </summary> /// <param name="c">The array of color values.</param> /// <param name="w">The array of weight values.</param> /// <returns> /// Each color will be blended in proportionally to its weight value respective to /// the total summation of the weight values. /// </returns> /// <remarks> /// "WAIP" stands for "weights, floating-point"</remarks> public static ColorBgra BlendColors(ColorBgra[] c, double[] w) { if (c.Length != w.Length) { throw new ArgumentException("c.Length != w.Length"); } if (c.Length == 0) { return Transparent; } double wsum = 0; double asum = 0; for (int i = 0; i < w.Length; ++i) { wsum += w[i]; asum += c[i].A * w[i]; } double a = asum / wsum; double aMultWsum = a * wsum; double b; double g; double r; if (Equals(asum, 0.0) == true) { b = 0; g = 0; r = 0; } else { b = 0; g = 0; r = 0; for (int i = 0; i < c.Length; ++i) { b += (double)c[i].A * c[i].B * w[i]; g += (double)c[i].A * c[i].G * w[i]; r += (double)c[i].A * c[i].R * w[i]; } b /= aMultWsum; g /= aMultWsum; r /= aMultWsum; } return FromBgra((byte)b, (byte)g, (byte)r, (byte)a); }
/// <summary> /// Blends the colors based on the given weight values. /// </summary> /// <param name="c">The array of color values.</param> /// <param name="w">The array of weight values.</param> /// <returns> /// The weights should be fixed point numbers. /// The total summation of the weight values will be treated as "1.0". /// Each color will be blended in proportionally to its weight value respective to /// the total summation of the weight values. /// </returns> /// <remarks> /// "WAIP" stands for "weights, arbitrary integer precision"</remarks> public static ColorBgra BlendColors(ColorBgra[] c, uint[] w) { if (c.Length != w.Length) { throw new ArgumentException("c.Length != w.Length"); } if (c.Length == 0) { return FromUInt32(0); } long wsum = 0; long asum = 0; for (int i = 0; i < w.Length; ++i) { wsum += w[i]; asum += c[i].A * w[i]; } var a = (uint)((asum + (wsum >> 1)) / wsum); long b; long g; long r; if (a == 0) { b = 0; g = 0; r = 0; } else { b = 0; g = 0; r = 0; for (int i = 0; i < c.Length; ++i) { b += (long)c[i].A * c[i].B * w[i]; g += (long)c[i].A * c[i].G * w[i]; r += (long)c[i].A * c[i].R * w[i]; } b /= asum; g /= asum; r /= asum; } return FromUInt32((uint)b + ((uint)g << 8) + ((uint)r << 16) + (a << 24)); }
/// <summary> /// Blends four colors together based on the given weight values. /// </summary> /// <returns>The blended color.</returns> /// <remarks> /// The weights should be 16-bit fixed point numbers that add up to 65536 ("1.0"). /// 4W16IP means "4 colors, weights, 16-bit integer precision" /// </remarks> public static ColorBgra BlendColors(ColorBgra c1, uint w1, ColorBgra c2, uint w2, ColorBgra c3, uint w3, ColorBgra c4, uint w4) { const uint ww = 32768; uint af = (c1.A * w1) + (c2.A * w2) + (c3.A * w3) + (c4.A * w4); uint a = (af + ww) >> 16; uint b; uint g; uint r; if (a == 0) { b = 0; g = 0; r = 0; } else { b = (uint) ((((long)c1.A * c1.B * w1) + ((long)c2.A * c2.B * w2) + ((long)c3.A * c3.B * w3) + ((long)c4.A * c4.B * w4)) / af); g = (uint) ((((long)c1.A * c1.G * w1) + ((long)c2.A * c2.G * w2) + ((long)c3.A * c3.G * w3) + ((long)c4.A * c4.G * w4)) / af); r = (uint) ((((long)c1.A * c1.R * w1) + ((long)c2.A * c2.R * w2) + ((long)c3.A * c3.R * w3) + ((long)c4.A * c4.R * w4)) / af); } return FromBgra((byte)b, (byte)g, (byte)r, (byte)a); }
/// <summary> /// Smoothly blends between two colors. /// </summary> public static ColorBgra Blend(ColorBgra ca, ColorBgra cb, byte cbAlpha) { uint caA = FastScaleByteByByte((byte)(255 - cbAlpha), ca.A); uint cbA = FastScaleByteByByte(cbAlpha, cb.A); uint cbAt = caA + cbA; uint r; uint g; uint b; if (cbAt == 0) { r = 0; g = 0; b = 0; } else { r = ((ca.R * caA) + (cb.R * cbA)) / cbAt; g = ((ca.G * caA) + (cb.G * cbA)) / cbAt; b = ((ca.B * caA) + (cb.B * cbA)) / cbAt; } return FromBgra((byte)b, (byte)g, (byte)r, (byte)cbAt); }
private void SyncHsvFromRgb(ColorBgra bgra) { ColorHsv hsv = ColorHsv.FromColor(bgra.ToColor()); this.SetColorGradientValuesHsv(hsv.Hue, hsv.Saturation, hsv.Value); this.SetColorGradientMinMaxColorsHsv(hsv.Hue, hsv.Saturation, hsv.Value); colorWheel1.Color = hsv; }