Skip to content

Commit 80c32b1

Browse files
committed
Restructure folder layout for ColorAnalyzer component
1 parent 0a54df9 commit 80c32b1

21 files changed

+69
-61
lines changed

components/ColorAnalyzer/samples/ColorAnalyzer.Samples.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,7 @@
1818
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
1919
</Content>
2020
</ItemGroup>
21+
<ItemGroup>
22+
<Folder Include="ContrastHelper\" />
23+
</ItemGroup>
2124
</Project>

components/ColorAnalyzer/samples/AccentAnalyzerSample.xaml renamed to components/ColorAnalyzer/samples/ColorPaletteSampler/AccentAnalyzerSample.xaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- 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. -->
1+
<!-- 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. -->
22
<Page x:Class="ColorAnalyzerExperiment.Samples.AccentAnalyzerSample"
33
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
44
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
@@ -11,7 +11,7 @@
1111
mc:Ignorable="d">
1212

1313
<Page.Resources>
14-
<helpers:ColorPaletteSampler x:Name="ColorPaletteSample"
14+
<helpers:ColorPaletteSampler x:Name="ColorPaletteSampler"
1515
Source="{x:Bind SampledImage}">
1616
<helpers:AccentColorPaletteSelector x:Name="AccentPalette"
1717
MinColorCount="3" />
@@ -41,7 +41,7 @@
4141
<interactivity:Interaction.Behaviors>
4242
<interactivity:EventTriggerBehavior EventName="ImageOpened">
4343
<interactivity:CallMethodAction MethodName="UpdatePalette"
44-
TargetObject="{x:Bind ColorPaletteSample}" />
44+
TargetObject="{x:Bind ColorPaletteSampler}" />
4545
</interactivity:EventTriggerBehavior>
4646
</interactivity:Interaction.Behaviors>
4747
</Image>

components/ColorAnalyzer/src/ColorExtensions.cs

Lines changed: 59 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,65 @@ namespace CommunityToolkit.WinUI.Helpers;
99

1010
internal static class ColorExtensions
1111
{
12+
internal static Color ToColor(this Vector3 color)
13+
{
14+
color *= 255;
15+
return Color.FromArgb(255, (byte)(color.X), (byte)(color.Y), (byte)(color.Z));
16+
}
17+
18+
internal static Vector3 ToVector3(this Color color)
19+
{
20+
var vector = new Vector3(color.R, color.G, color.B);
21+
return vector / 255;
22+
}
23+
24+
/// <summary>
25+
/// Get WCAG contrast ratio between two colors.
26+
/// </summary>
27+
internal static double ContrastRatio(this Color color1, Color color2)
28+
{
29+
// Using the formula for contrast ratio
30+
// Source WCAG guidelines: https://www.w3.org/TR/WCAG20/#contrast-ratiodef
31+
32+
// Calculate perceived luminance for both colors
33+
double luminance1 = color1.PerceivedLuminance();
34+
double luminance2 = color2.PerceivedLuminance();
35+
36+
// Determine lighter and darker luminance
37+
double lighter = Math.Max(luminance1, luminance2);
38+
double darker = Math.Min(luminance1, luminance2);
39+
40+
// Calculate contrast ratio
41+
return (lighter + 0.05f) / (darker + 0.05f);
42+
}
43+
44+
internal static double PerceivedLuminance(this Color color)
45+
{
46+
// Color theory is a massive iceberg. Here's a peek at the tippy top:
47+
48+
// There's two (main) standards for calculating luminance from RGB values.
49+
50+
// + ------------- + ------------------------------------ + ------------------ + ------------------------------------------------------------------------------- +
51+
// | Standard | Formula | Ref. Section | Ref. Link |
52+
// + ------------- + ------------------------------------ + ------------------ + ------------------------------------------------------------------------------- +
53+
// | ITU Rec. 709 | Y = 0.2126 R + 0.7152 G + 0.0722 B | Page 4/Item 3.2 | https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.709-6-201506-I!!PDF-E.pdf |
54+
// + ------------- + ------------------------------------ + ------------------ + ------------------------------------------------------------------------------- +
55+
// | ITU Rec. 601 | Y = 0.299 R + 0.587 G + 0.114 B | Page 2/Item 2.5.1 | https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.601-7-201103-I!!PDF-E.pdf |
56+
// + ------------- + ------------------------------------ + ------------------ + ------------------------------------------------------------------------------- +
57+
58+
// They're based on the standard ability of the human eye to perceive brightness,
59+
// from different colors, as well as the average monitor's ability to produce them.
60+
// Both standards produce similar results, but Rec. 709 is more accurate for modern displays.
61+
62+
// NOTE: If we for whatever reason we ever need to optimize this code,
63+
// we can make approximations using integer math instead of floating point math.
64+
// The precise values are not critical, as long as the relative luminance is accurate.
65+
// Like so: return (2 * color.R + 7 * color.G + color.B);
66+
67+
// TLDR: We use ITU Rec. 709 standard formula for perceived luminance.
68+
return (0.2126f * color.R + 0.7152f * color.G + 0.0722 * color.B) / 255;
69+
}
70+
1271
internal static float FindColorfulness(this Color color)
1372
{
1473
var vectorColor = color.ToVector3();
@@ -37,18 +96,6 @@ internal static float FindColorfulness(this Color[] colors)
3796
return std + (0.3f * mean);
3897
}
3998

40-
internal static Color ToColor(this Vector3 color)
41-
{
42-
color *= 255;
43-
return Color.FromArgb(255, (byte)(color.X), (byte)(color.Y), (byte)(color.Z));
44-
}
45-
46-
internal static Vector3 ToVector3(this Color color)
47-
{
48-
var vector = new Vector3(color.R, color.G, color.B);
49-
return vector / 255;
50-
}
51-
5299
private static float FindStandardDeviation(IEnumerable<float> data, out float avg)
53100
{
54101
var average = data.Average();

0 commit comments

Comments
 (0)