diff --git a/src/ImageSharp/Primitives/ColorMatrix.Impl.cs b/src/ImageSharp/Primitives/ColorMatrix.Impl.cs
new file mode 100644
index 0000000000..d71f392730
--- /dev/null
+++ b/src/ImageSharp/Primitives/ColorMatrix.Impl.cs
@@ -0,0 +1,209 @@
+// Copyright (c) Six Labors.
+// Licensed under the Six Labors Split License.
+
+#if NET7_0_OR_GREATER
+#pragma warning disable SA1117 // Parameters should be on same line or separate lines
+using System.Diagnostics.CodeAnalysis;
+using System.Numerics;
+using System.Runtime.CompilerServices;
+
+namespace SixLabors.ImageSharp;
+
+///
+/// A structure encapsulating a 5x4 matrix used for transforming the color and alpha components of an image.
+///
+public partial struct ColorMatrix
+{
+ [UnscopedRef]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal ref Impl AsImpl() => ref Unsafe.As(ref this);
+
+ [UnscopedRef]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal readonly ref readonly Impl AsROImpl() => ref Unsafe.As(ref Unsafe.AsRef(in this));
+
+ internal struct Impl : IEquatable
+ {
+ public Vector4 X;
+ public Vector4 Y;
+ public Vector4 Z;
+ public Vector4 W;
+ public Vector4 V;
+
+ public static Impl Identity
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ Impl result;
+
+ result.X = Vector4.UnitX;
+ result.Y = Vector4.UnitY;
+ result.Z = Vector4.UnitZ;
+ result.W = Vector4.UnitW;
+ result.V = Vector4.Zero;
+
+ return result;
+ }
+ }
+
+ public readonly bool IsIdentity
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get =>
+ (this.X == Vector4.UnitX)
+ && (this.Y == Vector4.UnitY)
+ && (this.Z == Vector4.UnitZ)
+ && (this.W == Vector4.UnitW)
+ && (this.V == Vector4.Zero);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Impl operator +(in Impl left, in Impl right)
+ {
+ Impl result;
+
+ result.X = left.X + right.X;
+ result.Y = left.Y + right.Y;
+ result.Z = left.Z + right.Z;
+ result.W = left.W + right.W;
+ result.V = left.V + right.V;
+
+ return result;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Impl operator -(in Impl left, in Impl right)
+ {
+ Impl result;
+
+ result.X = left.X - right.X;
+ result.Y = left.Y - right.Y;
+ result.Z = left.Z - right.Z;
+ result.W = left.W - right.W;
+ result.V = left.V - right.V;
+
+ return result;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Impl operator -(in Impl value)
+ {
+ Impl result;
+
+ result.X = -value.X;
+ result.Y = -value.Y;
+ result.Z = -value.Z;
+ result.W = -value.W;
+ result.V = -value.V;
+
+ return result;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Impl operator *(in Impl left, in Impl right)
+ {
+ Impl result;
+
+ // result.X = Transform(left.X, in right);
+ result.X = right.X * left.X.X;
+ result.X += right.Y * left.X.Y;
+ result.X += right.Z * left.X.Z;
+ result.X += right.W * left.X.W;
+
+ // result.Y = Transform(left.Y, in right);
+ result.Y = right.X * left.Y.X;
+ result.Y += right.Y * left.Y.Y;
+ result.Y += right.Z * left.Y.Z;
+ result.Y += right.W * left.Y.W;
+
+ // result.Z = Transform(left.Z, in right);
+ result.Z = right.X * left.Z.X;
+ result.Z += right.Y * left.Z.Y;
+ result.Z += right.Z * left.Z.Z;
+ result.Z += right.W * left.Z.W;
+
+ // result.W = Transform(left.W, in right);
+ result.W = right.X * left.W.X;
+ result.W += right.Y * left.W.Y;
+ result.W += right.Z * left.W.Z;
+ result.W += right.W * left.W.W;
+
+ // result.V = Transform(left.V, in right);
+ result.V = right.X * left.V.X;
+ result.V += right.Y * left.V.Y;
+ result.V += right.Z * left.V.Z;
+ result.V += right.W * left.V.W;
+
+ return result;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Impl operator *(in Impl left, float right)
+ {
+ Impl result;
+
+ result.X = left.X * right;
+ result.Y = left.Y * right;
+ result.Z = left.Z * right;
+ result.W = left.W * right;
+ result.V = left.V * right;
+
+ return result;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool operator ==(in Impl left, in Impl right) =>
+ (left.X == right.X)
+ && (left.Y == right.Y)
+ && (left.Z == right.Z)
+ && (left.W == right.W)
+ && (left.V == right.V);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool operator !=(in Impl left, in Impl right) =>
+ (left.X != right.X)
+ && (left.Y != right.Y)
+ && (left.Z != right.Z)
+ && (left.W != right.W)
+ && (left.V != right.V);
+
+ [UnscopedRef]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ref ColorMatrix AsColorMatrix() => ref Unsafe.As(ref this);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Init(
+ float m11, float m12, float m13, float m14,
+ float m21, float m22, float m23, float m24,
+ float m31, float m32, float m33, float m34,
+ float m41, float m42, float m43, float m44,
+ float m51, float m52, float m53, float m54)
+ {
+ this.X = new Vector4(m11, m12, m13, m14);
+ this.Y = new Vector4(m21, m22, m23, m24);
+ this.Z = new Vector4(m31, m32, m33, m34);
+ this.W = new Vector4(m41, m42, m43, m44);
+ this.V = new Vector4(m51, m52, m53, m54);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public override readonly bool Equals([NotNullWhen(true)] object? obj)
+ => (obj is ColorMatrix other) && this.Equals(in other.AsImpl());
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public readonly bool Equals(in Impl other) =>
+ this.X.Equals(other.X)
+ && this.Y.Equals(other.Y)
+ && this.Z.Equals(other.Z)
+ && this.W.Equals(other.W)
+ && this.V.Equals(other.V);
+
+ bool IEquatable.Equals(Impl other) => this.Equals(in other);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public override readonly int GetHashCode() => HashCode.Combine(this.X, this.Y, this.Z, this.W, this.V);
+ }
+}
+#endif
+
diff --git a/src/ImageSharp/Primitives/ColorMatrix.cs b/src/ImageSharp/Primitives/ColorMatrix.cs
index e06dc1f6a5..fcc179266c 100644
--- a/src/ImageSharp/Primitives/ColorMatrix.cs
+++ b/src/ImageSharp/Primitives/ColorMatrix.cs
@@ -2,6 +2,269 @@
// Licensed under the Six Labors Split License.
#pragma warning disable SA1117 // Parameters should be on same line or separate lines
+
+#if NET7_0_OR_GREATER
+
+using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace SixLabors.ImageSharp;
+
+///
+/// A structure encapsulating a 5x4 matrix used for transforming the color and alpha components of an image.
+///
+[StructLayout(LayoutKind.Sequential)]
+public partial struct ColorMatrix : IEquatable
+{
+ ///
+ /// Value at row 1, column 1 of the matrix.
+ ///
+ public float M11;
+
+ ///
+ /// Value at row 1, column 2 of the matrix.
+ ///
+ public float M12;
+
+ ///
+ /// Value at row 1, column 3 of the matrix.
+ ///
+ public float M13;
+
+ ///
+ /// Value at row 1, column 4 of the matrix.
+ ///
+ public float M14;
+
+ ///
+ /// Value at row 2, column 1 of the matrix.
+ ///
+ public float M21;
+
+ ///
+ /// Value at row 2, column 2 of the matrix.
+ ///
+ public float M22;
+
+ ///
+ /// Value at row 2, column 3 of the matrix.
+ ///
+ public float M23;
+
+ ///
+ /// Value at row 2, column 4 of the matrix.
+ ///
+ public float M24;
+
+ ///
+ /// Value at row 3, column 1 of the matrix.
+ ///
+ public float M31;
+
+ ///
+ /// Value at row 3, column 2 of the matrix.
+ ///
+ public float M32;
+
+ ///
+ /// Value at row 3, column 3 of the matrix.
+ ///
+ public float M33;
+
+ ///
+ /// Value at row 3, column 4 of the matrix.
+ ///
+ public float M34;
+
+ ///
+ /// Value at row 4, column 1 of the matrix.
+ ///
+ public float M41;
+
+ ///
+ /// Value at row 4, column 2 of the matrix.
+ ///
+ public float M42;
+
+ ///
+ /// Value at row 4, column 3 of the matrix.
+ ///
+ public float M43;
+
+ ///
+ /// Value at row 4, column 4 of the matrix.
+ ///
+ public float M44;
+
+ ///
+ /// Value at row 5, column 1 of the matrix.
+ ///
+ public float M51;
+
+ ///
+ /// Value at row 5, column 2 of the matrix.
+ ///
+ public float M52;
+
+ ///
+ /// Value at row 5, column 3 of the matrix.
+ ///
+ public float M53;
+
+ ///
+ /// Value at row 5, column 4 of the matrix.
+ ///
+ public float M54;
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The value at row 1, column 1 of the matrix.
+ /// The value at row 1, column 2 of the matrix.
+ /// The value at row 1, column 3 of the matrix.
+ /// The value at row 1, column 4 of the matrix.
+ /// The value at row 2, column 1 of the matrix.
+ /// The value at row 2, column 2 of the matrix.
+ /// The value at row 2, column 3 of the matrix.
+ /// The value at row 2, column 4 of the matrix.
+ /// The value at row 3, column 1 of the matrix.
+ /// The value at row 3, column 2 of the matrix.
+ /// The value at row 3, column 3 of the matrix.
+ /// The value at row 3, column 4 of the matrix.
+ /// The value at row 4, column 1 of the matrix.
+ /// The value at row 4, column 2 of the matrix.
+ /// The value at row 4, column 3 of the matrix.
+ /// The value at row 4, column 4 of the matrix.
+ /// The value at row 5, column 1 of the matrix.
+ /// The value at row 5, column 2 of the matrix.
+ /// The value at row 5, column 3 of the matrix.
+ /// The value at row 5, column 4 of the matrix.
+ public ColorMatrix(float m11, float m12, float m13, float m14,
+ float m21, float m22, float m23, float m24,
+ float m31, float m32, float m33, float m34,
+ float m41, float m42, float m43, float m44,
+ float m51, float m52, float m53, float m54)
+ {
+ Unsafe.SkipInit(out this);
+
+ this.AsImpl().Init(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44, m51, m52, m53,
+ m54);
+ }
+
+ ///
+ /// Gets the multiplicative identity matrix.
+ ///
+ public static ColorMatrix Identity
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => Impl.Identity.AsColorMatrix();
+ }
+
+ ///
+ /// Gets a value indicating whether the matrix is the identity matrix.
+ ///
+ public bool IsIdentity
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => this.AsROImpl().IsIdentity;
+ }
+
+ ///
+ /// Adds two matrices together.
+ ///
+ /// The first source matrix.
+ /// The second source matrix.
+ /// The resulting matrix.
+ public static ColorMatrix operator +(ColorMatrix value1, ColorMatrix value2)
+ => (value1.AsImpl() + value2.AsImpl()).AsColorMatrix();
+
+ ///
+ /// Subtracts the second matrix from the first.
+ ///
+ /// The first source matrix.
+ /// The second source matrix.
+ /// The result of the subtraction.
+ public static ColorMatrix operator -(ColorMatrix value1, ColorMatrix value2)
+ => (value1.AsImpl() - value2.AsImpl()).AsColorMatrix();
+
+ ///
+ /// Returns a new matrix with the negated elements of the given matrix.
+ ///
+ /// The source matrix.
+ /// The negated matrix.
+ public static ColorMatrix operator -(ColorMatrix value)
+ => (-value.AsImpl()).AsColorMatrix();
+
+ ///
+ /// Multiplies a matrix by another matrix.
+ ///
+ /// The first source matrix.
+ /// The second source matrix.
+ /// The result of the multiplication.
+ public static ColorMatrix operator *(ColorMatrix value1, ColorMatrix value2)
+ => (value1.AsImpl() * value2.AsImpl()).AsColorMatrix();
+
+ ///
+ /// Multiplies a matrix by a scalar value.
+ ///
+ /// The source matrix.
+ /// The scaling factor.
+ /// The scaled matrix.
+ public static ColorMatrix operator *(ColorMatrix value1, float value2)
+ => (value1.AsImpl() * value2).AsColorMatrix();
+
+ ///
+ /// Returns a boolean indicating whether the given two matrices are equal.
+ ///
+ /// The first matrix to compare.
+ /// The second matrix to compare.
+ /// True if the given matrices are equal; False otherwise.
+ public static bool operator ==(ColorMatrix value1, ColorMatrix value2)
+ => value1.AsImpl() == value2.AsImpl();
+
+ ///
+ /// Returns a boolean indicating whether the given two matrices are not equal.
+ ///
+ /// The first matrix to compare.
+ /// The second matrix to compare.
+ /// True if the given matrices are equal; False otherwise.
+ public static bool operator !=(ColorMatrix value1, ColorMatrix value2)
+ => value1.AsImpl() != value2.AsImpl();
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public override readonly bool Equals([NotNullWhen(true)] object? obj)
+ => this.AsROImpl().Equals(obj);
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public readonly bool Equals(ColorMatrix other)
+ => this.AsROImpl().Equals(in other.AsImpl());
+
+ ///
+ public override int GetHashCode()
+ => this.AsROImpl().GetHashCode();
+
+ ///
+ public override string ToString()
+ {
+ CultureInfo ci = CultureInfo.CurrentCulture;
+
+ return string.Format(
+ ci,
+ "{{ {{M11:{0} M12:{1} M13:{2} M14:{3}}} {{M21:{4} M22:{5} M23:{6} M24:{7}}} {{M31:{8} M32:{9} M33:{10} M34:{11}}} {{M41:{12} M42:{13} M43:{14} M44:{15}}} {{M51:{16} M52:{17} M53:{18} M54:{19}}} }}",
+ this.M11.ToString(ci), this.M12.ToString(ci), this.M13.ToString(ci), this.M14.ToString(ci),
+ this.M21.ToString(ci), this.M22.ToString(ci), this.M23.ToString(ci), this.M24.ToString(ci),
+ this.M31.ToString(ci), this.M32.ToString(ci), this.M33.ToString(ci), this.M34.ToString(ci),
+ this.M41.ToString(ci), this.M42.ToString(ci), this.M43.ToString(ci), this.M44.ToString(ci),
+ this.M51.ToString(ci), this.M52.ToString(ci), this.M53.ToString(ci), this.M54.ToString(ci));
+ }
+}
+#endif
+#if NET6_0
+
using System.Globalization;
using System.Runtime.InteropServices;
@@ -455,3 +718,5 @@ public struct ColorMatrix : IEquatable
this.M51.ToString(ci), this.M52.ToString(ci), this.M53.ToString(ci), this.M54.ToString(ci));
}
}
+
+#endif