/// <summary> /// Gets the number of color properties for the current <see cref="ColorSpace"/> instance /// </summary> /// <param name="color">The <see cref="ColorSpace"/> object</param> /// <returns>The number of color properties for the current instance</returns> public static int GetPropertyCount(ColorSpace color) { return((int)color.GetType().GetField("PropertyCount").GetValue(color)); }
private static Rgb NormalizeRgb(ColorSpace colorSpace) { var rgb = colorSpace.ToRgb(); if (rgb.R < 0 || rgb.R.ApproximatelyEquals(0, 0.001)) { rgb.R = 0; } else if (rgb.R > 255 || rgb.R.ApproximatelyEquals(255, 0.001)) { rgb.R = 255; } else { rgb.R = System.Math.Round(rgb.R); } if (rgb.G < 0 || rgb.G.ApproximatelyEquals(0, 0.001)) { rgb.G = 0; } else if (rgb.G > 255 || rgb.G.ApproximatelyEquals(255, 0.001)) { rgb.G = 255; } else { rgb.G = System.Math.Round(rgb.G); } if (rgb.B < 0 || rgb.B.ApproximatelyEquals(0, 0.001)) { rgb.B = 0; } else if (rgb.B > 255 || rgb.B.ApproximatelyEquals(255, 0.001)) { rgb.B = 255; } else { rgb.B = System.Math.Round(rgb.B); } var rgba = rgb as Rgba; if (rgba != null) { if (rgba.A < 0 || rgba.A.ApproximatelyEquals(0, 0.001)) { rgba.A = 0; } else if (rgba.A > 255 || rgba.A.ApproximatelyEquals(255, 0.001)) { rgba.A = 255; } else { rgba.A = System.Math.Round(rgba.A); } } return(rgb); }
private static double CompareCie2000(ColorSpace color1, ColorSpace color2) { const double kl = 1.0; const double kc = 1.0; const double kh = 1.0; var lab1 = color1.ToColorSpace <Lab>(); var lab2 = color2.ToColorSpace <Lab>(); var lBar = (lab1.L + lab2.L) / 2.0; var c1 = System.Math.Sqrt(lab1.A * lab1.A + lab1.B * lab1.B); var c2 = System.Math.Sqrt(lab2.A * lab2.A + lab2.B * lab2.B); var cBar = (c1 + c2) / 2.0; var cBarInPower7 = cBar * cBar * cBar; cBarInPower7 *= cBarInPower7 * cBar; var g = 1 - System.Math.Sqrt(cBarInPower7 / (cBarInPower7 + 6103515625)); var aPrime1 = lab1.A + lab1.A / 2.0 * g; var aPrime2 = lab2.A + lab2.A / 2.0 * g; var cPrime1 = System.Math.Sqrt(aPrime1 * aPrime1 + lab1.B * lab1.B); var cPrime2 = System.Math.Sqrt(aPrime2 * aPrime2 + lab2.B * lab2.B); var cBarPrime = (cPrime1 + cPrime2) / 2.0; var hPrime1 = System.Math.Atan2(lab1.B, aPrime1) % 360; var hPrime2 = System.Math.Atan2(lab2.B, aPrime2) % 360; var hBar = System.Math.Abs(hPrime1 - hPrime2); double deltaHPrime; if (hBar <= 180) { deltaHPrime = hPrime2 - hPrime1; } else if (hBar > 180 && hPrime2 <= hPrime1) { deltaHPrime = hPrime2 - hPrime1 + 360.0; } else { deltaHPrime = hPrime2 - hPrime1 - 360.0; } var deltaLPrime = lab2.L - lab1.L; var deltaCPrime = cPrime2 - cPrime1; deltaHPrime = 2 * System.Math.Sqrt(cPrime1 * cPrime2) * System.Math.Sin(deltaHPrime / 2.0); var hBarPrime = hBar > 180 ? (hPrime1 + hPrime2 + 360) / 2.0 : (hPrime1 + hPrime2) / 2.0; var t = 1 - .17 * System.Math.Cos(hBarPrime - 30) + .24 * System.Math.Cos(2 * hBarPrime) + .32 * System.Math.Cos(3 * hBarPrime + 6) - .2 * System.Math.Cos(4 * hBarPrime - 63); var lBarMinus50Sqr = (lBar - 50) * (lBar - 50); var sl = 1 + .015 * lBarMinus50Sqr / System.Math.Sqrt(20 + lBarMinus50Sqr); var sc = 1 + .045 * cBarPrime; var sh = 1 + .015 * cBarPrime * t; var cBarPrimeInPower7 = cBarPrime * cBarPrime * cBarPrime; cBarPrimeInPower7 *= cBarPrimeInPower7 * cBarPrime; var rt = -2 * System.Math.Sqrt(cBarPrimeInPower7 / (cBarPrimeInPower7 + 6103515625)) // 25 ^ 7 * System.Math.Sin(60.0 * System.Math.Exp(-((hBarPrime - 275.0) / 25.0))); var deltaLPrimeDivklsl = deltaLPrime / (kl * sl); var deltaCPrimeDivkcsc = deltaCPrime / (kc * sc); var deltaHPrimeDivkhsh = deltaHPrime / (kh * sh); var deltaE = System.Math.Sqrt( deltaLPrimeDivklsl * deltaLPrimeDivklsl + deltaCPrimeDivkcsc * deltaCPrimeDivkcsc + deltaHPrimeDivkhsh * deltaHPrimeDivkhsh + rt * (deltaCPrime / (kc * kh)) * (deltaHPrime / (kh * sh))); return(deltaE); }
/// <summary> /// Gets the "Friendly Name" of the current <see cref="ColorSpace"/> instance /// </summary> /// <param name="color">The <see cref="ColorSpace"/> object</param> /// <returns>Friendly name string</returns> public static string GetFriendlyName(ColorSpace color) { return(color.GetType().GetField("FriendlyName").GetValue(color) as string); }
/// <summary> /// Calculates the ΔE of this color compared to another color, using the specified comparison method. /// This value represents the perceptual difference between the two colors. /// </summary> /// <param name="other">The color to compare to this color</param> /// <param name="method"> /// The algorith to use for the comparison. /// There is an efficiency/accuracy trade-off between the different methods. /// </param> /// <returns> /// ΔE value representing the perceived difference between this color and the comparison color. /// </returns> public double Compare(ColorSpace other, ComparisonMethod method = ComparisonMethod.Cie2000) { return(Compare(this, other, method)); }
/// <summary> /// Determines if two colors are "close enough" to be perceived as the same color. /// </summary> /// <param name="other">A color to compare to this instance.</param> /// <returns> /// true if this color and the comparison color can be perceived as the same. /// false if this color and the comparison color appear different to the human eye. /// </returns> public bool PerceptuallyEquals(ColorSpace other) { return(Compare(this, other) < JustNoticeableDifference); }
/// <summary> /// Gets basic color chords based on the current (dominant) color. /// Useful for creating color schemes. /// </summary> /// <param name="harmony">The type of color chord to create.</param> /// <param name="includeThisColor"> /// If true, the current color will be included in the resulting ColorSpace array. /// </param> /// <returns>An array of ColorSpace objects that make up the specified color chord.</returns> public ColorSpace[] GetHarmony(ColorHarmony harmony, bool includeThisColor = false) { var resultSizeOffset = includeThisColor ? 1 : 0; ColorSpace[] result; switch (harmony) { case ColorHarmony.Complementary: { var i = 0; result = new ColorSpace[1 + resultSizeOffset]; var hsl = ToColorSpace <Hsl>(); hsl.H = AddDegrees(hsl.H, 180); if (includeThisColor) { result[i++] = this; } result[i] = hsl; break; } case ColorHarmony.SplitComplementary: { var i = 0; result = new ColorSpace[2 + resultSizeOffset]; var hsl1 = ToColorSpace <Hsl>(); var hsl2 = ToColorSpace <Hsl>(); hsl1.H = AddDegrees(hsl1.H, 150); hsl2.H = SubtractDegrees(hsl2.H, 150); if (includeThisColor) { result[i++] = this; } result[i++] = hsl1; result[i] = hsl2; break; } case ColorHarmony.Analogous: { var i = 0; result = new ColorSpace[2 + resultSizeOffset]; var hsl1 = ToColorSpace <Hsl>(); var hsl2 = ToColorSpace <Hsl>(); hsl1.H = AddDegrees(hsl1.H, 30); hsl2.H = SubtractDegrees(hsl2.H, 30); if (includeThisColor) { result[i++] = this; } result[i++] = hsl1; result[i] = hsl2; break; } case ColorHarmony.Triadic: { var i = 0; result = new ColorSpace[2 + resultSizeOffset]; var hsl1 = ToColorSpace <Hsl>(); var hsl2 = ToColorSpace <Hsl>(); hsl1.H = AddDegrees(hsl1.H, 120); hsl2.H = SubtractDegrees(hsl2.H, 120); if (includeThisColor) { result[i++] = this; } result[i++] = hsl1; result[i] = hsl2; break; } case ColorHarmony.Tetradic: { var i = 0; result = new ColorSpace[3 + resultSizeOffset]; var hsl1 = ToColorSpace <Hsl>(); hsl1.H = AddDegrees(hsl1.H, 30); var hsl2And3 = GetHarmony(ColorHarmony.SplitComplementary); if (includeThisColor) { result[i++] = this; } result[i++] = hsl1; result[i++] = hsl2And3[0]; result[i] = hsl2And3[1]; break; } case ColorHarmony.Square: { var i = 0; result = new ColorSpace[3 + resultSizeOffset]; var hsl1 = ToColorSpace <Hsl>(); var hsl2 = ToColorSpace <Hsl>(); var hsl3 = ToColorSpace <Hsl>(); hsl1.H = AddDegrees(hsl1.H, 90); hsl2.H = AddDegrees(hsl2.H, 180); hsl3.H = AddDegrees(hsl3.H, 270); if (includeThisColor) { result[i++] = this; } result[i++] = hsl1; result[i++] = hsl2; result[i] = hsl3; break; } default: throw new ArgumentException("Unrecognized color harmony", nameof(harmony)); } return(result); }
public abstract bool VirtuallyEquals(ColorSpace other);
public abstract bool Equals(ColorSpace other);