diff --git a/src/ImageSharp/Formats/Png/Filters/AverageFilter.cs b/src/ImageSharp/Formats/Png/Filters/AverageFilter.cs index 2750aa6808..57c2029181 100644 --- a/src/ImageSharp/Formats/Png/Filters/AverageFilter.cs +++ b/src/ImageSharp/Formats/Png/Filters/AverageFilter.cs @@ -169,7 +169,7 @@ internal static class AverageFilter Vector256 sumAccumulator = Vector256.Zero; Vector256 allBitsSet = Avx2.CompareEqual(sumAccumulator, sumAccumulator).AsByte(); - for (nuint xLeft = x - bytesPerPixel; x <= (uint)(scanline.Length - Vector256.Count); xLeft += (uint)Vector256.Count) + for (nuint xLeft = x - bytesPerPixel; (int)x <= scanline.Length - Vector256.Count; xLeft += (uint)Vector256.Count) { Vector256 scan = Unsafe.As>(ref Unsafe.Add(ref scanBaseRef, x)); Vector256 left = Unsafe.As>(ref Unsafe.Add(ref scanBaseRef, xLeft)); @@ -192,7 +192,7 @@ internal static class AverageFilter Vector128 sumAccumulator = Vector128.Zero; Vector128 allBitsSet = Sse2.CompareEqual(sumAccumulator, sumAccumulator).AsByte(); - for (nuint xLeft = x - bytesPerPixel; x <= (uint)(scanline.Length - Vector128.Count); xLeft += (uint)Vector128.Count) + for (nuint xLeft = x - bytesPerPixel; (int)x <= scanline.Length - Vector128.Count; xLeft += (uint)Vector128.Count) { Vector128 scan = Unsafe.As>(ref Unsafe.Add(ref scanBaseRef, x)); Vector128 left = Unsafe.As>(ref Unsafe.Add(ref scanBaseRef, xLeft)); diff --git a/src/ImageSharp/Formats/Png/Filters/SubFilter.cs b/src/ImageSharp/Formats/Png/Filters/SubFilter.cs index d58ac6fb7b..1af4a3b729 100644 --- a/src/ImageSharp/Formats/Png/Filters/SubFilter.cs +++ b/src/ImageSharp/Formats/Png/Filters/SubFilter.cs @@ -136,7 +136,7 @@ internal static class SubFilter Vector256 zero = Vector256.Zero; Vector256 sumAccumulator = Vector256.Zero; - for (nuint xLeft = x - (uint)bytesPerPixel; x <= (uint)(scanline.Length - Vector256.Count); xLeft += (uint)Vector256.Count) + for (nuint xLeft = x - (uint)bytesPerPixel; (int)x <= (scanline.Length - Vector256.Count); xLeft += (uint)Vector256.Count) { Vector256 scan = Unsafe.As>(ref Unsafe.Add(ref scanBaseRef, x)); Vector256 prev = Unsafe.As>(ref Unsafe.Add(ref scanBaseRef, xLeft)); @@ -150,11 +150,12 @@ internal static class SubFilter sum += Numerics.EvenReduceSum(sumAccumulator); } - else if (Vector.IsHardwareAccelerated) + else + if (Vector.IsHardwareAccelerated) { Vector sumAccumulator = Vector.Zero; - for (nuint xLeft = x - (uint)bytesPerPixel; x <= (uint)(scanline.Length - Vector.Count); xLeft += (uint)Vector.Count) + for (nuint xLeft = x - (uint)bytesPerPixel; (int)x <= (scanline.Length - Vector.Count); xLeft += (uint)Vector.Count) { Vector scan = Unsafe.As>(ref Unsafe.Add(ref scanBaseRef, x)); Vector prev = Unsafe.As>(ref Unsafe.Add(ref scanBaseRef, xLeft)); diff --git a/src/ImageSharp/Formats/Png/Filters/UpFilter.cs b/src/ImageSharp/Formats/Png/Filters/UpFilter.cs index dd3c2d8612..405d89e6c1 100644 --- a/src/ImageSharp/Formats/Png/Filters/UpFilter.cs +++ b/src/ImageSharp/Formats/Png/Filters/UpFilter.cs @@ -179,7 +179,7 @@ internal static class UpFilter Vector256 zero = Vector256.Zero; Vector256 sumAccumulator = Vector256.Zero; - for (; x <= (uint)(scanline.Length - Vector256.Count);) + for (; (int)x <= scanline.Length - Vector256.Count;) { Vector256 scan = Unsafe.As>(ref Unsafe.Add(ref scanBaseRef, x)); Vector256 above = Unsafe.As>(ref Unsafe.Add(ref prevBaseRef, x)); @@ -197,7 +197,7 @@ internal static class UpFilter { Vector sumAccumulator = Vector.Zero; - for (; x <= (uint)(scanline.Length - Vector.Count);) + for (; (int)x <= scanline.Length - Vector.Count;) { Vector scan = Unsafe.As>(ref Unsafe.Add(ref scanBaseRef, x)); Vector above = Unsafe.As>(ref Unsafe.Add(ref prevBaseRef, x)); diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 6e8224f01e..e3dc0e93cc 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -1519,7 +1519,11 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable this.colorType = colorType.Value; this.bitDepth = bits.Value; - if (!encoder.FilterMethod.HasValue) + if (encoder.FilterMethod.HasValue) + { + this.filterMethod = encoder.FilterMethod.Value; + } + else { // Specification recommends default filter method None for paletted images and Paeth for others. this.filterMethod = this.colorType is PngColorType.Palette ? PngFilterMethod.None : PngFilterMethod.Paeth; diff --git a/src/ImageSharp/Image.WrapMemory.cs b/src/ImageSharp/Image.WrapMemory.cs index d8cea246fe..03bec8bc6a 100644 --- a/src/ImageSharp/Image.WrapMemory.cs +++ b/src/ImageSharp/Image.WrapMemory.cs @@ -50,7 +50,7 @@ public abstract partial class Image { Guard.NotNull(configuration, nameof(configuration)); Guard.NotNull(metadata, nameof(metadata)); - Guard.IsTrue(pixelMemory.Length >= width * height, nameof(pixelMemory), "The length of the input memory is less than the specified image size"); + Guard.IsTrue(pixelMemory.Length >= (long)width * height, nameof(pixelMemory), "The length of the input memory is less than the specified image size"); MemoryGroup memorySource = MemoryGroup.Wrap(pixelMemory); return new Image(configuration, memorySource, width, height, metadata); @@ -145,7 +145,7 @@ public abstract partial class Image { Guard.NotNull(configuration, nameof(configuration)); Guard.NotNull(metadata, nameof(metadata)); - Guard.IsTrue(pixelMemoryOwner.Memory.Length >= width * height, nameof(pixelMemoryOwner), "The length of the input memory is less than the specified image size"); + Guard.IsTrue(pixelMemoryOwner.Memory.Length >= (long)width * height, nameof(pixelMemoryOwner), "The length of the input memory is less than the specified image size"); MemoryGroup memorySource = MemoryGroup.Wrap(pixelMemoryOwner); return new Image(configuration, memorySource, width, height, metadata); @@ -232,7 +232,7 @@ public abstract partial class Image ByteMemoryManager memoryManager = new(byteMemory); - Guard.IsTrue(memoryManager.Memory.Length >= width * height, nameof(byteMemory), "The length of the input memory is less than the specified image size"); + Guard.IsTrue(memoryManager.Memory.Length >= (long)width * height, nameof(byteMemory), "The length of the input memory is less than the specified image size"); MemoryGroup memorySource = MemoryGroup.Wrap(memoryManager.Memory); return new Image(configuration, memorySource, width, height, metadata); @@ -422,10 +422,11 @@ public abstract partial class Image Guard.IsFalse(pointer == null, nameof(pointer), "Pointer must be not null"); Guard.NotNull(configuration, nameof(configuration)); Guard.NotNull(metadata, nameof(metadata)); + Guard.MustBeLessThanOrEqualTo(height * (long)width, int.MaxValue, "Total amount of pixels exceeds int.MaxValue"); UnmanagedMemoryManager memoryManager = new(pointer, width * height); - Guard.MustBeGreaterThanOrEqualTo(bufferSizeInBytes, memoryManager.Memory.Span.Length, nameof(bufferSizeInBytes)); + Guard.MustBeGreaterThanOrEqualTo(bufferSizeInBytes / sizeof(TPixel), memoryManager.Memory.Span.Length, nameof(bufferSizeInBytes)); MemoryGroup memorySource = MemoryGroup.Wrap(memoryManager.Memory); return new Image(configuration, memorySource, width, height, metadata); diff --git a/src/ImageSharp/Metadata/ImageMetadata.cs b/src/ImageSharp/Metadata/ImageMetadata.cs index e811cc1f76..0c1d05d50e 100644 --- a/src/ImageSharp/Metadata/ImageMetadata.cs +++ b/src/ImageSharp/Metadata/ImageMetadata.cs @@ -165,7 +165,7 @@ public sealed class ImageMetadata : IDeepCloneable public CicpProfile? CicpProfile { get; set; } /// - /// Gets the original format, if any, the image was decode from. + /// Gets the original format, if any, from which the image was decoded. /// public IImageFormat? DecodedImageFormat { get; internal set; } diff --git a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs index f22a55aae6..e3c4a7df18 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs @@ -294,19 +294,22 @@ public partial class ImageTests } } - [Fact] - public unsafe void WrapMemory_Throws_OnTooLessWrongSize() + [Theory] + [InlineData(20, 5, 5)] + [InlineData(1023, 32, 32)] + [InlineData(65536, 65537, 65536)] + public unsafe void WrapMemory_Throws_OnTooLessWrongSize(int size, int width, int height) { var cfg = Configuration.CreateDefaultInstance(); var metaData = new ImageMetadata(); - var array = new Rgba32[25]; + var array = new Rgba32[size]; Exception thrownException = null; fixed (void* ptr = array) { try { - using var image = Image.WrapMemory(cfg, ptr, 24, 5, 5, metaData); + using var image = Image.WrapMemory(cfg, ptr, size * sizeof(Rgba32), width, height, metaData); } catch (Exception e) { @@ -317,24 +320,30 @@ public partial class ImageTests Assert.IsType(thrownException); } - [Fact] - public unsafe void WrapMemory_FromPointer_CreatedImageIsCorrect() + [Theory] + [InlineData(25, 5, 5)] + [InlineData(26, 5, 5)] + [InlineData(2, 1, 1)] + [InlineData(1024, 32, 32)] + [InlineData(2048, 32, 32)] + public unsafe void WrapMemory_FromPointer_CreatedImageIsCorrect(int size, int width, int height) { var cfg = Configuration.CreateDefaultInstance(); var metaData = new ImageMetadata(); - var array = new Rgba32[25]; + var array = new Rgba32[size]; fixed (void* ptr = array) { - using (var image = Image.WrapMemory(cfg, ptr, 25, 5, 5, metaData)) + using (var image = Image.WrapMemory(cfg, ptr, size * sizeof(Rgba32), width, height, metaData)) { Assert.True(image.DangerousTryGetSinglePixelMemory(out Memory imageMem)); Span imageSpan = imageMem.Span; + Span sourceSpan = array.AsSpan(0, width * height); ref Rgba32 pixel0 = ref imageSpan[0]; - Assert.True(Unsafe.AreSame(ref array[0], ref pixel0)); + Assert.True(Unsafe.AreSame(ref sourceSpan[0], ref pixel0)); ref Rgba32 pixel_1 = ref imageSpan[imageSpan.Length - 1]; - Assert.True(Unsafe.AreSame(ref array[array.Length - 1], ref pixel_1)); + Assert.True(Unsafe.AreSame(ref sourceSpan[sourceSpan.Length - 1], ref pixel_1)); Assert.Equal(cfg, image.Configuration); Assert.Equal(metaData, image.Metadata); @@ -395,6 +404,7 @@ public partial class ImageTests [InlineData(0, 5, 5)] [InlineData(20, 5, 5)] [InlineData(1023, 32, 32)] + [InlineData(65536, 65537, 65536)] public void WrapMemory_MemoryOfT_InvalidSize(int size, int height, int width) { var array = new Rgba32[size]; @@ -430,6 +440,7 @@ public partial class ImageTests [InlineData(0, 5, 5)] [InlineData(20, 5, 5)] [InlineData(1023, 32, 32)] + [InlineData(65536, 65537, 65536)] public void WrapMemory_IMemoryOwnerOfT_InvalidSize(int size, int height, int width) { var array = new Rgba32[size]; @@ -476,6 +487,7 @@ public partial class ImageTests [InlineData(0, 5, 5)] [InlineData(20, 5, 5)] [InlineData(1023, 32, 32)] + [InlineData(65536, 65537, 65536)] public void WrapMemory_IMemoryOwnerOfByte_InvalidSize(int size, int height, int width) { var array = new byte[size * Unsafe.SizeOf()]; @@ -523,6 +535,7 @@ public partial class ImageTests [InlineData(0, 5, 5)] [InlineData(20, 5, 5)] [InlineData(1023, 32, 32)] + [InlineData(65536, 65537, 65536)] public void WrapMemory_MemoryOfByte_InvalidSize(int size, int height, int width) { var array = new byte[size * Unsafe.SizeOf()];