@@ -14,7 +14,7 @@ namespace CommunityToolkit.WinUI.Extensions;
1414/// <summary>
1515///
1616/// </summary>
17- public partial class AccentExtractor : DependencyObject
17+ public partial class AccentAnalyzer : DependencyObject
1818{
1919 private partial class Command : ICommand
2020 {
@@ -44,53 +44,117 @@ public void Execute(object? parameter)
4444 /// Gets the <see cref="DependencyProperty"/> for the <see cref="PrimaryAccentColor"/> property.
4545 /// </summary>
4646 public static readonly DependencyProperty PrimaryAccentColorProperty =
47- DependencyProperty . Register ( nameof ( PrimaryAccentColor ) , typeof ( Color ) , typeof ( AccentExtractor ) , new PropertyMetadata ( Colors . Transparent ) ) ;
47+ DependencyProperty . Register ( nameof ( PrimaryAccentColor ) , typeof ( Color ) , typeof ( AccentAnalyzer ) , new PropertyMetadata ( Colors . Transparent ) ) ;
4848
4949 /// <summary>
5050 /// Gets the <see cref="DependencyProperty"/> for the <see cref="SecondaryAccentColor"/> property.
5151 /// </summary>
5252 public static readonly DependencyProperty SecondaryAccentColorProperty =
53- DependencyProperty . Register ( nameof ( SecondaryAccentColor ) , typeof ( Color ) , typeof ( AccentExtractor ) , new PropertyMetadata ( Colors . Transparent ) ) ;
53+ DependencyProperty . Register ( nameof ( SecondaryAccentColor ) , typeof ( Color ) , typeof ( AccentAnalyzer ) , new PropertyMetadata ( Colors . Transparent ) ) ;
5454
5555 /// <summary>
5656 /// Gets the <see cref="DependencyProperty"/> for the <see cref="TertiaryAccentColor"/> property.
5757 /// </summary>
5858 public static readonly DependencyProperty TertiaryAccentColorProperty =
59- DependencyProperty . Register ( nameof ( TertiaryAccentColor ) , typeof ( Color ) , typeof ( AccentExtractor ) , new PropertyMetadata ( Colors . Transparent ) ) ;
59+ DependencyProperty . Register ( nameof ( TertiaryAccentColor ) , typeof ( Color ) , typeof ( AccentAnalyzer ) , new PropertyMetadata ( Colors . Transparent ) ) ;
60+
61+ /// <summary>
62+ /// Gets the <see cref="DependencyProperty"/> for the <see cref="BaseColor"/> property.
63+ /// </summary>
64+ public static readonly DependencyProperty BaseColorProperty =
65+ DependencyProperty . Register ( nameof ( BaseColor ) , typeof ( Color ) , typeof ( AccentAnalyzer ) , new PropertyMetadata ( Colors . Transparent ) ) ;
66+
67+ /// <summary>
68+ /// Gets the <see cref="DependencyProperty"/> for the <see cref="DominantColor"/> property.
69+ /// </summary>
70+ public static readonly DependencyProperty DominantColorProperty =
71+ DependencyProperty . Register ( nameof ( DominantColor ) , typeof ( Color ) , typeof ( AccentAnalyzer ) , new PropertyMetadata ( Colors . Transparent ) ) ;
72+
73+ /// <summary>
74+ /// Gets the <see cref="DependencyProperty"/> for the <see cref="Colorfulness"/> property.
75+ /// </summary>
76+ public static readonly DependencyProperty ColorfulnessProperty =
77+ DependencyProperty . Register ( nameof ( Colorfulness ) , typeof ( float ) , typeof ( AccentAnalyzer ) , new PropertyMetadata ( 0f ) ) ;
6078
6179 /// <summary>
62- /// Initialize an instance of the <see cref="AccentExtractor "/> class.
80+ /// Initialize an instance of the <see cref="AccentAnalyzer "/> class.
6381 /// </summary>
64- public AccentExtractor ( )
82+ public AccentAnalyzer ( )
6583 {
6684 AccentUpdateCommand = new Command ( UpdateAccent ) ;
6785 }
6886
6987 /// <summary>
70- /// Gets or sets the primary accent color as extracted from the <see cref="Source"/>.
88+ /// Gets the primary accent color as extracted from the <see cref="Source"/>.
7189 /// </summary>
90+ /// <remarks>
91+ /// The most "colorful" found in the image.
92+ /// </remarks>
7293 public Color PrimaryAccentColor
7394 {
7495 get => ( Color ) GetValue ( PrimaryAccentColorProperty ) ;
75- set => SetValue ( PrimaryAccentColorProperty , value ) ;
96+ private set => SetValue ( PrimaryAccentColorProperty , value ) ;
7697 }
7798
7899 /// <summary>
79- /// Gets or sets the secondary accent color as extracted from the <see cref="Source"/>.
100+ /// Gets the secondary accent color as extracted from the <see cref="Source"/>.
80101 /// </summary>
102+ /// <remarks>
103+ /// The second most "colorful" color found in the image.
104+ /// </remarks>
81105 public Color SecondaryAccentColor
82106 {
83107 get => ( Color ) GetValue ( SecondaryAccentColorProperty ) ;
84- set => SetValue ( SecondaryAccentColorProperty , value ) ;
108+ private set => SetValue ( SecondaryAccentColorProperty , value ) ;
85109 }
86110
87111 /// <summary>
88- /// Gets or sets the tertiary accent color as extracted from the <see cref="Source"/>.
112+ /// Gets the tertiary accent color as extracted from the <see cref="Source"/>.
89113 /// </summary>
114+ /// <remarks>
115+ /// The third most "colorful" color found in the image.
116+ /// </remarks>
90117 public Color TertiaryAccentColor
91118 {
92119 get => ( Color ) GetValue ( TertiaryAccentColorProperty ) ;
93- set => SetValue ( TertiaryAccentColorProperty , value ) ;
120+ private set => SetValue ( TertiaryAccentColorProperty , value ) ;
121+ }
122+
123+ /// <summary>
124+ /// Gets the base color as extracted from the <see cref="Source"/>.
125+ /// </summary>
126+ /// <remarks>
127+ /// The least "colorful" color found in the image.
128+ /// </remarks>
129+ public Color BaseColor
130+ {
131+ get => ( Color ) GetValue ( BaseColorProperty ) ;
132+ private set => SetValue ( BaseColorProperty , value ) ;
133+ }
134+
135+ /// <summary>
136+ /// Gets the dominent color as extracted from the <see cref="Source"/>.
137+ /// </summary>
138+ /// <remarks>
139+ /// The most color that takes up the most of the image.
140+ /// </remarks>
141+ public Color DominantColor
142+ {
143+ get => ( Color ) GetValue ( DominantColorProperty ) ;
144+ private set => SetValue ( DominantColorProperty , value ) ;
145+ }
146+
147+ /// <summary>
148+ /// Gets the "colorfulness" of the <see cref="Source"/>.
149+ /// </summary>
150+ /// <remarks>
151+ /// Colorfulness is defined by David Hasler and Sabine Susstrunk's paper on measuring colorfulness
152+ /// <seealso href="https://infoscience.epfl.ch/server/api/core/bitstreams/77f5adab-e825-4995-92db-c9ff4cd8bf5a/content"/>
153+ /// </remarks>
154+ public float Colorfulness
155+ {
156+ get => ( float ) GetValue ( ColorfulnessProperty ) ;
157+ set => SetValue ( ColorfulnessProperty , value ) ;
94158 }
95159
96160 /// <summary>
@@ -151,9 +215,7 @@ private async Task UpdateAccentAsync()
151215 colors = colors [ ..pos ] ;
152216
153217 // Determine most prominent colors and assess colorfulness
154- // Colorfulness is defined by David Hasler and Sabine Susstrunk's paper on measuring colorfulness
155- // https://infoscience.epfl.ch/server/api/core/bitstreams/77f5adab-e825-4995-92db-c9ff4cd8bf5a/content
156- var clusters = KMeansCluster ( colors , 5 ) ;
218+ var clusters = KMeansCluster ( colors , 5 , out var sizes ) ;
157219 var colorfulness = clusters . Select ( color => ( color , FindColorfulness ( color ) ) ) ;
158220
159221 // Select the accent color and convert to color
@@ -162,20 +224,37 @@ private async Task UpdateAccentAsync()
162224 . Select ( x => x . color * 255 )
163225 . Select ( x => Color . FromArgb ( 255 , ( byte ) x . X , ( byte ) x . Y , ( byte ) x . Z ) ) ;
164226
165- // Ensure tertiary population
166- var primary = accentColors . First ( ) ;
227+ // Get primary/secondary/ tertiary accents
228+ var primary = accentColors . First ( ) ;
167229 var secondary = accentColors . ElementAtOrDefault ( 1 ) ;
168230 var tertiary = accentColors . ElementAtOrDefault ( 2 ) ;
231+ var baseColor = accentColors . Last ( ) ;
169232
170- // Set the accent color on the UI thread
171- DispatcherQueue . GetForCurrentThread ( ) . TryEnqueue ( ( ) => UpdateAccentColors ( primary , secondary , tertiary ) ) ;
233+ // Get base color by prominence
234+ var dominant = clusters
235+ . Select ( ( color , i ) => ( color , sizes [ i ] ) )
236+ . MaxBy ( x => x . Item2 ) . color * 255 ;
237+ var dominantColor = Color . FromArgb ( 255 , ( byte ) dominant . X , ( byte ) dominant . Y , ( byte ) dominant . Z ) ;
238+
239+ // Evaluate colorfulness
240+ // TODO: Should this be weighted by cluster sizes?
241+ var overallColorfulness = FindColorfulness ( clusters ) ;
242+
243+ // Set the various properties from the UI thread
244+ UpdateAccentProperties ( primary , secondary , tertiary , baseColor , dominantColor , overallColorfulness ) ;
172245 }
173246
174- private void UpdateAccentColors ( Color primary , Color secondary , Color tertiary )
247+ private void UpdateAccentProperties ( Color primary , Color secondary , Color tertiary , Color baseColor , Color dominantColor , float colorfulness )
175248 {
176- PrimaryAccentColor = primary ;
177- SecondaryAccentColor = secondary ;
178- TertiaryAccentColor = tertiary ;
249+ DispatcherQueue . GetForCurrentThread ( ) . TryEnqueue ( ( ) =>
250+ {
251+ PrimaryAccentColor = primary ;
252+ SecondaryAccentColor = secondary ;
253+ TertiaryAccentColor = tertiary ;
254+ DominantColor = dominantColor ;
255+ BaseColor = baseColor ;
256+ Colorfulness = colorfulness ;
257+ } ) ;
179258 }
180259
181260 private void SetSource ( UIElement ? source )
0 commit comments