diff --git a/components/ColorAnalyzer/samples/AccentAnalyzer.md b/components/ColorAnalyzer/samples/AccentAnalyzer.md deleted file mode 100644 index 29591e7b1..000000000 --- a/components/ColorAnalyzer/samples/AccentAnalyzer.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -title: AccentAnalyzer Helper -author: Avid29 -description: A tool for extracting colors from an image -keywords: Accents, Color, Helpers -dev_langs: - - csharp -category: Helpers -subcategory: Miscellaneous -discussion-id: 254 -issue-id: 0 -icon: assets/icon.png ---- - -# AccentAnalyzer - -The AccentAnalyzer provides a pure XAML way to use the colors extracted from an image as a binding source for any `Color` property. - -> [!Sample AccentAnalyzerSample] - -> [!Sample ContrastHelperSample] diff --git a/components/ColorAnalyzer/samples/ColorAnalyzer.Samples.csproj b/components/ColorAnalyzer/samples/ColorAnalyzer.Samples.csproj index 724def1ee..57dfffe41 100644 --- a/components/ColorAnalyzer/samples/ColorAnalyzer.Samples.csproj +++ b/components/ColorAnalyzer/samples/ColorAnalyzer.Samples.csproj @@ -18,7 +18,4 @@ PreserveNewest - - - diff --git a/components/ColorAnalyzer/samples/ColorPaletteSampler/AccentAnalyzerSample.xaml b/components/ColorAnalyzer/samples/ColorPaletteSampler/AccentAnalyzerSample.xaml deleted file mode 100644 index 2b7f841c0..000000000 --- a/components/ColorAnalyzer/samples/ColorPaletteSampler/AccentAnalyzerSample.xaml +++ /dev/null @@ -1,146 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/components/ColorAnalyzer/samples/ColorPaletteSampler/AccentColorSample.xaml b/components/ColorAnalyzer/samples/ColorPaletteSampler/AccentColorSample.xaml new file mode 100644 index 000000000..5ae519283 --- /dev/null +++ b/components/ColorAnalyzer/samples/ColorPaletteSampler/AccentColorSample.xaml @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/ColorAnalyzer/samples/ColorPaletteSampler/AccentColorSample.xaml.cs b/components/ColorAnalyzer/samples/ColorPaletteSampler/AccentColorSample.xaml.cs new file mode 100644 index 000000000..63abce9f6 --- /dev/null +++ b/components/ColorAnalyzer/samples/ColorPaletteSampler/AccentColorSample.xaml.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace ColorAnalyzerExperiment.Samples; + +/// +/// An example sample page of a custom control inheriting from Panel. +/// +[ToolkitSample(id: nameof(AccentColorSample), "AccentAnalyzer helper", description: $"A sample for showing how the accent analyzer can be used.")] +public sealed partial class AccentColorSample : ColorPaletteSamplerToolkitSampleBase +{ + public AccentColorSample() + { + this.InitializeComponent(); + } +} diff --git a/components/ColorAnalyzer/samples/ColorPaletteSampler/BaseColorSample.xaml b/components/ColorAnalyzer/samples/ColorPaletteSampler/BaseColorSample.xaml new file mode 100644 index 000000000..6f37840d8 --- /dev/null +++ b/components/ColorAnalyzer/samples/ColorPaletteSampler/BaseColorSample.xaml @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/ColorAnalyzer/samples/ColorPaletteSampler/AccentAnalyzerSample.xaml.cs b/components/ColorAnalyzer/samples/ColorPaletteSampler/BaseColorSample.xaml.cs similarity index 60% rename from components/ColorAnalyzer/samples/ColorPaletteSampler/AccentAnalyzerSample.xaml.cs rename to components/ColorAnalyzer/samples/ColorPaletteSampler/BaseColorSample.xaml.cs index fca29f2c6..68a09e633 100644 --- a/components/ColorAnalyzer/samples/ColorPaletteSampler/AccentAnalyzerSample.xaml.cs +++ b/components/ColorAnalyzer/samples/ColorPaletteSampler/BaseColorSample.xaml.cs @@ -7,10 +7,10 @@ namespace ColorAnalyzerExperiment.Samples; /// /// An example sample page of a custom control inheriting from Panel. /// -[ToolkitSample(id: nameof(AccentAnalyzerSample), "AccentAnalyzer helper", description: $"A sample for showing how the accent analyzer can be used.")] -public sealed partial class AccentAnalyzerSample : Page +[ToolkitSample(id: nameof(BaseColorSample), "AccentAnalyzer helper", description: $"A sample for showing how the accent analyzer can be used.")] +public sealed partial class BaseColorSample : ColorPaletteSamplerToolkitSampleBase { - public AccentAnalyzerSample() + public BaseColorSample() { this.InitializeComponent(); } diff --git a/components/ColorAnalyzer/samples/ColorPaletteSampler/ColorPaletteSamplerToolkitSample.cs b/components/ColorAnalyzer/samples/ColorPaletteSampler/ColorPaletteSamplerToolkitSample.cs new file mode 100644 index 000000000..dbd0d7f74 --- /dev/null +++ b/components/ColorAnalyzer/samples/ColorPaletteSampler/ColorPaletteSamplerToolkitSample.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace ColorAnalyzerExperiment.Samples; + +public abstract partial class ColorPaletteSamplerToolkitSampleBase : Page +{ + public static readonly DependencyProperty SelectedImageProperty = + DependencyProperty.Register(nameof(SelectedImage), typeof(ImageSource), typeof(ColorPaletteSamplerToolkitSampleBase), new PropertyMetadata(null)); + + public ColorPaletteSamplerToolkitSampleBase() + { + } + + public ImageSource SelectedImage + { + get => (ImageSource)GetValue(SelectedImageProperty); + set => SetValue(SelectedImageProperty, value); + } +} diff --git a/components/ColorAnalyzer/samples/ColorPaletteSampler/ColorWeightSample.xaml b/components/ColorAnalyzer/samples/ColorPaletteSampler/ColorWeightSample.xaml new file mode 100644 index 000000000..145d29b73 --- /dev/null +++ b/components/ColorAnalyzer/samples/ColorPaletteSampler/ColorWeightSample.xaml @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/ColorAnalyzer/samples/ColorPaletteSampler/ColorWeightSample.xaml.cs b/components/ColorAnalyzer/samples/ColorPaletteSampler/ColorWeightSample.xaml.cs new file mode 100644 index 000000000..7e0bde747 --- /dev/null +++ b/components/ColorAnalyzer/samples/ColorPaletteSampler/ColorWeightSample.xaml.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace ColorAnalyzerExperiment.Samples; + +/// +/// An example sample page of a custom control inheriting from Panel. +/// +[ToolkitSample(id: nameof(ColorWeightSample), "AccentAnalyzer helper", description: $"A sample for showing how the accent analyzer can be used.")] +public sealed partial class ColorWeightSample : ColorPaletteSamplerToolkitSampleBase +{ + public ColorWeightSample() + { + this.InitializeComponent(); + } +} diff --git a/components/ColorAnalyzer/samples/ColorPaletteSampler/ImageOptionsPane.xaml b/components/ColorAnalyzer/samples/ColorPaletteSampler/ImageOptionsPane.xaml index 44227d2c9..34eb4f840 100644 --- a/components/ColorAnalyzer/samples/ColorPaletteSampler/ImageOptionsPane.xaml +++ b/components/ColorAnalyzer/samples/ColorPaletteSampler/ImageOptionsPane.xaml @@ -1,4 +1,4 @@ - $"ms-appx:///Assets/StockImages/{x}").ToList(); + SetImage(new Uri(StockImages.First())); } private void Button_Click(object sender, RoutedEventArgs e) @@ -39,6 +43,6 @@ private void GridView_ItemClick(object sender, ItemClickEventArgs e) private void SetImage(Uri uri) { - _sample.SampledImage.Source = new BitmapImage(uri); + _sample.SelectedImage = new BitmapImage(uri); } } diff --git a/components/ColorAnalyzer/samples/ColorPaletteSampler/MultiplePaletteSelectorSample.xaml b/components/ColorAnalyzer/samples/ColorPaletteSampler/MultiplePaletteSelectorSample.xaml new file mode 100644 index 000000000..c99816386 --- /dev/null +++ b/components/ColorAnalyzer/samples/ColorPaletteSampler/MultiplePaletteSelectorSample.xaml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/ColorAnalyzer/samples/ColorPaletteSampler/MultiplePaletteSelectorSample.xaml.cs b/components/ColorAnalyzer/samples/ColorPaletteSampler/MultiplePaletteSelectorSample.xaml.cs new file mode 100644 index 000000000..9206604b2 --- /dev/null +++ b/components/ColorAnalyzer/samples/ColorPaletteSampler/MultiplePaletteSelectorSample.xaml.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace ColorAnalyzerExperiment.Samples; + +/// +/// An example sample page of a custom control inheriting from Panel. +/// +[ToolkitSample(id: nameof(MultiplePaletteSelectorSample), "AccentAnalyzer helper", description: $"A sample for showing how the accent analyzer can be used.")] +public sealed partial class MultiplePaletteSelectorSample : ColorPaletteSamplerToolkitSampleBase +{ + public MultiplePaletteSelectorSample() + { + this.InitializeComponent(); + } +} diff --git a/components/ColorAnalyzer/samples/ColorPaletteSamplerToolkitSample.md b/components/ColorAnalyzer/samples/ColorPaletteSamplerToolkitSample.md new file mode 100644 index 000000000..17b37374c --- /dev/null +++ b/components/ColorAnalyzer/samples/ColorPaletteSamplerToolkitSample.md @@ -0,0 +1,53 @@ +--- +title: ColorPaletteSampler +author: Avid29 +description: A resource that generates a color palette from an image or any other UI element. +keywords: Color +dev_langs: + - csharp +category: Helpers +subcategory: Miscellaneous +discussion-id: 254 +issue-id: 736 +icon: assets/icon.png +--- + +# ColorPaletteSampler + +## Overview + +The `ColorPaletteSampler` is a resource that generates a color palette from any `UIElement`, +but most notably from an `Image`. After the palette is generated, you can use a `PaletteSelector` +or collection of `PaletteSelector` items to select colors from the palette to bind to in the UI. + +## AccentColorPaletteSelector + +The `AccentColorPaletteSelector` can be used to extract accent colors from an image. An +accent color is a color that stands out, which we detect by looking for colors following +a "colorness" formula. + +Here's an example where you can play around and see the results. + +> [!Sample AccentColorSample] + +## BaseColorPaletteSelector + +The `BaseColorPaletteSelector` can be used to extract basic colors from an image. +Basic colors are colors that standand out less stands out, which we detect by using +the same "colorness" formula, as accent colors, but inverting the results. + +> [!Sample BaseColorSample] + +## ColorWeightPaletteSelector + +The `ColorWeightPaletteSelector` can be used to determine which colors cover the most +area in an image. + +> [!Sample ColorWeightSample] + +## Using multiple `PaletteSelectors` items + +Finally, multiple `PaletteSelector` items can be used together in a single `ColorPaletteSampler` +to extract any combination of color data from an image. + +> [!Sample MultiplePaletteSelectorSample] diff --git a/components/ColorAnalyzer/samples/ContrastHelper.md b/components/ColorAnalyzer/samples/ContrastHelper.md new file mode 100644 index 000000000..3fdbc5561 --- /dev/null +++ b/components/ColorAnalyzer/samples/ContrastHelper.md @@ -0,0 +1,37 @@ +--- +title: ContrastHelper +author: Avid29 +description: A helper for adjusting colors to ensure sufficient contrast. +keywords: Color, Accesibility +dev_langs: + - csharp +category: Helpers +subcategory: Miscellaneous +discussion-id: 745 +issue-id: 736 +icon: assets/icon.png +--- + +# ContrastHelper + +### Using on TextBlocks or Controls + +The contrast helper can be applied to a `TextBlock` or `Control` to +apply updates on its `Foreground` property. + +When checking the original contrast ratio, the `ContrastHelper` will +attempt to grab the `Foreground` as a `SolidColorBrush`. If the original +`Foreground` is not a `SolidColorBrush` it will default to `Colors.Transparent`, +and always apply a raised contrast color. + +> [!Sample TextBlockContrastSample] + +If you are not using a `TextBlock` or `Control`, +you can directly apply the `ContrastHelper` to a `SolidColorBrush`. + +Here for example, we adjust the stroke of a `Shape` by applying +the helper on the `SolidColorBrush` inside the `Shape.Stroke` property.` + +### Using on SolidColorBrush + +> [!Sample SolidColorBrushContrastSample] diff --git a/components/ColorAnalyzer/samples/ContrastHelper/ContrastHelperSample.xaml b/components/ColorAnalyzer/samples/ContrastHelper/ContrastHelperSample.xaml deleted file mode 100644 index 6da841f01..000000000 --- a/components/ColorAnalyzer/samples/ContrastHelper/ContrastHelperSample.xaml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/components/ColorAnalyzer/samples/ContrastHelper/ContrastHelperSample.xaml.cs b/components/ColorAnalyzer/samples/ContrastHelper/ContrastHelperSampleBase.cs similarity index 62% rename from components/ColorAnalyzer/samples/ContrastHelper/ContrastHelperSample.xaml.cs rename to components/ColorAnalyzer/samples/ContrastHelper/ContrastHelperSampleBase.cs index e65cf3286..0d8d11d02 100644 --- a/components/ColorAnalyzer/samples/ContrastHelper/ContrastHelperSample.xaml.cs +++ b/components/ColorAnalyzer/samples/ContrastHelper/ContrastHelperSampleBase.cs @@ -2,25 +2,28 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#if WINUI3 using Microsoft.UI; +#endif + using Windows.UI; namespace ColorAnalyzerExperiment.Samples; -/// -/// An example sample page of a custom control inheriting from Panel. -/// -[ToolkitSample(id: nameof(ContrastHelperSample), "ContrastAnalyzer helper", description: $"A sample for showing how the contrast analyzer can be used.")] -public sealed partial class ContrastHelperSample : Page +public abstract partial class ContrastHelperSampleBase : Page { public static readonly DependencyProperty DesiredBackgroundProperty = - DependencyProperty.Register(nameof(DesiredBackground), typeof(Color), typeof(ContrastHelperSample), new PropertyMetadata(Colors.Black)); + DependencyProperty.Register(nameof(DesiredBackground), typeof(Color), typeof(ContrastHelperSampleBase), new PropertyMetadata(Colors.Black)); public static readonly DependencyProperty DesiredForegroundProperty = - DependencyProperty.Register(nameof(DesiredForeground), typeof(Color), typeof(ContrastHelperSample), new PropertyMetadata(Colors.White)); + DependencyProperty.Register(nameof(DesiredForeground), typeof(Color), typeof(ContrastHelperSampleBase), new PropertyMetadata(Colors.White)); + + public static readonly DependencyProperty MinRatioProperty = + DependencyProperty.Register(nameof(MinRatio), typeof(double), typeof(ContrastHelperSampleBase), new PropertyMetadata(3d)); - private static readonly DependencyProperty MinRatioProperty = - DependencyProperty.Register(nameof(MinRatio), typeof(double), typeof(ContrastHelperSample), new PropertyMetadata(0d)); + public ContrastHelperSampleBase() + { + } public Color DesiredBackground { @@ -39,9 +42,4 @@ public double MinRatio get => (double)GetValue(MinRatioProperty); set => SetValue(MinRatioProperty, value); } - - public ContrastHelperSample() - { - this.InitializeComponent(); - } } diff --git a/components/ColorAnalyzer/samples/ContrastHelper/ContrastOptionsPane.xaml b/components/ColorAnalyzer/samples/ContrastHelper/ContrastOptionsPane.xaml index 055ad47e0..685df7a76 100644 --- a/components/ColorAnalyzer/samples/ContrastHelper/ContrastOptionsPane.xaml +++ b/components/ColorAnalyzer/samples/ContrastHelper/ContrastOptionsPane.xaml @@ -1,4 +1,5 @@ - + - - - + + + + + + + + + + + + + + + + + + - - + + + + + - + + + + - - - - + + + diff --git a/components/ColorAnalyzer/samples/ContrastHelper/ContrastOptionsPane.xaml.cs b/components/ColorAnalyzer/samples/ContrastHelper/ContrastOptionsPane.xaml.cs index 4ba613fcb..69bfd0ab9 100644 --- a/components/ColorAnalyzer/samples/ContrastHelper/ContrastOptionsPane.xaml.cs +++ b/components/ColorAnalyzer/samples/ContrastHelper/ContrastOptionsPane.xaml.cs @@ -8,22 +8,39 @@ using Windows.UI.Xaml.Media.Imaging; #endif +#if WINUI3 +using Microsoft.UI; +#endif + +using Windows.UI; + namespace ColorAnalyzerExperiment.Samples; -[ToolkitSampleOptionsPane(nameof(ContrastHelperSample))] +[ToolkitSampleOptionsPane(nameof(TextBlockContrastSample))] +[ToolkitSampleOptionsPane(nameof(SolidColorBrushContrastSample))] public partial class ContrastOptionsPane : UserControl { - private ContrastHelperSample _sample; - private ContrastHelperSample.XamlNamedPropertyRelay _sampleXamlRelay; + private ContrastHelperSampleBase _sample; - public ContrastOptionsPane(ContrastHelperSample sample) + public ContrastOptionsPane(ContrastHelperSampleBase sample) { _sample = sample; - _sampleXamlRelay = new ContrastHelperSample.XamlNamedPropertyRelay(sample); - + this.InitializeComponent(); } + public Color DesiredForeground + { + get => _sample.DesiredForeground; + set => _sample.DesiredForeground = value; + } + + public Color DesiredBackground + { + get => _sample.DesiredBackground; + set => _sample.DesiredBackground = value; + } + private void Foreground_ColorChanged(MUXC.ColorPicker sender, MUXC.ColorChangedEventArgs args) { // TODO: Disect the colorpicker @@ -46,14 +63,4 @@ private void Ratio_ValueChanged(object sender, RangeBaseValueChangedEventArgs e) { _sample.MinRatio = (double)e.NewValue; } - - private void FontSize_ValueChanged(object sender, RangeBaseValueChangedEventArgs e) - { - _sampleXamlRelay.TextSample.FontSize = (double)e.NewValue; - } - - private void Thickness_ValueChanged(object sender, RangeBaseValueChangedEventArgs e) - { - _sampleXamlRelay.ShapeSample.StrokeThickness = (double)e.NewValue; - } } diff --git a/components/ColorAnalyzer/samples/ContrastHelper/SolidColorBrushContrastSample.xaml b/components/ColorAnalyzer/samples/ContrastHelper/SolidColorBrushContrastSample.xaml new file mode 100644 index 000000000..2767672a2 --- /dev/null +++ b/components/ColorAnalyzer/samples/ContrastHelper/SolidColorBrushContrastSample.xaml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/components/ColorAnalyzer/samples/ContrastHelper/SolidColorBrushContrastSample.xaml.cs b/components/ColorAnalyzer/samples/ContrastHelper/SolidColorBrushContrastSample.xaml.cs new file mode 100644 index 000000000..1cdd1f4f2 --- /dev/null +++ b/components/ColorAnalyzer/samples/ContrastHelper/SolidColorBrushContrastSample.xaml.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace ColorAnalyzerExperiment.Samples; + +/// +/// An example sample page of a custom control inheriting from Panel. +/// +[ToolkitSample(id: nameof(SolidColorBrushContrastSample), "ContrastAnalyzer helper", description: $"A sample for showing how the contrast analyzer can be used.")] +public sealed partial class SolidColorBrushContrastSample : ContrastHelperSampleBase +{ + public SolidColorBrushContrastSample() + { + this.InitializeComponent(); + } +} diff --git a/components/ColorAnalyzer/samples/ContrastHelper/TextBlockContrastSample.xaml b/components/ColorAnalyzer/samples/ContrastHelper/TextBlockContrastSample.xaml new file mode 100644 index 000000000..2c4bb713a --- /dev/null +++ b/components/ColorAnalyzer/samples/ContrastHelper/TextBlockContrastSample.xaml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/components/ColorAnalyzer/samples/ContrastHelper/TextBlockContrastSample.xaml.cs b/components/ColorAnalyzer/samples/ContrastHelper/TextBlockContrastSample.xaml.cs new file mode 100644 index 000000000..fcdbfd011 --- /dev/null +++ b/components/ColorAnalyzer/samples/ContrastHelper/TextBlockContrastSample.xaml.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace ColorAnalyzerExperiment.Samples; + +/// +/// An example sample page of a custom control inheriting from Panel. +/// +[ToolkitSample(id: nameof(TextBlockContrastSample), "ContrastAnalyzer helper", description: $"A sample for showing how the contrast analyzer can be used.")] +public sealed partial class TextBlockContrastSample : ContrastHelperSampleBase +{ + public TextBlockContrastSample() + { + this.InitializeComponent(); + } +} diff --git a/components/ColorAnalyzer/src/ColorExtensions.cs b/components/ColorAnalyzer/src/ColorExtensions.cs index 2f6cc1db7..b1755d043 100644 --- a/components/ColorAnalyzer/src/ColorExtensions.cs +++ b/components/ColorAnalyzer/src/ColorExtensions.cs @@ -30,22 +30,22 @@ internal static double ContrastRatio(this Color color1, Color color2) // Source WCAG guidelines: https://www.w3.org/TR/WCAG20/#contrast-ratiodef // Calculate perceived luminance for both colors - double luminance1 = color1.PerceivedLuminance(); - double luminance2 = color2.PerceivedLuminance(); + double luminance1 = color1.RelativeLuminance(); + double luminance2 = color2.RelativeLuminance(); // Determine lighter and darker luminance double lighter = Math.Max(luminance1, luminance2); double darker = Math.Min(luminance1, luminance2); // Calculate contrast ratio - return (lighter + 0.05f) / (darker + 0.05f); + return (lighter + 0.05) / (darker + 0.05); } - internal static double PerceivedLuminance(this Color color) + internal static double RelativeLuminance(this Color color) { // Color theory is a massive iceberg. Here's a peek at the tippy top: - // There's two (main) standards for calculating luminance from RGB values. + // There's two (main) standards for calculating percieved luminance from RGB values. // + ------------- + ------------------------------------ + ------------------ + ------------------------------------------------------------------------------- + // | Standard | Formula | Ref. Section | Ref. Link | @@ -61,11 +61,26 @@ internal static double PerceivedLuminance(this Color color) // NOTE: If we for whatever reason we ever need to optimize this code, // we can make approximations using integer math instead of floating point math. - // The precise values are not critical, as long as the relative luminance is accurate. + // The precise values are not critical, as long as the proportions are similar and sum to 1. // Like so: return (2 * color.R + 7 * color.G + color.B); + // Adjust channels relative luminance out of sRGB: + // https://www.w3.org/WAI/GL/wiki/Relative_luminance#Definition_as_Stated_in_WCAG_2.x + float sRGBtoRGB(float s) + { + if (s <= 0.03928f) + return s / 12.92f; + + return MathF.Pow(((s + 0.055f) / 1.055f), 2.4f); + } + + var vec = color.ToVector3(); + var r = sRGBtoRGB(vec.X); + var g = sRGBtoRGB(vec.Y); + var b = sRGBtoRGB(vec.Z); + // TLDR: We use ITU Rec. 709 standard formula for perceived luminance. - return (0.2126f * color.R + 0.7152f * color.G + 0.0722 * color.B) / 255; + return (0.2126f * r + 0.7152f * g + 0.0722 * b); } internal static float FindColorfulness(this Color color) diff --git a/components/ColorAnalyzer/src/ContrastHelper/ContrastHelper.Properties.cs b/components/ColorAnalyzer/src/ContrastHelper/ContrastHelper.Properties.cs index c621abf3b..0a65e9d5b 100644 --- a/components/ColorAnalyzer/src/ContrastHelper/ContrastHelper.Properties.cs +++ b/components/ColorAnalyzer/src/ContrastHelper/ContrastHelper.Properties.cs @@ -115,21 +115,39 @@ public partial class ContrastHelper /// public static double GetContrastRatio(DependencyObject obj) => (double)obj.GetValue(ContrastRatioProperty); - private static void SetContrastRatio(DependencyObject obj, double value) => obj.SetValue(ContrastRatioProperty, value); + /// + /// Sets the calculated contrast ratio compared to the actual foreground color. + /// + /// + /// This must be provided for binding, but should be treated as if it were private. + /// + public static void SetContrastRatio(DependencyObject obj, double value) => obj.SetValue(ContrastRatioProperty, value); /// /// Gets the calculated contrast ratio compared to the original foreground color. /// public static double GetOriginalContrastRatio(DependencyObject obj) => (double)obj.GetValue(OriginalContrastRatioProperty); - private static void SetOriginalContrastRatio(DependencyObject obj, double value) => obj.SetValue(OriginalContrastRatioProperty, value); + /// + /// Sets the calculated contrast ratio compared to the original foreground color. + /// + /// + /// This must be provided for binding, but should be treated as if it were private. + /// + public static void SetOriginalContrastRatio(DependencyObject obj, double value) => obj.SetValue(OriginalContrastRatioProperty, value); /// /// Gets the original color before adjustment for contrast. /// public static Color GetOriginalColor(DependencyObject obj) => (Color)obj.GetValue(OriginalColorProperty); - private static void SetOriginalColor(DependencyObject obj, Color color) => obj.SetValue(OriginalColorProperty, color); + /// + /// Sets the original color before adjustment for contrast. + /// + /// + /// This must be provided for binding, but should be treated as if it were private. + /// + public static void SetOriginalColor(DependencyObject obj, Color color) => obj.SetValue(OriginalColorProperty, color); private static DependencyObject GetCallbackObject(DependencyObject obj) => (DependencyObject)obj.GetValue(CallbackObjectProperty); diff --git a/components/ColorAnalyzer/src/ContrastHelper/ContrastHelper.cs b/components/ColorAnalyzer/src/ContrastHelper/ContrastHelper.cs index 7943822ac..7156ef4a8 100644 --- a/components/ColorAnalyzer/src/ContrastHelper/ContrastHelper.cs +++ b/components/ColorAnalyzer/src/ContrastHelper/ContrastHelper.cs @@ -44,7 +44,7 @@ private static void ApplyContrastCheck(DependencyObject d) // Current contrast is too small. // Select either black or white backed on the opponent luminance - var luminance = opponent.PerceivedLuminance(); + var luminance = opponent.RelativeLuminance(); var contrastingColor = luminance < 0.5f ? Colors.White : Colors.Black; UpdateContrastedProperties(d, contrastingColor); }