From d36d902456c668525334284b538fce8f86568533 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 13 Feb 2020 03:20:59 +0100 Subject: [PATCH] merge back GetRowSpan and GetRowSpanUnchecked --- .../Advanced/AdvancedImageExtensions.cs | 8 +- .../Common/Helpers/Buffer2DUtils.cs | 4 +- .../Common/Helpers/DenseMatrixUtils.cs | 4 +- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 18 ++-- src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs | 6 +- .../ColorConverters/JpegColorConverter.cs | 8 +- .../Components/Decoder/HuffmanScanDecoder.cs | 10 +- .../Decoder/JpegComponentPostProcessor.cs | 2 +- .../Formats/Jpeg/Components/RowOctet.cs | 16 ++-- src/ImageSharp/Formats/Tga/TgaDecoderCore.cs | 14 +-- src/ImageSharp/Formats/Tga/TgaEncoderCore.cs | 8 +- src/ImageSharp/ImageFrame{TPixel}.cs | 36 ++++++- src/ImageSharp/Image{TPixel}.cs | 36 ++++++- src/ImageSharp/Memory/Buffer2D{T}.cs | 60 +++++++----- .../Convolution/BokehBlurProcessor{TPixel}.cs | 10 +- .../Convolution2DProcessor{TPixel}.cs | 2 +- .../Convolution2PassProcessor{TPixel}.cs | 2 +- .../ConvolutionProcessor{TPixel}.cs | 2 +- .../EdgeDetectorCompassProcessor{TPixel}.cs | 4 +- .../Effects/OilPaintingProcessor{TPixel}.cs | 2 +- ...eHistogramEqualizationProcessor{TPixel}.cs | 6 +- .../Transforms/Resize/ResizeKernelMap.cs | 2 +- .../Transforms/Resize/ResizeWorker.cs | 4 +- .../Transforms/TransformKernelMap.cs | 4 +- .../PixelBlenders/PorterDuffBulkVsPixel.cs | 4 +- .../Jpg/Utils/LibJpegTools.ComponentData.cs | 2 +- .../ImageSharp.Tests/Image/ImageFrameTests.cs | 96 +++++++++++++++++++ tests/ImageSharp.Tests/Image/ImageTests.cs | 81 ++++++++++++++++ .../ImageSharp.Tests/Memory/Buffer2DTests.cs | 55 +++++++++-- .../Memory/BufferAreaTests.cs | 4 +- 30 files changed, 402 insertions(+), 108 deletions(-) create mode 100644 tests/ImageSharp.Tests/Image/ImageFrameTests.cs diff --git a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs index ba50f176e1..6bd65022e9 100644 --- a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs +++ b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs @@ -135,7 +135,7 @@ namespace SixLabors.ImageSharp.Advanced Guard.MustBeGreaterThanOrEqualTo(rowIndex, 0, nameof(rowIndex)); Guard.MustBeLessThan(rowIndex, source.Height, nameof(rowIndex)); - return source.PixelBuffer.GetRowSpanUnchecked(rowIndex); + return source.PixelBuffer.GetRowSpan(rowIndex); } /// @@ -153,7 +153,7 @@ namespace SixLabors.ImageSharp.Advanced Guard.MustBeGreaterThanOrEqualTo(rowIndex, 0, nameof(rowIndex)); Guard.MustBeLessThan(rowIndex, source.Height, nameof(rowIndex)); - return source.Frames.RootFrame.PixelBuffer.GetRowSpanUnchecked(rowIndex); + return source.Frames.RootFrame.PixelBuffer.GetRowSpan(rowIndex); } /// @@ -171,7 +171,7 @@ namespace SixLabors.ImageSharp.Advanced Guard.MustBeGreaterThanOrEqualTo(rowIndex, 0, nameof(rowIndex)); Guard.MustBeLessThan(rowIndex, source.Height, nameof(rowIndex)); - return source.PixelBuffer.GetRowMemorySafe(rowIndex); + return source.PixelBuffer.GetSafeRowMemory(rowIndex); } /// @@ -189,7 +189,7 @@ namespace SixLabors.ImageSharp.Advanced Guard.MustBeGreaterThanOrEqualTo(rowIndex, 0, nameof(rowIndex)); Guard.MustBeLessThan(rowIndex, source.Height, nameof(rowIndex)); - return source.Frames.RootFrame.PixelBuffer.GetRowMemorySafe(rowIndex); + return source.Frames.RootFrame.PixelBuffer.GetSafeRowMemory(rowIndex); } /// diff --git a/src/ImageSharp/Common/Helpers/Buffer2DUtils.cs b/src/ImageSharp/Common/Helpers/Buffer2DUtils.cs index 677520ddd4..f827746015 100644 --- a/src/ImageSharp/Common/Helpers/Buffer2DUtils.cs +++ b/src/ImageSharp/Common/Helpers/Buffer2DUtils.cs @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp { int offsetY = (row + i - radiusY).Clamp(minRow, maxRow); int offsetX = sourceOffsetColumnBase.Clamp(minColumn, maxColumn); - Span sourceRowSpan = sourcePixels.GetRowSpanUnchecked(offsetY); + Span sourceRowSpan = sourcePixels.GetRowSpan(offsetY); var currentColor = sourceRowSpan[offsetX].ToVector4(); vector.Sum(Unsafe.Add(ref baseRef, i) * currentColor); @@ -94,7 +94,7 @@ namespace SixLabors.ImageSharp int sourceOffsetColumnBase = column + minColumn; int offsetY = row.Clamp(minRow, maxRow); - ref ComplexVector4 sourceRef = ref MemoryMarshal.GetReference(sourceValues.GetRowSpanUnchecked(offsetY)); + ref ComplexVector4 sourceRef = ref MemoryMarshal.GetReference(sourceValues.GetRowSpan(offsetY)); ref Complex64 baseRef = ref MemoryMarshal.GetReference(kernel); for (int x = 0; x < kernelLength; x++) diff --git a/src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs b/src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs index baab397f8a..ff6e3a4ec6 100644 --- a/src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs +++ b/src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs @@ -134,7 +134,7 @@ namespace SixLabors.ImageSharp for (int y = 0; y < matrixHeight; y++) { int offsetY = (row + y - radiusY).Clamp(minRow, maxRow); - Span sourceRowSpan = sourcePixels.GetRowSpanUnchecked(offsetY); + Span sourceRowSpan = sourcePixels.GetRowSpan(offsetY); for (int x = 0; x < matrixWidth; x++) { @@ -264,7 +264,7 @@ namespace SixLabors.ImageSharp for (int y = 0; y < matrixHeight; y++) { int offsetY = (row + y - radiusY).Clamp(minRow, maxRow); - Span sourceRowSpan = sourcePixels.GetRowSpanUnchecked(offsetY); + Span sourceRowSpan = sourcePixels.GetRowSpan(offsetY); for (int x = 0; x < matrixWidth; x++) { diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index fdd371f547..80b20c0255 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -320,7 +320,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp int newY = Invert(y, height, inverted); int rowStartIdx = y * width; Span bufferRow = bufferSpan.Slice(rowStartIdx, width); - Span pixelRow = pixels.GetRowSpanUnchecked(newY); + Span pixelRow = pixels.GetRowSpan(newY); bool rowHasUndefinedPixels = rowsWithUndefinedPixelsSpan[y]; if (rowHasUndefinedPixels) @@ -391,7 +391,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp for (int y = 0; y < height; y++) { int newY = Invert(y, height, inverted); - Span pixelRow = pixels.GetRowSpanUnchecked(newY); + Span pixelRow = pixels.GetRowSpan(newY); bool rowHasUndefinedPixels = rowsWithUndefinedPixelsSpan[y]; if (rowHasUndefinedPixels) { @@ -841,7 +841,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp int newY = Invert(y, height, inverted); this.stream.Read(row.Array, 0, row.Length()); int offset = 0; - Span pixelRow = pixels.GetRowSpanUnchecked(newY); + Span pixelRow = pixels.GetRowSpan(newY); for (int x = 0; x < arrayWidth; x++) { @@ -893,7 +893,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp { this.stream.Read(buffer.Array, 0, stride); int newY = Invert(y, height, inverted); - Span pixelRow = pixels.GetRowSpanUnchecked(newY); + Span pixelRow = pixels.GetRowSpan(newY); int offset = 0; for (int x = 0; x < width; x++) @@ -949,7 +949,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp { this.stream.Read(row); int newY = Invert(y, height, inverted); - Span pixelSpan = pixels.GetRowSpanUnchecked(newY); + Span pixelSpan = pixels.GetRowSpan(newY); PixelOperations.Instance.FromBgr24Bytes( this.configuration, row.GetSpan(), @@ -978,7 +978,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp { this.stream.Read(row); int newY = Invert(y, height, inverted); - Span pixelSpan = pixels.GetRowSpanUnchecked(newY); + Span pixelSpan = pixels.GetRowSpan(newY); PixelOperations.Instance.FromBgra32Bytes( this.configuration, row.GetSpan(), @@ -1050,7 +1050,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp this.stream.Read(row); int newY = Invert(y, height, inverted); - Span pixelSpan = pixels.GetRowSpanUnchecked(newY); + Span pixelSpan = pixels.GetRowSpan(newY); PixelOperations.Instance.FromBgra32Bytes( this.configuration, @@ -1073,7 +1073,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp width); int newY = Invert(y, height, inverted); - Span pixelSpan = pixels.GetRowSpanUnchecked(newY); + Span pixelSpan = pixels.GetRowSpan(newY); for (int x = 0; x < width; x++) { @@ -1128,7 +1128,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp { this.stream.Read(buffer.Array, 0, stride); int newY = Invert(y, height, inverted); - Span pixelRow = pixels.GetRowSpanUnchecked(newY); + Span pixelRow = pixels.GetRowSpan(newY); int offset = 0; for (int x = 0; x < width; x++) diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index 12056fb0c3..1c7c606ca6 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -240,7 +240,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp { for (int y = pixels.Height - 1; y >= 0; y--) { - Span pixelSpan = pixels.GetRowSpanUnchecked(y); + Span pixelSpan = pixels.GetRowSpan(y); PixelOperations.Instance.ToBgra32Bytes( this.configuration, pixelSpan, @@ -264,7 +264,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp { for (int y = pixels.Height - 1; y >= 0; y--) { - Span pixelSpan = pixels.GetRowSpanUnchecked(y); + Span pixelSpan = pixels.GetRowSpan(y); PixelOperations.Instance.ToBgr24Bytes( this.configuration, pixelSpan, @@ -288,7 +288,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp { for (int y = pixels.Height - 1; y >= 0; y--) { - Span pixelSpan = pixels.GetRowSpanUnchecked(y); + Span pixelSpan = pixels.GetRowSpan(y); PixelOperations.Instance.ToBgra5551Bytes( this.configuration, diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs index 87f5233e9b..61e3598696 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs @@ -136,20 +136,20 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { this.ComponentCount = componentBuffers.Count; - this.Component0 = componentBuffers[0].GetRowSpanUnchecked(row); + this.Component0 = componentBuffers[0].GetRowSpan(row); this.Component1 = Span.Empty; this.Component2 = Span.Empty; this.Component3 = Span.Empty; if (this.ComponentCount > 1) { - this.Component1 = componentBuffers[1].GetRowSpanUnchecked(row); + this.Component1 = componentBuffers[1].GetRowSpan(row); if (this.ComponentCount > 2) { - this.Component2 = componentBuffers[2].GetRowSpanUnchecked(row); + this.Component2 = componentBuffers[2].GetRowSpan(row); if (this.ComponentCount > 3) { - this.Component3 = componentBuffers[3].GetRowSpanUnchecked(row); + this.Component3 = componentBuffers[3].GetRowSpan(row); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs index 294d1da196..fbb2b52727 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs @@ -167,7 +167,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder for (int y = 0; y < v; y++) { int blockRow = (mcuRow * v) + y; - Span blockSpan = component.SpectralBlocks.GetRowSpanUnchecked(blockRow); + Span blockSpan = component.SpectralBlocks.GetRowSpan(blockRow); ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan); for (int x = 0; x < h; x++) @@ -211,7 +211,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder for (int j = 0; j < h; j++) { - Span blockSpan = component.SpectralBlocks.GetRowSpanUnchecked(j); + Span blockSpan = component.SpectralBlocks.GetRowSpan(j); ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan); for (int i = 0; i < w; i++) @@ -334,7 +334,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder for (int y = 0; y < v; y++) { int blockRow = (mcuRow * v) + y; - Span blockSpan = component.SpectralBlocks.GetRowSpanUnchecked(blockRow); + Span blockSpan = component.SpectralBlocks.GetRowSpan(blockRow); ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan); for (int x = 0; x < h; x++) @@ -377,7 +377,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder for (int j = 0; j < h; j++) { - Span blockSpan = component.SpectralBlocks.GetRowSpanUnchecked(j); + Span blockSpan = component.SpectralBlocks.GetRowSpan(j); ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan); for (int i = 0; i < w; i++) @@ -403,7 +403,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder for (int j = 0; j < h; j++) { - Span blockSpan = component.SpectralBlocks.GetRowSpanUnchecked(j); + Span blockSpan = component.SpectralBlocks.GetRowSpan(j); ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan); for (int i = 0; i < w; i++) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs index 5a52c3ac43..39c8be3120 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs @@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder int yBuffer = y * this.blockAreaSize.Height; - Span blockRow = this.Component.SpectralBlocks.GetRowSpanUnchecked(yBlock); + Span blockRow = this.Component.SpectralBlocks.GetRowSpan(yBlock); ref Block8x8 blockRowBase = ref MemoryMarshal.GetReference(blockRow); diff --git a/src/ImageSharp/Formats/Jpeg/Components/RowOctet.cs b/src/ImageSharp/Formats/Jpeg/Components/RowOctet.cs index 54976110b5..57a1347034 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/RowOctet.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/RowOctet.cs @@ -27,14 +27,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components { int y = startY; int height = buffer.Height; - this.row0 = y < height ? buffer.GetRowSpanUnchecked(y++) : default; - this.row1 = y < height ? buffer.GetRowSpanUnchecked(y++) : default; - this.row2 = y < height ? buffer.GetRowSpanUnchecked(y++) : default; - this.row3 = y < height ? buffer.GetRowSpanUnchecked(y++) : default; - this.row4 = y < height ? buffer.GetRowSpanUnchecked(y++) : default; - this.row5 = y < height ? buffer.GetRowSpanUnchecked(y++) : default; - this.row6 = y < height ? buffer.GetRowSpanUnchecked(y++) : default; - this.row7 = y < height ? buffer.GetRowSpanUnchecked(y) : default; + this.row0 = y < height ? buffer.GetRowSpan(y++) : default; + this.row1 = y < height ? buffer.GetRowSpan(y++) : default; + this.row2 = y < height ? buffer.GetRowSpan(y++) : default; + this.row3 = y < height ? buffer.GetRowSpan(y++) : default; + this.row4 = y < height ? buffer.GetRowSpan(y++) : default; + this.row5 = y < height ? buffer.GetRowSpan(y++) : default; + this.row6 = y < height ? buffer.GetRowSpan(y++) : default; + this.row7 = y < height ? buffer.GetRowSpan(y) : default; } public Span this[int y] diff --git a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs index 6768f4db30..a86fd3bce3 100644 --- a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs +++ b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs @@ -233,7 +233,7 @@ namespace SixLabors.ImageSharp.Formats.Tga { this.currentStream.Read(row); int newY = Invert(y, height, inverted); - Span pixelRow = pixels.GetRowSpanUnchecked(newY); + Span pixelRow = pixels.GetRowSpan(newY); switch (colorMapPixelSizeInBytes) { case 2: @@ -297,7 +297,7 @@ namespace SixLabors.ImageSharp.Formats.Tga for (int y = 0; y < height; y++) { int newY = Invert(y, height, inverted); - Span pixelRow = pixels.GetRowSpanUnchecked(newY); + Span pixelRow = pixels.GetRowSpan(newY); int rowStartIdx = y * width * bytesPerPixel; for (int x = 0; x < width; x++) { @@ -344,7 +344,7 @@ namespace SixLabors.ImageSharp.Formats.Tga { this.currentStream.Read(row); int newY = Invert(y, height, inverted); - Span pixelSpan = pixels.GetRowSpanUnchecked(newY); + Span pixelSpan = pixels.GetRowSpan(newY); PixelOperations.Instance.FromL8Bytes( this.configuration, row.GetSpan(), @@ -379,7 +379,7 @@ namespace SixLabors.ImageSharp.Formats.Tga } int newY = Invert(y, height, inverted); - Span pixelSpan = pixels.GetRowSpanUnchecked(newY); + Span pixelSpan = pixels.GetRowSpan(newY); PixelOperations.Instance.FromBgra5551Bytes( this.configuration, rowSpan, @@ -406,7 +406,7 @@ namespace SixLabors.ImageSharp.Formats.Tga { this.currentStream.Read(row); int newY = Invert(y, height, inverted); - Span pixelSpan = pixels.GetRowSpanUnchecked(newY); + Span pixelSpan = pixels.GetRowSpan(newY); PixelOperations.Instance.FromBgr24Bytes( this.configuration, row.GetSpan(), @@ -433,7 +433,7 @@ namespace SixLabors.ImageSharp.Formats.Tga { this.currentStream.Read(row); int newY = Invert(y, height, inverted); - Span pixelSpan = pixels.GetRowSpanUnchecked(newY); + Span pixelSpan = pixels.GetRowSpan(newY); PixelOperations.Instance.FromBgra32Bytes( this.configuration, row.GetSpan(), @@ -463,7 +463,7 @@ namespace SixLabors.ImageSharp.Formats.Tga for (int y = 0; y < height; y++) { int newY = Invert(y, height, inverted); - Span pixelRow = pixels.GetRowSpanUnchecked(newY); + Span pixelRow = pixels.GetRowSpan(newY); int rowStartIdx = y * width * bytesPerPixel; for (int x = 0; x < width; x++) { diff --git a/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs b/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs index 9ad5a047eb..d1ec2ed4c5 100644 --- a/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs +++ b/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs @@ -255,7 +255,7 @@ namespace SixLabors.ImageSharp.Formats.Tga { for (int y = pixels.Height - 1; y >= 0; y--) { - Span pixelSpan = pixels.GetRowSpanUnchecked(y); + Span pixelSpan = pixels.GetRowSpan(y); PixelOperations.Instance.ToL8Bytes( this.configuration, pixelSpan, @@ -279,7 +279,7 @@ namespace SixLabors.ImageSharp.Formats.Tga { for (int y = pixels.Height - 1; y >= 0; y--) { - Span pixelSpan = pixels.GetRowSpanUnchecked(y); + Span pixelSpan = pixels.GetRowSpan(y); PixelOperations.Instance.ToBgra5551Bytes( this.configuration, pixelSpan, @@ -303,7 +303,7 @@ namespace SixLabors.ImageSharp.Formats.Tga { for (int y = pixels.Height - 1; y >= 0; y--) { - Span pixelSpan = pixels.GetRowSpanUnchecked(y); + Span pixelSpan = pixels.GetRowSpan(y); PixelOperations.Instance.ToBgr24Bytes( this.configuration, pixelSpan, @@ -327,7 +327,7 @@ namespace SixLabors.ImageSharp.Formats.Tga { for (int y = pixels.Height - 1; y >= 0; y--) { - Span pixelSpan = pixels.GetRowSpanUnchecked(y); + Span pixelSpan = pixels.GetRowSpan(y); PixelOperations.Instance.ToBgra32Bytes( this.configuration, pixelSpan, diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index 0d76810848..d5045a599e 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -150,11 +150,19 @@ namespace SixLabors.ImageSharp /// The at the specified position. public TPixel this[int x, int y] { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.PixelBuffer[x, y]; + [MethodImpl(InliningOptions.ShortMethod)] + get + { + this.VerifyCoords(x, y); + return this.PixelBuffer.GetElementUnsafe(x, y); + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - set => this.PixelBuffer[x, y] = value; + [MethodImpl(InliningOptions.ShortMethod)] + set + { + this.VerifyCoords(x, y); + this.PixelBuffer.GetElementUnsafe(x, y) = value; + } } /// @@ -287,6 +295,26 @@ namespace SixLabors.ImageSharp } } + [MethodImpl(InliningOptions.ShortMethod)] + private void VerifyCoords(int x, int y) + { + if (x < 0 || x >= this.Width) + { + ThrowArgumentOutOfRangeException(nameof(x)); + } + + if (y < 0 || y >= this.Height) + { + ThrowArgumentOutOfRangeException(nameof(y)); + } + } + + [MethodImpl(InliningOptions.ColdPath)] + private static void ThrowArgumentOutOfRangeException(string paramName) + { + throw new ArgumentOutOfRangeException(paramName); + } + /// /// A implementing the clone logic for . /// diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index c60f6638ce..9199696af4 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Memory; @@ -146,8 +147,19 @@ namespace SixLabors.ImageSharp /// The at the specified position. public TPixel this[int x, int y] { - get => this.PixelSource.PixelBuffer[x, y]; - set => this.PixelSource.PixelBuffer[x, y] = value; + [MethodImpl(InliningOptions.ShortMethod)] + get + { + this.VerifyCoords(x, y); + return this.PixelSource.PixelBuffer.GetElementUnsafe(x, y); + } + + [MethodImpl(InliningOptions.ShortMethod)] + set + { + this.VerifyCoords(x, y); + this.PixelSource.PixelBuffer.GetElementUnsafe(x, y) = value; + } } /// @@ -265,5 +277,25 @@ namespace SixLabors.ImageSharp return rootSize; } + + [MethodImpl(InliningOptions.ShortMethod)] + private void VerifyCoords(int x, int y) + { + if (x < 0 || x >= this.Width) + { + ThrowArgumentOutOfRangeException(nameof(x)); + } + + if (y < 0 || y >= this.Height) + { + ThrowArgumentOutOfRangeException(nameof(y)); + } + } + + [MethodImpl(InliningOptions.ColdPath)] + private static void ThrowArgumentOutOfRangeException(string paramName) + { + throw new ArgumentOutOfRangeException(paramName); + } } } diff --git a/src/ImageSharp/Memory/Buffer2D{T}.cs b/src/ImageSharp/Memory/Buffer2D{T}.cs index ef9898ad34..fe9e28e2ee 100644 --- a/src/ImageSharp/Memory/Buffer2D{T}.cs +++ b/src/ImageSharp/Memory/Buffer2D{T}.cs @@ -3,6 +3,7 @@ using System; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace SixLabors.ImageSharp.Memory { @@ -68,29 +69,15 @@ namespace SixLabors.ImageSharp.Memory [MethodImpl(MethodImplOptions.AggressiveInlining)] get { + DebugGuard.MustBeGreaterThanOrEqualTo(x, 0, nameof(x)); + DebugGuard.MustBeGreaterThanOrEqualTo(y, 0, nameof(y)); DebugGuard.MustBeLessThan(x, this.Width, nameof(x)); DebugGuard.MustBeLessThan(y, this.Height, nameof(y)); - return ref this.GetRowSpanUnchecked(y)[x]; + return ref this.GetRowSpan(y)[x]; } } - /// - /// Gets a to the row 'y' beginning from the pixel at the first pixel on that row. - /// - /// The y (row) coordinate. - /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span GetRowSpan(int y) - { - Guard.MustBeGreaterThanOrEqualTo(y, 0, nameof(y)); - Guard.MustBeLessThan(y, this.Height, nameof(y)); - - return this.cachedMemory.Length > 0 - ? this.cachedMemory.Span.Slice(y * this.Width, this.Width) - : this.GetRowMemorySlow(y).Span; - } - /// /// Disposes the instance /// @@ -101,10 +88,16 @@ namespace SixLabors.ImageSharp.Memory } /// - /// Same as , but does not validate index in Release mode. + /// Gets a to the row 'y' beginning from the pixel at the first pixel on that row. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Span GetRowSpanUnchecked(int y) + /// + /// This method does not validate the y argument for performance reason, + /// is being propagated from lower levels. + /// + /// The row index. + /// Thrown when row index is out of range. + [MethodImpl(InliningOptions.ShortMethod)] + public Span GetRowSpan(int y) { DebugGuard.MustBeGreaterThanOrEqualTo(y, 0, nameof(y)); DebugGuard.MustBeLessThan(y, this.Height, nameof(y)); @@ -114,6 +107,19 @@ namespace SixLabors.ImageSharp.Memory : this.GetRowMemorySlow(y).Span; } + [MethodImpl(InliningOptions.ShortMethod)] + internal ref T GetElementUnsafe(int x, int y) + { + if (this.cachedMemory.Length > 0) + { + Span span = this.cachedMemory.Span; + ref T start = ref MemoryMarshal.GetReference(span); + return ref Unsafe.Add(ref start, (y * this.Width) + x); + } + + return ref GetElementSlow(x, y); + } + /// /// Gets a to the row 'y' beginning from the pixel at the first pixel on that row. /// This method is intended for internal use only, since it does not use the indirection provided by @@ -121,8 +127,8 @@ namespace SixLabors.ImageSharp.Memory /// /// The y (row) coordinate. /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Memory GetRowMemoryFast(int y) + [MethodImpl(InliningOptions.ShortMethod)] + internal Memory GetFastRowMemory(int y) { DebugGuard.MustBeGreaterThanOrEqualTo(y, 0, nameof(y)); DebugGuard.MustBeLessThan(y, this.Height, nameof(y)); @@ -136,7 +142,8 @@ namespace SixLabors.ImageSharp.Memory /// /// The y (row) coordinate. /// The . - internal Memory GetRowMemorySafe(int y) + [MethodImpl(InliningOptions.ShortMethod)] + internal Memory GetSafeRowMemory(int y) { DebugGuard.MustBeGreaterThanOrEqualTo(y, 0, nameof(y)); DebugGuard.MustBeLessThan(y, this.Height, nameof(y)); @@ -156,6 +163,13 @@ namespace SixLabors.ImageSharp.Memory [MethodImpl(InliningOptions.ColdPath)] private Memory GetRowMemorySlow(int y) => this.MemoryGroup.GetBoundedSlice(y * this.Width, this.Width); + [MethodImpl(InliningOptions.ColdPath)] + private ref T GetElementSlow(int x, int y) + { + Span span = this.GetRowMemorySlow(y).Span; + return ref span[x]; + } + private static void SwapOwnData(Buffer2D a, Buffer2D b, bool swapCachedMemory) { Size aSize = a.Size(); diff --git a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs index 023a4cea0d..1ebd6476e0 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs @@ -364,7 +364,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution { for (int y = rows.Min; y < rows.Max; y++) { - Span targetRowSpan = this.targetValues.GetRowSpanUnchecked(y).Slice(this.bounds.X); + Span targetRowSpan = this.targetValues.GetRowSpan(y).Slice(this.bounds.X); for (int x = 0; x < this.bounds.Width; x++) { @@ -413,7 +413,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution { for (int y = rows.Min; y < rows.Max; y++) { - Span targetRowSpan = this.targetValues.GetRowSpanUnchecked(y).Slice(this.bounds.X); + Span targetRowSpan = this.targetValues.GetRowSpan(y).Slice(this.bounds.X); for (int x = 0; x < this.bounds.Width; x++) { @@ -452,7 +452,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution { for (int y = rows.Min; y < rows.Max; y++) { - Span targetRowSpan = this.targetPixels.GetRowSpanUnchecked(y).Slice(this.bounds.X); + Span targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X); PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, span.Length), span, PixelConversionModifiers.Premultiply); ref Vector4 baseRef = ref MemoryMarshal.GetReference(span); @@ -504,8 +504,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int y = rows.Min; y < rows.Max; y++) { - Span targetPixelSpan = this.targetPixels.GetRowSpanUnchecked(y).Slice(this.bounds.X); - Span sourceRowSpan = this.sourceValues.GetRowSpanUnchecked(y).Slice(this.bounds.X); + Span targetPixelSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X); + Span sourceRowSpan = this.sourceValues.GetRowSpan(y).Slice(this.bounds.X); ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceRowSpan); for (int x = 0; x < this.bounds.Width; x++) diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs index 9d68196f51..1c4987c799 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs @@ -119,7 +119,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int y = rows.Min; y < rows.Max; y++) { - Span targetRowSpan = this.targetPixels.GetRowSpanUnchecked(y).Slice(this.bounds.X); + Span targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X); PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, span.Length), span); if (this.preserveAlpha) diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs index 809cda8a35..33a8ab7d14 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs @@ -118,7 +118,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int y = rows.Min; y < rows.Max; y++) { - Span targetRowSpan = this.targetPixels.GetRowSpanUnchecked(y).Slice(this.bounds.X); + Span targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X); PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, span.Length), span); if (this.preserveAlpha) diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs index 426a2800cf..542ee389b7 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs @@ -106,7 +106,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int y = rows.Min; y < rows.Max; y++) { - Span targetRowSpan = this.targetPixels.GetRowSpanUnchecked(y).Slice(this.bounds.X); + Span targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X); PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, span.Length), span); if (this.preserveAlpha) diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs index 2764b0b3f7..c4da1e4b0e 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs @@ -114,8 +114,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution { for (int y = rows.Min; y < rows.Max; y++) { - ref TPixel passPixelsBase = ref MemoryMarshal.GetReference(this.passPixels.GetRowSpanUnchecked(y)); - ref TPixel targetPixelsBase = ref MemoryMarshal.GetReference(this.targetPixels.GetRowSpanUnchecked(y)); + ref TPixel passPixelsBase = ref MemoryMarshal.GetReference(this.passPixels.GetRowSpan(y)); + ref TPixel targetPixelsBase = ref MemoryMarshal.GetReference(this.targetPixels.GetRowSpan(y)); for (int x = this.minX; x < this.maxX; x++) { diff --git a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs index 9bf18671a3..50c0a22d3b 100644 --- a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs @@ -177,7 +177,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects } } - Span targetRowAreaPixelSpan = this.targetPixels.GetRowSpanUnchecked(y).Slice(this.bounds.X, this.bounds.Width); + Span targetRowAreaPixelSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X, this.bounds.Width); PixelOperations.Instance.FromVector4Destructive(this.configuration, targetRowAreaVector4Span, targetRowAreaPixelSpan); } diff --git a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs index 286eab8c0b..eb666a4f18 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs @@ -529,7 +529,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization } [MethodImpl(InliningOptions.ShortMethod)] - public Span GetCdfLutSpan(int tileX, int tileY) => this.cdfLutBuffer2D.GetRowSpanUnchecked(tileY).Slice(tileX * this.luminanceLevels, this.luminanceLevels); + public Span GetCdfLutSpan(int tileX, int tileY) => this.cdfLutBuffer2D.GetRowSpan(tileY).Slice(tileX * this.luminanceLevels, this.luminanceLevels); /// /// Remaps the grey value with the cdf. @@ -605,7 +605,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization int cdfY = this.tileYStartPositions[index].cdfY; int y = this.tileYStartPositions[index].y; int endY = Math.Min(y + this.tileHeight, this.sourceHeight); - ref int cdfMinBase = ref MemoryMarshal.GetReference(this.cdfMinBuffer2D.GetRowSpanUnchecked(cdfY)); + ref int cdfMinBase = ref MemoryMarshal.GetReference(this.cdfMinBuffer2D.GetRowSpan(cdfY)); using IMemoryOwner histogramBuffer = this.allocator.Allocate(this.luminanceLevels); Span histogram = histogramBuffer.GetSpan(); @@ -614,7 +614,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization for (int x = 0; x < this.sourceWidth; x += this.tileWidth) { histogram.Clear(); - Span cdfLutSpan = this.cdfLutBuffer2D.GetRowSpanUnchecked(index).Slice(cdfX * this.luminanceLevels, this.luminanceLevels); + Span cdfLutSpan = this.cdfLutBuffer2D.GetRowSpan(index).Slice(cdfX * this.luminanceLevels, this.luminanceLevels); ref int cdfBase = ref MemoryMarshal.GetReference(cdfLutSpan); int xlimit = Math.Min(x + this.tileWidth, this.sourceWidth); diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs index 5ee32f85ff..cc95169564 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs @@ -241,7 +241,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms $"Error in KernelMap.CreateKernel({dataRowIndex},{left},{right}): left > this.data.Width"); } - Span rowSpan = this.data.GetRowSpanUnchecked(dataRowIndex); + Span rowSpan = this.data.GetRowSpan(dataRowIndex); ref float rowReference = ref MemoryMarshal.GetReference(rowSpan); float* rowPtr = (float*)Unsafe.AsPointer(ref rowReference); diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs index d40a28b5d0..c3f8658063 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs @@ -102,7 +102,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms [MethodImpl(MethodImplOptions.AggressiveInlining)] public Span GetColumnSpan(int x, int startY) { - return this.transposedFirstPassBuffer.GetRowSpanUnchecked(x).Slice(startY - this.currentWindow.Min); + return this.transposedFirstPassBuffer.GetRowSpan(x).Slice(startY - this.currentWindow.Min); } public void Initialize() @@ -138,7 +138,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Unsafe.Add(ref tempRowBase, x) = kernel.ConvolveCore(ref firstPassColumnBase); } - Span targetRowSpan = destination.GetRowSpanUnchecked(y); + Span targetRowSpan = destination.GetRowSpan(y); PixelOperations.Instance.FromVector4Destructive(this.configuration, tempColSpan, targetRowSpan, this.conversionModifiers); } diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs index 7e261b81e7..a0d44cb7a1 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The reference to the first item of the window. [MethodImpl(InliningOptions.ShortMethod)] public ref float GetYStartReference(int y) - => ref MemoryMarshal.GetReference(this.yBuffer.GetRowSpanUnchecked(y)); + => ref MemoryMarshal.GetReference(this.yBuffer.GetRowSpan(y)); /// /// Gets a reference to the first item of the x window. @@ -61,7 +61,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The reference to the first item of the window. [MethodImpl(InliningOptions.ShortMethod)] public ref float GetXStartReference(int y) - => ref MemoryMarshal.GetReference(this.xBuffer.GetRowSpanUnchecked(y)); + => ref MemoryMarshal.GetReference(this.xBuffer.GetRowSpan(y)); public void Convolve( Vector2 transformedPoint, diff --git a/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs b/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs index 68cfa96ede..4241a12f6a 100644 --- a/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs +++ b/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs @@ -78,7 +78,7 @@ namespace SixLabors.ImageSharp.Benchmarks Buffer2D pixels = image.GetRootFramePixelBuffer(); for (int y = 0; y < image.Height; y++) { - Span span = pixels.GetRowSpanUnchecked(y); + Span span = pixels.GetRowSpan(y); this.BulkVectorConvert(span, span, span, amounts.GetSpan()); } @@ -98,7 +98,7 @@ namespace SixLabors.ImageSharp.Benchmarks Buffer2D pixels = image.GetRootFramePixelBuffer(); for (int y = 0; y < image.Height; y++) { - Span span = pixels.GetRowSpanUnchecked(y); + Span span = pixels.GetRowSpan(y); this.BulkPixelConvert(span, span, span, amounts.GetSpan()); } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs index d97c75dc63..b9526994eb 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils for (int y = 0; y < result.HeightInBlocks; y++) { - Span blockRow = c.SpectralBlocks.GetRowSpanUnchecked(y); + Span blockRow = c.SpectralBlocks.GetRowSpan(y); for (int x = 0; x < result.WidthInBlocks; x++) { short[] data = blockRow[x].ToArray(); diff --git a/tests/ImageSharp.Tests/Image/ImageFrameTests.cs b/tests/ImageSharp.Tests/Image/ImageFrameTests.cs new file mode 100644 index 0000000000..58d7d7981c --- /dev/null +++ b/tests/ImageSharp.Tests/Image/ImageFrameTests.cs @@ -0,0 +1,96 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; + +namespace SixLabors.ImageSharp.Tests +{ + public class ImageFrameTests + { + public class Indexer + { + private readonly Configuration configuration = Configuration.CreateDefaultInstance(); + + private void LimitBufferCapacity(int bufferCapacityInBytes) + { + var allocator = (ArrayPoolMemoryAllocator)this.configuration.MemoryAllocator; + allocator.BufferCapacityInBytes = bufferCapacityInBytes; + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void GetSet(bool enforceDisco) + { + if (enforceDisco) + { + this.LimitBufferCapacity(100); + } + + using var image = new Image(this.configuration, 10, 10); + ImageFrame frame = image.Frames.RootFrame; + Rgba32 val = frame[3, 4]; + Assert.Equal(default(Rgba32), val); + frame[3, 4] = Color.Red; + val = frame[3, 4]; + Assert.Equal(Color.Red.ToRgba32(), val); + } + + public static TheoryData OutOfRangeData = new TheoryData() + { + { false, -1 }, + { false, 10 }, + { true, -1 }, + { true, 10 }, + }; + + [Theory] + [MemberData(nameof(OutOfRangeData))] + public void Get_OutOfRangeX(bool enforceDisco, int x) + { + if (enforceDisco) + { + this.LimitBufferCapacity(100); + } + + using var image = new Image(this.configuration, 10, 10); + ImageFrame frame = image.Frames.RootFrame; + ArgumentOutOfRangeException ex = Assert.Throws(() => _ = frame[x, 3]); + Assert.Equal("x", ex.ParamName); + } + + [Theory] + [MemberData(nameof(OutOfRangeData))] + public void Set_OutOfRangeX(bool enforceDisco, int x) + { + if (enforceDisco) + { + this.LimitBufferCapacity(100); + } + + using var image = new Image(this.configuration, 10, 10); + ImageFrame frame = image.Frames.RootFrame; + ArgumentOutOfRangeException ex = Assert.Throws(() => frame[x, 3] = default); + Assert.Equal("x", ex.ParamName); + } + + [Theory] + [MemberData(nameof(OutOfRangeData))] + public void Set_OutOfRangeY(bool enforceDisco, int y) + { + if (enforceDisco) + { + this.LimitBufferCapacity(100); + } + + using var image = new Image(this.configuration, 10, 10); + ImageFrame frame = image.Frames.RootFrame; + ArgumentOutOfRangeException ex = Assert.Throws(() => frame[3, y] = default); + Assert.Equal("y", ex.ParamName); + } + } + } +} diff --git a/tests/ImageSharp.Tests/Image/ImageTests.cs b/tests/ImageSharp.Tests/Image/ImageTests.cs index 0fa917972f..c99b75733a 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.cs @@ -1,7 +1,9 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Tests.Memory; @@ -85,5 +87,84 @@ namespace SixLabors.ImageSharp.Tests } } } + + public class Indexer + { + private readonly Configuration configuration = Configuration.CreateDefaultInstance(); + + private void LimitBufferCapacity(int bufferCapacityInBytes) + { + var allocator = (ArrayPoolMemoryAllocator)this.configuration.MemoryAllocator; + allocator.BufferCapacityInBytes = bufferCapacityInBytes; + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void GetSet(bool enforceDisco) + { + if (enforceDisco) + { + this.LimitBufferCapacity(100); + } + + using var image = new Image(this.configuration, 10, 10); + Rgba32 val = image[3, 4]; + Assert.Equal(default(Rgba32), val); + image[3, 4] = Color.Red; + val = image[3, 4]; + Assert.Equal(Color.Red.ToRgba32(), val); + } + + public static TheoryData OutOfRangeData = new TheoryData() + { + { false, -1 }, + { false, 10 }, + { true, -1 }, + { true, 10 }, + }; + + [Theory] + [MemberData(nameof(OutOfRangeData))] + public void Get_OutOfRangeX(bool enforceDisco, int x) + { + if (enforceDisco) + { + this.LimitBufferCapacity(100); + } + + using var image = new Image(this.configuration, 10, 10); + ArgumentOutOfRangeException ex = Assert.Throws(() => _ = image[x, 3]); + Assert.Equal("x", ex.ParamName); + } + + [Theory] + [MemberData(nameof(OutOfRangeData))] + public void Set_OutOfRangeX(bool enforceDisco, int x) + { + if (enforceDisco) + { + this.LimitBufferCapacity(100); + } + + using var image = new Image(this.configuration, 10, 10); + ArgumentOutOfRangeException ex = Assert.Throws(() => image[x, 3] = default); + Assert.Equal("x", ex.ParamName); + } + + [Theory] + [MemberData(nameof(OutOfRangeData))] + public void Set_OutOfRangeY(bool enforceDisco, int y) + { + if (enforceDisco) + { + this.LimitBufferCapacity(100); + } + + using var image = new Image(this.configuration, 10, 10); + ArgumentOutOfRangeException ex = Assert.Throws(() => image[3, y] = default); + Assert.Equal("y", ex.ParamName); + } + } } } diff --git a/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs b/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs index 36adf98565..69de85044d 100644 --- a/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs +++ b/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs @@ -3,6 +3,7 @@ using System; using System.Buffers; +using System.Diagnostics; using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -95,7 +96,7 @@ namespace SixLabors.ImageSharp.Tests.Memory using (Buffer2D buffer = this.MemoryAllocator.Allocate2D(width, height)) { - Span span = buffer.GetRowSpanUnchecked(y); + Span span = buffer.GetRowSpan(y); Assert.Equal(width, span.Length); @@ -104,6 +105,48 @@ namespace SixLabors.ImageSharp.Tests.Memory } } + public static TheoryData GetRowSpanY_OutOfRange_Data = new TheoryData() + { + { Big, 10, 8, -1 }, + { Big, 10, 8, 8 }, + { 20, 10, 8, -1 }, + { 20, 10, 8, 10 }, + }; + + [Theory] + [MemberData(nameof(GetRowSpanY_OutOfRange_Data))] + public void GetRowSpan_OutOfRange(int bufferCapacity, int width, int height, int y) + { + this.MemoryAllocator.BufferCapacityInBytes = bufferCapacity; + using Buffer2D buffer = this.MemoryAllocator.Allocate2D(width, height); + + Exception ex = Assert.ThrowsAny(() => buffer.GetRowSpan(y)); + Assert.True(ex is ArgumentOutOfRangeException || ex is IndexOutOfRangeException); + } + + public static TheoryData Indexer_OutOfRange_Data = new TheoryData() + { + { Big, 10, 8, 1, -1 }, + { Big, 10, 8, 1, 8 }, + { Big, 10, 8, -1, 1 }, + { Big, 10, 8, 10, 1 }, + { 20, 10, 8, 1, -1 }, + { 20, 10, 8, 1, 10 }, + { 20, 10, 8, -1, 1 }, + { 20, 10, 8, 10, 1 }, + }; + + [Theory] + [MemberData(nameof(Indexer_OutOfRange_Data))] + public void Indexer_OutOfRange(int bufferCapacity, int width, int height, int x, int y) + { + this.MemoryAllocator.BufferCapacityInBytes = bufferCapacity; + using Buffer2D buffer = this.MemoryAllocator.Allocate2D(width, height); + + Exception ex = Assert.ThrowsAny(() => buffer[x, y]++); + Assert.True(ex is ArgumentOutOfRangeException || ex is IndexOutOfRangeException); + } + [Theory] [InlineData(Big, 42, 8, 0, 0)] [InlineData(Big, 400, 1000, 20, 10)] @@ -168,10 +211,10 @@ namespace SixLabors.ImageSharp.Tests.Memory Buffer2D.SwapOrCopyContent(dest, source); } - int actual1 = dest.GetRowSpanUnchecked(0)[0]; + int actual1 = dest.GetRowSpan(0)[0]; int actual2 = dest.GetRowSpan(0)[0]; - int actual3 = dest.GetRowMemorySafe(0).Span[0]; - int actual4 = dest.GetRowMemoryFast(0).Span[0]; + int actual3 = dest.GetSafeRowMemory(0).Span[0]; + int actual4 = dest.GetFastRowMemory(0).Span[0]; int actual5 = dest[0, 0]; Assert.Equal(1, actual1); @@ -199,7 +242,7 @@ namespace SixLabors.ImageSharp.Tests.Memory for (int y = 0; y < b.Height; y++) { - Span row = b.GetRowSpanUnchecked(y); + Span row = b.GetRowSpan(y); Span s = row.Slice(startIndex, columnCount); Span d = row.Slice(destIndex, columnCount); @@ -222,7 +265,7 @@ namespace SixLabors.ImageSharp.Tests.Memory for (int y = 0; y < b.Height; y++) { - Span row = b.GetRowSpanUnchecked(y); + Span row = b.GetRowSpan(y); Span s = row.Slice(0, 22); Span d = row.Slice(50, 22); diff --git a/tests/ImageSharp.Tests/Memory/BufferAreaTests.cs b/tests/ImageSharp.Tests/Memory/BufferAreaTests.cs index eeddb7daab..77e899a4c2 100644 --- a/tests/ImageSharp.Tests/Memory/BufferAreaTests.cs +++ b/tests/ImageSharp.Tests/Memory/BufferAreaTests.cs @@ -127,7 +127,7 @@ namespace SixLabors.ImageSharp.Tests.Memory for (int y = 0; y < 13; y++) { - Span row = buffer.GetRowSpanUnchecked(y); + Span row = buffer.GetRowSpan(y); Assert.True(row.SequenceEqual(emptyRow)); } } @@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.Tests.Memory for (int y = area.Rectangle.Y; y < area.Rectangle.Bottom; y++) { - Span span = buffer.GetRowSpanUnchecked(y).Slice(area.Rectangle.X, area.Width); + Span span = buffer.GetRowSpan(y).Slice(area.Rectangle.X, area.Width); Assert.True(span.SequenceEqual(new int[area.Width])); } }