diff --git a/src/ImageSharp/Primitives/DenseMatrix{T}.cs b/src/ImageSharp/Primitives/DenseMatrix{T}.cs index 4229e69e78..3fda03b77d 100644 --- a/src/ImageSharp/Primitives/DenseMatrix{T}.cs +++ b/src/ImageSharp/Primitives/DenseMatrix{T}.cs @@ -136,7 +136,7 @@ namespace SixLabors.ImageSharp /// [MethodImpl(InliningOptions.ShortMethod)] #pragma warning disable SA1008 // Opening parenthesis should be spaced correctly - public static implicit operator T[,] (in DenseMatrix data) + public static implicit operator T[,](in DenseMatrix data) #pragma warning restore SA1008 // Opening parenthesis should be spaced correctly { var result = new T[data.Rows, data.Columns]; @@ -153,6 +153,24 @@ namespace SixLabors.ImageSharp return result; } + /// + /// Compares the two instances to determine whether they are unequal. + /// + /// The first source instance. + /// The second source instance. + /// The . + public static bool operator ==(DenseMatrix left, DenseMatrix right) + => left.Equals(right); + + /// + /// Compares the two instances to determine whether they are equal. + /// + /// The first source instance. + /// The second source instance. + /// The . + public static bool operator !=(DenseMatrix left, DenseMatrix right) + => !(left == right); + /// /// Transposes the rows and columns of the dense matrix. /// @@ -210,15 +228,32 @@ namespace SixLabors.ImageSharp } /// - public override bool Equals(object obj) => obj is DenseMatrix other && this.Equals(other); + public override bool Equals(object obj) + => obj is DenseMatrix other && this.Equals(other); /// + [MethodImpl(InliningOptions.ShortMethod)] public bool Equals(DenseMatrix other) => this.Columns == other.Columns && this.Rows == other.Rows && this.Span.SequenceEqual(other.Span); /// - public override int GetHashCode() => this.Data.GetHashCode(); + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() + { + HashCode code = default; + + code.Add(this.Columns); + code.Add(this.Rows); + + Span span = this.Span; + for (int i = 0; i < span.Length; i++) + { + code.Add(span[i]); + } + + return code.ToHashCode(); + } } } diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs index 6a42540326..079a22ecce 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// An error diffusion dithering implementation. /// /// - public readonly partial struct ErrorDither : IDither, IEquatable + public readonly partial struct ErrorDither : IDither, IEquatable, IEquatable { private readonly int offset; private readonly DenseMatrix matrix; @@ -31,6 +31,60 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering this.offset = offset; } + /// + /// Compares the two instances to determine whether they are equal. + /// + /// The first source instance. + /// The second source instance. + /// The . + public static bool operator ==(IDither left, ErrorDither right) + => right == left; + + /// + /// Compares the two instances to determine whether they are unequal. + /// + /// The first source instance. + /// The second source instance. + /// The . + public static bool operator !=(IDither left, ErrorDither right) + => !(right == left); + + /// + /// Compares the two instances to determine whether they are equal. + /// + /// The first source instance. + /// The second source instance. + /// The . + public static bool operator ==(ErrorDither left, IDither right) + => left.Equals(right); + + /// + /// Compares the two instances to determine whether they are unequal. + /// + /// The first source instance. + /// The second source instance. + /// The . + public static bool operator !=(ErrorDither left, IDither right) + => !(left == right); + + /// + /// Compares the two instances to determine whether they are equal. + /// + /// The first source instance. + /// The second source instance. + /// The . + public static bool operator ==(ErrorDither left, ErrorDither right) + => left.Equals(right); + + /// + /// Compares the two instances to determine whether they are unequal. + /// + /// The first source instance. + /// The second source instance. + /// The . + public static bool operator !=(ErrorDither left, ErrorDither right) + => !(left == right); + /// [MethodImpl(InliningOptions.ShortMethod)] public void ApplyQuantizationDither( @@ -155,6 +209,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering public bool Equals(ErrorDither other) => this.offset == other.offset && this.matrix.Equals(other.matrix); + /// + public bool Equals(IDither other) + => this.Equals((object)other); + /// public override int GetHashCode() => HashCode.Combine(this.offset, this.matrix); diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs index daf3d4732f..69e323bd53 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// /// An ordered dithering matrix with equal sides of arbitrary length /// - public readonly partial struct OrderedDither : IDither, IEquatable + public readonly partial struct OrderedDither : IDither, IEquatable, IEquatable { private readonly DenseMatrix thresholdMatrix; private readonly int modulusX; @@ -47,6 +47,60 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering this.thresholdMatrix = thresholdMatrix; } + /// + /// Compares the two instances to determine whether they are equal. + /// + /// The first source instance. + /// The second source instance. + /// The . + public static bool operator ==(IDither left, OrderedDither right) + => right == left; + + /// + /// Compares the two instances to determine whether they are unequal. + /// + /// The first source instance. + /// The second source instance. + /// The . + public static bool operator !=(IDither left, OrderedDither right) + => !(right == left); + + /// + /// Compares the two instances to determine whether they are equal. + /// + /// The first source instance. + /// The second source instance. + /// The . + public static bool operator ==(OrderedDither left, IDither right) + => left.Equals(right); + + /// + /// Compares the two instances to determine whether they are unequal. + /// + /// The first source instance. + /// The second source instance. + /// The . + public static bool operator !=(OrderedDither left, IDither right) + => !(left == right); + + /// + /// Compares the two instances to determine whether they are equal. + /// + /// The first source instance. + /// The second source instance. + /// The . + public static bool operator ==(OrderedDither left, OrderedDither right) + => left.Equals(right); + + /// + /// Compares the two instances to determine whether they are unequal. + /// + /// The first source instance. + /// The second source instance. + /// The . + public static bool operator !=(OrderedDither left, OrderedDither right) + => !(left == right); + /// [MethodImpl(InliningOptions.ShortMethod)] public void ApplyQuantizationDither( @@ -133,10 +187,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering => obj is OrderedDither dither && this.Equals(dither); /// + [MethodImpl(InliningOptions.ShortMethod)] public bool Equals(OrderedDither other) => this.thresholdMatrix.Equals(other.thresholdMatrix) && this.modulusX == other.modulusX && this.modulusY == other.modulusY; /// + public bool Equals(IDither other) + => this.Equals((object)other); + + /// + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => HashCode.Combine(this.thresholdMatrix, this.modulusX, this.modulusY); diff --git a/tests/ImageSharp.Tests/Primitives/DenseMatrixTests.cs b/tests/ImageSharp.Tests/Primitives/DenseMatrixTests.cs index 3e37cb30b5..d515b21a9d 100644 --- a/tests/ImageSharp.Tests/Primitives/DenseMatrixTests.cs +++ b/tests/ImageSharp.Tests/Primitives/DenseMatrixTests.cs @@ -116,5 +116,25 @@ namespace SixLabors.ImageSharp.Tests.Primitives Assert.Equal(2, transposed[1, 0]); Assert.Equal(3, transposed[2, 0]); } + + [Fact] + public void DenseMatrixEquality() + { + var dense = new DenseMatrix(3, 1); + var dense2 = new DenseMatrix(3, 1); + var dense3 = new DenseMatrix(1, 3); + + Assert.True(dense == dense2); + Assert.False(dense != dense2); + Assert.Equal(dense, dense2); + Assert.Equal(dense, (object)dense2); + Assert.Equal(dense.GetHashCode(), dense2.GetHashCode()); + + Assert.False(dense == dense3); + Assert.True(dense != dense3); + Assert.NotEqual(dense, dense3); + Assert.NotEqual(dense, (object)dense3); + Assert.NotEqual(dense.GetHashCode(), dense3.GetHashCode()); + } } } diff --git a/tests/ImageSharp.Tests/Processing/Dithering/DitherTest.cs b/tests/ImageSharp.Tests/Processing/Dithering/DitherTest.cs index 5cb44ef032..0cc8db6518 100644 --- a/tests/ImageSharp.Tests/Processing/Dithering/DitherTest.cs +++ b/tests/ImageSharp.Tests/Processing/Dithering/DitherTest.cs @@ -104,5 +104,71 @@ namespace SixLabors.ImageSharp.Tests.Processing.Binarization Assert.Equal(this.errorDiffuser, p.Dither); Assert.Equal(this.testPalette, p.Palette); } + + [Fact] + public void ErrorDitherEquality() + { + IDither dither = KnownDitherings.FloydSteinberg; + ErrorDither dither2 = ErrorDither.FloydSteinberg; + ErrorDither dither3 = ErrorDither.FloydSteinberg; + + Assert.True(dither == dither2); + Assert.True(dither2 == dither); + Assert.False(dither != dither2); + Assert.False(dither2 != dither); + Assert.Equal(dither, dither2); + Assert.Equal(dither, (object)dither2); + Assert.Equal(dither.GetHashCode(), dither2.GetHashCode()); + + dither = null; + Assert.False(dither == dither2); + Assert.False(dither2 == dither); + Assert.True(dither != dither2); + Assert.True(dither2 != dither); + Assert.NotEqual(dither, dither2); + Assert.NotEqual(dither, (object)dither2); + Assert.NotEqual(dither?.GetHashCode(), dither2.GetHashCode()); + + Assert.True(dither2 == dither3); + Assert.True(dither3 == dither2); + Assert.False(dither2 != dither3); + Assert.False(dither3 != dither2); + Assert.Equal(dither2, dither3); + Assert.Equal(dither2, (object)dither3); + Assert.Equal(dither2.GetHashCode(), dither3.GetHashCode()); + } + + [Fact] + public void OrderedDitherEquality() + { + IDither dither = KnownDitherings.Bayer2x2; + OrderedDither dither2 = OrderedDither.Bayer2x2; + OrderedDither dither3 = OrderedDither.Bayer2x2; + + Assert.True(dither == dither2); + Assert.True(dither2 == dither); + Assert.False(dither != dither2); + Assert.False(dither2 != dither); + Assert.Equal(dither, dither2); + Assert.Equal(dither, (object)dither2); + Assert.Equal(dither.GetHashCode(), dither2.GetHashCode()); + + dither = null; + Assert.False(dither == dither2); + Assert.False(dither2 == dither); + Assert.True(dither != dither2); + Assert.True(dither2 != dither); + Assert.NotEqual(dither, dither2); + Assert.NotEqual(dither, (object)dither2); + Assert.NotEqual(dither?.GetHashCode(), dither2.GetHashCode()); + + Assert.True(dither2 == dither3); + Assert.True(dither3 == dither2); + Assert.False(dither2 != dither3); + Assert.False(dither3 != dither2); + Assert.Equal(dither2, dither3); + Assert.Equal(dither2, (object)dither3); + Assert.Equal(dither2.GetHashCode(), dither3.GetHashCode()); + } } }