private Bitmap DrawBitmap(string model) { var gamut = CIE1931Gamut.ForModel(model); int dimension = 500; Bitmap b = new Bitmap(dimension, dimension); for (int x = 0; x < dimension; x++) { for (int y = 0; y < dimension; y++) { CIE1931Point point = new CIE1931Point(x / (dimension * 1.0), y / (dimension * 1.0)); var rgb = HueColorConverter.XYToRgb(point, model); Color c; if (point.x + point.y > 1.0) { c = Color.Black; } else if (gamut.Contains(point)) { c = Color.FromArgb((int)(rgb.R * 255.999), (int)(rgb.G * 255.999), (int)(rgb.B * 255.999)); } else { c = Color.FromArgb((int)(rgb.R * 127.999), (int)(rgb.G * 127.999), (int)(rgb.B * 127.999)); } // CIE1931 charts are drawn with y-increasing being upwards, not downwards as in bitmaps. b.SetPixel(x, (dimension - 1) - y, c); } } return(b); }
public void ColorConversionRoundtripAllPoints() { // Use a consistent seed for test reproducability Random r = new Random(0); for (int trial = 0; trial < 1000; trial++) { CIE1931Point originalXy; // Randomly generate a test color that is at a valid CIE1931 coordinate. do { originalXy = new CIE1931Point(r.NextDouble(), r.NextDouble()); }while (originalXy.x + originalXy.y >= 1.0); RGBColor rgb = HueColorConverter.XYToRgb(originalXy, "LCT001"); var xy = HueColorConverter.RgbToXY(rgb, "LCT001"); // We expect a point that is both inside the lamp's gamut and the "wide gamut" // used for XYZ->RGB and RGB->XYZ conversion. // Conversion from XY to RGB var expectedXy = CIE1931Gamut.ForModel("LCT001").NearestContainedPoint(originalXy); expectedXy = CIE1931Gamut.PhilipsWideGamut.NearestContainedPoint(expectedXy); // RGB to XY expectedXy = CIE1931Gamut.ForModel("LCT001").NearestContainedPoint(expectedXy); AssertAreEqual(expectedXy, xy, 0.0001); } }
public void GamutContainsWorksCorrectly() { Random r = new Random(0); for (int trial = 0; trial < 1000; trial++) { var point = new CIE1931Point(r.NextDouble(), r.NextDouble()); var gamutB = CIE1931Gamut.ForModel("LCT001"); Assert.AreEqual(ReferenceColorConverter.CheckPointInLampsReach(point), gamutB.Contains(point)); } }
public void ColorsOutsideGamutAdjustedToInBeInGamut() { // This green is in the gamut of LST001, but not LCT001. CIE1931Point outsideGreen = new CIE1931Point(0.18, 0.72); CIE1931Point gamutAGreen = new CIE1931Point(0.2151, 0.7106); CIE1931Point gamutBGreen = new CIE1931Point(0.409, 0.518); CIE1931Point gamutCGreen = new CIE1931Point(0.17, 0.7); AssertAreEqual(gamutAGreen, CIE1931Gamut.ForModel("LST001").NearestContainedPoint(outsideGreen), 0.0001); AssertAreEqual(gamutBGreen, CIE1931Gamut.ForModel("LCT001").NearestContainedPoint(outsideGreen), 0.0001); AssertAreEqual(gamutCGreen, CIE1931Gamut.ForModel("LST002").NearestContainedPoint(outsideGreen), 0.0001); }
public void ColorsOutsideGamutAdjustedToInBeInGamutOnConversion() { // The green primary of Gamut A. CIE1931Point gamutGreen = new CIE1931Point(0.2151, 0.7106); // A color green outside Gamut A. CIE1931Point greenOutsideGamut = new CIE1931Point(0.21, 0.75); var a = HueColorConverter.XYToRgb(gamutGreen, CIE1931Gamut.ForModel("LST001")); var b = HueColorConverter.XYToRgb(greenOutsideGamut, CIE1931Gamut.ForModel("LST001")); // Points should be equal, since the green outside the gamut should // be adjusted the the nearest green in-gamut. Assert.AreEqual(a.R, b.R); Assert.AreEqual(a.G, b.G); Assert.AreEqual(a.B, b.B); }
public void ColorConversionWhitePoint() { // These light models are capable of Gamuts A, B and C respectively. // See http://www.developers.meethue.com/documentation/supported-lights string[] models = new string[] { "LST001", "LCT001", "LST002" }; foreach (string model in models) { // Make sure that Philips' white point resolves to #FFFFFF for all lights. var rgb = HueColorConverter.XYToRgb(CIE1931Point.PhilipsWhite, CIE1931Gamut.ForModel(model)); Assert.AreEqual(rgb.R, 1.0, 0.0001); Assert.AreEqual(rgb.G, 1.0, 0.0001); Assert.AreEqual(rgb.B, 1.0, 0.0001); var xy = HueColorConverter.RgbToXY(new RGBColor(1.0, 1.0, 1.0), CIE1931Gamut.ForModel(model)); AssertAreEqual(CIE1931Point.PhilipsWhite, xy, 0.0001); } }
public void ColorConversionRoundtripInsideGamut() { // Use a consistent seed for test reproducability Random r = new Random(0); for (int trial = 0; trial < 1000; trial++) { CIE1931Point originalXy; // Randomly generate a test color that is at a valid CIE1931 coordinate. do { originalXy = new CIE1931Point(r.NextDouble(), r.NextDouble()); }while (originalXy.x + originalXy.y >= 1.0 || !ReferenceColorConverter.CheckPointInLampsReach(originalXy) || !CIE1931Gamut.PhilipsWideGamut.Contains(originalXy)); RGBColor rgb = HueColorConverter.XYToRgb(originalXy, CIE1931Gamut.ForModel("LCT001")); var xy = HueColorConverter.RgbToXY(rgb, CIE1931Gamut.ForModel("LCT001")); AssertAreEqual(originalXy, xy, 0.0001); } }
public void CompareColorConversionWithReference() { // Use a consistent seed for test reproducability Random r = new Random(0); for (int trial = 0; trial < 1000; trial++) { double red = r.NextDouble(); double green = r.NextDouble(); double blue = r.NextDouble(); var referenceXy = ReferenceColorConverter.XyFromColor(red, green, blue); // LCT001 uses Gamut B, which is the gamut used in the reference implementation. var actualXy = HueColorConverter.RgbToXY(new RGBColor(red, green, blue), CIE1931Gamut.ForModel("LCT001")); AssertAreEqual(referenceXy, actualXy, 0.0001); } }
/// <summary> /// Set state on a single light /// </summary> /// <param name="light"></param> /// <param name="xy"></param> /// <param name="gamut"></param> /// <param name="brightness"></param> /// <param name="timeSpan"></param> /// <param name="cancellationToken"></param> /// <returns></returns> public static void SetState(this EntertainmentLight light, CancellationToken cancellationToken, CIE1931Point xy, CIE1931Gamut gamut, double?brightness = null, TimeSpan timeSpan = default(TimeSpan)) { var rgb = HueColorConverter.XYToRgb(xy, gamut); //Create a new transition for this light Transition transition = new Transition(rgb, brightness, timeSpan); light.Transition = transition; //Start the transition transition.Start(light.State.RGBColor, light.State.Brightness, cancellationToken); }
/// <summary> /// /// </summary> /// <param name="light"></param> /// <param name="xy"></param> /// <param name="gamut">The gamut to use</param> /// <param name="timeSpan"></param> /// <param name="cancellationToken"></param> /// <returns></returns> public static void SetColor(this EntertainmentLight light, CancellationToken cancellationToken, CIE1931Point xy, CIE1931Gamut gamut, TimeSpan timeSpan = default) { var rgb = HueColorConverter.XYToRgb(xy, gamut); light.SetState(cancellationToken, rgb, null, timeSpan); }