diff --git a/PowerToys.sln b/PowerToys.sln index c44829d472..1e9d13ae8e 100644 --- a/PowerToys.sln +++ b/PowerToys.sln @@ -269,6 +269,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Plugin.Calculator EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Plugin.Folder.UnitTests", "src\modules\launcher\Plugins\Microsoft.Plugin.Folder.UnitTests\Microsoft.Plugin.Folder.UnitTests.csproj", "{4FA206A5-F69F-4193-BF8F-F6EEB496734C}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTest-ColorPickerUI", "UnitTest-ColorPickerUI\UnitTest-ColorPickerUI.csproj", "{090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "logging", "src\logging\logging.vcxproj", "{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}" EndProject Global @@ -545,6 +547,10 @@ Global {4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Debug|x64.Build.0 = Debug|x64 {4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Release|x64.ActiveCfg = Release|x64 {4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Release|x64.Build.0 = Release|x64 + {090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Debug|x64.ActiveCfg = Debug|Any CPU + {090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Debug|x64.Build.0 = Debug|Any CPU + {090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Release|x64.ActiveCfg = Release|x64 + {090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Release|x64.Build.0 = Release|x64 {7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Debug|x64.ActiveCfg = Debug|x64 {7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Debug|x64.Build.0 = Debug|x64 {7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Release|x64.ActiveCfg = Release|x64 @@ -627,6 +633,7 @@ Global {0F85E674-34AE-443D-954C-8321EB8B93B1} = {C3081D9A-1586-441A-B5F4-ED815B3719C1} {632BBE62-5421-49EA-835A-7FFA4F499BD6} = {4AFC9975-2456-4C70-94A4-84073C1CED93} {4FA206A5-F69F-4193-BF8F-F6EEB496734C} = {4AFC9975-2456-4C70-94A4-84073C1CED93} + {090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1} = {1D78B84B-CA39-406C-98F4-71F7EC266CC0} {7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F} = {1AFB6476-670D-4E80-A464-657E01DFF482} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution diff --git a/UnitTest-ColorPickerUI/Helpers/ColorHelperTest.cs b/UnitTest-ColorPickerUI/Helpers/ColorHelperTest.cs new file mode 100644 index 0000000000..5f9c867b93 --- /dev/null +++ b/UnitTest-ColorPickerUI/Helpers/ColorHelperTest.cs @@ -0,0 +1,187 @@ +using System; +using System.Drawing; +using ColorPicker.Helpers; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace UnitTest_ColorPickerUI.Helpers +{ + /// + /// Test class to test + /// + [TestClass] + public class ColorConverterTest + { + // test values taken from https://de.wikipedia.org/wiki/HSV-Farbraum + [TestMethod] + [DataRow(000, 000, 000, 000, 000, 000)] // Black + [DataRow(000, 000, 100, 100, 100, 100)] // White + [DataRow(000, 100, 050, 100, 000, 000)] // Red + [DataRow(015, 100, 050, 100, 025, 000)] // Vermilion/Cinnabar + [DataRow(020, 060, 022.5, 036, 018, 009)] // Brown + [DataRow(030, 100, 050, 100, 050, 000)] // Orange + [DataRow(045, 100, 050, 100, 075, 000)] // Saffron + [DataRow(060, 100, 050, 100, 100, 000)] // Yellow + [DataRow(075, 100, 050, 075, 100, 000)] // Light green-yellow + [DataRow(090, 100, 050, 050, 100, 000)] // Green-yellow + [DataRow(105, 100, 050, 025, 100, 000)] // Lime + [DataRow(120, 100, 025, 000, 050, 000)] // Dark green + [DataRow(120, 100, 050, 000, 100, 000)] // Green + [DataRow(135, 100, 050, 000, 100, 025)] // Light blue-green + [DataRow(150, 100, 050, 000, 100, 050)] // Blue-green + [DataRow(165, 100, 050, 000, 100, 075)] // Green-cyan + [DataRow(180, 100, 050, 000, 100, 100)] // Cyan + [DataRow(195, 100, 050, 000, 075, 100)] // Blue-cyan + [DataRow(210, 100, 050, 000, 050, 100)] // Green-blue + [DataRow(225, 100, 050, 000, 025, 100)] // Light green-blue + [DataRow(240, 100, 050, 000, 000, 100)] // Blue + [DataRow(255, 100, 050, 025, 000, 100)] // Indigo + [DataRow(270, 100, 050, 050, 000, 100)] // Purple + [DataRow(285, 100, 050, 075, 000, 100)] // Blue-magenta + [DataRow(300, 100, 050, 100, 000, 100)] // Magenta + [DataRow(315, 100, 050, 100, 000, 075)] // Red-magenta + [DataRow(330, 100, 050, 100, 000, 050)] // Blue-red + [DataRow(345, 100, 050, 100, 000, 025)] // Light blue-red + public void ColorRGBtoHSL(double hue, double saturation, double lightness, int red, int green, int blue) + { + red = Convert.ToInt32(Math.Round(255d / 100d * red)); // [0%..100%] to [0..255] + green = Convert.ToInt32(Math.Round(255d / 100d * green)); // [0%..100%] to [0..255] + blue = Convert.ToInt32(Math.Round(255d / 100d * blue)); // [0%..100%] to [0..255] + + var color = Color.FromArgb(255, red, green, blue); + var result = ColorHelper.ConvertToHSLColor(color); + + // hue[0°..360°] + Assert.AreEqual(result.hue, hue, 0.2d); + + // saturation[0..1] + Assert.AreEqual(result.saturation * 100d, saturation, 0.2d); + + // lightness[0..1] + Assert.AreEqual(result.lightness * 100d, lightness, 0.2d); + } + + // test values taken from https://de.wikipedia.org/wiki/HSV-Farbraum + [TestMethod] + [DataRow(000, 000, 000, 000, 000, 000)] // Black + [DataRow(000, 000, 100, 100, 100, 100)] // White + [DataRow(000, 100, 100, 100, 000, 000)] // Red + [DataRow(015, 100, 100, 100, 025, 000)] // Vermilion/Cinnabar + [DataRow(020, 075, 036, 036, 018, 009)] // Brown + [DataRow(030, 100, 100, 100, 050, 000)] // Orange + [DataRow(045, 100, 100, 100, 075, 000)] // Saffron + [DataRow(060, 100, 100, 100, 100, 000)] // Yellow + [DataRow(075, 100, 100, 075, 100, 000)] // Light green-yellow + [DataRow(090, 100, 100, 050, 100, 000)] // Green-yellow + [DataRow(105, 100, 100, 025, 100, 000)] // Lime + [DataRow(120, 100, 050, 000, 050, 000)] // Dark green + [DataRow(120, 100, 100, 000, 100, 000)] // Green + [DataRow(135, 100, 100, 000, 100, 025)] // Light blue-green + [DataRow(150, 100, 100, 000, 100, 050)] // Blue-green + [DataRow(165, 100, 100, 000, 100, 075)] // Green-cyan + [DataRow(180, 100, 100, 000, 100, 100)] // Cyan + [DataRow(195, 100, 100, 000, 075, 100)] // Blue-cyan + [DataRow(210, 100, 100, 000, 050, 100)] // Green-blue + [DataRow(225, 100, 100, 000, 025, 100)] // Light green-blue + [DataRow(240, 100, 100, 000, 000, 100)] // Blue + [DataRow(255, 100, 100, 025, 000, 100)] // Indigo + [DataRow(270, 100, 100, 050, 000, 100)] // Purple + [DataRow(285, 100, 100, 075, 000, 100)] // Blue-magenta + [DataRow(300, 100, 100, 100, 000, 100)] // Magenta + [DataRow(315, 100, 100, 100, 000, 075)] // Red-magenta + [DataRow(330, 100, 100, 100, 000, 050)] // Blue-red + [DataRow(345, 100, 100, 100, 000, 025)] // Light blue-red + public void ColorRGBtoHSV(double hue, double saturation, double value, int red, int green, int blue) + { + red = Convert.ToInt32(Math.Round(255d / 100d * red)); // [0%..100%] to [0..255] + green = Convert.ToInt32(Math.Round(255d / 100d * green)); // [0%..100%] to [0..255] + blue = Convert.ToInt32(Math.Round(255d / 100d * blue)); // [0%..100%] to [0..255] + + var color = Color.FromArgb(255, red, green, blue); + var result = ColorHelper.ConvertToHSVColor(color); + + // hue [0°..360°] + Assert.AreEqual(result.hue, hue, 0.2d); + + // saturation[0..1] + Assert.AreEqual(result.saturation * 100d, saturation, 0.2d); + + // value[0..1] + Assert.AreEqual(result.value * 100d, value, 0.2d); + } + + [TestMethod] + [DataRow(000, 000, 000, 100, 000, 000, 000)] // Black + [DataRow(000, 000, 000, 000, 255, 255, 255)] // White + [DataRow(000, 100, 100, 000, 255, 000, 000)] // Red + [DataRow(000, 075, 100, 000, 255, 064, 000)] // Vermilion/Cinnabar + [DataRow(000, 050, 075, 064, 092, 046, 023)] // Brown + [DataRow(000, 050, 100, 000, 255, 128, 000)] // Orange + [DataRow(000, 025, 100, 000, 255, 192, 000)] // Saffron + [DataRow(000, 000, 100, 000, 255, 255, 000)] // Yellow + [DataRow(025, 000, 100, 000, 192, 255, 000)] // Light green-yellow + [DataRow(050, 000, 100, 000, 128, 255, 000)] // Green-yellow + [DataRow(075, 000, 100, 000, 064, 255, 000)] // Lime + [DataRow(100, 000, 100, 050, 000, 128, 000)] // Dark green + [DataRow(100, 000, 100, 000, 000, 255, 000)] // Green + [DataRow(100, 000, 075, 000, 000, 255, 064)] // Light blue-green + [DataRow(100, 000, 050, 000, 000, 255, 128)] // Blue-green + [DataRow(100, 000, 025, 000, 000, 255, 192)] // Green-cyan + [DataRow(100, 000, 000, 000, 000, 255, 255)] // Cyan + [DataRow(100, 025, 000, 000, 000, 192, 255)] // Blue-cyan + [DataRow(100, 050, 000, 000, 000, 128, 255)] // Green-blue + [DataRow(100, 075, 000, 000, 000, 064, 255)] // Light green-blue + [DataRow(100, 100, 000, 000, 000, 000, 255)] // Blue + [DataRow(075, 100, 000, 000, 064, 000, 255)] // Indigo + [DataRow(050, 100, 000, 000, 128, 000, 255)] // Purple + [DataRow(025, 100, 000, 000, 192, 000, 255)] // Blue-magenta + [DataRow(000, 100, 000, 000, 255, 000, 255)] // Magenta + [DataRow(000, 100, 025, 000, 255, 000, 192)] // Red-magenta + [DataRow(000, 100, 050, 000, 255, 000, 128)] // Blue-red + [DataRow(000, 100, 075, 000, 255, 000, 064)] // Light blue-red + public void ColorRGBtoCMYK(int cyan, int magenta, int yellow, int blackKey, int red, int green, int blue) + { + var color = Color.FromArgb(255, red, green, blue); + var result = ColorHelper.ConvertToCMYKColor(color); + + // cyan[0..1] + Assert.AreEqual(result.cyan * 100d, cyan, 0.5d); + + // magenta[0..1] + Assert.AreEqual(result.magenta * 100d, magenta, 0.5d); + + // yellow[0..1] + Assert.AreEqual(result.yellow * 100d, yellow, 0.5d); + + // black[0..1] + Assert.AreEqual(result.blackKey * 100d, blackKey, 0.5d); + } + + [TestMethod] + public void ColorRGBtoCMYKZeroDiv() + { + for(var red = 0; red < 256; red++) + { + for(var blue = 0; blue < 256; blue++) + { + for(var green = 0; green < 256; green++) + { + var color = Color.FromArgb(red, green, blue); + + Exception? exception = null; + + try + { + _ = ColorHelper.ConvertToCMYKColor(color); + } + catch(Exception ex) + { + exception = ex; + } + + Assert.IsNull(exception); + } + } + } + } + } +} diff --git a/UnitTest-ColorPickerUI/Helpers/ColorRepresentationHelperTest.cs b/UnitTest-ColorPickerUI/Helpers/ColorRepresentationHelperTest.cs new file mode 100644 index 0000000000..44ec52ea89 --- /dev/null +++ b/UnitTest-ColorPickerUI/Helpers/ColorRepresentationHelperTest.cs @@ -0,0 +1,24 @@ +using ColorPicker.Helpers; +using Microsoft.PowerToys.Settings.UI.Lib; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Drawing; + +namespace UnitTest_ColorPickerUI.Helpers +{ + [TestClass] + public class ColorRepresentationHelperTest + { + [TestMethod] + [DataRow(ColorRepresentationType.CMYK, "cmyk(0%, 0%, 0%, 100%)")] + [DataRow(ColorRepresentationType.HEX, "#000000")] + [DataRow(ColorRepresentationType.HSL, "hsl(0, 0%, 0%)")] + [DataRow(ColorRepresentationType.HSV, "hsv(0, 0%, 0%)")] + [DataRow(ColorRepresentationType.RGB, "rgb(0, 0, 0)")] + + public void ColorRGBtoCMYKZeroDiv(ColorRepresentationType type, string expected) + { + var result = ColorRepresentationHelper.GetStringRepresentation(Color.Black, type); + Assert.AreEqual(result, expected); + } + } +} diff --git a/UnitTest-ColorPickerUI/UnitTest-ColorPickerUI.csproj b/UnitTest-ColorPickerUI/UnitTest-ColorPickerUI.csproj new file mode 100644 index 0000000000..34a479102a --- /dev/null +++ b/UnitTest-ColorPickerUI/UnitTest-ColorPickerUI.csproj @@ -0,0 +1,35 @@ + + + + netcoreapp3.1 + UnitTest_ColorPickerUI + false + enable + 9.0 + Library + + + + x64 + + + + x64 + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + + diff --git a/src/core/Microsoft.PowerToys.Settings.UI.Lib/ColorPickerProperties.cs b/src/core/Microsoft.PowerToys.Settings.UI.Lib/ColorPickerProperties.cs index a726465679..e5ea8ef888 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI.Lib/ColorPickerProperties.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI.Lib/ColorPickerProperties.cs @@ -9,8 +9,30 @@ namespace Microsoft.PowerToys.Settings.UI.Lib { public enum ColorRepresentationType { + /// + /// Color presentation as hexadecimal color value without the alpha-value (e.g. #0055FF) + /// HEX = 0, + + /// + /// Color presentation as RGB color value (red[0..255], green[0..255], blue[0..255]) + /// RGB = 1, + + /// + /// Color presentation as CMYK color value (cyan[0%..100%], magenta[0%..100%], yellow[0%..100%], black key[0%..100%]) + /// + CMYK = 2, + + /// + /// Color presentation as HSL color value (hue[0°..360°], saturation[0..100%], lightness[0%..100%]) + /// + HSL = 3, + + /// + /// Color presentation as HSV color value (hue[0°..360°], saturation[0%..100%], value[0%..100%]) + /// + HSV = 4, } public class ColorPickerProperties @@ -31,8 +53,6 @@ namespace Microsoft.PowerToys.Settings.UI.Lib public ColorRepresentationType CopiedColorRepresentation { get; set; } public override string ToString() - { - return JsonSerializer.Serialize(this); - } + => JsonSerializer.Serialize(this); } } diff --git a/src/core/Microsoft.PowerToys.Settings.UI/Views/ColorPickerPage.xaml b/src/core/Microsoft.PowerToys.Settings.UI/Views/ColorPickerPage.xaml index 1ff3f00cc1..a28be48e6c 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI/Views/ColorPickerPage.xaml +++ b/src/core/Microsoft.PowerToys.Settings.UI/Views/ColorPickerPage.xaml @@ -68,7 +68,10 @@ Width="240" IsEnabled="{Binding IsEnabled}"> - + + + +