Browse Source

merge back GetRowSpan and GetRowSpanUnchecked

af/octree-no-pixelmap
Anton Firszov 6 years ago
parent
commit
d36d902456
  1. 8
      src/ImageSharp/Advanced/AdvancedImageExtensions.cs
  2. 4
      src/ImageSharp/Common/Helpers/Buffer2DUtils.cs
  3. 4
      src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs
  4. 18
      src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
  5. 6
      src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
  6. 8
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs
  7. 10
      src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs
  8. 2
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs
  9. 16
      src/ImageSharp/Formats/Jpeg/Components/RowOctet.cs
  10. 14
      src/ImageSharp/Formats/Tga/TgaDecoderCore.cs
  11. 8
      src/ImageSharp/Formats/Tga/TgaEncoderCore.cs
  12. 36
      src/ImageSharp/ImageFrame{TPixel}.cs
  13. 36
      src/ImageSharp/Image{TPixel}.cs
  14. 60
      src/ImageSharp/Memory/Buffer2D{T}.cs
  15. 10
      src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs
  16. 2
      src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs
  17. 2
      src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs
  18. 2
      src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs
  19. 4
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs
  20. 2
      src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs
  21. 6
      src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs
  22. 2
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs
  23. 4
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs
  24. 4
      src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs
  25. 4
      tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs
  26. 2
      tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs
  27. 96
      tests/ImageSharp.Tests/Image/ImageFrameTests.cs
  28. 81
      tests/ImageSharp.Tests/Image/ImageTests.cs
  29. 55
      tests/ImageSharp.Tests/Memory/Buffer2DTests.cs
  30. 4
      tests/ImageSharp.Tests/Memory/BufferAreaTests.cs

8
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);
}
/// <summary>
@ -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);
}
/// <summary>
@ -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);
}
/// <summary>
@ -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);
}
/// <summary>

4
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<TPixel> sourceRowSpan = sourcePixels.GetRowSpanUnchecked(offsetY);
Span<TPixel> 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++)

4
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<TPixel> sourceRowSpan = sourcePixels.GetRowSpanUnchecked(offsetY);
Span<TPixel> 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<TPixel> sourceRowSpan = sourcePixels.GetRowSpanUnchecked(offsetY);
Span<TPixel> sourceRowSpan = sourcePixels.GetRowSpan(offsetY);
for (int x = 0; x < matrixWidth; x++)
{

18
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<byte> bufferRow = bufferSpan.Slice(rowStartIdx, width);
Span<TPixel> pixelRow = pixels.GetRowSpanUnchecked(newY);
Span<TPixel> 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<TPixel> pixelRow = pixels.GetRowSpanUnchecked(newY);
Span<TPixel> 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<TPixel> pixelRow = pixels.GetRowSpanUnchecked(newY);
Span<TPixel> 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<TPixel> pixelRow = pixels.GetRowSpanUnchecked(newY);
Span<TPixel> 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<TPixel> pixelSpan = pixels.GetRowSpanUnchecked(newY);
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
PixelOperations<TPixel>.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<TPixel> pixelSpan = pixels.GetRowSpanUnchecked(newY);
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
PixelOperations<TPixel>.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<TPixel> pixelSpan = pixels.GetRowSpanUnchecked(newY);
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
PixelOperations<TPixel>.Instance.FromBgra32Bytes(
this.configuration,
@ -1073,7 +1073,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
width);
int newY = Invert(y, height, inverted);
Span<TPixel> pixelSpan = pixels.GetRowSpanUnchecked(newY);
Span<TPixel> 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<TPixel> pixelRow = pixels.GetRowSpanUnchecked(newY);
Span<TPixel> pixelRow = pixels.GetRowSpan(newY);
int offset = 0;
for (int x = 0; x < width; x++)

6
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<TPixel> pixelSpan = pixels.GetRowSpanUnchecked(y);
Span<TPixel> pixelSpan = pixels.GetRowSpan(y);
PixelOperations<TPixel>.Instance.ToBgra32Bytes(
this.configuration,
pixelSpan,
@ -264,7 +264,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
{
for (int y = pixels.Height - 1; y >= 0; y--)
{
Span<TPixel> pixelSpan = pixels.GetRowSpanUnchecked(y);
Span<TPixel> pixelSpan = pixels.GetRowSpan(y);
PixelOperations<TPixel>.Instance.ToBgr24Bytes(
this.configuration,
pixelSpan,
@ -288,7 +288,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
{
for (int y = pixels.Height - 1; y >= 0; y--)
{
Span<TPixel> pixelSpan = pixels.GetRowSpanUnchecked(y);
Span<TPixel> pixelSpan = pixels.GetRowSpan(y);
PixelOperations<TPixel>.Instance.ToBgra5551Bytes(
this.configuration,

8
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<float>.Empty;
this.Component2 = Span<float>.Empty;
this.Component3 = Span<float>.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);
}
}
}

10
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<Block8x8> blockSpan = component.SpectralBlocks.GetRowSpanUnchecked(blockRow);
Span<Block8x8> 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<Block8x8> blockSpan = component.SpectralBlocks.GetRowSpanUnchecked(j);
Span<Block8x8> 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<Block8x8> blockSpan = component.SpectralBlocks.GetRowSpanUnchecked(blockRow);
Span<Block8x8> 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<Block8x8> blockSpan = component.SpectralBlocks.GetRowSpanUnchecked(j);
Span<Block8x8> 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<Block8x8> blockSpan = component.SpectralBlocks.GetRowSpanUnchecked(j);
Span<Block8x8> blockSpan = component.SpectralBlocks.GetRowSpan(j);
ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan);
for (int i = 0; i < w; i++)

2
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<Block8x8> blockRow = this.Component.SpectralBlocks.GetRowSpanUnchecked(yBlock);
Span<Block8x8> blockRow = this.Component.SpectralBlocks.GetRowSpan(yBlock);
ref Block8x8 blockRowBase = ref MemoryMarshal.GetReference(blockRow);

16
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<T> this[int y]

14
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<TPixel> pixelRow = pixels.GetRowSpanUnchecked(newY);
Span<TPixel> 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<TPixel> pixelRow = pixels.GetRowSpanUnchecked(newY);
Span<TPixel> 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<TPixel> pixelSpan = pixels.GetRowSpanUnchecked(newY);
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
PixelOperations<TPixel>.Instance.FromL8Bytes(
this.configuration,
row.GetSpan(),
@ -379,7 +379,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
}
int newY = Invert(y, height, inverted);
Span<TPixel> pixelSpan = pixels.GetRowSpanUnchecked(newY);
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
PixelOperations<TPixel>.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<TPixel> pixelSpan = pixels.GetRowSpanUnchecked(newY);
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
PixelOperations<TPixel>.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<TPixel> pixelSpan = pixels.GetRowSpanUnchecked(newY);
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
PixelOperations<TPixel>.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<TPixel> pixelRow = pixels.GetRowSpanUnchecked(newY);
Span<TPixel> pixelRow = pixels.GetRowSpan(newY);
int rowStartIdx = y * width * bytesPerPixel;
for (int x = 0; x < width; x++)
{

8
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<TPixel> pixelSpan = pixels.GetRowSpanUnchecked(y);
Span<TPixel> pixelSpan = pixels.GetRowSpan(y);
PixelOperations<TPixel>.Instance.ToL8Bytes(
this.configuration,
pixelSpan,
@ -279,7 +279,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
{
for (int y = pixels.Height - 1; y >= 0; y--)
{
Span<TPixel> pixelSpan = pixels.GetRowSpanUnchecked(y);
Span<TPixel> pixelSpan = pixels.GetRowSpan(y);
PixelOperations<TPixel>.Instance.ToBgra5551Bytes(
this.configuration,
pixelSpan,
@ -303,7 +303,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
{
for (int y = pixels.Height - 1; y >= 0; y--)
{
Span<TPixel> pixelSpan = pixels.GetRowSpanUnchecked(y);
Span<TPixel> pixelSpan = pixels.GetRowSpan(y);
PixelOperations<TPixel>.Instance.ToBgr24Bytes(
this.configuration,
pixelSpan,
@ -327,7 +327,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
{
for (int y = pixels.Height - 1; y >= 0; y--)
{
Span<TPixel> pixelSpan = pixels.GetRowSpanUnchecked(y);
Span<TPixel> pixelSpan = pixels.GetRowSpan(y);
PixelOperations<TPixel>.Instance.ToBgra32Bytes(
this.configuration,
pixelSpan,

36
src/ImageSharp/ImageFrame{TPixel}.cs

@ -150,11 +150,19 @@ namespace SixLabors.ImageSharp
/// <returns>The <see typeparam="TPixel"/> at the specified position.</returns>
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;
}
}
/// <summary>
@ -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);
}
/// <summary>
/// A <see langword="struct"/> implementing the clone logic for <see cref="ImageFrame{TPixel}"/>.
/// </summary>

36
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
/// <returns>The <see typeparam="TPixel"/> at the specified position.</returns>
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;
}
}
/// <summary>
@ -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);
}
}
}

60
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];
}
}
/// <summary>
/// Gets a <see cref="Span{T}"/> to the row 'y' beginning from the pixel at the first pixel on that row.
/// </summary>
/// <param name="y">The y (row) coordinate.</param>
/// <returns>The <see cref="Span{T}"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<T> 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;
}
/// <summary>
/// Disposes the <see cref="Buffer2D{T}"/> instance
/// </summary>
@ -101,10 +88,16 @@ namespace SixLabors.ImageSharp.Memory
}
/// <summary>
/// Same as <see cref="GetRowSpan"/>, but does not validate index in Release mode.
/// Gets a <see cref="Span{T}"/> to the row 'y' beginning from the pixel at the first pixel on that row.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal Span<T> GetRowSpanUnchecked(int y)
/// <remarks>
/// This method does not validate the y argument for performance reason,
/// <see cref="ArgumentOutOfRangeException"/> is being propagated from lower levels.
/// </remarks>
/// <param name="y">The row index.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown when row index is out of range.</exception>
[MethodImpl(InliningOptions.ShortMethod)]
public Span<T> 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<T> 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);
}
/// <summary>
/// Gets a <see cref="Memory{T}"/> 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
/// </summary>
/// <param name="y">The y (row) coordinate.</param>
/// <returns>The <see cref="Span{T}"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal Memory<T> GetRowMemoryFast(int y)
[MethodImpl(InliningOptions.ShortMethod)]
internal Memory<T> GetFastRowMemory(int y)
{
DebugGuard.MustBeGreaterThanOrEqualTo(y, 0, nameof(y));
DebugGuard.MustBeLessThan(y, this.Height, nameof(y));
@ -136,7 +142,8 @@ namespace SixLabors.ImageSharp.Memory
/// </summary>
/// <param name="y">The y (row) coordinate.</param>
/// <returns>The <see cref="Span{T}"/>.</returns>
internal Memory<T> GetRowMemorySafe(int y)
[MethodImpl(InliningOptions.ShortMethod)]
internal Memory<T> 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<T> GetRowMemorySlow(int y) => this.MemoryGroup.GetBoundedSlice(y * this.Width, this.Width);
[MethodImpl(InliningOptions.ColdPath)]
private ref T GetElementSlow(int x, int y)
{
Span<T> span = this.GetRowMemorySlow(y).Span;
return ref span[x];
}
private static void SwapOwnData(Buffer2D<T> a, Buffer2D<T> b, bool swapCachedMemory)
{
Size aSize = a.Size();

10
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<ComplexVector4> targetRowSpan = this.targetValues.GetRowSpanUnchecked(y).Slice(this.bounds.X);
Span<ComplexVector4> 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<Vector4> targetRowSpan = this.targetValues.GetRowSpanUnchecked(y).Slice(this.bounds.X);
Span<Vector4> 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<TPixel> targetRowSpan = this.targetPixels.GetRowSpanUnchecked(y).Slice(this.bounds.X);
Span<TPixel> targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X);
PixelOperations<TPixel>.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<TPixel> targetPixelSpan = this.targetPixels.GetRowSpanUnchecked(y).Slice(this.bounds.X);
Span<Vector4> sourceRowSpan = this.sourceValues.GetRowSpanUnchecked(y).Slice(this.bounds.X);
Span<TPixel> targetPixelSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X);
Span<Vector4> 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++)

2
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<TPixel> targetRowSpan = this.targetPixels.GetRowSpanUnchecked(y).Slice(this.bounds.X);
Span<TPixel> targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, span.Length), span);
if (this.preserveAlpha)

2
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<TPixel> targetRowSpan = this.targetPixels.GetRowSpanUnchecked(y).Slice(this.bounds.X);
Span<TPixel> targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, span.Length), span);
if (this.preserveAlpha)

2
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<TPixel> targetRowSpan = this.targetPixels.GetRowSpanUnchecked(y).Slice(this.bounds.X);
Span<TPixel> targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, span.Length), span);
if (this.preserveAlpha)

4
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++)
{

2
src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs

@ -177,7 +177,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects
}
}
Span<TPixel> targetRowAreaPixelSpan = this.targetPixels.GetRowSpanUnchecked(y).Slice(this.bounds.X, this.bounds.Width);
Span<TPixel> targetRowAreaPixelSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X, this.bounds.Width);
PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, targetRowAreaVector4Span, targetRowAreaPixelSpan);
}

6
src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs

@ -529,7 +529,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
}
[MethodImpl(InliningOptions.ShortMethod)]
public Span<int> GetCdfLutSpan(int tileX, int tileY) => this.cdfLutBuffer2D.GetRowSpanUnchecked(tileY).Slice(tileX * this.luminanceLevels, this.luminanceLevels);
public Span<int> GetCdfLutSpan(int tileX, int tileY) => this.cdfLutBuffer2D.GetRowSpan(tileY).Slice(tileX * this.luminanceLevels, this.luminanceLevels);
/// <summary>
/// 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<int> histogramBuffer = this.allocator.Allocate<int>(this.luminanceLevels);
Span<int> 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<int> cdfLutSpan = this.cdfLutBuffer2D.GetRowSpanUnchecked(index).Slice(cdfX * this.luminanceLevels, this.luminanceLevels);
Span<int> 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);

2
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<float> rowSpan = this.data.GetRowSpanUnchecked(dataRowIndex);
Span<float> rowSpan = this.data.GetRowSpan(dataRowIndex);
ref float rowReference = ref MemoryMarshal.GetReference(rowSpan);
float* rowPtr = (float*)Unsafe.AsPointer(ref rowReference);

4
src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs

@ -102,7 +102,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<Vector4> 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<TPixel> targetRowSpan = destination.GetRowSpanUnchecked(y);
Span<TPixel> targetRowSpan = destination.GetRowSpan(y);
PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, tempColSpan, targetRowSpan, this.conversionModifiers);
}

4
src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs

@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <returns>The reference to the first item of the window.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public ref float GetYStartReference(int y)
=> ref MemoryMarshal.GetReference(this.yBuffer.GetRowSpanUnchecked(y));
=> ref MemoryMarshal.GetReference(this.yBuffer.GetRowSpan(y));
/// <summary>
/// Gets a reference to the first item of the x window.
@ -61,7 +61,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <returns>The reference to the first item of the window.</returns>
[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<TPixel>(
Vector2 transformedPoint,

4
tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs

@ -78,7 +78,7 @@ namespace SixLabors.ImageSharp.Benchmarks
Buffer2D<Rgba32> pixels = image.GetRootFramePixelBuffer();
for (int y = 0; y < image.Height; y++)
{
Span<Rgba32> span = pixels.GetRowSpanUnchecked(y);
Span<Rgba32> span = pixels.GetRowSpan(y);
this.BulkVectorConvert(span, span, span, amounts.GetSpan());
}
@ -98,7 +98,7 @@ namespace SixLabors.ImageSharp.Benchmarks
Buffer2D<Rgba32> pixels = image.GetRootFramePixelBuffer();
for (int y = 0; y < image.Height; y++)
{
Span<Rgba32> span = pixels.GetRowSpanUnchecked(y);
Span<Rgba32> span = pixels.GetRowSpan(y);
this.BulkPixelConvert(span, span, span, amounts.GetSpan());
}

2
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<Block8x8> blockRow = c.SpectralBlocks.GetRowSpanUnchecked(y);
Span<Block8x8> blockRow = c.SpectralBlocks.GetRowSpan(y);
for (int x = 0; x < result.WidthInBlocks; x++)
{
short[] data = blockRow[x].ToArray();

96
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<Rgba32>(this.configuration, 10, 10);
ImageFrame<Rgba32> 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<bool, int> OutOfRangeData = new TheoryData<bool, int>()
{
{ 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<Rgba32>(this.configuration, 10, 10);
ImageFrame<Rgba32> frame = image.Frames.RootFrame;
ArgumentOutOfRangeException ex = Assert.Throws<ArgumentOutOfRangeException>(() => _ = 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<Rgba32>(this.configuration, 10, 10);
ImageFrame<Rgba32> frame = image.Frames.RootFrame;
ArgumentOutOfRangeException ex = Assert.Throws<ArgumentOutOfRangeException>(() => 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<Rgba32>(this.configuration, 10, 10);
ImageFrame<Rgba32> frame = image.Frames.RootFrame;
ArgumentOutOfRangeException ex = Assert.Throws<ArgumentOutOfRangeException>(() => frame[3, y] = default);
Assert.Equal("y", ex.ParamName);
}
}
}
}

81
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<Rgba32>(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<bool, int> OutOfRangeData = new TheoryData<bool, int>()
{
{ 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<Rgba32>(this.configuration, 10, 10);
ArgumentOutOfRangeException ex = Assert.Throws<ArgumentOutOfRangeException>(() => _ = 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<Rgba32>(this.configuration, 10, 10);
ArgumentOutOfRangeException ex = Assert.Throws<ArgumentOutOfRangeException>(() => 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<Rgba32>(this.configuration, 10, 10);
ArgumentOutOfRangeException ex = Assert.Throws<ArgumentOutOfRangeException>(() => image[3, y] = default);
Assert.Equal("y", ex.ParamName);
}
}
}
}

55
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<TestStructs.Foo> buffer = this.MemoryAllocator.Allocate2D<TestStructs.Foo>(width, height))
{
Span<TestStructs.Foo> span = buffer.GetRowSpanUnchecked(y);
Span<TestStructs.Foo> span = buffer.GetRowSpan(y);
Assert.Equal(width, span.Length);
@ -104,6 +105,48 @@ namespace SixLabors.ImageSharp.Tests.Memory
}
}
public static TheoryData<int, int, int, int> GetRowSpanY_OutOfRange_Data = new TheoryData<int, int, int, int>()
{
{ 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<byte> buffer = this.MemoryAllocator.Allocate2D<byte>(width, height);
Exception ex = Assert.ThrowsAny<Exception>(() => buffer.GetRowSpan(y));
Assert.True(ex is ArgumentOutOfRangeException || ex is IndexOutOfRangeException);
}
public static TheoryData<int, int, int, int, int> Indexer_OutOfRange_Data = new TheoryData<int, int, int, int, int>()
{
{ 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<byte> buffer = this.MemoryAllocator.Allocate2D<byte>(width, height);
Exception ex = Assert.ThrowsAny<Exception>(() => 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<int>.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<float> row = b.GetRowSpanUnchecked(y);
Span<float> row = b.GetRowSpan(y);
Span<float> s = row.Slice(startIndex, columnCount);
Span<float> d = row.Slice(destIndex, columnCount);
@ -222,7 +265,7 @@ namespace SixLabors.ImageSharp.Tests.Memory
for (int y = 0; y < b.Height; y++)
{
Span<float> row = b.GetRowSpanUnchecked(y);
Span<float> row = b.GetRowSpan(y);
Span<float> s = row.Slice(0, 22);
Span<float> d = row.Slice(50, 22);

4
tests/ImageSharp.Tests/Memory/BufferAreaTests.cs

@ -127,7 +127,7 @@ namespace SixLabors.ImageSharp.Tests.Memory
for (int y = 0; y < 13; y++)
{
Span<int> row = buffer.GetRowSpanUnchecked(y);
Span<int> 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<int> span = buffer.GetRowSpanUnchecked(y).Slice(area.Rectangle.X, area.Width);
Span<int> span = buffer.GetRowSpan(y).Slice(area.Rectangle.X, area.Width);
Assert.True(span.SequenceEqual(new int[area.Width]));
}
}

Loading…
Cancel
Save