diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index fe037003e3..716004f39c 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -362,10 +362,8 @@ internal override void CopyPixelsTo(MemoryGroup - { - PixelOperations.Instance.To(this.GetConfiguration(), s, d); - }); + this.PixelBuffer.FastMemoryGroup.TransformTo(destination, (s, d) + => PixelOperations.Instance.To(this.GetConfiguration(), s, d)); } /// diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.String.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.String.cs index 3fc353211d..286b31786e 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.String.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.String.cs @@ -94,7 +94,7 @@ public abstract partial class ExifTag /// /// Gets the MDFileUnits exif tag. /// - public static ExifTag MDFileUnits => new ExifTag(ExifTagValue.MDFileUnits); + public static ExifTag MDFileUnits { get; } = new ExifTag(ExifTagValue.MDFileUnits); /// /// Gets the SEMInfo exif tag. diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/RgbaVector.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/RgbaVector.PixelOperations.cs index c66526bbe5..e78a644af3 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/RgbaVector.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/RgbaVector.PixelOperations.cs @@ -21,7 +21,7 @@ public partial struct RgbaVector internal class PixelOperations : PixelOperations { private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); + new(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); /// public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; @@ -34,7 +34,7 @@ public override void From( { Span destinationVectors = MemoryMarshal.Cast(destinationPixels); - PixelOperations.Instance.ToVector4(configuration, sourcePixels, destinationVectors); + PixelOperations.Instance.ToVector4(configuration, sourcePixels, destinationVectors, PixelConversionModifiers.Scale); } /// diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index f748a4b574..710eb9c083 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.PixelFormats public partial class PixelOperations where TPixel : unmanaged, IPixel { - private static readonly Lazy LazyInfo = new Lazy(() => PixelTypeInfo.Create(), true); + private static readonly Lazy LazyInfo = new(() => PixelTypeInfo.Create(), true); /// /// Gets the global instance for the pixel type @@ -116,29 +116,29 @@ public virtual void From( Span destinationPixels) where TSourcePixel : unmanaged, IPixel { - const int SliceLength = 1024; - int numberOfSlices = sourcePixels.Length / SliceLength; + const int sliceLength = 1024; + int numberOfSlices = sourcePixels.Length / sliceLength; - using IMemoryOwner tempVectors = configuration.MemoryAllocator.Allocate(SliceLength); + using IMemoryOwner tempVectors = configuration.MemoryAllocator.Allocate(sliceLength); Span vectorSpan = tempVectors.GetSpan(); for (int i = 0; i < numberOfSlices; i++) { - int start = i * SliceLength; - ReadOnlySpan s = sourcePixels.Slice(start, SliceLength); - Span d = destinationPixels.Slice(start, SliceLength); - PixelOperations.Instance.ToVector4(configuration, s, vectorSpan); - this.FromVector4Destructive(configuration, vectorSpan, d); + int start = i * sliceLength; + ReadOnlySpan s = sourcePixels.Slice(start, sliceLength); + Span d = destinationPixels.Slice(start, sliceLength); + PixelOperations.Instance.ToVector4(configuration, s, vectorSpan, PixelConversionModifiers.Scale); + this.FromVector4Destructive(configuration, vectorSpan, d, PixelConversionModifiers.Scale); } - int endOfCompleteSlices = numberOfSlices * SliceLength; + int endOfCompleteSlices = numberOfSlices * sliceLength; int remainder = sourcePixels.Length - endOfCompleteSlices; if (remainder > 0) { ReadOnlySpan s = sourcePixels.Slice(endOfCompleteSlices); Span d = destinationPixels.Slice(endOfCompleteSlices); vectorSpan = vectorSpan.Slice(0, remainder); - PixelOperations.Instance.ToVector4(configuration, s, vectorSpan); - this.FromVector4Destructive(configuration, vectorSpan, d); + PixelOperations.Instance.ToVector4(configuration, s, vectorSpan, PixelConversionModifiers.Scale); + this.FromVector4Destructive(configuration, vectorSpan, d, PixelConversionModifiers.Scale); } } diff --git a/tests/ImageSharp.Tests.ruleset b/tests/ImageSharp.Tests.ruleset index 673f005170..50c275cd76 100644 --- a/tests/ImageSharp.Tests.ruleset +++ b/tests/ImageSharp.Tests.ruleset @@ -1,6 +1,9 @@  - + + + + diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs index 2a89c1d39d..3e1b22e859 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs @@ -320,30 +320,51 @@ public void ToVector4(int count) (s, d) => this.Operations.ToVector4(this.Configuration, s, d.GetSpan())); } - public static readonly TheoryData Generic_To_Data = new TheoryData + public static readonly TheoryData Generic_To_Data = new() { + new TestPixel(), new TestPixel(), - new TestPixel(), + new TestPixel(), + new TestPixel(), + new TestPixel(), new TestPixel(), - new TestPixel(), - new TestPixel(), + new TestPixel(), + new TestPixel(), + new TestPixel(), + new TestPixel(), + new TestPixel(), + new TestPixel(), new TestPixel(), + new TestPixel(), + new TestPixel(), + new TestPixel(), + new TestPixel(), + new TestPixel(), + new TestPixel(), + new TestPixel(), + new TestPixel(), + new TestPixel(), new TestPixel(), - new TestPixel() + new TestPixel(), + new TestPixel(), + new TestPixel(), + new TestPixel(), + new TestPixel(), + new TestPixel(), }; [Theory] [MemberData(nameof(Generic_To_Data))] - public void Generic_To(TestPixel dummy) + public void Generic_To(TestPixel _) where TDestPixel : unmanaged, IPixel { - const int Count = 2134; - TPixel[] source = CreatePixelTestData(Count); - var expected = new TDestPixel[Count]; + const int count = 2134; + TPixel[] source = CreatePixelTestData(count); + var expected = new TDestPixel[count]; PixelConverterTests.ReferenceImplementations.To(this.Configuration, source, expected); - TestOperation(source, expected, (s, d) => this.Operations.To(this.Configuration, s, d.GetSpan())); + TestOperation(source, expected, (s, d) => this.Operations.To(this.Configuration, s, d.GetSpan()), false); } [Theory] @@ -1234,23 +1255,11 @@ public void Verify() } // TODO: We really need a PixelTypeInfo.BitsPerComponent property!! - private static bool IsComplexPixel() + private static bool IsComplexPixel() => default(TDest) switch { - switch (default(TDest)) - { - case HalfSingle _: - case HalfVector2 _: - case L16 _: - case La32 _: - case NormalizedShort2 _: - case Rg32 _: - case Short2 _: - return true; - - default: - return Unsafe.SizeOf() > sizeof(int); - } - } + HalfSingle or HalfVector2 or L16 or La32 or NormalizedShort2 or Rg32 or Short2 => true, + _ => Unsafe.SizeOf() > sizeof(int), + }; } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs index 438d5f2ed3..bfd901b95a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs @@ -189,5 +189,21 @@ public void RgbaVector_FromGrey8() // assert Assert.Equal(expected, rgba.ToScaledVector4()); } + + [Fact] + public void Issue2048() + { + // https://github.com/SixLabors/ImageSharp/issues/2048 + RgbaVector green = Color.Green.ToPixel(); + using Image source = new(Configuration.Default, 1, 1, green); + using Image clone = source.CloneAs(); + + Rgba32 srcColor = default; + Rgba32 cloneColor = default; + source[0, 0].ToRgba32(ref srcColor); + clone[0, 0].ToRgba32(ref cloneColor); + + Assert.Equal(srcColor, cloneColor); + } } } diff --git a/tests/ImageSharp.Tests/TestUtilities/TestPixel.cs b/tests/ImageSharp.Tests/TestUtilities/TestPixel.cs index 7265e29c3a..104c54cee0 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestPixel.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestPixel.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Numerics; using SixLabors.ImageSharp.PixelFormats; using Xunit.Abstractions; @@ -16,6 +17,11 @@ public TestPixel() public TestPixel(float red, float green, float blue, float alpha) { + Guard.MustBeBetweenOrEqualTo(red, 0F, 1F, nameof(red)); + Guard.MustBeBetweenOrEqualTo(green, 0F, 1F, nameof(green)); + Guard.MustBeBetweenOrEqualTo(blue, 0F, 1F, nameof(blue)); + Guard.MustBeBetweenOrEqualTo(alpha, 0F, 1F, nameof(alpha)); + this.Red = red; this.Green = green; this.Blue = blue; @@ -33,14 +39,11 @@ public TestPixel(float red, float green, float blue, float alpha) public TPixel AsPixel() { var pix = default(TPixel); - pix.FromVector4(new System.Numerics.Vector4(this.Red, this.Green, this.Blue, this.Alpha)); + pix.FromScaledVector4(new Vector4(this.Red, this.Green, this.Blue, this.Alpha)); return pix; } - internal Span AsSpan() - { - return new Span(new[] { this.AsPixel() }); - } + internal Span AsSpan() => new(new[] { this.AsPixel() }); public void Deserialize(IXunitSerializationInfo info) { @@ -58,9 +61,6 @@ public void Serialize(IXunitSerializationInfo info) info.AddValue("alpha", this.Alpha); } - public override string ToString() - { - return $"{typeof(TPixel).Name}{this.AsPixel().ToString()}"; - } + public override string ToString() => $"{typeof(TPixel).Name}{this.AsPixel()}"; } }