Browse Source

remove ImageFrame.GetPixelRowSpan

af/UniformUnmanagedMemoryPoolMemoryAllocator-02-MemoryGuards
Anton Firszov 4 years ago
parent
commit
9047fc971d
  1. 14
      src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
  2. 2
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs
  3. 5
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  4. 12
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  5. 4
      src/ImageSharp/Formats/Tiff/Writers/TiffBiColorWriter{TPixel}.cs
  6. 4
      src/ImageSharp/Formats/Tiff/Writers/TiffPaletteWriter{TPixel}.cs
  7. 2
      src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs
  8. 6
      src/ImageSharp/Formats/Webp/Lossy/YuvConversion.cs
  9. 32
      src/ImageSharp/ImageFrame{TPixel}.cs
  10. 2
      src/ImageSharp/Image{TPixel}.cs
  11. 2
      src/ImageSharp/IndexedImageFrame{TPixel}.cs
  12. 2
      src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.CommonFactoryMethods.cs
  13. 2
      src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs
  14. 2
      src/ImageSharp/Memory/Allocators/Internals/UniformUnmanagedMemoryPool.Buffer{T}.cs
  15. 14
      src/ImageSharp/Memory/Buffer2DExtensions.cs
  16. 4
      src/ImageSharp/Processing/Extensions/ProcessingExtensions.IntegralImage.cs
  17. 12
      src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor{TPixel}.cs
  18. 9
      src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs
  19. 12
      src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs
  20. 7
      src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs
  21. 18
      src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs
  22. 10
      src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs
  23. 8
      src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs
  24. 9
      src/ImageSharp/Processing/Processors/Effects/PixelateProcessor{TPixel}.cs
  25. 8
      src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs
  26. 9
      src/ImageSharp/Processing/Processors/Filters/OpaqueProcessor{TPixel}.cs
  27. 44
      src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs
  28. 14
      src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs
  29. 16
      src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs
  30. 8
      src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs
  31. 8
      src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs
  32. 8
      src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs
  33. 5
      src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs
  34. 3
      src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs
  35. 12
      src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs
  36. 39
      src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor{TPixel}.cs
  37. 17
      src/ImageSharp/Processing/Processors/Transforms/Linear/FlipProcessor{TPixel}.cs
  38. 39
      src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor{TPixel}.cs
  39. 38
      src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor{TPixel}.cs
  40. 16
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs
  41. 4
      src/ImageSharp/Processing/Processors/Transforms/SwizzleProcessor{TSwizzler,TPixel}.cs
  42. 4
      tests/ImageSharp.Tests/Advanced/AdvancedImageExtensionsTests.cs
  43. 4
      tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs
  44. 2
      tests/ImageSharp.Tests/Formats/WebP/PredictorEncoderTests.cs
  45. 16
      tests/ImageSharp.Tests/Image/ImageCloneTests.cs
  46. 12
      tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs
  47. 2
      tests/ImageSharp.Tests/Image/ImageTests.cs
  48. 4
      tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs
  49. 16
      tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs
  50. 7
      tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs
  51. 7
      tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs
  52. 4
      tests/ImageSharp.Tests/TestUtilities/ImageProviders/BasicTestPatternProvider.cs
  53. 20
      tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs
  54. 8
      tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs

14
src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs

@ -379,7 +379,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
for (int y = image.Height - 1; y >= 0; y--)
{
ReadOnlySpan<byte> pixelSpan = quantized.GetPixelRowSpan(y);
ReadOnlySpan<byte> pixelSpan = quantized.DangerousGetRowSpan(y);
stream.Write(pixelSpan);
for (int i = 0; i < this.padding; i++)
@ -413,10 +413,10 @@ namespace SixLabors.ImageSharp.Formats.Bmp
}
stream.Write(colorPalette);
Buffer2D<TPixel> imageBuffer = image.PixelBuffer;
for (int y = image.Height - 1; y >= 0; y--)
{
ReadOnlySpan<TPixel> inputPixelRow = image.GetPixelRowSpan(y);
ReadOnlySpan<TPixel> inputPixelRow = imageBuffer.DangerousGetRowSpan(y);
ReadOnlySpan<byte> outputPixelRow = MemoryMarshal.AsBytes(inputPixelRow);
stream.Write(outputPixelRow);
@ -447,11 +447,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp
ReadOnlySpan<TPixel> quantizedColorPalette = quantized.Palette.Span;
this.WriteColorPalette(stream, quantizedColorPalette, colorPalette);
ReadOnlySpan<byte> pixelRowSpan = quantized.GetPixelRowSpan(0);
ReadOnlySpan<byte> pixelRowSpan = quantized.DangerousGetRowSpan(0);
int rowPadding = pixelRowSpan.Length % 2 != 0 ? this.padding - 1 : this.padding;
for (int y = image.Height - 1; y >= 0; y--)
{
pixelRowSpan = quantized.GetPixelRowSpan(y);
pixelRowSpan = quantized.DangerousGetRowSpan(y);
int endIdx = pixelRowSpan.Length % 2 == 0 ? pixelRowSpan.Length : pixelRowSpan.Length - 1;
for (int i = 0; i < endIdx; i += 2)
@ -491,11 +491,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp
ReadOnlySpan<TPixel> quantizedColorPalette = quantized.Palette.Span;
this.WriteColorPalette(stream, quantizedColorPalette, colorPalette);
ReadOnlySpan<byte> quantizedPixelRow = quantized.GetPixelRowSpan(0);
ReadOnlySpan<byte> quantizedPixelRow = quantized.DangerousGetRowSpan(0);
int rowPadding = quantizedPixelRow.Length % 8 != 0 ? this.padding - 1 : this.padding;
for (int y = image.Height - 1; y >= 0; y--)
{
quantizedPixelRow = quantized.GetPixelRowSpan(y);
quantizedPixelRow = quantized.DangerousGetRowSpan(y);
int endIdx = quantizedPixelRow.Length % 8 == 0 ? quantizedPixelRow.Length : quantizedPixelRow.Length - 8;
for (int i = 0; i < endIdx; i += 8)

2
src/ImageSharp/Formats/Gif/GifDecoderCore.cs

@ -481,7 +481,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
writeY = y;
}
ref TPixel rowRef = ref MemoryMarshal.GetReference(imageFrame.GetPixelRowSpan(writeY));
ref TPixel rowRef = ref MemoryMarshal.GetReference(imageFrame.PixelBuffer.DangerousGetRowSpan(writeY));
if (!transFlag)
{

5
src/ImageSharp/Formats/Png/PngDecoderCore.cs

@ -565,6 +565,7 @@ namespace SixLabors.ImageSharp.Formats.Png
{
int pass = 0;
int width = this.header.Width;
Buffer2D<TPixel> imageBuffer = image.PixelBuffer;
while (true)
{
int numColumns = Adam7.ComputeColumns(width, pass);
@ -623,7 +624,7 @@ namespace SixLabors.ImageSharp.Formats.Png
break;
}
Span<TPixel> rowSpan = image.GetPixelRowSpan(this.currentRow);
Span<TPixel> rowSpan = imageBuffer.DangerousGetRowSpan(this.currentRow);
this.ProcessInterlacedDefilteredScanline(this.scanline.GetSpan(), rowSpan, pngMetadata, Adam7.FirstColumn[pass], Adam7.ColumnIncrement[pass]);
this.SwapScanlineBuffers();
@ -656,7 +657,7 @@ namespace SixLabors.ImageSharp.Formats.Png
private void ProcessDefilteredScanline<TPixel>(ReadOnlySpan<byte> defilteredScanline, ImageFrame<TPixel> pixels, PngMetadata pngMetadata)
where TPixel : unmanaged, IPixel<TPixel>
{
Span<TPixel> rowSpan = pixels.GetPixelRowSpan(this.currentRow);
Span<TPixel> rowSpan = pixels.PixelBuffer.DangerousGetRowSpan(this.currentRow);
// Trim the first marker byte from the buffer
ReadOnlySpan<byte> trimmed = defilteredScanline.Slice(1, defilteredScanline.Length - 1);

12
src/ImageSharp/Formats/Png/PngEncoderCore.cs

@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.Formats.Png
Rgba32 rgba32 = default;
for (int y = 0; y < image.Height; y++)
{
Span<TPixel> span = image.GetPixelRowSpan(y);
Span<TPixel> span = image.DangerousGetRowSpan(y);
for (int x = 0; x < image.Width; x++)
{
span[x].ToRgba32(ref rgba32);
@ -391,11 +391,11 @@ namespace SixLabors.ImageSharp.Formats.Png
if (this.bitDepth < 8)
{
PngEncoderHelpers.ScaleDownFrom8BitArray(quantized.GetPixelRowSpan(row), this.currentScanline.GetSpan(), this.bitDepth);
PngEncoderHelpers.ScaleDownFrom8BitArray(quantized.DangerousGetRowSpan(row), this.currentScanline.GetSpan(), this.bitDepth);
}
else
{
quantized.GetPixelRowSpan(row).CopyTo(this.currentScanline.GetSpan());
quantized.DangerousGetRowSpan(row).CopyTo(this.currentScanline.GetSpan());
}
break;
@ -918,7 +918,7 @@ namespace SixLabors.ImageSharp.Formats.Png
Span<byte> attempt = attemptBuffer.GetSpan();
for (int y = 0; y < this.height; y++)
{
this.CollectAndFilterPixelRow(pixels.GetPixelRowSpan(y), ref filter, ref attempt, quantized, y);
this.CollectAndFilterPixelRow(pixels.DangerousGetRowSpan(y), ref filter, ref attempt, quantized, y);
deflateStream.Write(filter);
this.SwapScanlineBuffers();
}
@ -959,7 +959,7 @@ namespace SixLabors.ImageSharp.Formats.Png
for (int row = startRow; row < height; row += Adam7.RowIncrement[pass])
{
// Collect pixel data
Span<TPixel> srcRow = pixels.GetPixelRowSpan(row);
Span<TPixel> srcRow = pixels.DangerousGetRowSpan(row);
for (int col = startCol, i = 0; col < width; col += Adam7.ColumnIncrement[pass])
{
block[i++] = srcRow[col];
@ -1014,7 +1014,7 @@ namespace SixLabors.ImageSharp.Formats.Png
row += Adam7.RowIncrement[pass])
{
// Collect data
ReadOnlySpan<byte> srcRow = quantized.GetPixelRowSpan(row);
ReadOnlySpan<byte> srcRow = quantized.DangerousGetRowSpan(row);
for (int col = startCol, i = 0;
col < width;
col += Adam7.ColumnIncrement[pass])

4
src/ImageSharp/Formats/Tiff/Writers/TiffBiColorWriter{TPixel}.cs

@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Writers
int grayRowIdx = 0;
for (int row = y; row < lastRow; row++)
{
Span<TPixel> pixelsBlackWhiteRow = this.imageBlackWhite.GetPixelRowSpan(row);
Span<TPixel> pixelsBlackWhiteRow = this.imageBlackWhite.DangerousGetRowSpan(row);
Span<byte> pixelAsGrayRow = pixelAsGraySpan.Slice(grayRowIdx * width, width);
PixelOperations<TPixel>.Instance.ToL8Bytes(this.Configuration, pixelsBlackWhiteRow, pixelAsGrayRow, width);
grayRowIdx++;
@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Writers
int bitIndex = 0;
int byteIndex = 0;
Span<byte> outputRow = rows.Slice(outputRowIdx * this.BytesPerRow);
Span<TPixel> pixelsBlackWhiteRow = this.imageBlackWhite.GetPixelRowSpan(row);
Span<TPixel> pixelsBlackWhiteRow = this.imageBlackWhite.DangerousGetRowSpan(row);
PixelOperations<TPixel>.Instance.ToL8Bytes(this.Configuration, pixelsBlackWhiteRow, pixelAsGraySpan, width);
for (int x = 0; x < this.Image.Width; x++)
{

4
src/ImageSharp/Formats/Tiff/Writers/TiffPaletteWriter{TPixel}.cs

@ -67,7 +67,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Writers
int lastRow = y + height;
for (int row = y; row < lastRow; row++)
{
ReadOnlySpan<byte> indexedPixelRow = this.quantizedImage.GetPixelRowSpan(row);
ReadOnlySpan<byte> indexedPixelRow = this.quantizedImage.DangerousGetRowSpan(row);
int idxPixels = 0;
for (int x = 0; x < halfWidth; x++)
{
@ -94,7 +94,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Writers
int indexedPixelsRowIdx = 0;
for (int row = y; row < lastRow; row++)
{
ReadOnlySpan<byte> indexedPixelRow = this.quantizedImage.GetPixelRowSpan(row);
ReadOnlySpan<byte> indexedPixelRow = this.quantizedImage.DangerousGetRowSpan(row);
indexedPixelRow.CopyTo(indexedPixels.Slice(indexedPixelsRowIdx * width, width));
indexedPixelsRowIdx++;
}

2
src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs

@ -395,7 +395,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
int widthBytes = width * 4;
for (int y = 0; y < height; y++)
{
Span<TPixel> rowSpan = image.GetPixelRowSpan(y);
Span<TPixel> rowSpan = image.DangerousGetRowSpan(y);
Span<byte> rowBytes = bgraBytes.Slice(y * widthBytes, widthBytes);
PixelOperations<TPixel>.Instance.ToBgra32Bytes(this.configuration, rowSpan, rowBytes, width);
if (!nonOpaque)

6
src/ImageSharp/Formats/Webp/Lossy/YuvConversion.cs

@ -46,8 +46,8 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
int rowIndex;
for (rowIndex = 0; rowIndex < height - 1; rowIndex += 2)
{
Span<TPixel> rowSpan = image.GetPixelRowSpan(rowIndex);
Span<TPixel> nextRowSpan = image.GetPixelRowSpan(rowIndex + 1);
Span<TPixel> rowSpan = image.DangerousGetRowSpan(rowIndex);
Span<TPixel> nextRowSpan = image.DangerousGetRowSpan(rowIndex + 1);
PixelOperations<TPixel>.Instance.ToBgra32(configuration, rowSpan, bgraRow0);
PixelOperations<TPixel>.Instance.ToBgra32(configuration, nextRowSpan, bgraRow1);
@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
// Extra last row.
if ((height & 1) != 0)
{
Span<TPixel> rowSpan = image.GetPixelRowSpan(rowIndex);
Span<TPixel> rowSpan = image.DangerousGetRowSpan(rowIndex);
PixelOperations<TPixel>.Instance.ToBgra32(configuration, rowSpan, bgraRow0);
ConvertRgbaToY(bgraRow0, y.Slice(rowIndex * width), width);

32
src/ImageSharp/ImageFrame{TPixel}.cs

@ -177,24 +177,6 @@ namespace SixLabors.ImageSharp
}
}
/// <summary>
/// Gets the representation of the pixels as a <see cref="Span{T}"/> of contiguous memory
/// at row <paramref name="rowIndex"/> beginning from the first pixel on that row.
/// <para />
/// WARNING: Disposing or leaking the underlying image while still working with it's <see cref="Span{T}"/>
/// might lead to memory corruption.
/// </summary>
/// <param name="rowIndex">The row.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when row index is out of range.</exception>
public Span<TPixel> GetPixelRowSpan(int rowIndex)
{
Guard.MustBeGreaterThanOrEqualTo(rowIndex, 0, nameof(rowIndex));
Guard.MustBeLessThan(rowIndex, this.Height, nameof(rowIndex));
return this.PixelBuffer.DangerousGetRowSpan(rowIndex);
}
/// <summary>
/// Execute <paramref name="processPixels"/> to process image pixels in a safe and efficient manner.
/// </summary>
@ -418,7 +400,7 @@ namespace SixLabors.ImageSharp
}
var target = new ImageFrame<TPixel2>(configuration, this.Width, this.Height, this.Metadata.DeepClone());
var operation = new RowIntervalOperation<TPixel2>(this, target, configuration);
var operation = new RowIntervalOperation<TPixel2>(this.PixelBuffer, target.PixelBuffer, configuration);
ParallelRowIterator.IterateRowIntervals(
configuration,
@ -472,14 +454,14 @@ namespace SixLabors.ImageSharp
private readonly struct RowIntervalOperation<TPixel2> : IRowIntervalOperation
where TPixel2 : unmanaged, IPixel<TPixel2>
{
private readonly ImageFrame<TPixel> source;
private readonly ImageFrame<TPixel2> target;
private readonly Buffer2D<TPixel> source;
private readonly Buffer2D<TPixel2> target;
private readonly Configuration configuration;
[MethodImpl(InliningOptions.ShortMethod)]
public RowIntervalOperation(
ImageFrame<TPixel> source,
ImageFrame<TPixel2> target,
Buffer2D<TPixel> source,
Buffer2D<TPixel2> target,
Configuration configuration)
{
this.source = source;
@ -493,8 +475,8 @@ namespace SixLabors.ImageSharp
{
for (int y = rows.Min; y < rows.Max; y++)
{
Span<TPixel> sourceRow = this.source.GetPixelRowSpan(y);
Span<TPixel2> targetRow = this.target.GetPixelRowSpan(y);
Span<TPixel> sourceRow = this.source.DangerousGetRowSpan(y);
Span<TPixel2> targetRow = this.target.DangerousGetRowSpan(y);
PixelOperations<TPixel>.Instance.To(this.configuration, sourceRow, targetRow);
}
}

2
src/ImageSharp/Image{TPixel}.cs

@ -310,7 +310,7 @@ namespace SixLabors.ImageSharp
/// <param name="rowIndex">The row.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when row index is out of range.</exception>
public Span<TPixel> GetPixelRowSpan(int rowIndex)
public Span<TPixel> DangerousGetRowSpan(int rowIndex)
{
Guard.MustBeGreaterThanOrEqualTo(rowIndex, 0, nameof(rowIndex));
Guard.MustBeLessThan(rowIndex, this.Height, nameof(rowIndex));

2
src/ImageSharp/IndexedImageFrame{TPixel}.cs

@ -82,7 +82,7 @@ namespace SixLabors.ImageSharp
/// <param name="rowIndex">The row index in the pixel buffer.</param>
/// <returns>The pixel row as a <see cref="ReadOnlySpan{T}"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public ReadOnlySpan<byte> GetPixelRowSpan(int rowIndex)
public ReadOnlySpan<byte> DangerousGetRowSpan(int rowIndex)
=> this.GetWritablePixelRowSpanUnsafe(rowIndex);
/// <summary>

2
src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.CommonFactoryMethods.cs

@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Memory
/// This is the default. Should be good for most use cases.
/// </summary>
/// <returns>The memory manager.</returns>
public static new ArrayPoolMemoryAllocator CreateDefault()
public static ArrayPoolMemoryAllocator CreateDefault()
{
return new ArrayPoolMemoryAllocator(
DefaultMaxPooledBufferSizeInBytes,

2
src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs

@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.Memory.Internals
// The worst thing that could happen is that a VERY poorly written user code holding a Span<TPixel> on the stack,
// while loosing the reference to Image<TPixel> (or disposing it) may write to an unrelated ArrayPool array.
// This is an unlikely scenario we mitigate by a warning in GetPixelRowSpan(i) APIs.
// This is an unlikely scenario we mitigate by a warning in DangerousGetRowSpan(i) APIs.
#pragma warning disable CA2015 // Adding a finalizer to a type derived from MemoryManager<T> may permit memory to be freed while it is still in use by a Span<T>
~SharedArrayPoolBuffer() => this.Dispose(false);
#pragma warning restore

2
src/ImageSharp/Memory/Allocators/Internals/UniformUnmanagedMemoryPool.Buffer{T}.cs

@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Memory.Internals
// A VERY poorly written user code holding a Span<TPixel> on the stack,
// while loosing the reference to Image<TPixel> (or disposing it) may write to (now unrelated) pool buffer,
// or cause memory corruption if the underlying UmnanagedMemoryHandle has been released.
// This is an unlikely scenario we mitigate a warning in GetPixelRowSpan(i) APIs.
// This is an unlikely scenario we mitigate a warning in DangerousGetRowSpan(i) APIs.
#pragma warning disable CA2015 // Adding a finalizer to a type derived from MemoryManager<T> may permit memory to be freed while it is still in use by a Span<T>
~FinalizableBuffer() => this.Dispose(false);
#pragma warning restore

14
src/ImageSharp/Memory/Buffer2DExtensions.cs

@ -111,10 +111,16 @@ namespace SixLabors.ImageSharp.Memory
/// <param name="buffer">The <see cref="Buffer2D{T}"/></param>
/// <returns>The <see cref="Size{T}"/> of the buffer</returns>
internal static Size Size<T>(this Buffer2D<T> buffer)
where T : struct
{
return new Size(buffer.Width, buffer.Height);
}
where T : struct =>
new(buffer.Width, buffer.Height);
/// <summary>
/// Gets the bounds of the buffer.
/// </summary>
/// <returns>The <see cref="Rectangle"/></returns>
internal static Rectangle Bounds<T>(this Buffer2D<T> buffer)
where T : struct =>
new(0, 0, buffer.Width, buffer.Height);
[Conditional("DEBUG")]
private static void CheckColumnRegionsDoNotOverlap<T>(

4
src/ImageSharp/Processing/Extensions/ProcessingExtensions.IntegralImage.cs

@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.Processing
using (IMemoryOwner<L8> tempRow = configuration.MemoryAllocator.Allocate<L8>(source.Width))
{
Span<L8> tempSpan = tempRow.GetSpan();
Span<TPixel> sourceRow = source.GetPixelRowSpan(0);
Span<TPixel> sourceRow = source.DangerousGetRowSpan(0);
Span<ulong> destRow = intImage.DangerousGetRowSpan(0);
PixelOperations<TPixel>.Instance.ToL8(configuration, sourceRow, tempSpan);
@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Processing
// All other rows
for (int y = 1; y < endY; y++)
{
sourceRow = source.GetPixelRowSpan(y);
sourceRow = source.DangerousGetRowSpan(y);
destRow = intImage.DangerousGetRowSpan(y);
PixelOperations<TPixel>.Instance.ToL8(configuration, sourceRow, tempSpan);

12
src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor{TPixel}.cs

@ -52,6 +52,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
// ClusterSize defines the size of cluster to used to check for average. Tweaked to support up to 4k wide pixels and not more. 4096 / 16 is 256 thus the '-1'
byte clusterSize = (byte)Math.Truncate((width / 16f) - 1);
Buffer2D<TPixel> sourceBuffer = source.PixelBuffer;
// Using pooled 2d buffer for integer image table and temp memory to hold Rgb24 converted pixel data.
using (Buffer2D<ulong> intImage = this.Configuration.MemoryAllocator.Allocate2D<ulong>(width, height))
{
@ -61,7 +63,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
ulong sum = 0;
for (int y = startY; y < endY; y++)
{
Span<TPixel> row = source.GetPixelRowSpan(y);
Span<TPixel> row = sourceBuffer.DangerousGetRowSpan(y);
ref TPixel rowRef = ref MemoryMarshal.GetReference(row);
ref TPixel color = ref Unsafe.Add(ref rowRef, x);
color.ToRgba32(ref rgb);
@ -79,7 +81,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
}
}
var operation = new RowOperation(intersect, source, intImage, upper, lower, thresholdLimit, clusterSize, startX, endX, startY);
var operation = new RowOperation(intersect, source.PixelBuffer, intImage, upper, lower, thresholdLimit, clusterSize, startX, endX, startY);
ParallelRowIterator.IterateRows(
configuration,
intersect,
@ -90,7 +92,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
private readonly struct RowOperation : IRowOperation
{
private readonly Rectangle bounds;
private readonly ImageFrame<TPixel> source;
private readonly Buffer2D<TPixel> source;
private readonly Buffer2D<ulong> intImage;
private readonly TPixel upper;
private readonly TPixel lower;
@ -103,7 +105,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
[MethodImpl(InliningOptions.ShortMethod)]
public RowOperation(
Rectangle bounds,
ImageFrame<TPixel> source,
Buffer2D<TPixel> source,
Buffer2D<ulong> intImage,
TPixel upper,
TPixel lower,
@ -130,7 +132,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
public void Invoke(int y)
{
Rgba32 rgb = default;
Span<TPixel> pixelRow = this.source.GetPixelRowSpan(y);
Span<TPixel> pixelRow = this.source.DangerousGetRowSpan(y);
for (int x = this.startX; x < this.endX; x++)
{

9
src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs

@ -4,6 +4,7 @@
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Binarization
@ -41,7 +42,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
var interest = Rectangle.Intersect(sourceRectangle, source.Bounds());
var operation = new RowOperation(
interest.X,
source,
source.PixelBuffer,
upper,
lower,
threshold,
@ -59,7 +60,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
/// </summary>
private readonly struct RowOperation : IRowOperation<Rgb24>
{
private readonly ImageFrame<TPixel> source;
private readonly Buffer2D<TPixel> source;
private readonly TPixel upper;
private readonly TPixel lower;
private readonly byte threshold;
@ -70,7 +71,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
[MethodImpl(InliningOptions.ShortMethod)]
public RowOperation(
int startX,
ImageFrame<TPixel> source,
Buffer2D<TPixel> source,
TPixel upper,
TPixel lower,
byte threshold,
@ -93,7 +94,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
TPixel upper = this.upper;
TPixel lower = this.lower;
Span<TPixel> rowSpan = this.source.GetPixelRowSpan(y).Slice(this.startX, span.Length);
Span<TPixel> rowSpan = this.source.DangerousGetRowSpan(y).Slice(this.startX, span.Length);
PixelOperations<TPixel>.Instance.ToRgb24(this.configuration, rowSpan, span);
switch (this.mode)

12
src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs

@ -5,6 +5,7 @@ using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Quantization;
@ -105,14 +106,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
int offsetY = bounds.Top;
int offsetX = bounds.Left;
float scale = quantizer.Options.DitherScale;
Buffer2D<TPixel> sourceBuffer = source.PixelBuffer;
for (int y = bounds.Top; y < bounds.Bottom; y++)
{
// Unsafe optimizations undone temporarily.
// Sporadic local AccessViolationException indicates possible indexing bug.
// ref TPixel sourceRowRef = ref MemoryMarshal.GetReference(source.GetPixelRowSpan(y));
// ref TPixel sourceRowRef = ref MemoryMarshal.GetReference(source.DangerousGetRowSpan(y));
// ref byte destinationRowRef = ref MemoryMarshal.GetReference(destination.GetWritablePixelRowSpanUnsafe(y - offsetY));
Span<TPixel> sourceSpan = source.GetPixelRowSpan(y);
Span<TPixel> sourceSpan = sourceBuffer.DangerousGetRowSpan(y);
Span<byte> destSpan = destination.GetWritablePixelRowSpanUnsafe(y - offsetY);
for (int x = bounds.Left; x < bounds.Right; x++)
@ -140,10 +142,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
ThrowDefaultInstance();
}
Buffer2D<TPixel> sourceBuffer = source.PixelBuffer;
float scale = processor.DitherScale;
for (int y = bounds.Top; y < bounds.Bottom; y++)
{
ref TPixel sourceRowRef = ref MemoryMarshal.GetReference(source.GetPixelRowSpan(y));
ref TPixel sourceRowRef = ref MemoryMarshal.GetReference(sourceBuffer.DangerousGetRowSpan(y));
for (int x = bounds.Left; x < bounds.Right; x++)
{
ref TPixel sourcePixel = ref Unsafe.Add(ref sourceRowRef, x);
@ -177,6 +180,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
int offset = this.offset;
DenseMatrix<float> matrix = this.matrix;
Buffer2D<TPixel> imageBuffer = image.PixelBuffer;
// Loop through and distribute the error amongst neighboring pixels.
for (int row = 0, targetY = y; row < matrix.Rows; row++, targetY++)
@ -186,7 +190,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
continue;
}
Span<TPixel> rowSpan = image.GetPixelRowSpan(targetY);
Span<TPixel> rowSpan = imageBuffer.DangerousGetRowSpan(targetY);
for (int col = 0; col < matrix.Columns; col++)
{

7
src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs

@ -3,6 +3,7 @@
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Quantization;
@ -118,10 +119,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
int spread = CalculatePaletteSpread(destination.Palette.Length);
float scale = quantizer.Options.DitherScale;
Buffer2D<TPixel> sourceBuffer = source.PixelBuffer;
for (int y = bounds.Top; y < bounds.Bottom; y++)
{
ReadOnlySpan<TPixel> sourceRow = source.GetPixelRowSpan(y).Slice(bounds.X, bounds.Width);
ReadOnlySpan<TPixel> sourceRow = sourceBuffer.DangerousGetRowSpan(y).Slice(bounds.X, bounds.Width);
Span<byte> destRow = destination.GetWritablePixelRowSpanUnsafe(y - bounds.Y).Slice(0, sourceRow.Length);
for (int x = 0; x < sourceRow.Length; x++)
@ -148,10 +150,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
int spread = CalculatePaletteSpread(processor.Palette.Length);
float scale = processor.DitherScale;
Buffer2D<TPixel> sourceBuffer = source.PixelBuffer;
for (int y = bounds.Top; y < bounds.Bottom; y++)
{
Span<TPixel> row = source.GetPixelRowSpan(y).Slice(bounds.X, bounds.Width);
Span<TPixel> row = sourceBuffer.DangerousGetRowSpan(y).Slice(bounds.X, bounds.Width);
for (int x = 0; x < row.Length; x++)
{

18
src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs

@ -99,7 +99,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
"Cannot draw image because the source image does not overlap the target image.");
}
var operation = new RowOperation(source, targetImage, blender, configuration, minX, width, locationY, targetX, this.Opacity);
var operation = new RowOperation(source.PixelBuffer, targetImage.Frames.RootFrame.PixelBuffer, blender, configuration, minX, width, locationY, targetX, this.Opacity);
ParallelRowIterator.IterateRows(
configuration,
workingRect,
@ -111,8 +111,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
/// </summary>
private readonly struct RowOperation : IRowOperation
{
private readonly ImageFrame<TPixelBg> sourceFrame;
private readonly Image<TPixelFg> targetImage;
private readonly Buffer2D<TPixelBg> source;
private readonly Buffer2D<TPixelFg> target;
private readonly PixelBlender<TPixelBg> blender;
private readonly Configuration configuration;
private readonly int minX;
@ -123,8 +123,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
[MethodImpl(InliningOptions.ShortMethod)]
public RowOperation(
ImageFrame<TPixelBg> sourceFrame,
Image<TPixelFg> targetImage,
Buffer2D<TPixelBg> source,
Buffer2D<TPixelFg> target,
PixelBlender<TPixelBg> blender,
Configuration configuration,
int minX,
@ -133,8 +133,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
int targetX,
float opacity)
{
this.sourceFrame = sourceFrame;
this.targetImage = targetImage;
this.source = source;
this.target = target;
this.blender = blender;
this.configuration = configuration;
this.minX = minX;
@ -148,8 +148,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
[MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(int y)
{
Span<TPixelBg> background = this.sourceFrame.GetPixelRowSpan(y).Slice(this.minX, this.width);
Span<TPixelFg> foreground = this.targetImage.GetPixelRowSpan(y - this.locationY).Slice(this.targetX, this.width);
Span<TPixelBg> background = this.source.DangerousGetRowSpan(y).Slice(this.minX, this.width);
Span<TPixelFg> foreground = this.target.DangerousGetRowSpan(y - this.locationY).Slice(this.targetX, this.width);
this.blender.Blend<TPixelFg>(this.configuration, background, background, foreground, this.opacity);
}
}

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

@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects
source.CopyTo(targetPixels);
var operation = new RowIntervalOperation(this.SourceRectangle, targetPixels, source, this.Configuration, brushSize >> 1, this.definition.Levels);
var operation = new RowIntervalOperation(this.SourceRectangle, targetPixels, source.PixelBuffer, this.Configuration, brushSize >> 1, this.definition.Levels);
ParallelRowIterator.IterateRowIntervals(
this.Configuration,
this.SourceRectangle,
@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects
{
private readonly Rectangle bounds;
private readonly Buffer2D<TPixel> targetPixels;
private readonly ImageFrame<TPixel> source;
private readonly Buffer2D<TPixel> source;
private readonly Configuration configuration;
private readonly int radius;
private readonly int levels;
@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects
public RowIntervalOperation(
Rectangle bounds,
Buffer2D<TPixel> targetPixels,
ImageFrame<TPixel> source,
Buffer2D<TPixel> source,
Configuration configuration,
int radius,
int levels)
@ -120,7 +120,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects
for (int y = rows.Min; y < rows.Max; y++)
{
Span<TPixel> sourceRowPixelSpan = this.source.GetPixelRowSpan(y);
Span<TPixel> sourceRowPixelSpan = this.source.DangerousGetRowSpan(y);
Span<TPixel> sourceRowAreaPixelSpan = sourceRowPixelSpan.Slice(this.bounds.X, this.bounds.Width);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, sourceRowAreaPixelSpan, sourceRowAreaVector4Span);
@ -139,7 +139,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects
int offsetY = y + fyr;
offsetY = Numerics.Clamp(offsetY, 0, maxY);
Span<TPixel> sourceOffsetRow = this.source.GetPixelRowSpan(offsetY);
Span<TPixel> sourceOffsetRow = this.source.DangerousGetRowSpan(offsetY);
for (int fx = 0; fx <= this.radius; fx++)
{

8
src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs

@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects
protected override void OnFrameApply(ImageFrame<TPixel> source)
{
var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
var operation = new RowOperation(interest.X, source, this.Configuration, this.modifiers, this.rowDelegate);
var operation = new RowOperation(interest.X, source.PixelBuffer, this.Configuration, this.modifiers, this.rowDelegate);
ParallelRowIterator.IterateRows<RowOperation, Vector4>(
this.Configuration,
@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects
private readonly struct RowOperation : IRowOperation<Vector4>
{
private readonly int startX;
private readonly ImageFrame<TPixel> source;
private readonly Buffer2D<TPixel> source;
private readonly Configuration configuration;
private readonly PixelConversionModifiers modifiers;
private readonly TDelegate rowProcessor;
@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects
[MethodImpl(InliningOptions.ShortMethod)]
public RowOperation(
int startX,
ImageFrame<TPixel> source,
Buffer2D<TPixel> source,
Configuration configuration,
PixelConversionModifiers modifiers,
in TDelegate rowProcessor)
@ -88,7 +88,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects
[MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(int y, Span<Vector4> span)
{
Span<TPixel> rowSpan = this.source.GetPixelRowSpan(y).Slice(this.startX, span.Length);
Span<TPixel> rowSpan = this.source.DangerousGetRowSpan(y).Slice(this.startX, span.Length);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, rowSpan, span, this.modifiers);
// Run the user defined pixel shader to the current row of pixels

9
src/ImageSharp/Processing/Processors/Effects/PixelateProcessor{TPixel}.cs

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Effects
@ -48,7 +49,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects
Parallel.ForEach(
range,
this.Configuration.GetParallelOptions(),
new RowOperation(interest, size, source).Invoke);
new RowOperation(interest, size, source.PixelBuffer).Invoke);
}
private readonly struct RowOperation
@ -60,13 +61,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects
private readonly int maxYIndex;
private readonly int size;
private readonly int radius;
private readonly ImageFrame<TPixel> source;
private readonly Buffer2D<TPixel> source;
[MethodImpl(InliningOptions.ShortMethod)]
public RowOperation(
Rectangle bounds,
int size,
ImageFrame<TPixel> source)
Buffer2D<TPixel> source)
{
this.minX = bounds.X;
this.maxX = bounds.Right;
@ -81,7 +82,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects
[MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(int y)
{
Span<TPixel> rowSpan = this.source.GetPixelRowSpan(Math.Min(y + this.radius, this.maxYIndex));
Span<TPixel> rowSpan = this.source.DangerousGetRowSpan(Math.Min(y + this.radius, this.maxYIndex));
for (int x = this.minX; x < this.maxX; x += this.size)
{

8
src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs

@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
protected override void OnFrameApply(ImageFrame<TPixel> source)
{
var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
var operation = new RowOperation(interest.X, source, this.definition.Matrix, this.Configuration);
var operation = new RowOperation(interest.X, source.PixelBuffer, this.definition.Matrix, this.Configuration);
ParallelRowIterator.IterateRows<RowOperation, Vector4>(
this.Configuration,
@ -50,14 +50,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
private readonly struct RowOperation : IRowOperation<Vector4>
{
private readonly int startX;
private readonly ImageFrame<TPixel> source;
private readonly Buffer2D<TPixel> source;
private readonly ColorMatrix matrix;
private readonly Configuration configuration;
[MethodImpl(InliningOptions.ShortMethod)]
public RowOperation(
int startX,
ImageFrame<TPixel> source,
Buffer2D<TPixel> source,
ColorMatrix matrix,
Configuration configuration)
{
@ -71,7 +71,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
[MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(int y, Span<Vector4> span)
{
Span<TPixel> rowSpan = this.source.GetPixelRowSpan(y).Slice(this.startX, span.Length);
Span<TPixel> rowSpan = this.source.DangerousGetRowSpan(y).Slice(this.startX, span.Length);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, rowSpan, span, PixelConversionModifiers.Scale);
ColorNumerics.Transform(span, ref Unsafe.AsRef(this.matrix));

9
src/ImageSharp/Processing/Processors/Filters/OpaqueProcessor{TPixel}.cs

@ -6,6 +6,7 @@ using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Filters
@ -25,20 +26,20 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
{
var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
var operation = new OpaqueRowOperation(this.Configuration, source, interest);
var operation = new OpaqueRowOperation(this.Configuration, source.PixelBuffer, interest);
ParallelRowIterator.IterateRows<OpaqueRowOperation, Vector4>(this.Configuration, interest, in operation);
}
private readonly struct OpaqueRowOperation : IRowOperation<Vector4>
{
private readonly Configuration configuration;
private readonly ImageFrame<TPixel> target;
private readonly Buffer2D<TPixel> target;
private readonly Rectangle bounds;
[MethodImpl(InliningOptions.ShortMethod)]
public OpaqueRowOperation(
Configuration configuration,
ImageFrame<TPixel> target,
Buffer2D<TPixel> target,
Rectangle bounds)
{
this.configuration = configuration;
@ -50,7 +51,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
[MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(int y, Span<Vector4> span)
{
Span<TPixel> targetRowSpan = this.target.GetPixelRowSpan(y).Slice(this.bounds.X);
Span<TPixel> targetRowSpan = this.target.DangerousGetRowSpan(y).Slice(this.bounds.X);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, span.Length), span, PixelConversionModifiers.Scale);
ref Vector4 baseRef = ref MemoryMarshal.GetReference(span);

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

@ -80,37 +80,37 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
yStart += tileHeight;
}
var operation = new RowIntervalOperation(cdfData, tileYStartPositions, tileWidth, tileHeight, tileCount, halfTileWidth, luminanceLevels, source);
var operation = new RowIntervalOperation(cdfData, tileYStartPositions, tileWidth, tileHeight, tileCount, halfTileWidth, luminanceLevels, source.PixelBuffer);
ParallelRowIterator.IterateRowIntervals(
this.Configuration,
new Rectangle(0, 0, sourceWidth, tileYStartPositions.Count),
in operation);
// Fix left column
ProcessBorderColumn(source, cdfData, 0, sourceHeight, this.Tiles, tileHeight, xStart: 0, xEnd: halfTileWidth, luminanceLevels);
ProcessBorderColumn(source.PixelBuffer, cdfData, 0, sourceHeight, this.Tiles, tileHeight, xStart: 0, xEnd: halfTileWidth, luminanceLevels);
// Fix right column
int rightBorderStartX = ((this.Tiles - 1) * tileWidth) + halfTileWidth;
ProcessBorderColumn(source, cdfData, this.Tiles - 1, sourceHeight, this.Tiles, tileHeight, xStart: rightBorderStartX, xEnd: sourceWidth, luminanceLevels);
ProcessBorderColumn(source.PixelBuffer, cdfData, this.Tiles - 1, sourceHeight, this.Tiles, tileHeight, xStart: rightBorderStartX, xEnd: sourceWidth, luminanceLevels);
// Fix top row
ProcessBorderRow(source, cdfData, 0, sourceWidth, this.Tiles, tileWidth, yStart: 0, yEnd: halfTileHeight, luminanceLevels);
ProcessBorderRow(source.PixelBuffer, cdfData, 0, sourceWidth, this.Tiles, tileWidth, yStart: 0, yEnd: halfTileHeight, luminanceLevels);
// Fix bottom row
int bottomBorderStartY = ((this.Tiles - 1) * tileHeight) + halfTileHeight;
ProcessBorderRow(source, cdfData, this.Tiles - 1, sourceWidth, this.Tiles, tileWidth, yStart: bottomBorderStartY, yEnd: sourceHeight, luminanceLevels);
ProcessBorderRow(source.PixelBuffer, cdfData, this.Tiles - 1, sourceWidth, this.Tiles, tileWidth, yStart: bottomBorderStartY, yEnd: sourceHeight, luminanceLevels);
// Left top corner
ProcessCornerTile(source, cdfData, 0, 0, xStart: 0, xEnd: halfTileWidth, yStart: 0, yEnd: halfTileHeight, luminanceLevels);
ProcessCornerTile(source.PixelBuffer, cdfData, 0, 0, xStart: 0, xEnd: halfTileWidth, yStart: 0, yEnd: halfTileHeight, luminanceLevels);
// Left bottom corner
ProcessCornerTile(source, cdfData, 0, this.Tiles - 1, xStart: 0, xEnd: halfTileWidth, yStart: bottomBorderStartY, yEnd: sourceHeight, luminanceLevels);
ProcessCornerTile(source.PixelBuffer, cdfData, 0, this.Tiles - 1, xStart: 0, xEnd: halfTileWidth, yStart: bottomBorderStartY, yEnd: sourceHeight, luminanceLevels);
// Right top corner
ProcessCornerTile(source, cdfData, this.Tiles - 1, 0, xStart: rightBorderStartX, xEnd: sourceWidth, yStart: 0, yEnd: halfTileHeight, luminanceLevels);
ProcessCornerTile(source.PixelBuffer, cdfData, this.Tiles - 1, 0, xStart: rightBorderStartX, xEnd: sourceWidth, yStart: 0, yEnd: halfTileHeight, luminanceLevels);
// Right bottom corner
ProcessCornerTile(source, cdfData, this.Tiles - 1, this.Tiles - 1, xStart: rightBorderStartX, xEnd: sourceWidth, yStart: bottomBorderStartY, yEnd: sourceHeight, luminanceLevels);
ProcessCornerTile(source.PixelBuffer, cdfData, this.Tiles - 1, this.Tiles - 1, xStart: rightBorderStartX, xEnd: sourceWidth, yStart: bottomBorderStartY, yEnd: sourceHeight, luminanceLevels);
}
}
@ -130,7 +130,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
/// or 65536 for 16-bit grayscale images.
/// </param>
private static void ProcessCornerTile(
ImageFrame<TPixel> source,
Buffer2D<TPixel> source,
CdfTileData cdfData,
int cdfX,
int cdfY,
@ -142,7 +142,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
{
for (int dy = yStart; dy < yEnd; dy++)
{
Span<TPixel> rowSpan = source.GetPixelRowSpan(dy);
Span<TPixel> rowSpan = source.DangerousGetRowSpan(dy);
for (int dx = xStart; dx < xEnd; dx++)
{
ref TPixel pixel = ref rowSpan[dx];
@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
/// or 65536 for 16-bit grayscale images.
/// </param>
private static void ProcessBorderColumn(
ImageFrame<TPixel> source,
Buffer2D<TPixel> source,
CdfTileData cdfData,
int cdfX,
int sourceHeight,
@ -188,7 +188,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
int tileY = 0;
for (int dy = y; dy < yLimit; dy++)
{
Span<TPixel> rowSpan = source.GetPixelRowSpan(dy);
Span<TPixel> rowSpan = source.DangerousGetRowSpan(dy);
for (int dx = xStart; dx < xEnd; dx++)
{
ref TPixel pixel = ref rowSpan[dx];
@ -220,7 +220,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
/// or 65536 for 16-bit grayscale images.
/// </param>
private static void ProcessBorderRow(
ImageFrame<TPixel> source,
Buffer2D<TPixel> source,
CdfTileData cdfData,
int cdfY,
int sourceWidth,
@ -238,7 +238,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
{
for (int dy = yStart; dy < yEnd; dy++)
{
Span<TPixel> rowSpan = source.GetPixelRowSpan(dy);
Span<TPixel> rowSpan = source.DangerousGetRowSpan(dy);
int tileX = 0;
int xLimit = Math.Min(x + tileWidth, sourceWidth - 1);
for (int dx = x; dx < xLimit; dx++)
@ -373,7 +373,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
private readonly int tileCount;
private readonly int halfTileWidth;
private readonly int luminanceLevels;
private readonly ImageFrame<TPixel> source;
private readonly Buffer2D<TPixel> source;
private readonly int sourceWidth;
private readonly int sourceHeight;
@ -386,7 +386,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
int tileCount,
int halfTileWidth,
int luminanceLevels,
ImageFrame<TPixel> source)
Buffer2D<TPixel> source)
{
this.cdfData = cdfData;
this.tileYStartPositions = tileYStartPositions;
@ -419,7 +419,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
int xEnd = Math.Min(x + this.tileWidth, this.sourceWidth);
for (int dy = y; dy < yEnd; dy++)
{
Span<TPixel> rowSpan = this.source.GetPixelRowSpan(dy);
Span<TPixel> rowSpan = this.source.DangerousGetRowSpan(dy);
int tileX = 0;
for (int dx = x; dx < xEnd; dx++)
{
@ -516,7 +516,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
this.tileWidth,
this.tileHeight,
this.luminanceLevels,
source);
source.PixelBuffer);
ParallelRowIterator.IterateRowIntervals(
this.configuration,
@ -560,7 +560,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
private readonly int tileWidth;
private readonly int tileHeight;
private readonly int luminanceLevels;
private readonly ImageFrame<TPixel> source;
private readonly Buffer2D<TPixel> source;
private readonly int sourceWidth;
private readonly int sourceHeight;
@ -574,7 +574,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
int tileWidth,
int tileHeight,
int luminanceLevels,
ImageFrame<TPixel> source)
Buffer2D<TPixel> source)
{
this.processor = processor;
this.allocator = allocator;
@ -615,7 +615,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
int xlimit = Math.Min(x + this.tileWidth, this.sourceWidth);
for (int dy = y; dy < endY; dy++)
{
Span<TPixel> rowSpan = this.source.GetPixelRowSpan(dy);
Span<TPixel> rowSpan = this.source.DangerousGetRowSpan(dy);
for (int dx = x; dx < xlimit; dx++)
{
int luminance = GetLuminance(rowSpan[dx], this.luminanceLevels);

14
src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs

@ -189,7 +189,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
y = source.Height - diff - 1;
}
// Special cases for the left and the right border where GetPixelRowSpan can not be used.
// Special cases for the left and the right border where DangerousGetRowSpan can not be used.
if (x < 0)
{
rowPixels.Clear();
@ -224,7 +224,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
return;
}
this.CopyPixelRowFast(source, rowPixels, x, y, tileWidth, configuration);
this.CopyPixelRowFast(source.PixelBuffer, rowPixels, x, y, tileWidth, configuration);
}
/// <summary>
@ -238,13 +238,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
/// <param name="configuration">The configuration.</param>
[MethodImpl(InliningOptions.ShortMethod)]
private void CopyPixelRowFast(
ImageFrame<TPixel> source,
Buffer2D<TPixel> source,
Span<Vector4> rowPixels,
int x,
int y,
int tileWidth,
Configuration configuration)
=> PixelOperations<TPixel>.Instance.ToVector4(configuration, source.GetPixelRowSpan(y).Slice(start: x, length: tileWidth), rowPixels);
=> PixelOperations<TPixel>.Instance.ToVector4(configuration, source.DangerousGetRowSpan(y).Slice(start: x, length: tileWidth), rowPixels);
/// <summary>
/// Adds a column of grey values to the histogram.
@ -356,7 +356,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
{
if (this.useFastPath)
{
this.processor.CopyPixelRowFast(this.source, pixelRow, x - this.swInfos.HalfTileWidth, dy, this.swInfos.TileWidth, this.configuration);
this.processor.CopyPixelRowFast(this.source.PixelBuffer, pixelRow, x - this.swInfos.HalfTileWidth, dy, this.swInfos.TileWidth, this.configuration);
}
else
{
@ -390,7 +390,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
// Remove top most row from the histogram, mirroring rows which exceeds the borders.
if (this.useFastPath)
{
this.processor.CopyPixelRowFast(this.source, pixelRow, x - this.swInfos.HalfTileWidth, y - this.swInfos.HalfTileWidth, this.swInfos.TileWidth, this.configuration);
this.processor.CopyPixelRowFast(this.source.PixelBuffer, pixelRow, x - this.swInfos.HalfTileWidth, y - this.swInfos.HalfTileWidth, this.swInfos.TileWidth, this.configuration);
}
else
{
@ -402,7 +402,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
// Add new bottom row to the histogram, mirroring rows which exceeds the borders.
if (this.useFastPath)
{
this.processor.CopyPixelRowFast(this.source, pixelRow, x - this.swInfos.HalfTileWidth, y + this.swInfos.HalfTileWidth, this.swInfos.TileWidth, this.configuration);
this.processor.CopyPixelRowFast(this.source.PixelBuffer, pixelRow, x - this.swInfos.HalfTileWidth, y + this.swInfos.HalfTileWidth, this.swInfos.TileWidth, this.configuration);
}
else
{

16
src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs

@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
using IMemoryOwner<int> histogramBuffer = memoryAllocator.Allocate<int>(this.LuminanceLevels, AllocationOptions.Clean);
// Build the histogram of the grayscale levels.
var grayscaleOperation = new GrayscaleLevelsRowOperation(interest, histogramBuffer, source, this.LuminanceLevels);
var grayscaleOperation = new GrayscaleLevelsRowOperation(interest, histogramBuffer, source.PixelBuffer, this.LuminanceLevels);
ParallelRowIterator.IterateRows(
this.Configuration,
interest,
@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
float numberOfPixelsMinusCdfMin = numberOfPixels - cdfMin;
// Apply the cdf to each pixel of the image
var cdfOperation = new CdfApplicationRowOperation(interest, cdfBuffer, source, this.LuminanceLevels, numberOfPixelsMinusCdfMin);
var cdfOperation = new CdfApplicationRowOperation(interest, cdfBuffer, source.PixelBuffer, this.LuminanceLevels, numberOfPixelsMinusCdfMin);
ParallelRowIterator.IterateRows(
this.Configuration,
interest,
@ -90,14 +90,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
{
private readonly Rectangle bounds;
private readonly IMemoryOwner<int> histogramBuffer;
private readonly ImageFrame<TPixel> source;
private readonly Buffer2D<TPixel> source;
private readonly int luminanceLevels;
[MethodImpl(InliningOptions.ShortMethod)]
public GrayscaleLevelsRowOperation(
Rectangle bounds,
IMemoryOwner<int> histogramBuffer,
ImageFrame<TPixel> source,
Buffer2D<TPixel> source,
int luminanceLevels)
{
this.bounds = bounds;
@ -116,7 +116,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
public void Invoke(int y)
{
ref int histogramBase = ref MemoryMarshal.GetReference(this.histogramBuffer.GetSpan());
Span<TPixel> pixelRow = this.source.GetPixelRowSpan(y);
Span<TPixel> pixelRow = this.source.DangerousGetRowSpan(y);
int levels = this.luminanceLevels;
for (int x = 0; x < this.bounds.Width; x++)
@ -136,7 +136,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
{
private readonly Rectangle bounds;
private readonly IMemoryOwner<int> cdfBuffer;
private readonly ImageFrame<TPixel> source;
private readonly Buffer2D<TPixel> source;
private readonly int luminanceLevels;
private readonly float numberOfPixelsMinusCdfMin;
@ -144,7 +144,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
public CdfApplicationRowOperation(
Rectangle bounds,
IMemoryOwner<int> cdfBuffer,
ImageFrame<TPixel> source,
Buffer2D<TPixel> source,
int luminanceLevels,
float numberOfPixelsMinusCdfMin)
{
@ -165,7 +165,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
public void Invoke(int y)
{
ref int cdfBase = ref MemoryMarshal.GetReference(this.cdfBuffer.GetSpan());
Span<TPixel> pixelRow = this.source.GetPixelRowSpan(y);
Span<TPixel> pixelRow = this.source.DangerousGetRowSpan(y);
int levels = this.luminanceLevels;
float noOfPixelsMinusCdfMin = this.numberOfPixelsMinusCdfMin;

8
src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs

@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
PixelBlender<TPixel> blender = PixelOperations<TPixel>.Instance.GetPixelBlender(graphicsOptions);
var operation = new RowOperation(configuration, interest, blender, amount, colors, source);
var operation = new RowOperation(configuration, interest, blender, amount, colors, source.PixelBuffer);
ParallelRowIterator.IterateRows(
configuration,
interest,
@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
private readonly PixelBlender<TPixel> blender;
private readonly IMemoryOwner<float> amount;
private readonly IMemoryOwner<TPixel> colors;
private readonly ImageFrame<TPixel> source;
private readonly Buffer2D<TPixel> source;
[MethodImpl(InliningOptions.ShortMethod)]
public RowOperation(
@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
PixelBlender<TPixel> blender,
IMemoryOwner<float> amount,
IMemoryOwner<TPixel> colors,
ImageFrame<TPixel> source)
Buffer2D<TPixel> source)
{
this.configuration = configuration;
this.bounds = bounds;
@ -86,7 +86,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
public void Invoke(int y)
{
Span<TPixel> destination =
this.source.GetPixelRowSpan(y)
this.source.DangerousGetRowSpan(y)
.Slice(this.bounds.X, this.bounds.Width);
// Switch color & destination in the 2nd and 3rd places because we are

8
src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs

@ -55,7 +55,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
using IMemoryOwner<TPixel> rowColors = allocator.Allocate<TPixel>(interest.Width);
rowColors.GetSpan().Fill(glowColor);
var operation = new RowOperation(configuration, interest, rowColors, this.blender, center, maxDistance, blendPercent, source);
var operation = new RowOperation(configuration, interest, rowColors, this.blender, center, maxDistance, blendPercent, source.PixelBuffer);
ParallelRowIterator.IterateRows<RowOperation, float>(
configuration,
interest,
@ -71,7 +71,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
private readonly float maxDistance;
private readonly float blendPercent;
private readonly IMemoryOwner<TPixel> colors;
private readonly ImageFrame<TPixel> source;
private readonly Buffer2D<TPixel> source;
[MethodImpl(InliningOptions.ShortMethod)]
public RowOperation(
@ -82,7 +82,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
Vector2 center,
float maxDistance,
float blendPercent,
ImageFrame<TPixel> source)
Buffer2D<TPixel> source)
{
this.configuration = configuration;
this.bounds = bounds;
@ -105,7 +105,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
span[i] = Numerics.Clamp(this.blendPercent * (1 - (.95F * (distance / this.maxDistance))), 0, 1F);
}
Span<TPixel> destination = this.source.GetPixelRowSpan(y).Slice(this.bounds.X, this.bounds.Width);
Span<TPixel> destination = this.source.DangerousGetRowSpan(y).Slice(this.bounds.X, this.bounds.Width);
this.blender.Blend(
this.configuration,

8
src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs

@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
using IMemoryOwner<TPixel> rowColors = allocator.Allocate<TPixel>(interest.Width);
rowColors.GetSpan().Fill(vignetteColor);
var operation = new RowOperation(configuration, interest, rowColors, this.blender, center, maxDistance, blendPercent, source);
var operation = new RowOperation(configuration, interest, rowColors, this.blender, center, maxDistance, blendPercent, source.PixelBuffer);
ParallelRowIterator.IterateRows<RowOperation, float>(
configuration,
interest,
@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
private readonly float maxDistance;
private readonly float blendPercent;
private readonly IMemoryOwner<TPixel> colors;
private readonly ImageFrame<TPixel> source;
private readonly Buffer2D<TPixel> source;
[MethodImpl(InliningOptions.ShortMethod)]
public RowOperation(
@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
Vector2 center,
float maxDistance,
float blendPercent,
ImageFrame<TPixel> source)
Buffer2D<TPixel> source)
{
this.configuration = configuration;
this.bounds = bounds;
@ -113,7 +113,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
span[i] = Numerics.Clamp(this.blendPercent * (.9F * (distance / this.maxDistance)), 0, 1F);
}
Span<TPixel> destination = this.source.GetPixelRowSpan(y).Slice(this.bounds.X, this.bounds.Width);
Span<TPixel> destination = this.source.DangerousGetRowSpan(y).Slice(this.bounds.X, this.bounds.Width);
this.blender.Blend(
this.configuration,

5
src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs

@ -44,11 +44,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
ReadOnlySpan<TPixel> paletteSpan = quantized.Palette.Span;
int offsetY = interest.Top;
int offsetX = interest.Left;
Buffer2D<TPixel> sourceBuffer = source.PixelBuffer;
for (int y = interest.Y; y < interest.Height; y++)
{
Span<TPixel> row = source.GetPixelRowSpan(y);
ReadOnlySpan<byte> quantizedRow = quantized.GetPixelRowSpan(y - offsetY);
Span<TPixel> row = sourceBuffer.DangerousGetRowSpan(y);
ReadOnlySpan<byte> quantizedRow = quantized.DangerousGetRowSpan(y - offsetY);
for (int x = interest.Left; x < interest.Right; x++)
{

3
src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs

@ -122,6 +122,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
where TPixel : unmanaged, IPixel<TPixel>
{
IDither dither = quantizer.Options.Dither;
Buffer2D<TPixel> sourceBuffer = source.PixelBuffer;
if (dither is null)
{
@ -130,7 +131,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
for (int y = bounds.Y; y < bounds.Height; y++)
{
Span<TPixel> sourceRow = source.GetPixelRowSpan(y);
Span<TPixel> sourceRow = sourceBuffer.DangerousGetRowSpan(y);
Span<byte> destinationRow = destination.GetWritablePixelRowSpanUnsafe(y - offsetY);
for (int x = bounds.Left; x < bounds.Right; x++)

12
src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs

@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
ParallelExecutionSettings parallelSettings =
ParallelExecutionSettings.FromConfiguration(this.Configuration).MultiplyMinimumPixelsPerTask(4);
var operation = new RowOperation(bounds, source, destination);
var operation = new RowOperation(bounds, source.PixelBuffer, destination.PixelBuffer);
ParallelRowIterator.IterateRows(
bounds,
@ -65,8 +65,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private readonly struct RowOperation : IRowOperation
{
private readonly Rectangle bounds;
private readonly ImageFrame<TPixel> source;
private readonly ImageFrame<TPixel> destination;
private readonly Buffer2D<TPixel> source;
private readonly Buffer2D<TPixel> destination;
/// <summary>
/// Initializes a new instance of the <see cref="RowOperation"/> struct.
@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <param name="source">The source <see cref="Image{TPixel}"/> for the current instance.</param>
/// <param name="destination">The destination <see cref="Image{TPixel}"/> for the current instance.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public RowOperation(Rectangle bounds, ImageFrame<TPixel> source, ImageFrame<TPixel> destination)
public RowOperation(Rectangle bounds, Buffer2D<TPixel> source, Buffer2D<TPixel> destination)
{
this.bounds = bounds;
this.source = source;
@ -86,8 +86,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
[MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(int y)
{
Span<TPixel> sourceRow = this.source.GetPixelRowSpan(y).Slice(this.bounds.Left);
Span<TPixel> targetRow = this.destination.GetPixelRowSpan(y - this.bounds.Top);
Span<TPixel> sourceRow = this.source.DangerousGetRowSpan(y).Slice(this.bounds.Left);
Span<TPixel> targetRow = this.destination.DangerousGetRowSpan(y - this.bounds.Top);
sourceRow.Slice(0, this.bounds.Width).CopyTo(targetRow);
}
}

39
src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor{TPixel}.cs

@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
if (sampler is NearestNeighborResampler)
{
var nnOperation = new NNAffineOperation(source, destination, matrix);
var nnOperation = new NNAffineOperation(source.PixelBuffer, destination.PixelBuffer, matrix);
ParallelRowIterator.IterateRows(
configuration,
destination.Bounds(),
@ -84,8 +84,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
var operation = new AffineOperation<TResampler>(
configuration,
source,
destination,
source.PixelBuffer,
destination.PixelBuffer,
in sampler,
matrix);
@ -97,15 +97,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private readonly struct NNAffineOperation : IRowOperation
{
private readonly ImageFrame<TPixel> source;
private readonly ImageFrame<TPixel> destination;
private readonly Buffer2D<TPixel> source;
private readonly Buffer2D<TPixel> destination;
private readonly Rectangle bounds;
private readonly Matrix3x2 matrix;
[MethodImpl(InliningOptions.ShortMethod)]
public NNAffineOperation(
ImageFrame<TPixel> source,
ImageFrame<TPixel> destination,
Buffer2D<TPixel> source,
Buffer2D<TPixel> destination,
Matrix3x2 matrix)
{
this.source = source;
@ -117,8 +117,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
[MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(int y)
{
Buffer2D<TPixel> sourceBuffer = this.source.PixelBuffer;
Span<TPixel> destRow = this.destination.GetPixelRowSpan(y);
Span<TPixel> destRow = this.destination.DangerousGetRowSpan(y);
for (int x = 0; x < destRow.Length; x++)
{
@ -128,7 +127,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
if (this.bounds.Contains(px, py))
{
destRow[x] = sourceBuffer.GetElementUnsafe(px, py);
destRow[x] = this.source.GetElementUnsafe(px, py);
}
}
}
@ -138,8 +137,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
where TResampler : struct, IResampler
{
private readonly Configuration configuration;
private readonly ImageFrame<TPixel> source;
private readonly ImageFrame<TPixel> destination;
private readonly Buffer2D<TPixel> source;
private readonly Buffer2D<TPixel> destination;
private readonly TResampler sampler;
private readonly Matrix3x2 matrix;
private readonly float yRadius;
@ -148,8 +147,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
[MethodImpl(InliningOptions.ShortMethod)]
public AffineOperation(
Configuration configuration,
ImageFrame<TPixel> source,
ImageFrame<TPixel> destination,
Buffer2D<TPixel> source,
Buffer2D<TPixel> destination,
in TResampler sampler,
Matrix3x2 matrix)
{
@ -186,11 +185,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
int maxY = this.source.Height - 1;
int maxX = this.source.Width - 1;
Buffer2D<TPixel> sourceBuffer = this.source.PixelBuffer;
for (int y = rows.Min; y < rows.Max; y++)
{
Span<TPixel> rowSpan = this.destination.GetPixelRowSpan(y);
Span<TPixel> rowSpan = this.destination.DangerousGetRowSpan(y);
PixelOperations<TPixel>.Instance.ToVector4(
this.configuration,
rowSpan,
@ -222,7 +219,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
{
float xWeight = sampler.GetValue(xK - pX);
Vector4 current = sourceBuffer.GetElementUnsafe(xK, yK).ToScaledVector4();
Vector4 current = this.source.GetElementUnsafe(xK, yK).ToScaledVector4();
Numerics.Premultiply(ref current);
sum += current * xWeight * yWeight;
}
@ -251,11 +248,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
int maxY = this.source.Height - 1;
int maxX = this.source.Width - 1;
Buffer2D<TPixel> sourceBuffer = this.source.PixelBuffer;
for (int y = rows.Min; y < rows.Max; y++)
{
Span<TPixel> rowSpan = this.destination.GetPixelRowSpan(y);
Span<TPixel> rowSpan = this.destination.DangerousGetRowSpan(y);
PixelOperations<TPixel>.Instance.ToVector4(
this.configuration,
rowSpan,
@ -287,7 +282,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
{
float xWeight = sampler.GetValue(xK - pX);
Vector4 current = sourceBuffer.GetElementUnsafe(xK, yK).ToScaledVector4();
Vector4 current = this.source.GetElementUnsafe(xK, yK).ToScaledVector4();
Numerics.Premultiply(ref current);
sum += current * xWeight * yWeight;
}

17
src/ImageSharp/Processing/Processors/Transforms/Linear/FlipProcessor{TPixel}.cs

@ -5,6 +5,7 @@ using System;
using System.Buffers;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms
@ -38,7 +39,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
{
// No default needed as we have already set the pixels.
case FlipMode.Vertical:
this.FlipX(source, this.Configuration);
this.FlipX(source.PixelBuffer, this.Configuration);
break;
case FlipMode.Horizontal:
this.FlipY(source, this.Configuration);
@ -51,7 +52,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// </summary>
/// <param name="source">The source image to apply the process to.</param>
/// <param name="configuration">The configuration.</param>
private void FlipX(ImageFrame<TPixel> source, Configuration configuration)
private void FlipX(Buffer2D<TPixel> source, Configuration configuration)
{
int height = source.Height;
using IMemoryOwner<TPixel> tempBuffer = configuration.MemoryAllocator.Allocate<TPixel>(source.Width);
@ -60,8 +61,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
for (int yTop = 0; yTop < height / 2; yTop++)
{
int yBottom = height - yTop - 1;
Span<TPixel> topRow = source.GetPixelRowSpan(yBottom);
Span<TPixel> bottomRow = source.GetPixelRowSpan(yTop);
Span<TPixel> topRow = source.DangerousGetRowSpan(yBottom);
Span<TPixel> bottomRow = source.DangerousGetRowSpan(yTop);
topRow.CopyTo(temp);
bottomRow.CopyTo(topRow);
temp.CopyTo(bottomRow);
@ -75,7 +76,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <param name="configuration">The configuration.</param>
private void FlipY(ImageFrame<TPixel> source, Configuration configuration)
{
var operation = new RowOperation(source);
var operation = new RowOperation(source.PixelBuffer);
ParallelRowIterator.IterateRows(
configuration,
source.Bounds(),
@ -84,13 +85,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private readonly struct RowOperation : IRowOperation
{
private readonly ImageFrame<TPixel> source;
private readonly Buffer2D<TPixel> source;
[MethodImpl(InliningOptions.ShortMethod)]
public RowOperation(ImageFrame<TPixel> source) => this.source = source;
public RowOperation(Buffer2D<TPixel> source) => this.source = source;
[MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(int y) => this.source.GetPixelRowSpan(y).Reverse();
public void Invoke(int y) => this.source.DangerousGetRowSpan(y).Reverse();
}
}
}

39
src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor{TPixel}.cs

@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
if (sampler is NearestNeighborResampler)
{
var nnOperation = new NNProjectiveOperation(source, destination, matrix);
var nnOperation = new NNProjectiveOperation(source.PixelBuffer, destination.PixelBuffer, matrix);
ParallelRowIterator.IterateRows(
configuration,
destination.Bounds(),
@ -83,8 +83,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
var operation = new ProjectiveOperation<TResampler>(
configuration,
source,
destination,
source.PixelBuffer,
destination.PixelBuffer,
in sampler,
matrix);
@ -96,15 +96,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private readonly struct NNProjectiveOperation : IRowOperation
{
private readonly ImageFrame<TPixel> source;
private readonly ImageFrame<TPixel> destination;
private readonly Buffer2D<TPixel> source;
private readonly Buffer2D<TPixel> destination;
private readonly Rectangle bounds;
private readonly Matrix4x4 matrix;
[MethodImpl(InliningOptions.ShortMethod)]
public NNProjectiveOperation(
ImageFrame<TPixel> source,
ImageFrame<TPixel> destination,
Buffer2D<TPixel> source,
Buffer2D<TPixel> destination,
Matrix4x4 matrix)
{
this.source = source;
@ -116,8 +116,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
[MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(int y)
{
Buffer2D<TPixel> sourceBuffer = this.source.PixelBuffer;
Span<TPixel> destRow = this.destination.GetPixelRowSpan(y);
Span<TPixel> destRow = this.destination.DangerousGetRowSpan(y);
for (int x = 0; x < destRow.Length; x++)
{
@ -127,7 +126,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
if (this.bounds.Contains(px, py))
{
destRow[x] = sourceBuffer.GetElementUnsafe(px, py);
destRow[x] = this.source.GetElementUnsafe(px, py);
}
}
}
@ -137,8 +136,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
where TResampler : struct, IResampler
{
private readonly Configuration configuration;
private readonly ImageFrame<TPixel> source;
private readonly ImageFrame<TPixel> destination;
private readonly Buffer2D<TPixel> source;
private readonly Buffer2D<TPixel> destination;
private readonly TResampler sampler;
private readonly Matrix4x4 matrix;
private readonly float yRadius;
@ -147,8 +146,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
[MethodImpl(InliningOptions.ShortMethod)]
public ProjectiveOperation(
Configuration configuration,
ImageFrame<TPixel> source,
ImageFrame<TPixel> destination,
Buffer2D<TPixel> source,
Buffer2D<TPixel> destination,
in TResampler sampler,
Matrix4x4 matrix)
{
@ -185,11 +184,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
int maxY = this.source.Height - 1;
int maxX = this.source.Width - 1;
Buffer2D<TPixel> sourceBuffer = this.source.PixelBuffer;
for (int y = rows.Min; y < rows.Max; y++)
{
Span<TPixel> rowSpan = this.destination.GetPixelRowSpan(y);
Span<TPixel> rowSpan = this.destination.DangerousGetRowSpan(y);
PixelOperations<TPixel>.Instance.ToVector4(
this.configuration,
rowSpan,
@ -221,7 +218,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
{
float xWeight = sampler.GetValue(xK - pX);
Vector4 current = sourceBuffer.GetElementUnsafe(xK, yK).ToScaledVector4();
Vector4 current = this.source.GetElementUnsafe(xK, yK).ToScaledVector4();
Numerics.Premultiply(ref current);
sum += current * xWeight * yWeight;
}
@ -250,11 +247,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
int maxY = this.source.Height - 1;
int maxX = this.source.Width - 1;
Buffer2D<TPixel> sourceBuffer = this.source.PixelBuffer;
for (int y = rows.Min; y < rows.Max; y++)
{
Span<TPixel> rowSpan = this.destination.GetPixelRowSpan(y);
Span<TPixel> rowSpan = this.destination.DangerousGetRowSpan(y);
PixelOperations<TPixel>.Instance.ToVector4(
this.configuration,
rowSpan,
@ -286,7 +281,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
{
float xWeight = sampler.GetValue(xK - pX);
Vector4 current = sourceBuffer.GetElementUnsafe(xK, yK).ToScaledVector4();
Vector4 current = this.source.GetElementUnsafe(xK, yK).ToScaledVector4();
Numerics.Premultiply(ref current);
sum += current * xWeight * yWeight;
}

38
src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor{TPixel}.cs

@ -131,7 +131,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <param name="configuration">The configuration.</param>
private void Rotate180(ImageFrame<TPixel> source, ImageFrame<TPixel> destination, Configuration configuration)
{
var operation = new Rotate180RowOperation(source.Width, source.Height, source, destination);
var operation = new Rotate180RowOperation(source.Width, source.Height, source.PixelBuffer, destination.PixelBuffer);
ParallelRowIterator.IterateRows(
configuration,
source.Bounds(),
@ -146,7 +146,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <param name="configuration">The configuration.</param>
private void Rotate270(ImageFrame<TPixel> source, ImageFrame<TPixel> destination, Configuration configuration)
{
var operation = new Rotate270RowIntervalOperation(destination.Bounds(), source.Width, source.Height, source, destination);
var operation = new Rotate270RowIntervalOperation(destination.Bounds(), source.Width, source.Height, source.PixelBuffer, destination.PixelBuffer);
ParallelRowIterator.IterateRowIntervals(
configuration,
source.Bounds(),
@ -161,7 +161,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <param name="configuration">The configuration.</param>
private void Rotate90(ImageFrame<TPixel> source, ImageFrame<TPixel> destination, Configuration configuration)
{
var operation = new Rotate90RowOperation(destination.Bounds(), source.Width, source.Height, source, destination);
var operation = new Rotate90RowOperation(destination.Bounds(), source.Width, source.Height, source.PixelBuffer, destination.PixelBuffer);
ParallelRowIterator.IterateRows(
configuration,
source.Bounds(),
@ -172,15 +172,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
{
private readonly int width;
private readonly int height;
private readonly ImageFrame<TPixel> source;
private readonly ImageFrame<TPixel> destination;
private readonly Buffer2D<TPixel> source;
private readonly Buffer2D<TPixel> destination;
[MethodImpl(InliningOptions.ShortMethod)]
public Rotate180RowOperation(
int width,
int height,
ImageFrame<TPixel> source,
ImageFrame<TPixel> destination)
Buffer2D<TPixel> source,
Buffer2D<TPixel> destination)
{
this.width = width;
this.height = height;
@ -191,8 +191,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
[MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(int y)
{
Span<TPixel> sourceRow = this.source.GetPixelRowSpan(y);
Span<TPixel> targetRow = this.destination.GetPixelRowSpan(this.height - y - 1);
Span<TPixel> sourceRow = this.source.DangerousGetRowSpan(y);
Span<TPixel> targetRow = this.destination.DangerousGetRowSpan(this.height - y - 1);
for (int x = 0; x < this.width; x++)
{
@ -206,16 +206,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private readonly Rectangle bounds;
private readonly int width;
private readonly int height;
private readonly ImageFrame<TPixel> source;
private readonly ImageFrame<TPixel> destination;
private readonly Buffer2D<TPixel> source;
private readonly Buffer2D<TPixel> destination;
[MethodImpl(InliningOptions.ShortMethod)]
public Rotate270RowIntervalOperation(
Rectangle bounds,
int width,
int height,
ImageFrame<TPixel> source,
ImageFrame<TPixel> destination)
Buffer2D<TPixel> source,
Buffer2D<TPixel> destination)
{
this.bounds = bounds;
this.width = width;
@ -229,7 +229,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
{
for (int y = rows.Min; y < rows.Max; y++)
{
Span<TPixel> sourceRow = this.source.GetPixelRowSpan(y);
Span<TPixel> sourceRow = this.source.DangerousGetRowSpan(y);
for (int x = 0; x < this.width; x++)
{
int newX = this.height - y - 1;
@ -250,16 +250,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private readonly Rectangle bounds;
private readonly int width;
private readonly int height;
private readonly ImageFrame<TPixel> source;
private readonly ImageFrame<TPixel> destination;
private readonly Buffer2D<TPixel> source;
private readonly Buffer2D<TPixel> destination;
[MethodImpl(InliningOptions.ShortMethod)]
public Rotate90RowOperation(
Rectangle bounds,
int width,
int height,
ImageFrame<TPixel> source,
ImageFrame<TPixel> destination)
Buffer2D<TPixel> source,
Buffer2D<TPixel> destination)
{
this.bounds = bounds;
this.width = width;
@ -271,7 +271,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
[MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(int y)
{
Span<TPixel> sourceRow = this.source.GetPixelRowSpan(y);
Span<TPixel> sourceRow = this.source.DangerousGetRowSpan(y);
int newX = this.height - y - 1;
for (int x = 0; x < this.width; x++)
{

16
src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs

@ -155,8 +155,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
interest,
widthFactor,
heightFactor,
source,
destination);
source.PixelBuffer,
destination.PixelBuffer);
ParallelRowIterator.IterateRows(
configuration,
@ -223,8 +223,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private readonly Rectangle interest;
private readonly float widthFactor;
private readonly float heightFactor;
private readonly ImageFrame<TPixel> source;
private readonly ImageFrame<TPixel> destination;
private readonly Buffer2D<TPixel> source;
private readonly Buffer2D<TPixel> destination;
[MethodImpl(InliningOptions.ShortMethod)]
public NNRowOperation(
@ -233,8 +233,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
Rectangle interest,
float widthFactor,
float heightFactor,
ImageFrame<TPixel> source,
ImageFrame<TPixel> destination)
Buffer2D<TPixel> source,
Buffer2D<TPixel> destination)
{
this.sourceBounds = sourceBounds;
this.destinationBounds = destinationBounds;
@ -256,8 +256,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
int destRight = this.interest.Right;
// Y coordinates of source points
Span<TPixel> sourceRow = this.source.GetPixelRowSpan((int)(((y - destOriginY) * this.heightFactor) + sourceY));
Span<TPixel> targetRow = this.destination.GetPixelRowSpan(y);
Span<TPixel> sourceRow = this.source.DangerousGetRowSpan((int)(((y - destOriginY) * this.heightFactor) + sourceY));
Span<TPixel> targetRow = this.destination.DangerousGetRowSpan(y);
for (int x = destLeft; x < destRight; x++)
{

4
src/ImageSharp/Processing/Processors/Transforms/SwizzleProcessor{TSwizzler,TPixel}.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms
@ -27,9 +28,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
{
Point p = default;
Point newPoint;
Buffer2D<TPixel> sourceBuffer = source.PixelBuffer;
for (p.Y = 0; p.Y < source.Height; p.Y++)
{
Span<TPixel> rowSpan = source.GetPixelRowSpan(p.Y);
Span<TPixel> rowSpan = sourceBuffer.DangerousGetRowSpan(p.Y);
for (p.X = 0; p.X < source.Width; p.X++)
{
newPoint = this.swizzler.Transform(p);

4
tests/ImageSharp.Tests/Advanced/AdvancedImageExtensionsTests.cs

@ -153,7 +153,7 @@ namespace SixLabors.ImageSharp.Tests.Advanced
[WithBlankImages(1, 1, PixelTypes.Rgba32)]
[WithBlankImages(100, 111, PixelTypes.Rgba32)]
[WithBlankImages(400, 600, PixelTypes.Rgba32)]
public void GetPixelRowSpan_ShouldReferenceSpanOfMemory<TPixel>(TestImageProvider<TPixel> provider)
public void DangerousGetRowSpan_ShouldReferenceSpanOfMemory<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
provider.LimitAllocatorBufferCapacity().InPixelsSqrt(200);
@ -161,7 +161,7 @@ namespace SixLabors.ImageSharp.Tests.Advanced
using Image<TPixel> image = provider.GetImage();
Memory<TPixel> memory = image.DangerousGetPixelRowMemory(image.Height - 1);
Span<TPixel> span = image.GetPixelRowSpan(image.Height - 1);
Span<TPixel> span = image.DangerousGetRowSpan(image.Height - 1);
Assert.True(span == memory.Span);
}

4
tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs

@ -413,7 +413,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
Rgba32 rgba32 = Color.Blue;
for (int y = 0; y < image.Height; y++)
{
System.Span<Rgba32> rowSpan = image.GetPixelRowSpan(y);
System.Span<Rgba32> rowSpan = image.DangerousGetRowSpan(y);
// Half of the test image should be transparent.
if (y > 25)
@ -443,7 +443,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
for (int y = 0; y < actual.Height; y++)
{
System.Span<Rgba32> rowSpan = actual.GetPixelRowSpan(y);
System.Span<Rgba32> rowSpan = actual.DangerousGetRowSpan(y);
if (y > 25)
{

2
tests/ImageSharp.Tests/Formats/WebP/PredictorEncoderTests.cs

@ -134,7 +134,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Webp
int idx = 0;
for (int y = 0; y < image.Height; y++)
{
Span<TPixel> rowSpan = image.GetPixelRowSpan(y);
Span<TPixel> rowSpan = image.DangerousGetRowSpan(y);
for (int x = 0; x < rowSpan.Length; x++)
{
bgra[idx++] = ToBgra32(rowSpan[x]).PackedValue;

16
tests/ImageSharp.Tests/Image/ImageCloneTests.cs

@ -37,8 +37,8 @@ namespace SixLabors.ImageSharp.Tests
{
for (int y = 0; y < image.Height; y++)
{
Span<Rgba32> row = image.GetPixelRowSpan(y);
Span<Bgra32> rowClone = clone.GetPixelRowSpan(y);
Span<Rgba32> row = image.DangerousGetRowSpan(y);
Span<Bgra32> rowClone = clone.DangerousGetRowSpan(y);
for (int x = 0; x < image.Width; x++)
{
@ -63,8 +63,8 @@ namespace SixLabors.ImageSharp.Tests
{
for (int y = 0; y < image.Height; y++)
{
Span<Rgba32> row = image.GetPixelRowSpan(y);
Span<Bgr24> rowClone = clone.GetPixelRowSpan(y);
Span<Rgba32> row = image.DangerousGetRowSpan(y);
Span<Bgr24> rowClone = clone.DangerousGetRowSpan(y);
for (int x = 0; x < image.Width; x++)
{
@ -88,8 +88,8 @@ namespace SixLabors.ImageSharp.Tests
{
for (int y = 0; y < image.Height; y++)
{
Span<Rgba32> row = image.GetPixelRowSpan(y);
Span<Argb32> rowClone = clone.GetPixelRowSpan(y);
Span<Rgba32> row = image.DangerousGetRowSpan(y);
Span<Argb32> rowClone = clone.DangerousGetRowSpan(y);
for (int x = 0; x < image.Width; x++)
{
@ -114,8 +114,8 @@ namespace SixLabors.ImageSharp.Tests
{
for (int y = 0; y < image.Height; y++)
{
Span<Rgba32> row = image.GetPixelRowSpan(y);
Span<Rgb24> rowClone = clone.GetPixelRowSpan(y);
Span<Rgba32> row = image.DangerousGetRowSpan(y);
Span<Rgb24> rowClone = clone.DangerousGetRowSpan(y);
for (int x = 0; x < image.Width; x++)
{

12
tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs

@ -165,7 +165,7 @@ namespace SixLabors.ImageSharp.Tests
image.GetPixelMemoryGroup().Fill(bg);
for (var i = 10; i < 20; i++)
{
image.GetPixelRowSpan(i).Slice(10, 10).Fill(fg);
image.DangerousGetRowSpan(i).Slice(10, 10).Fill(fg);
}
}
@ -200,7 +200,7 @@ namespace SixLabors.ImageSharp.Tests
image.GetPixelMemoryGroup().Fill(bg);
for (var i = 10; i < 20; i++)
{
image.GetPixelRowSpan(i).Slice(10, 10).Fill(fg);
image.DangerousGetRowSpan(i).Slice(10, 10).Fill(fg);
}
}
@ -265,7 +265,7 @@ namespace SixLabors.ImageSharp.Tests
image.GetPixelMemoryGroup().Fill(bg);
for (var i = 10; i < 20; i++)
{
image.GetPixelRowSpan(i).Slice(10, 10).Fill(fg);
image.DangerousGetRowSpan(i).Slice(10, 10).Fill(fg);
}
}
@ -334,7 +334,7 @@ namespace SixLabors.ImageSharp.Tests
image.GetPixelMemoryGroup().Fill(bg);
for (var i = 10; i < 20; i++)
{
image.GetPixelRowSpan(i).Slice(10, 10).Fill(fg);
image.DangerousGetRowSpan(i).Slice(10, 10).Fill(fg);
}
}
@ -417,7 +417,7 @@ namespace SixLabors.ImageSharp.Tests
{
var arrayIndex = width * i;
Span<Rgba32> rowSpan = img.GetPixelRowSpan(i);
Span<Rgba32> rowSpan = img.DangerousGetRowSpan(i);
ref Rgba32 r0 = ref rowSpan[0];
ref Rgba32 r1 = ref array[arrayIndex];
@ -461,7 +461,7 @@ namespace SixLabors.ImageSharp.Tests
{
var arrayIndex = pixelSize * width * i;
Span<Rgba32> rowSpan = img.GetPixelRowSpan(i);
Span<Rgba32> rowSpan = img.DangerousGetRowSpan(i);
ref Rgba32 r0 = ref rowSpan[0];
ref Rgba32 r1 = ref Unsafe.As<byte, Rgba32>(ref array[arrayIndex]);

2
tests/ImageSharp.Tests/Image/ImageTests.cs

@ -271,7 +271,7 @@ namespace SixLabors.ImageSharp.Tests
// Image<TPixel>
Assert.Throws<ObjectDisposedException>(() => { var res = image.Clone(this.configuration); });
Assert.Throws<ObjectDisposedException>(() => { var res = image.CloneAs<Rgba32>(this.configuration); });
Assert.Throws<ObjectDisposedException>(() => { var res = image.GetPixelRowSpan(default); });
Assert.Throws<ObjectDisposedException>(() => { var res = image.DangerousGetRowSpan(default); });
Assert.Throws<ObjectDisposedException>(() => { var res = image.DangerousTryGetSinglePixelMemory(out Memory<Rgba32> _); });
// Image

4
tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs

@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Tests
using (IndexedImageFrame<TPixel> quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(frame, frame.Bounds()))
{
int index = this.GetTransparentIndex(quantized);
Assert.Equal(index, quantized.GetPixelRowSpan(0)[0]);
Assert.Equal(index, quantized.DangerousGetRowSpan(0)[0]);
}
}
}
@ -103,7 +103,7 @@ namespace SixLabors.ImageSharp.Tests
using (IndexedImageFrame<TPixel> quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(frame, frame.Bounds()))
{
int index = this.GetTransparentIndex(quantized);
Assert.Equal(index, quantized.GetPixelRowSpan(0)[0]);
Assert.Equal(index, quantized.DangerousGetRowSpan(0)[0]);
}
}
}

16
tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs

@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization
Assert.Equal(1, result.Height);
Assert.Equal(Color.Black, (Color)result.Palette.Span[0]);
Assert.Equal(0, result.GetPixelRowSpan(0)[0]);
Assert.Equal(0, result.DangerousGetRowSpan(0)[0]);
}
[Fact]
@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization
Assert.Equal(1, result.Height);
Assert.Equal(default, result.Palette.Span[0]);
Assert.Equal(0, result.GetPixelRowSpan(0)[0]);
Assert.Equal(0, result.DangerousGetRowSpan(0)[0]);
}
[Fact]
@ -99,8 +99,8 @@ namespace SixLabors.ImageSharp.Tests.Quantization
int paletteCount = paletteSpan.Length - 1;
for (int y = 0; y < actualImage.Height; y++)
{
Span<Rgba32> row = actualImage.GetPixelRowSpan(y);
ReadOnlySpan<byte> quantizedPixelSpan = result.GetPixelRowSpan(y);
Span<Rgba32> row = actualImage.DangerousGetRowSpan(y);
ReadOnlySpan<byte> quantizedPixelSpan = result.DangerousGetRowSpan(y);
for (int x = 0; x < actualImage.Width; x++)
{
@ -110,7 +110,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization
for (int y = 0; y < image.Height; y++)
{
Assert.True(image.GetPixelRowSpan(y).SequenceEqual(actualImage.GetPixelRowSpan(y)));
Assert.True(image.DangerousGetRowSpan(y).SequenceEqual(actualImage.DangerousGetRowSpan(y)));
}
}
@ -166,8 +166,8 @@ namespace SixLabors.ImageSharp.Tests.Quantization
int paletteCount = paletteSpan.Length - 1;
for (int y = 0; y < actualImage.Height; y++)
{
Span<Rgba32> row = actualImage.GetPixelRowSpan(y);
ReadOnlySpan<byte> quantizedPixelSpan = result.GetPixelRowSpan(y);
Span<Rgba32> row = actualImage.DangerousGetRowSpan(y);
ReadOnlySpan<byte> quantizedPixelSpan = result.DangerousGetRowSpan(y);
for (int x = 0; x < actualImage.Width; x++)
{
@ -178,7 +178,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization
for (int y = 0; y < expectedImage.Height; y++)
{
Assert.True(expectedImage.GetPixelRowSpan(y).SequenceEqual(actualImage.GetPixelRowSpan(y)));
Assert.True(expectedImage.DangerousGetRowSpan(y).SequenceEqual(actualImage.DangerousGetRowSpan(y)));
}
}
}

7
tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison
@ -29,11 +30,13 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison
var differences = new List<PixelDifference>();
Configuration configuration = expected.GetConfiguration();
Buffer2D<TPixelA> expectedBuffer = expected.PixelBuffer;
Buffer2D<TPixelB> actualBuffer = actual.PixelBuffer;
for (int y = 0; y < actual.Height; y++)
{
Span<TPixelA> aSpan = expected.GetPixelRowSpan(y);
Span<TPixelB> bSpan = actual.GetPixelRowSpan(y);
Span<TPixelA> aSpan = expectedBuffer.DangerousGetRowSpan(y);
Span<TPixelB> bSpan = actualBuffer.DangerousGetRowSpan(y);
PixelOperations<TPixelA>.Instance.ToRgba64(configuration, aSpan, aBuffer);
PixelOperations<TPixelB>.Instance.ToRgba64(configuration, bSpan, bBuffer);

7
tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison
@ -74,11 +75,13 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison
var differences = new List<PixelDifference>();
Configuration configuration = expected.GetConfiguration();
Buffer2D<TPixelA> expectedBuffer = expected.PixelBuffer;
Buffer2D<TPixelB> actualBuffer = actual.PixelBuffer;
for (int y = 0; y < actual.Height; y++)
{
Span<TPixelA> aSpan = expected.GetPixelRowSpan(y);
Span<TPixelB> bSpan = actual.GetPixelRowSpan(y);
Span<TPixelA> aSpan = expectedBuffer.DangerousGetRowSpan(y);
Span<TPixelB> bSpan = actualBuffer.DangerousGetRowSpan(y);
PixelOperations<TPixelA>.Instance.ToRgba64(configuration, aSpan, aBuffer);
PixelOperations<TPixelB>.Instance.ToRgba64(configuration, bSpan, bBuffer);

4
tests/ImageSharp.Tests/TestUtilities/ImageProviders/BasicTestPatternProvider.cs

@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Tests
for (int y = 0; y < midY; y++)
{
Span<TPixel> row = result.GetPixelRowSpan(y);
Span<TPixel> row = result.DangerousGetRowSpan(y);
row.Slice(0, midX).Fill(TopLeftColor);
row.Slice(midX, this.Width - midX).Fill(TopRightColor);
@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Tests
for (int y = midY; y < this.Height; y++)
{
Span<TPixel> row = result.GetPixelRowSpan(y);
Span<TPixel> row = result.DangerousGetRowSpan(y);
row.Slice(0, midX).Fill(BottomLeftColor);
row.Slice(midX, this.Width - midX).Fill(BottomRightColor);

20
tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs

@ -47,14 +47,14 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs
long destRowByteCount = w * sizeof(Bgra32);
Configuration configuration = image.GetConfiguration();
using (IMemoryOwner<Bgra32> workBuffer = Configuration.Default.MemoryAllocator.Allocate<Bgra32>(w))
image.ProcessPixelRows(accessor =>
{
using IMemoryOwner<Bgra32> workBuffer = Configuration.Default.MemoryAllocator.Allocate<Bgra32>(w);
fixed (Bgra32* destPtr = &workBuffer.GetReference())
{
for (int y = 0; y < h; y++)
{
Span<TPixel> row = image.Frames.RootFrame.GetPixelRowSpan(y);
Span<TPixel> row = accessor.GetRowSpan(y);
byte* sourcePtr = sourcePtrBase + (data.Stride * y);
@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs
row);
}
}
}
});
}
finally
{
@ -106,6 +106,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs
long destRowByteCount = w * sizeof(Bgr24);
Configuration configuration = image.GetConfiguration();
Buffer2D<TPixel> imageBuffer = image.Frames.RootFrame.PixelBuffer;
using (IMemoryOwner<Bgr24> workBuffer = Configuration.Default.MemoryAllocator.Allocate<Bgr24>(w))
{
@ -113,7 +114,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs
{
for (int y = 0; y < h; y++)
{
Span<TPixel> row = image.Frames.RootFrame.GetPixelRowSpan(y);
Span<TPixel> row = imageBuffer.DangerousGetRowSpan(y);
byte* sourcePtr = sourcePtrBase + (data.Stride * y);
@ -144,24 +145,23 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs
try
{
byte* destPtrBase = (byte*)data.Scan0;
long destRowByteCount = data.Stride;
long sourceRowByteCount = w * sizeof(Bgra32);
using (IMemoryOwner<Bgra32> workBuffer = image.GetConfiguration().MemoryAllocator.Allocate<Bgra32>(w))
image.ProcessPixelRows(accessor =>
{
using IMemoryOwner<Bgra32> workBuffer = image.GetConfiguration().MemoryAllocator.Allocate<Bgra32>(w);
fixed (Bgra32* sourcePtr = &workBuffer.GetReference())
{
for (int y = 0; y < h; y++)
{
Span<TPixel> row = image.Frames.RootFrame.GetPixelRowSpan(y);
Span<TPixel> row = accessor.GetRowSpan(y);
PixelOperations<TPixel>.Instance.ToBgra32(configuration, row, workBuffer.GetSpan());
byte* destPtr = destPtrBase + (data.Stride * y);
Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount);
}
}
}
});
}
finally
{

8
tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs

@ -738,7 +738,7 @@ namespace SixLabors.ImageSharp.Tests
Rectangle sourceRectangle = this.SourceRectangle;
Configuration configuration = this.Configuration;
var operation = new RowOperation(configuration, sourceRectangle, source);
var operation = new RowOperation(configuration, sourceRectangle, source.PixelBuffer);
ParallelRowIterator.IterateRowIntervals<RowOperation, Vector4>(
configuration,
@ -750,9 +750,9 @@ namespace SixLabors.ImageSharp.Tests
{
private readonly Configuration configuration;
private readonly Rectangle bounds;
private readonly ImageFrame<TPixel> source;
private readonly Buffer2D<TPixel> source;
public RowOperation(Configuration configuration, Rectangle bounds, ImageFrame<TPixel> source)
public RowOperation(Configuration configuration, Rectangle bounds, Buffer2D<TPixel> source)
{
this.configuration = configuration;
this.bounds = bounds;
@ -763,7 +763,7 @@ namespace SixLabors.ImageSharp.Tests
{
for (int y = rows.Min; y < rows.Max; y++)
{
Span<TPixel> rowSpan = this.source.GetPixelRowSpan(y).Slice(this.bounds.Left, this.bounds.Width);
Span<TPixel> rowSpan = this.source.DangerousGetRowSpan(y).Slice(this.bounds.Left, this.bounds.Width);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, rowSpan, span, PixelConversionModifiers.Scale);
for (int i = 0; i < span.Length; i++)
{

Loading…
Cancel
Save