From b40cc526fd99d9d7ff1007d1aa7d03ef229ca620 Mon Sep 17 00:00:00 2001 From: Avishai Dernis Date: Mon, 22 Dec 2025 18:39:23 +0200 Subject: [PATCH 1/8] Refactored color sampling to utilize ColorSource abstraction --- .../AccentColorSample.xaml | 97 ++++++++++--------- .../ColorPaletteSampler/BaseColorSample.xaml | 97 ++++++++++--------- .../ColorWeightSample.xaml | 97 ++++++++++--------- .../MultiplePaletteSelectorSample.xaml | 96 +++++++++--------- .../ColorPaletteSampler.Properties.cs | 8 +- .../ColorPaletteSampler.cs | 23 +---- .../ColorSources/ColorSource.cs | 28 ++++++ .../ColorSources/UIColorSource.cs | 65 +++++++++++++ 8 files changed, 297 insertions(+), 214 deletions(-) create mode 100644 components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/ColorSource.cs create mode 100644 components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/UIColorSource.cs diff --git a/components/ColorAnalyzer/samples/ColorPaletteSampler/AccentColorSample.xaml b/components/ColorAnalyzer/samples/ColorPaletteSampler/AccentColorSample.xaml index 5ae519283..07d4ee6a9 100644 --- a/components/ColorAnalyzer/samples/ColorPaletteSampler/AccentColorSample.xaml +++ b/components/ColorAnalyzer/samples/ColorPaletteSampler/AccentColorSample.xaml @@ -1,20 +1,22 @@ - + - - + + + + + @@ -29,27 +31,27 @@ - - + + - + - + @@ -61,43 +63,44 @@ - + - + - + - + - + - + - + diff --git a/components/ColorAnalyzer/samples/ColorPaletteSampler/BaseColorSample.xaml b/components/ColorAnalyzer/samples/ColorPaletteSampler/BaseColorSample.xaml index 6f37840d8..17dead11e 100644 --- a/components/ColorAnalyzer/samples/ColorPaletteSampler/BaseColorSample.xaml +++ b/components/ColorAnalyzer/samples/ColorPaletteSampler/BaseColorSample.xaml @@ -1,20 +1,22 @@ - + - - + + + + + @@ -29,27 +31,27 @@ - - + + - + - + @@ -61,43 +63,44 @@ - + - + - + - + - + - + - + diff --git a/components/ColorAnalyzer/samples/ColorPaletteSampler/ColorWeightSample.xaml b/components/ColorAnalyzer/samples/ColorPaletteSampler/ColorWeightSample.xaml index 145d29b73..695989faf 100644 --- a/components/ColorAnalyzer/samples/ColorPaletteSampler/ColorWeightSample.xaml +++ b/components/ColorAnalyzer/samples/ColorPaletteSampler/ColorWeightSample.xaml @@ -1,20 +1,22 @@ - + - - + + + + + @@ -29,27 +31,27 @@ - - + + - + - + @@ -61,43 +63,44 @@ - + - + - + - + - + - + - + diff --git a/components/ColorAnalyzer/samples/ColorPaletteSampler/MultiplePaletteSelectorSample.xaml b/components/ColorAnalyzer/samples/ColorPaletteSampler/MultiplePaletteSelectorSample.xaml index c99816386..e73b6ece3 100644 --- a/components/ColorAnalyzer/samples/ColorPaletteSampler/MultiplePaletteSelectorSample.xaml +++ b/components/ColorAnalyzer/samples/ColorPaletteSampler/MultiplePaletteSelectorSample.xaml @@ -1,24 +1,24 @@ - + - - - - + + + + + + + @@ -33,27 +33,27 @@ - - + + - + - + @@ -64,37 +64,37 @@ - + - + - + - + - + - + diff --git a/components/ColorAnalyzer/src/ColorPaletteSampler/ColorPaletteSampler.Properties.cs b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorPaletteSampler.Properties.cs index 488d46365..1085cc65b 100644 --- a/components/ColorAnalyzer/src/ColorPaletteSampler/ColorPaletteSampler.Properties.cs +++ b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorPaletteSampler.Properties.cs @@ -10,7 +10,7 @@ public partial class ColorPaletteSampler /// Gets the for the property. /// public static readonly DependencyProperty SourceProperty = - DependencyProperty.Register(nameof(Source), typeof(UIElement), typeof(ColorPaletteSampler), new PropertyMetadata(null, OnSourceChanged)); + DependencyProperty.Register(nameof(Source), typeof(ColorSource), typeof(ColorPaletteSampler), new PropertyMetadata(null, OnSourceChanged)); /// /// An event fired when the and are updated. @@ -18,11 +18,11 @@ public partial class ColorPaletteSampler public event EventHandler? PaletteUpdated; /// - /// Gets or sets the source sampled for a color palette. + /// Gets or sets the for the color palette. /// - public UIElement? Source + public ColorSource? Source { - get => (UIElement)GetValue(SourceProperty); + get => (ColorSource)GetValue(SourceProperty); set => SetValue(SourceProperty, value); } diff --git a/components/ColorAnalyzer/src/ColorPaletteSampler/ColorPaletteSampler.cs b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorPaletteSampler.cs index bfa4b68ab..17c88bf96 100644 --- a/components/ColorAnalyzer/src/ColorPaletteSampler/ColorPaletteSampler.cs +++ b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorPaletteSampler.cs @@ -91,32 +91,13 @@ public async Task UpdatePaletteAsync() private async Task SampleSourcePixelColorsAsync(int sampleCount) { - // Ensure the source is populated if (Source is null) return []; - // Grab actual size - // If actualSize is 0, replace with 1:1 aspect ratio - var sourceSize = Source.ActualSize; - sourceSize = sourceSize != Vector2.Zero ? sourceSize : Vector2.One; - - // Calculate size of scaled rerender using the actual size - // scaled down to the sample count, maintaining aspect ration - var sourceArea = sourceSize.X * sourceSize.Y; - var sampleScale = MathF.Sqrt(sampleCount / sourceArea); - var sampleSize = sourceSize * sampleScale; - - // Rerender the UIElement to a bitmap of about sampleCount pixels - // Note: RenderTargetBitmap is not supported with Uno Platform. - var bitmap = new RenderTargetBitmap(); - await bitmap.RenderAsync(Source, (int)sampleSize.X, (int)sampleSize.Y); - - // Create a stream from the bitmap - var pixels = await bitmap.GetPixelsAsync(); - var pixelByteStream = pixels.AsStream(); + var pixelByteStream = await Source.GetPixelStreamAsync(sampleCount); // Something went wrong - if (pixelByteStream.Length == 0) + if (pixelByteStream is null || pixelByteStream.Length == 0) return []; // Read the stream into a a color array diff --git a/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/ColorSource.cs b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/ColorSource.cs new file mode 100644 index 000000000..03cbb4ebd --- /dev/null +++ b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/ColorSource.cs @@ -0,0 +1,28 @@ +// 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 CommunityToolkit.WinUI.Helpers; + +/// +/// A base class for a color data source in the . +/// +public abstract class ColorSource : DependencyObject +{ + /// + /// An event invoked when the source pixels changed. + /// + public event EventHandler? SourceUpdated; + + /// + /// Retreives the pixels from the source as a stream + /// + /// The approximate number of samples the method should return. + /// A stream of pixels in rgba format. + public abstract Task GetPixelStreamAsync(int sampleCount); + + /// + /// Invokes the event. + /// + protected void InvokeSourceUpdated() => SourceUpdated?.Invoke(this, EventArgs.Empty); +} diff --git a/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/UIColorSource.cs b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/UIColorSource.cs new file mode 100644 index 000000000..cd7f111ae --- /dev/null +++ b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/UIColorSource.cs @@ -0,0 +1,65 @@ +// 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. + + +using System.Numerics; + +namespace CommunityToolkit.WinUI.Helpers; + +/// +/// A that samples the +/// +public class UIColorSource : ColorSource +{ + /// + /// Gets the for the property. + /// + public static readonly DependencyProperty SourceProperty = + DependencyProperty.Register(nameof(Source), typeof(UIElement), typeof(UIColorSource), new PropertyMetadata(null, OnSourceChanged)); + + /// + /// Gets or sets the source sampled for a color palette. + /// + public UIElement? Source + { + get => (UIElement)GetValue(SourceProperty); + set => SetValue(SourceProperty, value); + } + + /// + public override async Task GetPixelStreamAsync(int sampleCount) + { + // Ensure the source is populated + if (Source is null) + return null; + + // Grab actual size + // If actualSize is 0, replace with 1:1 aspect ratio + var sourceSize = Source.ActualSize; + sourceSize = sourceSize != Vector2.Zero ? sourceSize : Vector2.One; + + // Calculate size of scaled rerender using the actual size + // scaled down to the sample count, maintaining aspect ration + var sourceArea = sourceSize.X * sourceSize.Y; + var sampleScale = MathF.Sqrt(sampleCount / sourceArea); + var sampleSize = sourceSize * sampleScale; + + // Rerender the UIElement to a bitmap of about sampleCount pixels + // Note: RenderTargetBitmap is not supported with Uno Platform. + var bitmap = new RenderTargetBitmap(); + await bitmap.RenderAsync(Source, (int)sampleSize.X, (int)sampleSize.Y); + + // Create a stream from the bitmap + var pixels = await bitmap.GetPixelsAsync(); + return pixels.AsStream(); + } + + private static void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is not UIColorSource source) + return; + + source.InvokeSourceUpdated(); + } +} From cea1b5da7ea7cf02d6faf7ce126052b61d17ec47 Mon Sep 17 00:00:00 2001 From: Avishai Dernis Date: Mon, 22 Dec 2025 18:43:09 +0200 Subject: [PATCH 2/8] Fixed source updated not being invoked --- .../ColorPaletteSampler.Properties.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/components/ColorAnalyzer/src/ColorPaletteSampler/ColorPaletteSampler.Properties.cs b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorPaletteSampler.Properties.cs index 1085cc65b..755ea620a 100644 --- a/components/ColorAnalyzer/src/ColorPaletteSampler/ColorPaletteSampler.Properties.cs +++ b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorPaletteSampler.Properties.cs @@ -45,6 +45,21 @@ private static void OnSourceChanged(DependencyObject d, DependencyPropertyChange if (d is not ColorPaletteSampler analyzer) return; + if (e.OldValue is ColorSource oldSource) + { + oldSource.SourceUpdated -= analyzer.OnSourceUpdated; + } + + if (e.NewValue is ColorSource newSource) + { + newSource.SourceUpdated += analyzer.OnSourceUpdated; + } + _ = analyzer.UpdatePaletteAsync(); } + + private void OnSourceUpdated(object? sender, EventArgs e) + { + _ = UpdatePaletteAsync(); + } } From e5d1ab02e997a23115c25fe9b8991690e56b256e Mon Sep 17 00:00:00 2001 From: Avishai Dernis Date: Mon, 22 Dec 2025 18:56:04 +0200 Subject: [PATCH 3/8] Added StreamColorSource as a ColorSource option --- .../ColorPaletteSampler.cs | 2 - .../ColorSources/StreamColorSource.cs | 43 +++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/StreamColorSource.cs diff --git a/components/ColorAnalyzer/src/ColorPaletteSampler/ColorPaletteSampler.cs b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorPaletteSampler.cs index e372a785a..f8a8ef348 100644 --- a/components/ColorAnalyzer/src/ColorPaletteSampler/ColorPaletteSampler.cs +++ b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorPaletteSampler.cs @@ -12,8 +12,6 @@ #endif using System.Numerics; -using System.Windows.Input; -using Windows.UI; namespace CommunityToolkit.WinUI.Helpers; diff --git a/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/StreamColorSource.cs b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/StreamColorSource.cs new file mode 100644 index 000000000..72578efb9 --- /dev/null +++ b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/StreamColorSource.cs @@ -0,0 +1,43 @@ +// 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. + +using CommunityToolkit.WinUI.Helpers; + +namespace CommunityToolkit.WinUI.ColorAnalyzerRns.ColorPaletteSampler.ColorSources; + +/// +/// A that uses a directly as a source. +/// +public class StreamColorSource : ColorSource +{ + /// + /// Gets the for the property. + /// + public static readonly DependencyProperty SourceProperty = + DependencyProperty.Register(nameof(Source), typeof(UIElement), typeof(StreamColorSource), new PropertyMetadata(null, OnSourceChanged)); + + /// + /// Gets or sets the source sampled for a color palette. + /// + public Stream? Source + { + get => (Stream)GetValue(SourceProperty); + set => SetValue(SourceProperty, value); + } + + /// + public override async Task GetPixelStreamAsync(int sampleCount) + { + // TODO: Sample the data + return Source; + } + + private static void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is not StreamColorSource source) + return; + + source.InvokeSourceUpdated(); + } +} From 6fc97865542a88c9974c73d64d6e8f76eafd2cf0 Mon Sep 17 00:00:00 2001 From: Avishai Dernis Date: Fri, 26 Dec 2025 16:45:25 +0200 Subject: [PATCH 4/8] WIP Added Url color source --- .../AccentColorSample.xaml | 3 +- .../ColorPaletteSamplerToolkitSample.cs | 9 ++++ .../ImageOptionsPane.xaml.cs | 1 + .../ColorPaletteSampler.cs | 2 +- .../ColorSources/ColorSource.cs | 4 +- .../ColorSources/StreamColorSource.cs | 11 ++-- .../ColorSources/UIColorSource.cs | 6 +-- .../ColorSources/UrlColorSource.cs | 52 +++++++++++++++++++ 8 files changed, 77 insertions(+), 11 deletions(-) create mode 100644 components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/UrlColorSource.cs diff --git a/components/ColorAnalyzer/samples/ColorPaletteSampler/AccentColorSample.xaml b/components/ColorAnalyzer/samples/ColorPaletteSampler/AccentColorSample.xaml index 07d4ee6a9..6e15f6979 100644 --- a/components/ColorAnalyzer/samples/ColorPaletteSampler/AccentColorSample.xaml +++ b/components/ColorAnalyzer/samples/ColorPaletteSampler/AccentColorSample.xaml @@ -14,7 +14,8 @@ - + + diff --git a/components/ColorAnalyzer/samples/ColorPaletteSampler/ColorPaletteSamplerToolkitSample.cs b/components/ColorAnalyzer/samples/ColorPaletteSampler/ColorPaletteSamplerToolkitSample.cs index dbd0d7f74..dacbb12b1 100644 --- a/components/ColorAnalyzer/samples/ColorPaletteSampler/ColorPaletteSamplerToolkitSample.cs +++ b/components/ColorAnalyzer/samples/ColorPaletteSampler/ColorPaletteSamplerToolkitSample.cs @@ -9,10 +9,19 @@ public abstract partial class ColorPaletteSamplerToolkitSampleBase : Page public static readonly DependencyProperty SelectedImageProperty = DependencyProperty.Register(nameof(SelectedImage), typeof(ImageSource), typeof(ColorPaletteSamplerToolkitSampleBase), new PropertyMetadata(null)); + public static readonly DependencyProperty SelectedImageUrlProperty = + DependencyProperty.Register(nameof(SelectedImageUrl), typeof(string), typeof(ColorPaletteSamplerToolkitSampleBase), new PropertyMetadata(null)); + public ColorPaletteSamplerToolkitSampleBase() { } + public string? SelectedImageUrl + { + get => (string?)GetValue(SelectedImageUrlProperty); + set => SetValue(SelectedImageUrlProperty, value); + } + public ImageSource SelectedImage { get => (ImageSource)GetValue(SelectedImageProperty); diff --git a/components/ColorAnalyzer/samples/ColorPaletteSampler/ImageOptionsPane.xaml.cs b/components/ColorAnalyzer/samples/ColorPaletteSampler/ImageOptionsPane.xaml.cs index 5b27b8bc7..ec699570a 100644 --- a/components/ColorAnalyzer/samples/ColorPaletteSampler/ImageOptionsPane.xaml.cs +++ b/components/ColorAnalyzer/samples/ColorPaletteSampler/ImageOptionsPane.xaml.cs @@ -43,6 +43,7 @@ private void GridView_ItemClick(object sender, ItemClickEventArgs e) private void SetImage(Uri uri) { + _sample.SelectedImageUrl = uri.AbsoluteUri; _sample.SelectedImage = new BitmapImage(uri); } } diff --git a/components/ColorAnalyzer/src/ColorPaletteSampler/ColorPaletteSampler.cs b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorPaletteSampler.cs index f8a8ef348..6763563c0 100644 --- a/components/ColorAnalyzer/src/ColorPaletteSampler/ColorPaletteSampler.cs +++ b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorPaletteSampler.cs @@ -96,7 +96,7 @@ private async Task SampleSourcePixelColorsAsync(int sampleCount) if (Source is null) return []; - var pixelByteStream = await Source.GetPixelStreamAsync(sampleCount); + var pixelByteStream = await Source.GetPixelDataAsync(sampleCount); // Something went wrong if (pixelByteStream is null || pixelByteStream.Length == 0) diff --git a/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/ColorSource.cs b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/ColorSource.cs index 03cbb4ebd..a1919370d 100644 --- a/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/ColorSource.cs +++ b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/ColorSource.cs @@ -17,9 +17,9 @@ public abstract class ColorSource : DependencyObject /// /// Retreives the pixels from the source as a stream /// - /// The approximate number of samples the method should return. + /// The number of samples requested by the . /// A stream of pixels in rgba format. - public abstract Task GetPixelStreamAsync(int sampleCount); + public abstract Task GetPixelDataAsync(int requestedSamples); /// /// Invokes the event. diff --git a/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/StreamColorSource.cs b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/StreamColorSource.cs index 72578efb9..c3d0229d0 100644 --- a/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/StreamColorSource.cs +++ b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/StreamColorSource.cs @@ -2,9 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using CommunityToolkit.WinUI.Helpers; +using Windows.Graphics.Imaging; -namespace CommunityToolkit.WinUI.ColorAnalyzerRns.ColorPaletteSampler.ColorSources; +namespace CommunityToolkit.WinUI.Helpers; /// /// A that uses a directly as a source. @@ -27,10 +27,13 @@ public Stream? Source } /// - public override async Task GetPixelStreamAsync(int sampleCount) + public override async Task GetPixelDataAsync(int requestedSamples) { // TODO: Sample the data - return Source; + var decoder = await BitmapDecoder.CreateAsync(Source.AsRandomAccessStream()); + var pixelData = await decoder.GetPixelDataAsync(); + var bytes = pixelData.DetachPixelData(); + return new MemoryStream(bytes); } private static void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) diff --git a/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/UIColorSource.cs b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/UIColorSource.cs index cd7f111ae..df49ea9e9 100644 --- a/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/UIColorSource.cs +++ b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/UIColorSource.cs @@ -8,7 +8,7 @@ namespace CommunityToolkit.WinUI.Helpers; /// -/// A that samples the +/// A that gets pixel data from a . /// public class UIColorSource : ColorSource { @@ -28,7 +28,7 @@ public UIElement? Source } /// - public override async Task GetPixelStreamAsync(int sampleCount) + public override async Task GetPixelDataAsync(int requestedSamples) { // Ensure the source is populated if (Source is null) @@ -42,7 +42,7 @@ public UIElement? Source // Calculate size of scaled rerender using the actual size // scaled down to the sample count, maintaining aspect ration var sourceArea = sourceSize.X * sourceSize.Y; - var sampleScale = MathF.Sqrt(sampleCount / sourceArea); + var sampleScale = MathF.Sqrt(requestedSamples / sourceArea); var sampleSize = sourceSize * sampleScale; // Rerender the UIElement to a bitmap of about sampleCount pixels diff --git a/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/UrlColorSource.cs b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/UrlColorSource.cs new file mode 100644 index 000000000..a2fd9ceab --- /dev/null +++ b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/UrlColorSource.cs @@ -0,0 +1,52 @@ +// 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. + + +using Windows.Graphics.Imaging; +using Windows.Storage.Streams; + +namespace CommunityToolkit.WinUI.Helpers; + +/// +/// A that that loads pixel data from a url. +/// +public class UrlColorSource : ColorSource +{ + /// + /// Gets the for the property. + /// + public static readonly DependencyProperty SourceProperty = + DependencyProperty.Register(nameof(Source), typeof(string), typeof(UrlColorSource), new PropertyMetadata(null, OnSourceChanged)); + + /// + /// Gets or sets the url source sampled for a color palette. + /// + public string? Source + { + get => (string?)GetValue(SourceProperty); + set => SetValue(SourceProperty, value); + } + + /// + public override async Task GetPixelDataAsync(int requestedSamples) + { + if (Source is null) + return null; + + // TODO: Sample the data + var stream = await RandomAccessStreamReference.CreateFromUri(new Uri(Source)).OpenReadAsync(); + var decoder = await BitmapDecoder.CreateAsync(stream); + var pixelData = await decoder.GetPixelDataAsync(); + var bytes = pixelData.DetachPixelData(); + return new MemoryStream(bytes); + } + + private static void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is not UrlColorSource source) + return; + + source.InvokeSourceUpdated(); + } +} From 11af2d4238baaaf8508d8946ff4caffee9e12c3b Mon Sep 17 00:00:00 2001 From: Avishai Dernis Date: Fri, 26 Dec 2025 17:00:04 +0200 Subject: [PATCH 5/8] Added sample limiting to ColorPaletteSampler --- .../src/ColorPaletteSampler/ColorPaletteSampler.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/components/ColorAnalyzer/src/ColorPaletteSampler/ColorPaletteSampler.cs b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorPaletteSampler.cs index 6763563c0..87496fff6 100644 --- a/components/ColorAnalyzer/src/ColorPaletteSampler/ColorPaletteSampler.cs +++ b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorPaletteSampler.cs @@ -104,11 +104,13 @@ private async Task SampleSourcePixelColorsAsync(int sampleCount) // Read the stream into a a color array const int bytesPerPixel = 4; - var samples = new Vector3[(int)pixelByteStream.Length / bytesPerPixel]; + var samples = new Vector3[sampleCount]; // Iterate through the stream reading a pixel (4 bytes) at a time // and storing them as a Vector3. Opacity info is dropped. int colorIndex = 0; + var step = (pixelByteStream.Length / sampleCount); + step -= step % 4; #if NET7_0_OR_GREATER Span pixelBytes = stackalloc byte[bytesPerPixel]; while (pixelByteStream.Read(pixelBytes) == bytesPerPixel) @@ -124,6 +126,9 @@ private async Task SampleSourcePixelColorsAsync(int sampleCount) // Take the red, green, and blue channels to make a floating-point space color. samples[colorIndex] = new Vector3(pixelBytes[2], pixelBytes[1], pixelBytes[0]) / byte.MaxValue; colorIndex++; + + // Advance by step amount + pixelByteStream.Position += step; } // If we skipped any pixels, trim the span From 8817e06f7ec05f71990d7a4644547bf1e32b598e Mon Sep 17 00:00:00 2001 From: Avishai Dernis Date: Fri, 26 Dec 2025 17:28:30 +0200 Subject: [PATCH 6/8] WIP Preparing to add UNO support to ColorPaletteSampler --- .../samples/ColorPaletteSampler/BaseColorSample.xaml | 3 ++- .../samples/ColorPaletteSampler/ColorWeightSample.xaml | 3 ++- .../MultiplePaletteSelectorSample.xaml | 3 ++- .../src/ColorPaletteSampler/ColorSources/ColorSource.cs | 2 +- .../ColorPaletteSampler/ColorSources/StreamColorSource.cs | 7 ++++++- .../src/ColorPaletteSampler/ColorSources/UIColorSource.cs | 3 +++ .../ColorPaletteSampler/ColorSources/UrlColorSource.cs | 7 ++++++- .../PaletteSelectors/ColorPaletteSelector.cs | 2 +- components/ColorAnalyzer/src/MultiTarget.props | 8 ++++---- global.json | 2 +- 10 files changed, 28 insertions(+), 12 deletions(-) diff --git a/components/ColorAnalyzer/samples/ColorPaletteSampler/BaseColorSample.xaml b/components/ColorAnalyzer/samples/ColorPaletteSampler/BaseColorSample.xaml index 17dead11e..e6f1322f5 100644 --- a/components/ColorAnalyzer/samples/ColorPaletteSampler/BaseColorSample.xaml +++ b/components/ColorAnalyzer/samples/ColorPaletteSampler/BaseColorSample.xaml @@ -14,7 +14,8 @@ - + + diff --git a/components/ColorAnalyzer/samples/ColorPaletteSampler/ColorWeightSample.xaml b/components/ColorAnalyzer/samples/ColorPaletteSampler/ColorWeightSample.xaml index 695989faf..1b2135a93 100644 --- a/components/ColorAnalyzer/samples/ColorPaletteSampler/ColorWeightSample.xaml +++ b/components/ColorAnalyzer/samples/ColorPaletteSampler/ColorWeightSample.xaml @@ -14,7 +14,8 @@ - + + diff --git a/components/ColorAnalyzer/samples/ColorPaletteSampler/MultiplePaletteSelectorSample.xaml b/components/ColorAnalyzer/samples/ColorPaletteSampler/MultiplePaletteSelectorSample.xaml index e73b6ece3..324dc2844 100644 --- a/components/ColorAnalyzer/samples/ColorPaletteSampler/MultiplePaletteSelectorSample.xaml +++ b/components/ColorAnalyzer/samples/ColorPaletteSampler/MultiplePaletteSelectorSample.xaml @@ -14,7 +14,8 @@ - + + diff --git a/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/ColorSource.cs b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/ColorSource.cs index a1919370d..f8e04cb2d 100644 --- a/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/ColorSource.cs +++ b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/ColorSource.cs @@ -7,7 +7,7 @@ namespace CommunityToolkit.WinUI.Helpers; /// /// A base class for a color data source in the . /// -public abstract class ColorSource : DependencyObject +public abstract partial class ColorSource : DependencyObject { /// /// An event invoked when the source pixels changed. diff --git a/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/StreamColorSource.cs b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/StreamColorSource.cs index c3d0229d0..eca0200f1 100644 --- a/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/StreamColorSource.cs +++ b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/StreamColorSource.cs @@ -29,11 +29,16 @@ public Stream? Source /// public override async Task GetPixelDataAsync(int requestedSamples) { - // TODO: Sample the data +#if !HAS_UNO var decoder = await BitmapDecoder.CreateAsync(Source.AsRandomAccessStream()); var pixelData = await decoder.GetPixelDataAsync(); var bytes = pixelData.DetachPixelData(); return new MemoryStream(bytes); +#else + // NOTE: This assumes raw pixel data. + // TODO: Uses some form of image processing + return Source; +#endif } private static void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) diff --git a/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/UIColorSource.cs b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/UIColorSource.cs index df49ea9e9..baf729472 100644 --- a/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/UIColorSource.cs +++ b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/UIColorSource.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#if !HAS_UNO using System.Numerics; @@ -63,3 +64,5 @@ private static void OnSourceChanged(DependencyObject d, DependencyPropertyChange source.InvokeSourceUpdated(); } } + +#endif diff --git a/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/UrlColorSource.cs b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/UrlColorSource.cs index a2fd9ceab..42f48379e 100644 --- a/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/UrlColorSource.cs +++ b/components/ColorAnalyzer/src/ColorPaletteSampler/ColorSources/UrlColorSource.cs @@ -34,12 +34,17 @@ public string? Source if (Source is null) return null; - // TODO: Sample the data var stream = await RandomAccessStreamReference.CreateFromUri(new Uri(Source)).OpenReadAsync(); +#if !HAS_UNO var decoder = await BitmapDecoder.CreateAsync(stream); var pixelData = await decoder.GetPixelDataAsync(); var bytes = pixelData.DetachPixelData(); return new MemoryStream(bytes); +#else + // NOTE: This assumes raw pixel data. + // TODO: Uses some form of image processing + return stream.AsStream(); +#endif } private static void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) diff --git a/components/ColorAnalyzer/src/ColorPaletteSampler/PaletteSelectors/ColorPaletteSelector.cs b/components/ColorAnalyzer/src/ColorPaletteSampler/PaletteSelectors/ColorPaletteSelector.cs index 13015d8f8..78ba92a41 100644 --- a/components/ColorAnalyzer/src/ColorPaletteSampler/PaletteSelectors/ColorPaletteSelector.cs +++ b/components/ColorAnalyzer/src/ColorPaletteSampler/PaletteSelectors/ColorPaletteSelector.cs @@ -9,7 +9,7 @@ namespace CommunityToolkit.WinUI.Helpers; /// /// A base class for selecting colors from a palette extracted by the . /// -public abstract class ColorPaletteSelector : DependencyObject +public abstract partial class ColorPaletteSelector : DependencyObject { private IEnumerable? _palette; diff --git a/components/ColorAnalyzer/src/MultiTarget.props b/components/ColorAnalyzer/src/MultiTarget.props index fff19e9d3..55cf440ef 100644 --- a/components/ColorAnalyzer/src/MultiTarget.props +++ b/components/ColorAnalyzer/src/MultiTarget.props @@ -1,10 +1,10 @@ - - - uwp;wasdk; - + uwp;wasdk; + diff --git a/global.json b/global.json index 27a187755..5d98085d1 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "9.0.101", + "version": "10.0.101", "rollForward": "latestFeature" }, "msbuild-sdks": From e4fcd6c9e78ca0364105dac69155da3deef98229 Mon Sep 17 00:00:00 2001 From: Avishai Dernis Date: Fri, 26 Dec 2025 17:29:41 +0200 Subject: [PATCH 7/8] Apply XAML styling --- .../AccentColorSample.xaml | 96 +++++++++---------- .../ColorPaletteSampler/BaseColorSample.xaml | 96 +++++++++---------- .../ColorWeightSample.xaml | 96 +++++++++---------- .../MultiplePaletteSelectorSample.xaml | 95 +++++++++--------- 4 files changed, 189 insertions(+), 194 deletions(-) diff --git a/components/ColorAnalyzer/samples/ColorPaletteSampler/AccentColorSample.xaml b/components/ColorAnalyzer/samples/ColorPaletteSampler/AccentColorSample.xaml index 6e15f6979..c3b5d7a7e 100644 --- a/components/ColorAnalyzer/samples/ColorPaletteSampler/AccentColorSample.xaml +++ b/components/ColorAnalyzer/samples/ColorPaletteSampler/AccentColorSample.xaml @@ -1,23 +1,22 @@ - - + + - - + - + @@ -32,27 +31,27 @@ - - + + - + - + @@ -64,44 +63,43 @@ - + - + - + - + - + - + - + diff --git a/components/ColorAnalyzer/samples/ColorPaletteSampler/BaseColorSample.xaml b/components/ColorAnalyzer/samples/ColorPaletteSampler/BaseColorSample.xaml index e6f1322f5..ff947e126 100644 --- a/components/ColorAnalyzer/samples/ColorPaletteSampler/BaseColorSample.xaml +++ b/components/ColorAnalyzer/samples/ColorPaletteSampler/BaseColorSample.xaml @@ -1,23 +1,22 @@ - - + + - - + - + @@ -32,27 +31,27 @@ - - + + - + - + @@ -64,44 +63,43 @@ - + - + - + - + - + - + - + diff --git a/components/ColorAnalyzer/samples/ColorPaletteSampler/ColorWeightSample.xaml b/components/ColorAnalyzer/samples/ColorPaletteSampler/ColorWeightSample.xaml index 1b2135a93..3ac6efb08 100644 --- a/components/ColorAnalyzer/samples/ColorPaletteSampler/ColorWeightSample.xaml +++ b/components/ColorAnalyzer/samples/ColorPaletteSampler/ColorWeightSample.xaml @@ -1,23 +1,22 @@ - - + + - - + - + @@ -32,27 +31,27 @@ - - + + - + - + @@ -64,44 +63,43 @@ - + - + - + - + - + - + - + diff --git a/components/ColorAnalyzer/samples/ColorPaletteSampler/MultiplePaletteSelectorSample.xaml b/components/ColorAnalyzer/samples/ColorPaletteSampler/MultiplePaletteSelectorSample.xaml index 324dc2844..c51f45792 100644 --- a/components/ColorAnalyzer/samples/ColorPaletteSampler/MultiplePaletteSelectorSample.xaml +++ b/components/ColorAnalyzer/samples/ColorPaletteSampler/MultiplePaletteSelectorSample.xaml @@ -1,25 +1,26 @@ - - + + - - + - - - + + + @@ -34,27 +35,27 @@ - - + + - + - + @@ -65,37 +66,37 @@ - + - + - + - + - + - + From db31aeb132f65901da131ac2011f31d49c8a48c5 Mon Sep 17 00:00:00 2001 From: Avishai Dernis Date: Thu, 8 Jan 2026 01:27:52 +0200 Subject: [PATCH 8/8] Reverted global .NET SDK version to 9.0.101 --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index 5d98085d1..27a187755 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "10.0.101", + "version": "9.0.101", "rollForward": "latestFeature" }, "msbuild-sdks":