diff --git a/src/Avalonia.Controls/ColorPicker/ColorSpectrum/Hsv.cs b/src/Avalonia.Controls/ColorPicker/ColorSpectrum/Hsv.cs
new file mode 100644
index 0000000000..6d9f8440bf
--- /dev/null
+++ b/src/Avalonia.Controls/ColorPicker/ColorSpectrum/Hsv.cs
@@ -0,0 +1,87 @@
+// Portions of this source file are adapted from the WinUI project.
+// (https://github.com/microsoft/microsoft-ui-xaml)
+//
+// Licensed to The Avalonia Project under the MIT License.
+
+using System.Numerics;
+using Avalonia.Media;
+
+namespace Avalonia.Controls.Primitives
+{
+ ///
+ /// Contains and allows modification of Hue, Saturation and Value channel values.
+ ///
+ ///
+ /// The is a specialized struct optimized for permanence and memory:
+ ///
+ /// - This is not a read-only struct like and allows editing the fields
+ /// - Removes the alpha component unnecessary in core calculations
+ /// - No channel value bounds checks or clamping is done.
+ ///
+ ///
+ internal struct Hsv
+ {
+ ///
+ /// The Hue channel value in the range from 0..359.
+ ///
+ public double H;
+
+ ///
+ /// The Saturation channel value in the range from 0..1.
+ ///
+ public double S;
+
+ ///
+ /// The Value channel value in the range from 0..1.
+ ///
+ public double V;
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The Hue channel value in the range from 0..360.
+ /// The Saturation channel value in the range from 0..1.
+ /// The Value channel value in the range from 0..1.
+ public Hsv(double h, double s, double v)
+ {
+ H = h;
+ S = s;
+ V = v;
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// An existing to convert to .
+ public Hsv(HsvColor hsvColor)
+ {
+ H = hsvColor.H;
+ S = hsvColor.S;
+ V = hsvColor.V;
+ }
+
+ ///
+ /// Converts this struct into a standard .
+ ///
+ /// The Alpha channel value in the range from 0..1.
+ /// A new representing this struct.
+ public HsvColor ToHsvColor(double alpha = 1.0)
+ {
+ // Clamping is done automatically in the constructor
+ return HsvColor.FromAhsv(alpha, H, S, V);
+ }
+
+ ///
+ /// Returns the color model equivalent of this color.
+ ///
+ /// The equivalent color.
+ public Rgb ToRgb()
+ {
+ // Instantiating a Color is unfortunately necessary to use existing conversions
+ // Clamping is done internally in the conversion method
+ Color color = HsvColor.ToRgb(H, S, V);
+
+ return new Rgb(color);
+ }
+ }
+}
diff --git a/src/Avalonia.Controls/ColorPicker/ColorSpectrum/Rgb.cs b/src/Avalonia.Controls/ColorPicker/ColorSpectrum/Rgb.cs
new file mode 100644
index 0000000000..c2358b7bee
--- /dev/null
+++ b/src/Avalonia.Controls/ColorPicker/ColorSpectrum/Rgb.cs
@@ -0,0 +1,94 @@
+// Portions of this source file are adapted from the WinUI project.
+// (https://github.com/microsoft/microsoft-ui-xaml)
+//
+// Licensed to The Avalonia Project under the MIT License.
+
+using System;
+using Avalonia.Media;
+using Avalonia.Utilities;
+
+namespace Avalonia.Controls.Primitives
+{
+ ///
+ /// Contains and allows modification of Red, Green and Blue channel values.
+ ///
+ ///
+ /// The is a specialized struct optimized for permanence and memory:
+ ///
+ /// - This is not a read-only struct like and allows editing the fields
+ /// - Removes the alpha component unnecessary in core calculations
+ /// - Normalizes RGB channel values in the range of 0..1 to simplify calculations.
+ /// - No channel value bounds checks or clamping is done.
+ ///
+ ///
+ internal struct Rgb
+ {
+ ///
+ /// The Red channel value in the range from 0..1.
+ ///
+ public double R;
+
+ ///
+ /// The Green channel value in the range from 0..1.
+ ///
+ public double G;
+
+ ///
+ /// The Blue channel value in the range from 0..1.
+ ///
+ public double B;
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The Red channel value in the range from 0..1.
+ /// The Green channel value in the range from 0..1.
+ /// The Blue channel value in the range from 0..1.
+ public Rgb(double r, double g, double b)
+ {
+ R = r;
+ G = g;
+ B = b;
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// An existing to convert to .
+ public Rgb(Color color)
+ {
+ R = color.R / 255.0;
+ G = color.G / 255.0;
+ B = color.B / 255.0;
+ }
+
+ ///
+ /// Converts this struct into a standard .
+ ///
+ /// The Alpha channel value in the range from 0..1.
+ /// A new representing this struct.
+ public Color ToColor(double alpha = 1.0)
+ {
+ return Color.FromArgb(
+ (byte)MathUtilities.Clamp(alpha * 255.0, 0x00, 0xFF),
+ (byte)MathUtilities.Clamp(R * 255.0, 0x00, 0xFF),
+ (byte)MathUtilities.Clamp(G * 255.0, 0x00, 0xFF),
+ (byte)MathUtilities.Clamp(B * 255.0, 0x00, 0xFF));
+ }
+
+ ///
+ /// Returns the color model equivalent of this color.
+ ///
+ /// The equivalent color.
+ public Hsv ToHsv()
+ {
+ // Instantiating an HsvColor is unfortunately necessary to use existing conversions
+ HsvColor hsvColor = HsvColor.FromRgb(
+ MathUtilities.Clamp(R, 0.0, 1.0),
+ MathUtilities.Clamp(G, 0.0, 1.0),
+ MathUtilities.Clamp(B, 0.0, 1.0));
+
+ return new Hsv(hsvColor);
+ }
+ }
+}