Browse Source

Merge branch 'master' into netcore21

af/merge-core
Jason Nelson 8 years ago
committed by GitHub
parent
commit
ac9b3768c3
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 7
      src/ImageSharp.Drawing/Primitives/Region.cs
  2. 21
      src/ImageSharp.Drawing/Primitives/ShapeRegion.cs
  3. 14
      src/ImageSharp.Drawing/Processing/Drawing/Brushes/BrushApplicator.cs
  4. 12
      src/ImageSharp.Drawing/Processing/Drawing/Brushes/ImageBrush{TPixel}.cs
  5. 14
      src/ImageSharp.Drawing/Processing/Drawing/Brushes/PatternBrush{TPixel}.cs
  6. 14
      src/ImageSharp.Drawing/Processing/Drawing/Brushes/RecolorBrush{TPixel}.cs
  7. 18
      src/ImageSharp.Drawing/Processing/Drawing/Brushes/SolidBrush{TPixel}.cs
  8. 10
      src/ImageSharp.Drawing/Processing/Drawing/Processors/DrawImageProcessor.cs
  9. 8
      src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs
  10. 65
      src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs
  11. 114
      src/ImageSharp/Advanced/AdvancedImageExtensions.cs
  12. 2
      src/ImageSharp/Advanced/IPixelSource.cs
  13. 8
      src/ImageSharp/Common/Helpers/ParallelFor.cs
  14. 8
      src/ImageSharp/Configuration.cs
  15. 111
      src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
  16. 2
      src/ImageSharp/Formats/Bmp/BmpEncoder.cs
  17. 42
      src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
  18. 12
      src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs
  19. 20
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs
  20. 2
      src/ImageSharp/Formats/Gif/GifEncoder.cs
  21. 16
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  22. 18
      src/ImageSharp/Formats/Gif/LzwDecoder.cs
  23. 16
      src/ImageSharp/Formats/Gif/LzwEncoder.cs
  24. 2
      src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs
  25. 4
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs
  26. 2
      src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs
  27. 2
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs
  28. 6
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs
  29. 16
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs
  30. 3
      src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs
  31. 8
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangComponent.cs
  32. 4
      src/ImageSharp/Formats/Jpeg/GolangPort/GolangJpegDecoderCore.cs
  33. 8
      src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/DoubleBufferedStreamReader.cs
  34. 12
      src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFrameComponent.cs
  35. 14
      src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsHuffmanTable.cs
  36. 11
      src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsScanDecoder.cs
  37. 24
      src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs
  38. 2
      src/ImageSharp/Formats/Png/PngChunk.cs
  39. 48
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  40. 2
      src/ImageSharp/Formats/Png/PngEncoder.cs
  41. 60
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  42. 6
      src/ImageSharp/Image.Decode.cs
  43. 167
      src/ImageSharp/Image.FromBytes.cs
  44. 59
      src/ImageSharp/Image.WrapMemory.cs
  45. 31
      src/ImageSharp/ImageExtensions.Internal.cs
  46. 11
      src/ImageSharp/ImageFrameCollection.cs
  47. 91
      src/ImageSharp/ImageFrame{TPixel}.cs
  48. 15
      src/ImageSharp/ImageSharp.csproj
  49. 28
      src/ImageSharp/Image{TPixel}.cs
  50. 24
      src/ImageSharp/Memory/ArrayPoolMemoryAllocator.Buffer{T}.cs
  51. 20
      src/ImageSharp/Memory/ArrayPoolMemoryAllocator.CommonFactoryMethods.cs
  52. 24
      src/ImageSharp/Memory/ArrayPoolMemoryAllocator.cs
  53. 24
      src/ImageSharp/Memory/BasicArrayBuffer.cs
  54. 5
      src/ImageSharp/Memory/BasicByteBuffer.cs
  55. 53
      src/ImageSharp/Memory/Buffer2DExtensions.cs
  56. 48
      src/ImageSharp/Memory/Buffer2D{T}.cs
  57. 28
      src/ImageSharp/Memory/BufferArea{T}.cs
  58. 14
      src/ImageSharp/Memory/BufferExtensions.cs
  59. 34
      src/ImageSharp/Memory/ConsumedBuffer.cs
  60. 31
      src/ImageSharp/Memory/IBuffer2D{T}.cs
  61. 27
      src/ImageSharp/Memory/IBuffer{T}.cs
  62. 2
      src/ImageSharp/Memory/IManagedByteBuffer.cs
  63. 43
      src/ImageSharp/Memory/ManagedBufferBase.cs
  64. 14
      src/ImageSharp/Memory/MemoryAllocator.cs
  65. 46
      src/ImageSharp/Memory/MemoryAllocatorExtensions.cs
  66. 6
      src/ImageSharp/Memory/SimpleGcMemoryAllocator.cs
  67. 48
      src/ImageSharp/PixelAccessorExtensions.cs
  68. 154
      src/ImageSharp/PixelAccessor{TPixel}.cs
  69. 44
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs
  70. 2
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt
  71. 6
      src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs
  72. 2
      src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs
  73. 6
      src/ImageSharp/Processing/Convolution/Processors/Convolution2DProcessor.cs
  74. 4
      src/ImageSharp/Processing/Convolution/Processors/Convolution2PassProcessor.cs
  75. 6
      src/ImageSharp/Processing/Convolution/Processors/ConvolutionProcessor.cs
  76. 35
      src/ImageSharp/Processing/Convolution/Processors/EdgeDetectorCompassProcessor.cs
  77. 1
      src/ImageSharp/Processing/Convolution/Processors/SobelProcessor.cs
  78. 4
      src/ImageSharp/Processing/DefaultInternalImageProcessorContext.cs
  79. 6
      src/ImageSharp/Processing/Effects/Processors/OilPaintingProcessor.cs
  80. 6
      src/ImageSharp/Processing/IImageProcessingContext{TPixel}.cs
  81. 12
      src/ImageSharp/Processing/Overlays/Processors/BackgroundColorProcessor.cs
  82. 12
      src/ImageSharp/Processing/Overlays/Processors/GlowProcessor.cs
  83. 12
      src/ImageSharp/Processing/Overlays/Processors/VignetteProcessor.cs
  84. 2
      src/ImageSharp/Processing/Processors/CloningImageProcessor.cs
  85. 156
      src/ImageSharp/Processing/Quantization/FrameQuantizers/WuFrameQuantizer{TPixel}.cs
  86. 8
      src/ImageSharp/Processing/Transforms/Processors/AffineTransformProcessor.cs
  87. 1
      src/ImageSharp/Processing/Transforms/Processors/CropProcessor.cs
  88. 10
      src/ImageSharp/Processing/Transforms/Processors/FlipProcessor.cs
  89. 8
      src/ImageSharp/Processing/Transforms/Processors/ProjectiveTransformProcessor.cs
  90. 18
      src/ImageSharp/Processing/Transforms/Processors/ResizeProcessor.cs
  91. 8
      src/ImageSharp/Processing/Transforms/Processors/WeightsBuffer.cs
  92. 4
      src/ImageSharp/Processing/Transforms/Processors/WeightsWindow.cs
  93. 48
      tests/ImageSharp.Benchmarks/Codecs/CopyPixels.cs
  94. 4
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/DoubleBufferedStreams.cs
  95. 4
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs
  96. 14
      tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs
  97. 14
      tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs
  98. 14
      tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs
  99. 14
      tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs
  100. 14
      tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs

7
src/ImageSharp.Drawing/Primitives/Region.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Primitives namespace SixLabors.ImageSharp.Primitives
@ -19,7 +20,7 @@ namespace SixLabors.ImageSharp.Primitives
/// Gets the bounding box that entirely surrounds this region. /// Gets the bounding box that entirely surrounds this region.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// This should always contains all possible points returned from <see cref="Scan(float, float[], int)"/>. /// This should always contains all possible points returned from <see cref="Scan"/>.
/// </remarks> /// </remarks>
public abstract Rectangle Bounds { get; } public abstract Rectangle Bounds { get; }
@ -28,8 +29,8 @@ namespace SixLabors.ImageSharp.Primitives
/// </summary> /// </summary>
/// <param name="y">The position along the y axis to find intersections.</param> /// <param name="y">The position along the y axis to find intersections.</param>
/// <param name="buffer">The buffer.</param> /// <param name="buffer">The buffer.</param>
/// <param name="offset">The point in the buffer to start setting offset.</param> /// <param name="configuration">A <see cref="Configuration"/> instance in the context of the caller.</param>
/// <returns>The number of intersections found.</returns> /// <returns>The number of intersections found.</returns>
public abstract int Scan(float y, float[] buffer, int offset); public abstract int Scan(float y, Span<float> buffer, Configuration configuration);
} }
} }

21
src/ImageSharp.Drawing/Primitives/ShapeRegion.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
using SixLabors.Shapes; using SixLabors.Shapes;
@ -39,21 +40,23 @@ namespace SixLabors.ImageSharp.Primitives
public override Rectangle Bounds { get; } public override Rectangle Bounds { get; }
/// <inheritdoc/> /// <inheritdoc/>
public override int Scan(float y, float[] buffer, int offset) public override int Scan(float y, Span<float> buffer, Configuration configuration)
{ {
var start = new PointF(this.Bounds.Left - 1, y); var start = new PointF(this.Bounds.Left - 1, y);
var end = new PointF(this.Bounds.Right + 1, y); var end = new PointF(this.Bounds.Right + 1, y);
// TODO: This is a temporary workaround because of the lack of Span<T> API-s on IPath. We should use MemoryManager.Allocate() here! using (IBuffer<PointF> tempBuffer = configuration.MemoryAllocator.Allocate<PointF>(buffer.Length))
var innerBuffer = new PointF[buffer.Length];
int count = this.Shape.FindIntersections(start, end, innerBuffer, 0);
for (int i = 0; i < count; i++)
{ {
buffer[i + offset] = innerBuffer[i].X; Span<PointF> innerBuffer = tempBuffer.GetSpan();
} int count = this.Shape.FindIntersections(start, end, innerBuffer);
return count; for (int i = 0; i < count; i++)
{
buffer[i] = innerBuffer[i].X;
}
return count;
}
} }
} }
} }

14
src/ImageSharp.Drawing/Processing/Drawing/Brushes/BrushApplicator.cs

@ -3,8 +3,8 @@
using System; using System;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Processing.Drawing.Brushes namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
{ {
@ -65,13 +65,13 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
/// <remarks>scanlineBuffer will be > scanlineWidth but provide and offset in case we want to share a larger buffer across runs.</remarks> /// <remarks>scanlineBuffer will be > scanlineWidth but provide and offset in case we want to share a larger buffer across runs.</remarks>
internal virtual void Apply(Span<float> scanline, int x, int y) internal virtual void Apply(Span<float> scanline, int x, int y)
{ {
MemoryManager memoryManager = this.Target.MemoryManager; MemoryAllocator memoryAllocator = this.Target.MemoryAllocator;
using (IBuffer<float> amountBuffer = memoryManager.Allocate<float>(scanline.Length)) using (IBuffer<float> amountBuffer = memoryAllocator.Allocate<float>(scanline.Length))
using (IBuffer<TPixel> overlay = memoryManager.Allocate<TPixel>(scanline.Length)) using (IBuffer<TPixel> overlay = memoryAllocator.Allocate<TPixel>(scanline.Length))
{ {
Span<float> amountSpan = amountBuffer.Span; Span<float> amountSpan = amountBuffer.GetSpan();
Span<TPixel> overlaySpan = overlay.Span; Span<TPixel> overlaySpan = overlay.GetSpan();
for (int i = 0; i < scanline.Length; i++) for (int i = 0; i < scanline.Length; i++)
{ {
@ -88,7 +88,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
} }
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(memoryManager, destinationRow, destinationRow, overlaySpan, amountSpan); this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan);
} }
} }
} }

12
src/ImageSharp.Drawing/Processing/Drawing/Brushes/ImageBrush{TPixel}.cs

@ -3,8 +3,8 @@
using System; using System;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Drawing.Brushes namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
@ -118,11 +118,11 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
internal override void Apply(Span<float> scanline, int x, int y) internal override void Apply(Span<float> scanline, int x, int y)
{ {
// Create a span for colors // Create a span for colors
using (IBuffer<float> amountBuffer = this.Target.MemoryManager.Allocate<float>(scanline.Length)) using (IBuffer<float> amountBuffer = this.Target.MemoryAllocator.Allocate<float>(scanline.Length))
using (IBuffer<TPixel> overlay = this.Target.MemoryManager.Allocate<TPixel>(scanline.Length)) using (IBuffer<TPixel> overlay = this.Target.MemoryAllocator.Allocate<TPixel>(scanline.Length))
{ {
Span<float> amountSpan = amountBuffer.Span; Span<float> amountSpan = amountBuffer.GetSpan();
Span<TPixel> overlaySpan = overlay.Span; Span<TPixel> overlaySpan = overlay.GetSpan();
int sourceY = (y - this.offsetY) % this.yLength; int sourceY = (y - this.offsetY) % this.yLength;
int offsetX = x - this.offsetX; int offsetX = x - this.offsetX;
@ -138,7 +138,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
} }
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(this.source.MemoryManager, destinationRow, destinationRow, overlaySpan, amountSpan); this.Blender.Blend(this.source.MemoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan);
} }
} }
} }

14
src/ImageSharp.Drawing/Processing/Drawing/Brushes/PatternBrush{TPixel}.cs

@ -4,9 +4,9 @@
using System; using System;
using System.Numerics; using System.Numerics;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives; using SixLabors.ImageSharp.Primitives;
using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Drawing.Brushes namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
@ -151,13 +151,13 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
internal override void Apply(Span<float> scanline, int x, int y) internal override void Apply(Span<float> scanline, int x, int y)
{ {
int patternY = y % this.pattern.Rows; int patternY = y % this.pattern.Rows;
MemoryManager memoryManager = this.Target.MemoryManager; MemoryAllocator memoryAllocator = this.Target.MemoryAllocator;
using (IBuffer<float> amountBuffer = memoryManager.Allocate<float>(scanline.Length)) using (IBuffer<float> amountBuffer = memoryAllocator.Allocate<float>(scanline.Length))
using (IBuffer<TPixel> overlay = memoryManager.Allocate<TPixel>(scanline.Length)) using (IBuffer<TPixel> overlay = memoryAllocator.Allocate<TPixel>(scanline.Length))
{ {
Span<float> amountSpan = amountBuffer.Span; Span<float> amountSpan = amountBuffer.GetSpan();
Span<TPixel> overlaySpan = overlay.Span; Span<TPixel> overlaySpan = overlay.GetSpan();
for (int i = 0; i < scanline.Length; i++) for (int i = 0; i < scanline.Length; i++)
{ {
@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
} }
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(memoryManager, destinationRow, destinationRow, overlaySpan, amountSpan); this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan);
} }
} }
} }

14
src/ImageSharp.Drawing/Processing/Drawing/Brushes/RecolorBrush{TPixel}.cs

@ -4,8 +4,8 @@
using System; using System;
using System.Numerics; using System.Numerics;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Drawing.Brushes namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
@ -136,13 +136,13 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
/// <inheritdoc /> /// <inheritdoc />
internal override void Apply(Span<float> scanline, int x, int y) internal override void Apply(Span<float> scanline, int x, int y)
{ {
MemoryManager memoryManager = this.Target.MemoryManager; MemoryAllocator memoryAllocator = this.Target.MemoryAllocator;
using (IBuffer<float> amountBuffer = memoryManager.Allocate<float>(scanline.Length)) using (IBuffer<float> amountBuffer = memoryAllocator.Allocate<float>(scanline.Length))
using (IBuffer<TPixel> overlay = memoryManager.Allocate<TPixel>(scanline.Length)) using (IBuffer<TPixel> overlay = memoryAllocator.Allocate<TPixel>(scanline.Length))
{ {
Span<float> amountSpan = amountBuffer.Span; Span<float> amountSpan = amountBuffer.GetSpan();
Span<TPixel> overlaySpan = overlay.Span; Span<TPixel> overlaySpan = overlay.GetSpan();
for (int i = 0; i < scanline.Length; i++) for (int i = 0; i < scanline.Length; i++)
{ {
@ -156,7 +156,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
} }
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(memoryManager, destinationRow, destinationRow, overlaySpan, amountSpan); this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan);
} }
} }
} }

18
src/ImageSharp.Drawing/Processing/Drawing/Brushes/SolidBrush{TPixel}.cs

@ -3,8 +3,8 @@
using System; using System;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Drawing.Brushes namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
@ -58,8 +58,8 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
public SolidBrushApplicator(ImageFrame<TPixel> source, TPixel color, GraphicsOptions options) public SolidBrushApplicator(ImageFrame<TPixel> source, TPixel color, GraphicsOptions options)
: base(source, options) : base(source, options)
{ {
this.Colors = source.MemoryManager.Allocate<TPixel>(source.Width); this.Colors = source.MemoryAllocator.Allocate<TPixel>(source.Width);
this.Colors.Span.Fill(color); this.Colors.GetSpan().Fill(color);
} }
/// <summary> /// <summary>
@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
/// <returns> /// <returns>
/// The color /// The color
/// </returns> /// </returns>
internal override TPixel this[int x, int y] => this.Colors.Span[x]; internal override TPixel this[int x, int y] => this.Colors.GetSpan()[x];
/// <inheritdoc /> /// <inheritdoc />
public override void Dispose() public override void Dispose()
@ -88,24 +88,24 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
{ {
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
MemoryManager memoryManager = this.Target.MemoryManager; MemoryAllocator memoryAllocator = this.Target.MemoryAllocator;
if (this.Options.BlendPercentage == 1f) if (this.Options.BlendPercentage == 1f)
{ {
this.Blender.Blend(memoryManager, destinationRow, destinationRow, this.Colors.Span, scanline); this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, this.Colors.GetSpan(), scanline);
} }
else else
{ {
using (IBuffer<float> amountBuffer = memoryManager.Allocate<float>(scanline.Length)) using (IBuffer<float> amountBuffer = memoryAllocator.Allocate<float>(scanline.Length))
{ {
Span<float> amountSpan = amountBuffer.Span; Span<float> amountSpan = amountBuffer.GetSpan();
for (int i = 0; i < scanline.Length; i++) for (int i = 0; i < scanline.Length; i++)
{ {
amountSpan[i] = scanline[i] * this.Options.BlendPercentage; amountSpan[i] = scanline[i] * this.Options.BlendPercentage;
} }
this.Blender.Blend(memoryManager, destinationRow, destinationRow, this.Colors.Span, amountSpan); this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, this.Colors.GetSpan(), amountSpan);
} }
} }
} }

10
src/ImageSharp.Drawing/Processing/Drawing/Processors/DrawImageProcessor.cs

@ -4,9 +4,9 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors; using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Drawing.Processors namespace SixLabors.ImageSharp.Processing.Drawing.Processors
@ -133,11 +133,11 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors
int width = maxX - minX; int width = maxX - minX;
MemoryManager memoryManager = this.Image.GetConfiguration().MemoryManager; MemoryAllocator memoryAllocator = this.Image.GetConfiguration().MemoryAllocator;
using (IBuffer<float> amount = memoryManager.Allocate<float>(width)) using (IBuffer<float> amount = memoryAllocator.Allocate<float>(width))
{ {
amount.Span.Fill(this.Opacity); amount.GetSpan().Fill(this.Opacity);
Parallel.For( Parallel.For(
minY, minY,
@ -147,7 +147,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors
{ {
Span<TPixel> background = source.GetPixelRowSpan(y).Slice(minX, width); Span<TPixel> background = source.GetPixelRowSpan(y).Slice(minX, width);
Span<TPixel> foreground = targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width); Span<TPixel> foreground = targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width);
blender.Blend(memoryManager, background, background, foreground, amount.Span); blender.Blend(memoryAllocator, background, background, foreground, amount.GetSpan());
}); });
} }
} }

8
src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs

@ -4,10 +4,10 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Drawing.Brushes; using SixLabors.ImageSharp.Processing.Drawing.Brushes;
using SixLabors.ImageSharp.Processing.Processors; using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Drawing.Processors namespace SixLabors.ImageSharp.Processing.Drawing.Processors
@ -77,13 +77,13 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors
startY = 0; startY = 0;
} }
using (IBuffer<float> amount = source.MemoryManager.Allocate<float>(width)) using (IBuffer<float> amount = source.MemoryAllocator.Allocate<float>(width))
using (BrushApplicator<TPixel> applicator = this.brush.CreateApplicator( using (BrushApplicator<TPixel> applicator = this.brush.CreateApplicator(
source, source,
sourceRectangle, sourceRectangle,
this.options)) this.options))
{ {
amount.Span.Fill(1f); amount.GetSpan().Fill(1f);
Parallel.For( Parallel.For(
minY, minY,
@ -94,7 +94,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors
int offsetY = y - startY; int offsetY = y - startY;
int offsetX = minX - startX; int offsetX = minX - startX;
applicator.Apply(amount.Span, offsetX, offsetY); applicator.Apply(amount.GetSpan(), offsetX, offsetY);
}); });
} }
} }

65
src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs

@ -3,11 +3,11 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives; using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Drawing.Brushes; using SixLabors.ImageSharp.Processing.Drawing.Brushes;
using SixLabors.ImageSharp.Processing.Processors; using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Drawing.Processors namespace SixLabors.ImageSharp.Processing.Drawing.Processors
@ -96,36 +96,35 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors
using (BrushApplicator<TPixel> applicator = this.Brush.CreateApplicator(source, rect, this.Options)) using (BrushApplicator<TPixel> applicator = this.Brush.CreateApplicator(source, rect, this.Options))
{ {
int scanlineWidth = maxX - minX; int scanlineWidth = maxX - minX;
using (BasicArrayBuffer<float> buffer = source.MemoryManager.AllocateFake<float>(maxIntersections)) using (IBuffer<float> bBuffer = source.MemoryAllocator.Allocate<float>(maxIntersections))
using (BasicArrayBuffer<float> scanline = source.MemoryManager.AllocateFake<float>(scanlineWidth)) using (IBuffer<float> bScanline = source.MemoryAllocator.Allocate<float>(scanlineWidth))
{ {
bool scanlineDirty = true; bool scanlineDirty = true;
float subpixelFraction = 1f / subpixelCount; float subpixelFraction = 1f / subpixelCount;
float subpixelFractionPoint = subpixelFraction / subpixelCount; float subpixelFractionPoint = subpixelFraction / subpixelCount;
Span<float> buffer = bBuffer.GetSpan();
Span<float> scanline = bScanline.GetSpan();
for (int y = minY; y < maxY; y++) for (int y = minY; y < maxY; y++)
{ {
if (scanlineDirty) if (scanlineDirty)
{ {
// clear the buffer scanline.Clear();
for (int x = 0; x < scanlineWidth; x++)
{
scanline[x] = 0;
}
scanlineDirty = false; scanlineDirty = false;
} }
float yPlusOne = y + 1; float yPlusOne = y + 1;
for (float subPixel = (float)y; subPixel < yPlusOne; subPixel += subpixelFraction) for (float subPixel = (float)y; subPixel < yPlusOne; subPixel += subpixelFraction)
{ {
int pointsFound = region.Scan(subPixel + offset, buffer.Array, 0); int pointsFound = region.Scan(subPixel + offset, buffer, configuration);
if (pointsFound == 0) if (pointsFound == 0)
{ {
// nothing on this line skip // nothing on this line skip
continue; continue;
} }
QuickSort(new Span<float>(buffer.Array, 0, pointsFound)); QuickSort(buffer.Slice(0, pointsFound));
for (int point = 0; point < pointsFound; point += 2) for (int point = 0; point < pointsFound; point += 2)
{ {
@ -181,7 +180,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors
} }
} }
applicator.Apply(scanline.Span, minX, y); applicator.Apply(scanline, minX, y);
} }
} }
} }
@ -189,31 +188,45 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void Swap(Span<float> data, int left, int right) private static void Swap(ref float left, ref float right)
{ {
float tmp = data[left]; float tmp = left;
data[left] = data[right]; left = right;
data[right] = tmp; right = tmp;
} }
private static void QuickSort(Span<float> data) private static void QuickSort(Span<float> data)
{ {
QuickSort(data, 0, data.Length - 1); if (data.Length < 2)
{
return;
}
else if (data.Length == 2)
{
if (data[0] > data[1])
{
Swap(ref data[0], ref data[1]);
}
return;
}
QuickSort(ref data[0], 0, data.Length - 1);
} }
private static void QuickSort(Span<float> data, int lo, int hi) private static void QuickSort(ref float data0, int lo, int hi)
{ {
if (lo < hi) if (lo < hi)
{ {
int p = Partition(data, lo, hi); int p = Partition(ref data0, lo, hi);
QuickSort(data, lo, p); QuickSort(ref data0, lo, p);
QuickSort(data, p + 1, hi); QuickSort(ref data0, p + 1, hi);
} }
} }
private static int Partition(Span<float> data, int lo, int hi) private static int Partition(ref float data0, int lo, int hi)
{ {
float pivot = data[lo]; float pivot = Unsafe.Add(ref data0, lo);
int i = lo - 1; int i = lo - 1;
int j = hi + 1; int j = hi + 1;
while (true) while (true)
@ -222,20 +235,20 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors
{ {
i = i + 1; i = i + 1;
} }
while (data[i] < pivot && i < hi); while (Unsafe.Add(ref data0, i) < pivot && i < hi);
do do
{ {
j = j - 1; j = j - 1;
} }
while (data[j] > pivot && j > lo); while (Unsafe.Add(ref data0, j) > pivot && j > lo);
if (i >= j) if (i >= j)
{ {
return j; return j;
} }
Swap(data, i, j); Swap(ref Unsafe.Add(ref data0, i), ref Unsafe.Add(ref data0, j));
} }
} }
} }

114
src/ImageSharp/Advanced/AdvancedImageExtensions.cs

@ -3,8 +3,8 @@
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Advanced namespace SixLabors.ImageSharp.Advanced
{ {
@ -23,6 +23,52 @@ namespace SixLabors.ImageSharp.Advanced
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> GetConfiguration((IConfigurable)source); => GetConfiguration((IConfigurable)source);
/// <summary>
/// Gets the representation of the pixels as a <see cref="Span{T}"/> of contiguous memory in the source image's pixel format
/// stored in row major order.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="source">The source.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns>
public static Span<TPixel> GetPixelSpan<TPixel>(this ImageFrame<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> source.GetPixelMemory().Span;
/// <summary>
/// Gets the representation of the pixels as a <see cref="Span{T}"/> of contiguous memory in the source image's pixel format
/// stored in row major order.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="source">The source.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns>
public static Span<TPixel> GetPixelSpan<TPixel>(this Image<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> source.Frames.RootFrame.GetPixelSpan();
/// <summary>
/// Gets the representation of the pixels as a <see cref="Span{T}"/> of contiguous memory
/// at row <paramref name="rowIndex"/> beginning from the the first pixel on that row.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="source">The source.</param>
/// <param name="rowIndex">The row.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns>
public static Span<TPixel> GetPixelRowSpan<TPixel>(this ImageFrame<TPixel> source, int rowIndex)
where TPixel : struct, IPixel<TPixel>
=> source.PixelBuffer.GetRowSpan(rowIndex);
/// <summary>
/// Gets the representation of the pixels as <see cref="Span{T}"/> of of contiguous memory
/// at row <paramref name="rowIndex"/> beginning from the the first pixel on that row.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="source">The source.</param>
/// <param name="rowIndex">The row.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns>
public static Span<TPixel> GetPixelRowSpan<TPixel>(this Image<TPixel> source, int rowIndex)
where TPixel : struct, IPixel<TPixel>
=> source.Frames.RootFrame.GetPixelRowSpan(rowIndex);
/// <summary> /// <summary>
/// Returns a reference to the 0th element of the Pixel buffer, /// Returns a reference to the 0th element of the Pixel buffer,
/// allowing direct manipulation of pixel data through unsafe operations. /// allowing direct manipulation of pixel data through unsafe operations.
@ -31,9 +77,10 @@ namespace SixLabors.ImageSharp.Advanced
/// <typeparam name="TPixel">The Pixel format.</typeparam> /// <typeparam name="TPixel">The Pixel format.</typeparam>
/// <param name="source">The source image frame</param> /// <param name="source">The source image frame</param>
/// <returns>A pinnable reference the first root of the pixel buffer.</returns> /// <returns>A pinnable reference the first root of the pixel buffer.</returns>
[Obsolete("This method will be removed in our next release! Please use MemoryMarshal.GetReference(source.GetPixelSpan())!")]
public static ref TPixel DangerousGetPinnableReferenceToPixelBuffer<TPixel>(this ImageFrame<TPixel> source) public static ref TPixel DangerousGetPinnableReferenceToPixelBuffer<TPixel>(this ImageFrame<TPixel> source)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> ref DangerousGetPinnableReferenceToPixelBuffer((IPixelSource<TPixel>)source); => ref DangerousGetPinnableReferenceToPixelBuffer((IPixelSource<TPixel>)source);
/// <summary> /// <summary>
/// Returns a reference to the 0th element of the Pixel buffer, /// Returns a reference to the 0th element of the Pixel buffer,
@ -43,59 +90,68 @@ namespace SixLabors.ImageSharp.Advanced
/// <typeparam name="TPixel">The Pixel format.</typeparam> /// <typeparam name="TPixel">The Pixel format.</typeparam>
/// <param name="source">The source image</param> /// <param name="source">The source image</param>
/// <returns>A pinnable reference the first root of the pixel buffer.</returns> /// <returns>A pinnable reference the first root of the pixel buffer.</returns>
[Obsolete("This method will be removed in our next release! Please use MemoryMarshal.GetReference(source.GetPixelSpan())!")]
public static ref TPixel DangerousGetPinnableReferenceToPixelBuffer<TPixel>(this Image<TPixel> source) public static ref TPixel DangerousGetPinnableReferenceToPixelBuffer<TPixel>(this Image<TPixel> source)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> ref source.Frames.RootFrame.DangerousGetPinnableReferenceToPixelBuffer(); => ref source.Frames.RootFrame.DangerousGetPinnableReferenceToPixelBuffer();
/// <summary> /// <summary>
/// Gets the representation of the pixels as an area of contiguous memory in the given pixel format. /// Gets the representation of the pixels as a <see cref="Memory{T}"/> of contiguous memory in the source image's pixel format
/// stored in row major order.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam> /// <typeparam name="TPixel">The Pixel format.</typeparam>
/// <param name="source">The source.</param> /// <param name="source">The source <see cref="ImageFrame{TPixel}"/></param>
/// <returns>The <see cref="Span{TPixel}"/></returns> /// <returns>The <see cref="Memory{T}"/></returns>
internal static Span<TPixel> GetPixelSpan<TPixel>(this ImageFrame<TPixel> source) internal static Memory<TPixel> GetPixelMemory<TPixel>(this ImageFrame<TPixel> source)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> GetSpan(source); {
return source.PixelBuffer.Buffer.Memory;
}
/// <summary> /// <summary>
/// Gets the representation of the pixels as an area of contiguous memory at row 'y' beginning from the the first pixel on that row. /// Gets the representation of the pixels as a <see cref="Memory{T}"/> of contiguous memory in the source image's pixel format
/// stored in row major order.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam> /// <typeparam name="TPixel">The Pixel format.</typeparam>
/// <param name="source">The source.</param> /// <param name="source">The source <see cref="Image{TPixel}"/></param>
/// <param name="row">The row.</param> /// <returns>The <see cref="Memory{T}"/></returns>
/// <returns>The <see cref="Span{TPixel}"/></returns> internal static Memory<TPixel> GetPixelMemory<TPixel>(this Image<TPixel> source)
internal static Span<TPixel> GetPixelRowSpan<TPixel>(this ImageFrame<TPixel> source, int row)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> GetSpan(source, row); {
return source.Frames.RootFrame.GetPixelMemory();
}
/// <summary> /// <summary>
/// Gets the representation of the pixels as an area of contiguous memory in the given pixel format. /// Gets the representation of the pixels as a <see cref="Span{T}"/> of contiguous memory
/// at row <paramref name="rowIndex"/> beginning from the the first pixel on that row.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam> /// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="source">The source.</param> /// <param name="source">The source.</param>
/// <param name="rowIndex">The row.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns> /// <returns>The <see cref="Span{TPixel}"/></returns>
internal static Span<TPixel> GetPixelSpan<TPixel>(this Image<TPixel> source) internal static Memory<TPixel> GetPixelRowMemory<TPixel>(this ImageFrame<TPixel> source, int rowIndex)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> source.Frames.RootFrame.GetPixelSpan(); => source.PixelBuffer.GetRowMemory(rowIndex);
/// <summary> /// <summary>
/// Gets the representation of the pixels as an area of contiguous memory at row 'y' beginning from the the first pixel on that row. /// Gets the representation of the pixels as <see cref="Span{T}"/> of of contiguous memory
/// at row <paramref name="rowIndex"/> beginning from the the first pixel on that row.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam> /// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="source">The source.</param> /// <param name="source">The source.</param>
/// <param name="row">The row.</param> /// <param name="rowIndex">The row.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns> /// <returns>The <see cref="Span{TPixel}"/></returns>
internal static Span<TPixel> GetPixelRowSpan<TPixel>(this Image<TPixel> source, int row) internal static Memory<TPixel> GetPixelRowMemory<TPixel>(this Image<TPixel> source, int rowIndex)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> source.Frames.RootFrame.GetPixelRowSpan(row); => source.Frames.RootFrame.GetPixelRowMemory(rowIndex);
/// <summary> /// <summary>
/// Gets the <see cref="MemoryManager"/> assigned to 'source'. /// Gets the <see cref="MemoryAllocator"/> assigned to 'source'.
/// </summary> /// </summary>
/// <param name="source">The source image</param> /// <param name="source">The source image</param>
/// <returns>Returns the configuration.</returns> /// <returns>Returns the configuration.</returns>
internal static MemoryManager GetMemoryManager(this IConfigurable source) internal static MemoryAllocator GetMemoryAllocator(this IConfigurable source)
=> GetConfiguration(source).MemoryManager; => GetConfiguration(source).MemoryAllocator;
/// <summary> /// <summary>
/// Gets the span to the backing buffer. /// Gets the span to the backing buffer.
@ -105,7 +161,7 @@ namespace SixLabors.ImageSharp.Advanced
/// <returns>The span retuned from Pixel source</returns> /// <returns>The span retuned from Pixel source</returns>
private static Span<TPixel> GetSpan<TPixel>(IPixelSource<TPixel> source) private static Span<TPixel> GetSpan<TPixel>(IPixelSource<TPixel> source)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> source.PixelBuffer.Span; => source.PixelBuffer.GetSpan();
/// <summary> /// <summary>
/// Gets the span to the backing buffer at the given row. /// Gets the span to the backing buffer at the given row.
@ -131,7 +187,7 @@ namespace SixLabors.ImageSharp.Advanced
/// </returns> /// </returns>
private static Span<TPixel> GetSpan<TPixel>(Buffer2D<TPixel> source, int row) private static Span<TPixel> GetSpan<TPixel>(Buffer2D<TPixel> source, int row)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> source.Span.Slice(row * source.Width, source.Width); => source.GetSpan().Slice(row * source.Width, source.Width);
/// <summary> /// <summary>
/// Gets the configuration. /// Gets the configuration.
@ -149,6 +205,6 @@ namespace SixLabors.ImageSharp.Advanced
/// <returns>A reference to the element.</returns> /// <returns>A reference to the element.</returns>
private static ref TPixel DangerousGetPinnableReferenceToPixelBuffer<TPixel>(IPixelSource<TPixel> source) private static ref TPixel DangerousGetPinnableReferenceToPixelBuffer<TPixel>(IPixelSource<TPixel> source)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> ref MemoryMarshal.GetReference(source.PixelBuffer.Span); => ref MemoryMarshal.GetReference(source.PixelBuffer.GetSpan());
} }
} }

2
src/ImageSharp/Advanced/IPixelSource.cs

@ -1,8 +1,8 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Advanced namespace SixLabors.ImageSharp.Advanced
{ {

8
src/ImageSharp/Common/Helpers/ParallelFor.cs

@ -1,6 +1,6 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using SixLabors.ImageSharp.Memory; using SixLabors.Memory;
namespace SixLabors.ImageSharp namespace SixLabors.ImageSharp
{ {
@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp
/// <typeparam name="T">The value type of the buffer</typeparam> /// <typeparam name="T">The value type of the buffer</typeparam>
/// <param name="fromInclusive">The start index, inclusive.</param> /// <param name="fromInclusive">The start index, inclusive.</param>
/// <param name="toExclusive">The end index, exclusive.</param> /// <param name="toExclusive">The end index, exclusive.</param>
/// <param name="configuration">The <see cref="Configuration"/> used for getting the <see cref="MemoryManager"/> and <see cref="ParallelOptions"/></param> /// <param name="configuration">The <see cref="Configuration"/> used for getting the <see cref="MemoryAllocator"/> and <see cref="ParallelOptions"/></param>
/// <param name="bufferLength">The length of the requested parallel buffer</param> /// <param name="bufferLength">The length of the requested parallel buffer</param>
/// <param name="body">The delegate that is invoked once per iteration.</param> /// <param name="body">The delegate that is invoked once per iteration.</param>
public static void WithTemporaryBuffer<T>( public static void WithTemporaryBuffer<T>(
@ -35,12 +35,12 @@ namespace SixLabors.ImageSharp
Action<int, IBuffer<T>> body) Action<int, IBuffer<T>> body)
where T : struct where T : struct
{ {
MemoryManager memoryManager = configuration.MemoryManager; MemoryAllocator memoryAllocator = configuration.MemoryAllocator;
ParallelOptions parallelOptions = configuration.ParallelOptions; ParallelOptions parallelOptions = configuration.ParallelOptions;
IBuffer<T> InitBuffer() IBuffer<T> InitBuffer()
{ {
return memoryManager.Allocate<T>(bufferLength); return memoryAllocator.Allocate<T>(bufferLength);
} }
void CleanUpBuffer(IBuffer<T> buffer) void CleanUpBuffer(IBuffer<T> buffer)

8
src/ImageSharp/Configuration.cs

@ -12,8 +12,8 @@ using SixLabors.ImageSharp.Formats.Png;
#if !NETSTANDARD1_1 #if !NETSTANDARD1_1
using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.IO;
#endif #endif
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing;
using SixLabors.Memory;
namespace SixLabors.ImageSharp namespace SixLabors.ImageSharp
{ {
@ -75,9 +75,9 @@ namespace SixLabors.ImageSharp
public ImageFormatManager ImageFormatsManager { get; set; } = new ImageFormatManager(); public ImageFormatManager ImageFormatsManager { get; set; } = new ImageFormatManager();
/// <summary> /// <summary>
/// Gets or sets the <see cref="MemoryManager"/> that is currently in use. /// Gets or sets the <see cref="MemoryAllocator"/> that is currently in use.
/// </summary> /// </summary>
public MemoryManager MemoryManager { get; set; } = ArrayPoolMemoryManager.CreateDefault(); public MemoryAllocator MemoryAllocator { get; set; } = ArrayPoolMemoryAllocator.CreateDefault();
/// <summary> /// <summary>
/// Gets the maximum header size of all the formats. /// Gets the maximum header size of all the formats.
@ -116,7 +116,7 @@ namespace SixLabors.ImageSharp
{ {
ParallelOptions = this.ParallelOptions, ParallelOptions = this.ParallelOptions,
ImageFormatsManager = this.ImageFormatsManager, ImageFormatsManager = this.ImageFormatsManager,
MemoryManager = this.MemoryManager, MemoryAllocator = this.MemoryAllocator,
ImageOperationsProvider = this.ImageOperationsProvider, ImageOperationsProvider = this.ImageOperationsProvider,
ReadOrigin = this.ReadOrigin, ReadOrigin = this.ReadOrigin,

111
src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs

@ -5,9 +5,9 @@ using System;
using System.Buffers.Binary; using System.Buffers.Binary;
using System.IO; using System.IO;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Bmp namespace SixLabors.ImageSharp.Formats.Bmp
{ {
@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
private readonly Configuration configuration; private readonly Configuration configuration;
private readonly MemoryManager memoryManager; private readonly MemoryAllocator memoryAllocator;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="BmpDecoderCore"/> class. /// Initializes a new instance of the <see cref="BmpDecoderCore"/> class.
@ -82,7 +82,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
public BmpDecoderCore(Configuration configuration, IBmpDecoderOptions options) public BmpDecoderCore(Configuration configuration, IBmpDecoderOptions options)
{ {
this.configuration = configuration; this.configuration = configuration;
this.memoryManager = configuration.MemoryManager; this.memoryAllocator = configuration.MemoryAllocator;
} }
/// <summary> /// <summary>
@ -104,36 +104,42 @@ namespace SixLabors.ImageSharp.Formats.Bmp
this.ReadImageHeaders(stream, out bool inverted, out byte[] palette); this.ReadImageHeaders(stream, out bool inverted, out byte[] palette);
var image = new Image<TPixel>(this.configuration, this.infoHeader.Width, this.infoHeader.Height); var image = new Image<TPixel>(this.configuration, this.infoHeader.Width, this.infoHeader.Height);
using (PixelAccessor<TPixel> pixels = image.Lock())
Buffer2D<TPixel> pixels = image.GetRootFramePixelBuffer();
switch (this.infoHeader.Compression)
{ {
switch (this.infoHeader.Compression) case BmpCompression.RGB:
{ if (this.infoHeader.BitsPerPixel == 32)
case BmpCompression.RGB: {
if (this.infoHeader.BitsPerPixel == 32) this.ReadRgb32(pixels, this.infoHeader.Width, this.infoHeader.Height, inverted);
{ }
this.ReadRgb32(pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); else if (this.infoHeader.BitsPerPixel == 24)
} {
else if (this.infoHeader.BitsPerPixel == 24) this.ReadRgb24(pixels, this.infoHeader.Width, this.infoHeader.Height, inverted);
{ }
this.ReadRgb24(pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); else if (this.infoHeader.BitsPerPixel == 16)
} {
else if (this.infoHeader.BitsPerPixel == 16) this.ReadRgb16(pixels, this.infoHeader.Width, this.infoHeader.Height, inverted);
{ }
this.ReadRgb16(pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); else if (this.infoHeader.BitsPerPixel <= 8)
} {
else if (this.infoHeader.BitsPerPixel <= 8) this.ReadRgbPalette(
{ pixels,
this.ReadRgbPalette(pixels, palette, this.infoHeader.Width, this.infoHeader.Height, this.infoHeader.BitsPerPixel, inverted); palette,
} this.infoHeader.Width,
this.infoHeader.Height,
this.infoHeader.BitsPerPixel,
inverted);
}
break; break;
case BmpCompression.RLE8: case BmpCompression.RLE8:
this.ReadRle8(pixels, palette, this.infoHeader.Width, this.infoHeader.Height, inverted); this.ReadRle8(pixels, palette, this.infoHeader.Width, this.infoHeader.Height, inverted);
break; break;
default: default:
throw new NotSupportedException("Does not support this kind of bitmap files."); throw new NotSupportedException("Does not support this kind of bitmap files.");
}
} }
return image; return image;
@ -203,20 +209,20 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// Compresssed RLE8 stream is uncompressed by <see cref="UncompressRle8(int, Span{byte})"/> /// Compresssed RLE8 stream is uncompressed by <see cref="UncompressRle8(int, Span{byte})"/>
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="pixels">The <see cref="PixelAccessor{TPixel}"/> to assign the palette to.</param> /// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param>
/// <param name="colors">The <see cref="T:byte[]"/> containing the colors.</param> /// <param name="colors">The <see cref="T:byte[]"/> containing the colors.</param>
/// <param name="width">The width of the bitmap.</param> /// <param name="width">The width of the bitmap.</param>
/// <param name="height">The height of the bitmap.</param> /// <param name="height">The height of the bitmap.</param>
/// <param name="inverted">Whether the bitmap is inverted.</param> /// <param name="inverted">Whether the bitmap is inverted.</param>
private void ReadRle8<TPixel>(PixelAccessor<TPixel> pixels, byte[] colors, int width, int height, bool inverted) private void ReadRle8<TPixel>(Buffer2D<TPixel> pixels, byte[] colors, int width, int height, bool inverted)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
var color = default(TPixel); var color = default(TPixel);
var rgba = new Rgba32(0, 0, 0, 255); var rgba = new Rgba32(0, 0, 0, 255);
using (Buffer2D<byte> buffer = this.memoryManager.AllocateClean2D<byte>(width, height)) using (Buffer2D<byte> buffer = this.memoryAllocator.AllocateClean2D<byte>(width, height))
{ {
this.UncompressRle8(width, buffer.Span); this.UncompressRle8(width, buffer.GetSpan());
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
@ -318,13 +324,13 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// Reads the color palette from the stream. /// Reads the color palette from the stream.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="pixels">The <see cref="PixelAccessor{TPixel}"/> to assign the palette to.</param> /// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param>
/// <param name="colors">The <see cref="T:byte[]"/> containing the colors.</param> /// <param name="colors">The <see cref="T:byte[]"/> containing the colors.</param>
/// <param name="width">The width of the bitmap.</param> /// <param name="width">The width of the bitmap.</param>
/// <param name="height">The height of the bitmap.</param> /// <param name="height">The height of the bitmap.</param>
/// <param name="bits">The number of bits per pixel.</param> /// <param name="bits">The number of bits per pixel.</param>
/// <param name="inverted">Whether the bitmap is inverted.</param> /// <param name="inverted">Whether the bitmap is inverted.</param>
private void ReadRgbPalette<TPixel>(PixelAccessor<TPixel> pixels, byte[] colors, int width, int height, int bits, bool inverted) private void ReadRgbPalette<TPixel>(Buffer2D<TPixel> pixels, byte[] colors, int width, int height, int bits, bool inverted)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
// Pixels per byte (bits per pixel) // Pixels per byte (bits per pixel)
@ -342,12 +348,12 @@ namespace SixLabors.ImageSharp.Formats.Bmp
padding = 4 - padding; padding = 4 - padding;
} }
using (IManagedByteBuffer row = this.memoryManager.AllocateCleanManagedByteBuffer(arrayWidth + padding)) using (IManagedByteBuffer row = this.memoryAllocator.AllocateCleanManagedByteBuffer(arrayWidth + padding))
{ {
TPixel color = default; TPixel color = default;
var rgba = new Rgba32(0, 0, 0, 255); var rgba = new Rgba32(0, 0, 0, 255);
Span<byte> rowSpan = row.Span; Span<byte> rowSpan = row.GetSpan();
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
@ -382,11 +388,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// Reads the 16 bit color palette from the stream /// Reads the 16 bit color palette from the stream
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="pixels">The <see cref="PixelAccessor{TPixel}"/> to assign the palette to.</param> /// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param>
/// <param name="width">The width of the bitmap.</param> /// <param name="width">The width of the bitmap.</param>
/// <param name="height">The height of the bitmap.</param> /// <param name="height">The height of the bitmap.</param>
/// <param name="inverted">Whether the bitmap is inverted.</param> /// <param name="inverted">Whether the bitmap is inverted.</param>
private void ReadRgb16<TPixel>(PixelAccessor<TPixel> pixels, int width, int height, bool inverted) private void ReadRgb16<TPixel>(Buffer2D<TPixel> pixels, int width, int height, bool inverted)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
int padding = CalculatePadding(width, 2); int padding = CalculatePadding(width, 2);
@ -394,7 +400,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
var color = default(TPixel); var color = default(TPixel);
var rgba = new Rgba32(0, 0, 0, 255); var rgba = new Rgba32(0, 0, 0, 255);
using (IManagedByteBuffer buffer = this.memoryManager.AllocateManagedByteBuffer(stride)) using (IManagedByteBuffer buffer = this.memoryAllocator.AllocateManagedByteBuffer(stride))
{ {
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
@ -423,23 +429,23 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// Reads the 24 bit color palette from the stream /// Reads the 24 bit color palette from the stream
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="pixels">The <see cref="PixelAccessor{TPixel}"/> to assign the palette to.</param> /// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param>
/// <param name="width">The width of the bitmap.</param> /// <param name="width">The width of the bitmap.</param>
/// <param name="height">The height of the bitmap.</param> /// <param name="height">The height of the bitmap.</param>
/// <param name="inverted">Whether the bitmap is inverted.</param> /// <param name="inverted">Whether the bitmap is inverted.</param>
private void ReadRgb24<TPixel>(PixelAccessor<TPixel> pixels, int width, int height, bool inverted) private void ReadRgb24<TPixel>(Buffer2D<TPixel> pixels, int width, int height, bool inverted)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
int padding = CalculatePadding(width, 3); int padding = CalculatePadding(width, 3);
using (IManagedByteBuffer row = this.memoryManager.AllocatePaddedPixelRowBuffer(width, 3, padding)) using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 3, padding))
{ {
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
this.stream.Read(row); this.stream.Read(row);
int newY = Invert(y, height, inverted); int newY = Invert(y, height, inverted);
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY); Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
PixelOperations<TPixel>.Instance.PackFromBgr24Bytes(row.Span, pixelSpan, width); PixelOperations<TPixel>.Instance.PackFromBgr24Bytes(row.GetSpan(), pixelSpan, width);
} }
} }
} }
@ -448,23 +454,23 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// Reads the 32 bit color palette from the stream /// Reads the 32 bit color palette from the stream
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="pixels">The <see cref="PixelAccessor{TPixel}"/> to assign the palette to.</param> /// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param>
/// <param name="width">The width of the bitmap.</param> /// <param name="width">The width of the bitmap.</param>
/// <param name="height">The height of the bitmap.</param> /// <param name="height">The height of the bitmap.</param>
/// <param name="inverted">Whether the bitmap is inverted.</param> /// <param name="inverted">Whether the bitmap is inverted.</param>
private void ReadRgb32<TPixel>(PixelAccessor<TPixel> pixels, int width, int height, bool inverted) private void ReadRgb32<TPixel>(Buffer2D<TPixel> pixels, int width, int height, bool inverted)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
int padding = CalculatePadding(width, 4); int padding = CalculatePadding(width, 4);
using (IManagedByteBuffer row = this.memoryManager.AllocatePaddedPixelRowBuffer(width, 4, padding)) using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 4, padding))
{ {
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
this.stream.Read(row); this.stream.Read(row);
int newY = Invert(y, height, inverted); int newY = Invert(y, height, inverted);
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY); Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
PixelOperations<TPixel>.Instance.PackFromBgra32Bytes(row.Span, pixelSpan, width); PixelOperations<TPixel>.Instance.PackFromBgra32Bytes(row.GetSpan(), pixelSpan, width);
} }
} }
} }
@ -584,12 +590,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
this.stream.Read(palette, 0, colorMapSize); this.stream.Read(palette, 0, colorMapSize);
} }
if (this.infoHeader.Width > int.MaxValue || this.infoHeader.Height > int.MaxValue) this.infoHeader.VerifyDimensions();
{
throw new ArgumentOutOfRangeException(
$"The input bmp '{this.infoHeader.Width}x{this.infoHeader.Height}' is "
+ $"bigger then the max allowed size '{int.MaxValue}x{int.MaxValue}'");
}
} }
} }
} }

2
src/ImageSharp/Formats/Bmp/BmpEncoder.cs

@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
public void Encode<TPixel>(Image<TPixel> image, Stream stream) public void Encode<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
var encoder = new BmpEncoderCore(this, image.GetMemoryManager()); var encoder = new BmpEncoderCore(this, image.GetMemoryAllocator());
encoder.Encode(image, stream); encoder.Encode(image, stream);
} }
} }

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

@ -3,8 +3,8 @@
using System; using System;
using System.IO; using System.IO;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Bmp namespace SixLabors.ImageSharp.Formats.Bmp
{ {
@ -20,16 +20,16 @@ namespace SixLabors.ImageSharp.Formats.Bmp
private readonly BmpBitsPerPixel bitsPerPixel; private readonly BmpBitsPerPixel bitsPerPixel;
private readonly MemoryManager memoryManager; private readonly MemoryAllocator memoryAllocator;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="BmpEncoderCore"/> class. /// Initializes a new instance of the <see cref="BmpEncoderCore"/> class.
/// </summary> /// </summary>
/// <param name="options">The encoder options</param> /// <param name="options">The encoder options</param>
/// <param name="memoryManager">The memory manager</param> /// <param name="memoryAllocator">The memory manager</param>
public BmpEncoderCore(IBmpEncoderOptions options, MemoryManager memoryManager) public BmpEncoderCore(IBmpEncoderOptions options, MemoryAllocator memoryAllocator)
{ {
this.memoryManager = memoryManager; this.memoryAllocator = memoryAllocator;
this.bitsPerPixel = options.BitsPerPixel; this.bitsPerPixel = options.BitsPerPixel;
} }
@ -95,24 +95,22 @@ namespace SixLabors.ImageSharp.Formats.Bmp
private void WriteImage<TPixel>(Stream stream, ImageFrame<TPixel> image) private void WriteImage<TPixel>(Stream stream, ImageFrame<TPixel> image)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
using (PixelAccessor<TPixel> pixels = image.Lock()) Buffer2D<TPixel> pixels = image.PixelBuffer;
switch (this.bitsPerPixel)
{ {
switch (this.bitsPerPixel) case BmpBitsPerPixel.Pixel32:
{ this.Write32Bit(stream, pixels);
case BmpBitsPerPixel.Pixel32: break;
this.Write32Bit(stream, pixels);
break;
case BmpBitsPerPixel.Pixel24: case BmpBitsPerPixel.Pixel24:
this.Write24Bit(stream, pixels); this.Write24Bit(stream, pixels);
break; break;
}
} }
} }
private IManagedByteBuffer AllocateRow(int width, int bytesPerPixel) private IManagedByteBuffer AllocateRow(int width, int bytesPerPixel)
{ {
return this.memoryManager.AllocatePaddedPixelRowBuffer(width, bytesPerPixel, this.padding); return this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, bytesPerPixel, this.padding);
} }
/// <summary> /// <summary>
@ -120,8 +118,8 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="stream">The <see cref="Stream"/> to write to.</param> /// <param name="stream">The <see cref="Stream"/> to write to.</param>
/// <param name="pixels">The <see cref="PixelAccessor{TPixel}"/> containing pixel data.</param> /// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> containing pixel data.</param>
private void Write32Bit<TPixel>(Stream stream, PixelAccessor<TPixel> pixels) private void Write32Bit<TPixel>(Stream stream, Buffer2D<TPixel> pixels)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
using (IManagedByteBuffer row = this.AllocateRow(pixels.Width, 4)) using (IManagedByteBuffer row = this.AllocateRow(pixels.Width, 4))
@ -129,7 +127,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
for (int y = pixels.Height - 1; y >= 0; y--) for (int y = pixels.Height - 1; y >= 0; y--)
{ {
Span<TPixel> pixelSpan = pixels.GetRowSpan(y); Span<TPixel> pixelSpan = pixels.GetRowSpan(y);
PixelOperations<TPixel>.Instance.ToBgra32Bytes(pixelSpan, row.Span, pixelSpan.Length); PixelOperations<TPixel>.Instance.ToBgra32Bytes(pixelSpan, row.GetSpan(), pixelSpan.Length);
stream.Write(row.Array, 0, row.Length()); stream.Write(row.Array, 0, row.Length());
} }
} }
@ -140,8 +138,8 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="stream">The <see cref="Stream"/> to write to.</param> /// <param name="stream">The <see cref="Stream"/> to write to.</param>
/// <param name="pixels">The <see cref="PixelAccessor{TPixel}"/> containing pixel data.</param> /// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> containing pixel data.</param>
private void Write24Bit<TPixel>(Stream stream, PixelAccessor<TPixel> pixels) private void Write24Bit<TPixel>(Stream stream, Buffer2D<TPixel> pixels)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
using (IManagedByteBuffer row = this.AllocateRow(pixels.Width, 3)) using (IManagedByteBuffer row = this.AllocateRow(pixels.Width, 3))
@ -149,7 +147,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
for (int y = pixels.Height - 1; y >= 0; y--) for (int y = pixels.Height - 1; y >= 0; y--)
{ {
Span<TPixel> pixelSpan = pixels.GetRowSpan(y); Span<TPixel> pixelSpan = pixels.GetRowSpan(y);
PixelOperations<TPixel>.Instance.ToBgr24Bytes(pixelSpan, row.Span, pixelSpan.Length); PixelOperations<TPixel>.Instance.ToBgr24Bytes(pixelSpan, row.GetSpan(), pixelSpan.Length);
stream.Write(row.Array, 0, row.Length()); stream.Write(row.Array, 0, row.Length());
} }
} }

12
src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs

@ -162,5 +162,17 @@ namespace SixLabors.ImageSharp.Formats.Bmp
dest = this; dest = this;
} }
internal void VerifyDimensions()
{
const int MaximumBmpDimension = 65535;
if (this.Width > MaximumBmpDimension || this.Height > MaximumBmpDimension)
{
throw new InvalidOperationException(
$"The input bmp '{this.Width}x{this.Height}' is "
+ $"bigger then the max allowed size '{MaximumBmpDimension}x{MaximumBmpDimension}'");
}
}
} }
} }

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

@ -7,9 +7,9 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Gif namespace SixLabors.ImageSharp.Formats.Gif
@ -87,7 +87,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// </summary> /// </summary>
public FrameDecodingMode DecodingMode { get; } public FrameDecodingMode DecodingMode { get; }
private MemoryManager MemoryManager => this.configuration.MemoryManager; private MemoryAllocator MemoryAllocator => this.configuration.MemoryAllocator;
/// <summary> /// <summary>
/// Decodes the stream to the image. /// Decodes the stream to the image.
@ -293,7 +293,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
continue; continue;
} }
using (IManagedByteBuffer commentsBuffer = this.MemoryManager.AllocateManagedByteBuffer(length)) using (IManagedByteBuffer commentsBuffer = this.MemoryAllocator.AllocateManagedByteBuffer(length))
{ {
this.stream.Read(commentsBuffer.Array, 0, length); this.stream.Read(commentsBuffer.Array, 0, length);
string comments = this.TextEncoding.GetString(commentsBuffer.Array, 0, length); string comments = this.TextEncoding.GetString(commentsBuffer.Array, 0, length);
@ -321,15 +321,15 @@ namespace SixLabors.ImageSharp.Formats.Gif
if (imageDescriptor.LocalColorTableFlag) if (imageDescriptor.LocalColorTableFlag)
{ {
int length = imageDescriptor.LocalColorTableSize * 3; int length = imageDescriptor.LocalColorTableSize * 3;
localColorTable = this.configuration.MemoryManager.AllocateManagedByteBuffer(length, true); localColorTable = this.configuration.MemoryAllocator.AllocateManagedByteBuffer(length, true);
this.stream.Read(localColorTable.Array, 0, length); this.stream.Read(localColorTable.Array, 0, length);
} }
indices = this.configuration.MemoryManager.AllocateManagedByteBuffer(imageDescriptor.Width * imageDescriptor.Height, true); indices = this.configuration.MemoryAllocator.AllocateManagedByteBuffer(imageDescriptor.Width * imageDescriptor.Height, true);
this.ReadFrameIndices(imageDescriptor, indices.Span); this.ReadFrameIndices(imageDescriptor, indices.GetSpan());
ReadOnlySpan<Rgb24> colorTable = MemoryMarshal.Cast<byte, Rgb24>((localColorTable ?? this.globalColorTable).Span); ReadOnlySpan<Rgb24> colorTable = MemoryMarshal.Cast<byte, Rgb24>((localColorTable ?? this.globalColorTable).GetSpan());
this.ReadFrameColors(ref image, ref previousFrame, indices.Span, colorTable, imageDescriptor); this.ReadFrameColors(ref image, ref previousFrame, indices.GetSpan(), colorTable, imageDescriptor);
// Skip any remaining blocks // Skip any remaining blocks
this.Skip(0); this.Skip(0);
@ -350,7 +350,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
private void ReadFrameIndices(in GifImageDescriptor imageDescriptor, Span<byte> indices) private void ReadFrameIndices(in GifImageDescriptor imageDescriptor, Span<byte> indices)
{ {
int dataSize = this.stream.ReadByte(); int dataSize = this.stream.ReadByte();
using (var lzwDecoder = new LzwDecoder(this.configuration.MemoryManager, this.stream)) using (var lzwDecoder = new LzwDecoder(this.configuration.MemoryAllocator, this.stream))
{ {
lzwDecoder.DecodePixels(imageDescriptor.Width, imageDescriptor.Height, dataSize, indices); lzwDecoder.DecodePixels(imageDescriptor.Width, imageDescriptor.Height, dataSize, indices);
} }
@ -528,7 +528,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
{ {
int globalColorTableLength = this.logicalScreenDescriptor.GlobalColorTableSize * 3; int globalColorTableLength = this.logicalScreenDescriptor.GlobalColorTableSize * 3;
this.globalColorTable = this.MemoryManager.AllocateManagedByteBuffer(globalColorTableLength, true); this.globalColorTable = this.MemoryAllocator.AllocateManagedByteBuffer(globalColorTableLength, true);
// Read the global color table data from the stream // Read the global color table data from the stream
stream.Read(this.globalColorTable.Array, 0, globalColorTableLength); stream.Read(this.globalColorTable.Array, 0, globalColorTableLength);

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

@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
public void Encode<TPixel>(Image<TPixel> image, Stream stream) public void Encode<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
var encoder = new GifEncoderCore(image.GetConfiguration().MemoryManager, this); var encoder = new GifEncoderCore(image.GetConfiguration().MemoryAllocator, this);
encoder.Encode(image, stream); encoder.Encode(image, stream);
} }
} }

16
src/ImageSharp/Formats/Gif/GifEncoderCore.cs

@ -7,10 +7,10 @@ using System.IO;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Quantization; using SixLabors.ImageSharp.Processing.Quantization;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Gif namespace SixLabors.ImageSharp.Formats.Gif
{ {
@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// </summary> /// </summary>
internal sealed class GifEncoderCore internal sealed class GifEncoderCore
{ {
private readonly MemoryManager memoryManager; private readonly MemoryAllocator memoryAllocator;
/// <summary> /// <summary>
/// A reusable buffer used to reduce allocations. /// A reusable buffer used to reduce allocations.
@ -49,11 +49,11 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="GifEncoderCore"/> class. /// Initializes a new instance of the <see cref="GifEncoderCore"/> class.
/// </summary> /// </summary>
/// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations.</param> /// <param name="memoryAllocator">The <see cref="MemoryAllocator"/> to use for buffer allocations.</param>
/// <param name="options">The options for the encoder.</param> /// <param name="options">The options for the encoder.</param>
public GifEncoderCore(MemoryManager memoryManager, IGifEncoderOptions options) public GifEncoderCore(MemoryAllocator memoryAllocator, IGifEncoderOptions options)
{ {
this.memoryManager = memoryManager; this.memoryAllocator = memoryAllocator;
this.textEncoding = options.TextEncoding ?? GifConstants.DefaultEncoding; this.textEncoding = options.TextEncoding ?? GifConstants.DefaultEncoding;
this.quantizer = options.Quantizer; this.quantizer = options.Quantizer;
this.ignoreMetadata = options.IgnoreMetadata; this.ignoreMetadata = options.IgnoreMetadata;
@ -317,10 +317,10 @@ namespace SixLabors.ImageSharp.Formats.Gif
int colorTableLength = (int)Math.Pow(2, this.bitDepth) * 3; // The maximium number of colors for the bit depth int colorTableLength = (int)Math.Pow(2, this.bitDepth) * 3; // The maximium number of colors for the bit depth
Rgb24 rgb = default; Rgb24 rgb = default;
using (IManagedByteBuffer colorTable = this.memoryManager.AllocateManagedByteBuffer(colorTableLength)) using (IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength))
{ {
ref TPixel paletteRef = ref MemoryMarshal.GetReference(image.Palette.AsSpan()); ref TPixel paletteRef = ref MemoryMarshal.GetReference(image.Palette.AsSpan());
ref Rgb24 rgb24Ref = ref Unsafe.As<byte, Rgb24>(ref MemoryMarshal.GetReference(colorTable.Span)); ref Rgb24 rgb24Ref = ref Unsafe.As<byte, Rgb24>(ref MemoryMarshal.GetReference(colorTable.GetSpan()));
for (int i = 0; i < pixelCount; i++) for (int i = 0; i < pixelCount; i++)
{ {
ref TPixel entry = ref Unsafe.Add(ref paletteRef, i); ref TPixel entry = ref Unsafe.Add(ref paletteRef, i);
@ -342,7 +342,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
private void WriteImageData<TPixel>(QuantizedFrame<TPixel> image, Stream stream) private void WriteImageData<TPixel>(QuantizedFrame<TPixel> image, Stream stream)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
using (var encoder = new LzwEncoder(this.memoryManager, image.Pixels, (byte)this.bitDepth)) using (var encoder = new LzwEncoder(this.memoryAllocator, image.Pixels, (byte)this.bitDepth))
{ {
encoder.Encode(stream); encoder.Encode(stream);
} }

18
src/ImageSharp/Formats/Gif/LzwDecoder.cs

@ -5,7 +5,7 @@ using System;
using System.IO; using System.IO;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory; using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Gif namespace SixLabors.ImageSharp.Formats.Gif
{ {
@ -48,18 +48,18 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// Initializes a new instance of the <see cref="LzwDecoder"/> class /// Initializes a new instance of the <see cref="LzwDecoder"/> class
/// and sets the stream, where the compressed data should be read from. /// and sets the stream, where the compressed data should be read from.
/// </summary> /// </summary>
/// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations.</param> /// <param name="memoryAllocator">The <see cref="MemoryAllocator"/> to use for buffer allocations.</param>
/// <param name="stream">The stream to read from.</param> /// <param name="stream">The stream to read from.</param>
/// <exception cref="System.ArgumentNullException"><paramref name="stream"/> is null.</exception> /// <exception cref="System.ArgumentNullException"><paramref name="stream"/> is null.</exception>
public LzwDecoder(MemoryManager memoryManager, Stream stream) public LzwDecoder(MemoryAllocator memoryAllocator, Stream stream)
{ {
Guard.NotNull(stream, nameof(stream)); Guard.NotNull(stream, nameof(stream));
this.stream = stream; this.stream = stream;
this.prefix = memoryManager.Allocate<int>(MaxStackSize, true); this.prefix = memoryAllocator.Allocate<int>(MaxStackSize, true);
this.suffix = memoryManager.Allocate<int>(MaxStackSize, true); this.suffix = memoryAllocator.Allocate<int>(MaxStackSize, true);
this.pixelStack = memoryManager.Allocate<int>(MaxStackSize + 1, true); this.pixelStack = memoryAllocator.Allocate<int>(MaxStackSize + 1, true);
} }
/// <summary> /// <summary>
@ -102,9 +102,9 @@ namespace SixLabors.ImageSharp.Formats.Gif
int data = 0; int data = 0;
int first = 0; int first = 0;
ref int prefixRef = ref MemoryMarshal.GetReference(this.prefix.Span); ref int prefixRef = ref MemoryMarshal.GetReference(this.prefix.GetSpan());
ref int suffixRef = ref MemoryMarshal.GetReference(this.suffix.Span); ref int suffixRef = ref MemoryMarshal.GetReference(this.suffix.GetSpan());
ref int pixelStackRef = ref MemoryMarshal.GetReference(this.pixelStack.Span); ref int pixelStackRef = ref MemoryMarshal.GetReference(this.pixelStack.GetSpan());
ref byte pixelsRef = ref MemoryMarshal.GetReference(pixels); ref byte pixelsRef = ref MemoryMarshal.GetReference(pixels);
for (code = 0; code < clearCode; code++) for (code = 0; code < clearCode; code++)

16
src/ImageSharp/Formats/Gif/LzwEncoder.cs

@ -5,7 +5,7 @@ using System;
using System.IO; using System.IO;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory; using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Gif namespace SixLabors.ImageSharp.Formats.Gif
{ {
@ -168,16 +168,16 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="LzwEncoder"/> class. /// Initializes a new instance of the <see cref="LzwEncoder"/> class.
/// </summary> /// </summary>
/// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations.</param> /// <param name="memoryAllocator">The <see cref="MemoryAllocator"/> to use for buffer allocations.</param>
/// <param name="indexedPixels">The array of indexed pixels.</param> /// <param name="indexedPixels">The array of indexed pixels.</param>
/// <param name="colorDepth">The color depth in bits.</param> /// <param name="colorDepth">The color depth in bits.</param>
public LzwEncoder(MemoryManager memoryManager, byte[] indexedPixels, int colorDepth) public LzwEncoder(MemoryAllocator memoryAllocator, byte[] indexedPixels, int colorDepth)
{ {
this.pixelArray = indexedPixels; this.pixelArray = indexedPixels;
this.initialCodeSize = Math.Max(2, colorDepth); this.initialCodeSize = Math.Max(2, colorDepth);
this.hashTable = memoryManager.Allocate<int>(HashSize, true); this.hashTable = memoryAllocator.Allocate<int>(HashSize, true);
this.codeTable = memoryManager.Allocate<int>(HashSize, true); this.codeTable = memoryAllocator.Allocate<int>(HashSize, true);
} }
/// <summary> /// <summary>
@ -246,7 +246,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ResetCodeTable() private void ResetCodeTable()
{ {
this.hashTable.Span.Fill(-1); this.hashTable.GetSpan().Fill(-1);
} }
/// <summary> /// <summary>
@ -293,8 +293,8 @@ namespace SixLabors.ImageSharp.Formats.Gif
this.Output(this.clearCode, stream); this.Output(this.clearCode, stream);
ref int hashTableRef = ref MemoryMarshal.GetReference(this.hashTable.Span); ref int hashTableRef = ref MemoryMarshal.GetReference(this.hashTable.GetSpan());
ref int codeTableRef = ref MemoryMarshal.GetReference(this.codeTable.Span); ref int codeTableRef = ref MemoryMarshal.GetReference(this.codeTable.GetSpan());
while (this.position < this.pixelArray.Length) while (this.position < this.pixelArray.Length)
{ {

2
src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs

@ -4,7 +4,7 @@
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory; using SixLabors.Memory;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Formats.Jpeg.Components namespace SixLabors.ImageSharp.Formats.Jpeg.Components

4
src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs

@ -7,7 +7,7 @@ using System.Linq;
using System.Numerics; using System.Numerics;
using SixLabors.ImageSharp.Common.Tuples; using SixLabors.ImageSharp.Common.Tuples;
using SixLabors.ImageSharp.Memory; using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{ {
@ -101,7 +101,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
/// </summary> /// </summary>
/// <param name="componentBuffers">The 1-4 sized list of component buffers.</param> /// <param name="componentBuffers">The 1-4 sized list of component buffers.</param>
/// <param name="row">The row to convert</param> /// <param name="row">The row to convert</param>
public ComponentValues(IReadOnlyList<IBuffer2D<float>> componentBuffers, int row) public ComponentValues(IReadOnlyList<Buffer2D<float>> componentBuffers, int row)
{ {
this.ComponentCount = componentBuffers.Count; this.ComponentCount = componentBuffers.Count;

2
src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs

@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Memory; using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder

2
src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs

@ -3,7 +3,7 @@
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory; using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder

6
src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs

@ -3,7 +3,7 @@
using System; using System;
using SixLabors.ImageSharp.Memory; using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
@ -26,11 +26,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="JpegComponentPostProcessor"/> class. /// Initializes a new instance of the <see cref="JpegComponentPostProcessor"/> class.
/// </summary> /// </summary>
public JpegComponentPostProcessor(MemoryManager memoryManager, JpegImagePostProcessor imagePostProcessor, IJpegComponent component) public JpegComponentPostProcessor(MemoryAllocator memoryAllocator, JpegImagePostProcessor imagePostProcessor, IJpegComponent component)
{ {
this.Component = component; this.Component = component;
this.ImagePostProcessor = imagePostProcessor; this.ImagePostProcessor = imagePostProcessor;
this.ColorBuffer = memoryManager.Allocate2D<float>( this.ColorBuffer = memoryAllocator.Allocate2D<float>(
imagePostProcessor.PostProcessorBufferSize.Width, imagePostProcessor.PostProcessorBufferSize.Width,
imagePostProcessor.PostProcessorBufferSize.Height); imagePostProcessor.PostProcessorBufferSize.Height);

16
src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs

@ -4,12 +4,10 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
using JpegColorConverter = SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters.JpegColorConverter; using JpegColorConverter = SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters.JpegColorConverter;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
@ -49,17 +47,17 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="JpegImagePostProcessor"/> class. /// Initializes a new instance of the <see cref="JpegImagePostProcessor"/> class.
/// </summary> /// </summary>
/// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations.</param> /// <param name="memoryAllocator">The <see cref="MemoryAllocator"/> to use for buffer allocations.</param>
/// <param name="rawJpeg">The <see cref="IRawJpegData"/> representing the uncompressed spectral Jpeg data</param> /// <param name="rawJpeg">The <see cref="IRawJpegData"/> representing the uncompressed spectral Jpeg data</param>
public JpegImagePostProcessor(MemoryManager memoryManager, IRawJpegData rawJpeg) public JpegImagePostProcessor(MemoryAllocator memoryAllocator, IRawJpegData rawJpeg)
{ {
this.RawJpeg = rawJpeg; this.RawJpeg = rawJpeg;
IJpegComponent c0 = rawJpeg.Components.First(); IJpegComponent c0 = rawJpeg.Components.First();
this.NumberOfPostProcessorSteps = c0.SizeInBlocks.Height / BlockRowsPerStep; this.NumberOfPostProcessorSteps = c0.SizeInBlocks.Height / BlockRowsPerStep;
this.PostProcessorBufferSize = new Size(c0.SizeInBlocks.Width * 8, PixelRowsPerStep); this.PostProcessorBufferSize = new Size(c0.SizeInBlocks.Width * 8, PixelRowsPerStep);
this.ComponentProcessors = rawJpeg.Components.Select(c => new JpegComponentPostProcessor(memoryManager, this, c)).ToArray(); this.ComponentProcessors = rawJpeg.Components.Select(c => new JpegComponentPostProcessor(memoryAllocator, this, c)).ToArray();
this.rgbaBuffer = memoryManager.Allocate<Vector4>(rawJpeg.ImageSizeInPixels.Width); this.rgbaBuffer = memoryAllocator.Allocate<Vector4>(rawJpeg.ImageSizeInPixels.Width);
this.colorConverter = JpegColorConverter.GetConverter(rawJpeg.ColorSpace); this.colorConverter = JpegColorConverter.GetConverter(rawJpeg.ColorSpace);
} }
@ -155,11 +153,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
int y = yy - this.PixelRowCounter; int y = yy - this.PixelRowCounter;
var values = new JpegColorConverter.ComponentValues(buffers, y); var values = new JpegColorConverter.ComponentValues(buffers, y);
this.colorConverter.ConvertToRgba(values, this.rgbaBuffer.Span); this.colorConverter.ConvertToRgba(values, this.rgbaBuffer.GetSpan());
Span<TPixel> destRow = destination.GetPixelRowSpan(yy); Span<TPixel> destRow = destination.GetPixelRowSpan(yy);
PixelOperations<TPixel>.Instance.PackFromVector4(this.rgbaBuffer.Span, destRow, destination.Width); PixelOperations<TPixel>.Instance.PackFromVector4(this.rgbaBuffer.GetSpan(), destRow, destination.Width);
} }
} }
} }

3
src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs

@ -4,10 +4,9 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Formats.Jpeg.Components namespace SixLabors.ImageSharp.Formats.Jpeg.Components

8
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangComponent.cs

@ -6,7 +6,7 @@ using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Formats.Jpeg.Components; using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder; using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.Memory; using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
@ -56,9 +56,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// <summary> /// <summary>
/// Initializes <see cref="SpectralBlocks"/> /// Initializes <see cref="SpectralBlocks"/>
/// </summary> /// </summary>
/// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations.</param> /// <param name="memoryAllocator">The <see cref="MemoryAllocator"/> to use for buffer allocations.</param>
/// <param name="decoder">The <see cref="GolangJpegDecoderCore"/> instance</param> /// <param name="decoder">The <see cref="GolangJpegDecoderCore"/> instance</param>
public void InitializeDerivedData(MemoryManager memoryManager, GolangJpegDecoderCore decoder) public void InitializeDerivedData(MemoryAllocator memoryAllocator, GolangJpegDecoderCore decoder)
{ {
// For 4-component images (either CMYK or YCbCrK), we only support two // For 4-component images (either CMYK or YCbCrK), we only support two
// hv vectors: [0x11 0x11 0x11 0x11] and [0x22 0x11 0x11 0x22]. // hv vectors: [0x11 0x11 0x11 0x11] and [0x22 0x11 0x11 0x22].
@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
this.SubSamplingDivisors = c0.SamplingFactors.DivideBy(this.SamplingFactors); this.SubSamplingDivisors = c0.SamplingFactors.DivideBy(this.SamplingFactors);
} }
this.SpectralBlocks = memoryManager.Allocate2D<Block8x8>(this.SizeInBlocks.Width, this.SizeInBlocks.Height, true); this.SpectralBlocks = memoryAllocator.Allocate2D<Block8x8>(this.SizeInBlocks.Width, this.SizeInBlocks.Height, true);
} }
/// <summary> /// <summary>

4
src/ImageSharp/Formats/Jpeg/GolangPort/GolangJpegDecoderCore.cs

@ -705,7 +705,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
foreach (GolangComponent component in this.Components) foreach (GolangComponent component in this.Components)
{ {
component.InitializeDerivedData(this.configuration.MemoryManager, this); component.InitializeDerivedData(this.configuration.MemoryAllocator, this);
} }
} }
} }
@ -812,7 +812,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
private Image<TPixel> PostProcessIntoImage<TPixel>() private Image<TPixel> PostProcessIntoImage<TPixel>()
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
using (var postProcessor = new JpegImagePostProcessor(this.configuration.MemoryManager, this)) using (var postProcessor = new JpegImagePostProcessor(this.configuration.MemoryAllocator, this))
{ {
var image = new Image<TPixel>(this.configuration, this.ImageWidth, this.ImageHeight, this.MetaData); var image = new Image<TPixel>(this.configuration, this.ImageWidth, this.ImageHeight, this.MetaData);
postProcessor.PostProcess(image.Frames.RootFrame); postProcessor.PostProcess(image.Frames.RootFrame);

8
src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/DoubleBufferedStreamReader.cs

@ -5,7 +5,7 @@ using System;
using System.IO; using System.IO;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory; using SixLabors.Memory;
// TODO: This could be useful elsewhere. // TODO: This could be useful elsewhere.
namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
@ -38,13 +38,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DoubleBufferedStreamReader"/> class. /// Initializes a new instance of the <see cref="DoubleBufferedStreamReader"/> class.
/// </summary> /// </summary>
/// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations.</param> /// <param name="memoryAllocator">The <see cref="MemoryAllocator"/> to use for buffer allocations.</param>
/// <param name="stream">The input stream.</param> /// <param name="stream">The input stream.</param>
public DoubleBufferedStreamReader(MemoryManager memoryManager, Stream stream) public DoubleBufferedStreamReader(MemoryAllocator memoryAllocator, Stream stream)
{ {
this.stream = stream; this.stream = stream;
this.length = (int)stream.Length; this.length = (int)stream.Length;
this.managedBuffer = memoryManager.AllocateCleanManagedByteBuffer(ChunkLength); this.managedBuffer = memoryAllocator.AllocateCleanManagedByteBuffer(ChunkLength);
this.bufferChunk = this.managedBuffer.Array; this.bufferChunk = this.managedBuffer.Array;
} }

12
src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFrameComponent.cs

@ -7,7 +7,7 @@ using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Formats.Jpeg.Components; using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder; using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.Memory; using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
@ -17,11 +17,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
/// </summary> /// </summary>
internal class PdfJsFrameComponent : IDisposable, IJpegComponent internal class PdfJsFrameComponent : IDisposable, IJpegComponent
{ {
private readonly MemoryManager memoryManager; private readonly MemoryAllocator memoryAllocator;
public PdfJsFrameComponent(MemoryManager memoryManager, PdfJsFrame frame, byte id, int horizontalFactor, int verticalFactor, byte quantizationTableIndex, int index) public PdfJsFrameComponent(MemoryAllocator memoryAllocator, PdfJsFrame frame, byte id, int horizontalFactor, int verticalFactor, byte quantizationTableIndex, int index)
{ {
this.memoryManager = memoryManager; this.memoryAllocator = memoryAllocator;
this.Frame = frame; this.Frame = frame;
this.Id = id; this.Id = id;
this.HorizontalSamplingFactor = horizontalFactor; this.HorizontalSamplingFactor = horizontalFactor;
@ -129,14 +129,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
this.SubSamplingDivisors = c0.SamplingFactors.DivideBy(this.SamplingFactors); this.SubSamplingDivisors = c0.SamplingFactors.DivideBy(this.SamplingFactors);
} }
this.SpectralBlocks = this.memoryManager.Allocate2D<Block8x8>(blocksPerColumnForMcu, blocksPerLineForMcu + 1, true); this.SpectralBlocks = this.memoryAllocator.Allocate2D<Block8x8>(blocksPerColumnForMcu, blocksPerLineForMcu + 1, true);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref Block8x8 GetBlockReference(int column, int row) public ref Block8x8 GetBlockReference(int column, int row)
{ {
int offset = ((this.WidthInBlocks + 1) * row) + column; int offset = ((this.WidthInBlocks + 1) * row) + column;
return ref Unsafe.Add(ref MemoryMarshal.GetReference(this.SpectralBlocks.Span), offset); return ref Unsafe.Add(ref MemoryMarshal.GetReference(this.SpectralBlocks.GetSpan()), offset);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]

14
src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsHuffmanTable.cs

@ -4,7 +4,7 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory; using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{ {
@ -37,17 +37,17 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="PdfJsHuffmanTable"/> struct. /// Initializes a new instance of the <see cref="PdfJsHuffmanTable"/> struct.
/// </summary> /// </summary>
/// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations.</param> /// <param name="memoryAllocator">The <see cref="MemoryAllocator"/> to use for buffer allocations.</param>
/// <param name="lengths">The code lengths</param> /// <param name="lengths">The code lengths</param>
/// <param name="values">The huffman values</param> /// <param name="values">The huffman values</param>
public PdfJsHuffmanTable(MemoryManager memoryManager, ReadOnlySpan<byte> lengths, ReadOnlySpan<byte> values) public PdfJsHuffmanTable(MemoryAllocator memoryAllocator, ReadOnlySpan<byte> lengths, ReadOnlySpan<byte> values)
{ {
const int length = 257; const int length = 257;
using (IBuffer<short> huffsize = memoryManager.Allocate<short>(length)) using (IBuffer<short> huffsize = memoryAllocator.Allocate<short>(length))
using (IBuffer<short> huffcode = memoryManager.Allocate<short>(length)) using (IBuffer<short> huffcode = memoryAllocator.Allocate<short>(length))
{ {
ref short huffsizeRef = ref MemoryMarshal.GetReference(huffsize.Span); ref short huffsizeRef = ref MemoryMarshal.GetReference(huffsize.GetSpan());
ref short huffcodeRef = ref MemoryMarshal.GetReference(huffcode.Span); ref short huffcodeRef = ref MemoryMarshal.GetReference(huffcode.GetSpan());
GenerateSizeTable(lengths, ref huffsizeRef); GenerateSizeTable(lengths, ref huffsizeRef);
GenerateCodeTable(ref huffsizeRef, ref huffcodeRef, length); GenerateCodeTable(ref huffsizeRef, ref huffcodeRef, length);

11
src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsScanDecoder.cs

@ -2,13 +2,14 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
#if DEBUG #if DEBUG
using System.Diagnostics; using System.Diagnostics;
#endif #endif
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Formats.Jpeg.Components; using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{ {
@ -166,7 +167,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
if (componentsLength == 1) if (componentsLength == 1)
{ {
PdfJsFrameComponent component = components[this.compIndex]; PdfJsFrameComponent component = components[this.compIndex];
ref short blockDataRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast<Block8x8, short>(component.SpectralBlocks.Span)); ref short blockDataRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast<Block8x8, short>(component.SpectralBlocks.GetSpan()));
ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId]; ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId]; ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
@ -188,7 +189,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
for (int i = 0; i < componentsLength; i++) for (int i = 0; i < componentsLength; i++)
{ {
PdfJsFrameComponent component = components[i]; PdfJsFrameComponent component = components[i];
ref short blockDataRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast<Block8x8, short>(component.SpectralBlocks.Span)); ref short blockDataRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast<Block8x8, short>(component.SpectralBlocks.GetSpan()));
ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId]; ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId]; ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
int h = component.HorizontalSamplingFactor; int h = component.HorizontalSamplingFactor;
@ -224,7 +225,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
if (componentsLength == 1) if (componentsLength == 1)
{ {
PdfJsFrameComponent component = components[this.compIndex]; PdfJsFrameComponent component = components[this.compIndex];
ref short blockDataRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast<Block8x8, short>(component.SpectralBlocks.Span)); ref short blockDataRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast<Block8x8, short>(component.SpectralBlocks.GetSpan()));
ref PdfJsHuffmanTable huffmanTable = ref huffmanTables[isAC ? component.ACHuffmanTableId : component.DCHuffmanTableId]; ref PdfJsHuffmanTable huffmanTable = ref huffmanTables[isAC ? component.ACHuffmanTableId : component.DCHuffmanTableId];
for (int n = 0; n < this.mcuToRead; n++) for (int n = 0; n < this.mcuToRead; n++)
@ -267,7 +268,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
for (int i = 0; i < componentsLength; i++) for (int i = 0; i < componentsLength; i++)
{ {
PdfJsFrameComponent component = components[i]; PdfJsFrameComponent component = components[i];
ref short blockDataRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast<Block8x8, short>(component.SpectralBlocks.Span)); ref short blockDataRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast<Block8x8, short>(component.SpectralBlocks.GetSpan()));
ref PdfJsHuffmanTable huffmanTable = ref huffmanTables[isAC ? component.ACHuffmanTableId : component.DCHuffmanTableId]; ref PdfJsHuffmanTable huffmanTable = ref huffmanTables[isAC ? component.ACHuffmanTableId : component.DCHuffmanTableId];
int h = component.HorizontalSamplingFactor; int h = component.HorizontalSamplingFactor;
int v = component.VerticalSamplingFactor; int v = component.VerticalSamplingFactor;

24
src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs

@ -11,12 +11,12 @@ using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Formats.Jpeg.Components; using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder; using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components; using SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.MetaData.Profiles.Exif;
using SixLabors.ImageSharp.MetaData.Profiles.Icc; using SixLabors.ImageSharp.MetaData.Profiles.Icc;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives; using SixLabors.ImageSharp.Primitives;
using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
@ -219,7 +219,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
public void ParseStream(Stream stream, bool metadataOnly = false) public void ParseStream(Stream stream, bool metadataOnly = false)
{ {
this.MetaData = new ImageMetaData(); this.MetaData = new ImageMetaData();
this.InputStream = new DoubleBufferedStreamReader(this.configuration.MemoryManager, stream); this.InputStream = new DoubleBufferedStreamReader(this.configuration.MemoryAllocator, stream);
// Check for the Start Of Image marker. // Check for the Start Of Image marker.
this.InputStream.Read(this.markerBuffer, 0, 2); this.InputStream.Read(this.markerBuffer, 0, 2);
@ -675,7 +675,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
maxV = v; maxV = v;
} }
var component = new PdfJsFrameComponent(this.configuration.MemoryManager, this.Frame, this.temp[index], h, v, this.temp[index + 2], i); var component = new PdfJsFrameComponent(this.configuration.MemoryAllocator, this.Frame, this.temp[index], h, v, this.temp[index + 2], i);
this.Frame.Components[i] = component; this.Frame.Components[i] = component;
this.Frame.ComponentIds[i] = component.Id; this.Frame.ComponentIds[i] = component.Id;
@ -703,17 +703,17 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
throw new ImageFormatException($"DHT has wrong length: {remaining}"); throw new ImageFormatException($"DHT has wrong length: {remaining}");
} }
using (IManagedByteBuffer huffmanData = this.configuration.MemoryManager.AllocateCleanManagedByteBuffer(256)) using (IManagedByteBuffer huffmanData = this.configuration.MemoryAllocator.AllocateCleanManagedByteBuffer(256))
{ {
ref byte huffmanDataRef = ref MemoryMarshal.GetReference(huffmanData.Span); ref byte huffmanDataRef = ref MemoryMarshal.GetReference(huffmanData.GetSpan());
for (int i = 2; i < remaining;) for (int i = 2; i < remaining;)
{ {
byte huffmanTableSpec = (byte)this.InputStream.ReadByte(); byte huffmanTableSpec = (byte)this.InputStream.ReadByte();
this.InputStream.Read(huffmanData.Array, 0, 16); this.InputStream.Read(huffmanData.Array, 0, 16);
using (IManagedByteBuffer codeLengths = this.configuration.MemoryManager.AllocateCleanManagedByteBuffer(17)) using (IManagedByteBuffer codeLengths = this.configuration.MemoryAllocator.AllocateCleanManagedByteBuffer(17))
{ {
ref byte codeLengthsRef = ref MemoryMarshal.GetReference(codeLengths.Span); ref byte codeLengthsRef = ref MemoryMarshal.GetReference(codeLengths.GetSpan());
int codeLengthSum = 0; int codeLengthSum = 0;
for (int j = 1; j < 17; j++) for (int j = 1; j < 17; j++)
@ -721,7 +721,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
codeLengthSum += Unsafe.Add(ref codeLengthsRef, j) = Unsafe.Add(ref huffmanDataRef, j - 1); codeLengthSum += Unsafe.Add(ref codeLengthsRef, j) = Unsafe.Add(ref huffmanDataRef, j - 1);
} }
using (IManagedByteBuffer huffmanValues = this.configuration.MemoryManager.AllocateCleanManagedByteBuffer(256)) using (IManagedByteBuffer huffmanValues = this.configuration.MemoryAllocator.AllocateCleanManagedByteBuffer(256))
{ {
this.InputStream.Read(huffmanValues.Array, 0, codeLengthSum); this.InputStream.Read(huffmanValues.Array, 0, codeLengthSum);
@ -730,8 +730,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
this.BuildHuffmanTable( this.BuildHuffmanTable(
huffmanTableSpec >> 4 == 0 ? this.dcHuffmanTables : this.acHuffmanTables, huffmanTableSpec >> 4 == 0 ? this.dcHuffmanTables : this.acHuffmanTables,
huffmanTableSpec & 15, huffmanTableSpec & 15,
codeLengths.Span, codeLengths.GetSpan(),
huffmanValues.Span); huffmanValues.GetSpan());
} }
} }
} }
@ -817,7 +817,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void BuildHuffmanTable(PdfJsHuffmanTables tables, int index, ReadOnlySpan<byte> codeLengths, ReadOnlySpan<byte> values) private void BuildHuffmanTable(PdfJsHuffmanTables tables, int index, ReadOnlySpan<byte> codeLengths, ReadOnlySpan<byte> values)
{ {
tables[index] = new PdfJsHuffmanTable(this.configuration.MemoryManager, codeLengths, values); tables[index] = new PdfJsHuffmanTable(this.configuration.MemoryAllocator, codeLengths, values);
} }
/// <summary> /// <summary>
@ -834,7 +834,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
private Image<TPixel> PostProcessIntoImage<TPixel>() private Image<TPixel> PostProcessIntoImage<TPixel>()
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
using (var postProcessor = new JpegImagePostProcessor(this.configuration.MemoryManager, this)) using (var postProcessor = new JpegImagePostProcessor(this.configuration.MemoryAllocator, this))
{ {
var image = new Image<TPixel>(this.configuration, this.ImageWidth, this.ImageHeight, this.MetaData); var image = new Image<TPixel>(this.configuration, this.ImageWidth, this.ImageHeight, this.MetaData);
postProcessor.PostProcess(image.Frames.RootFrame); postProcessor.PostProcess(image.Frames.RootFrame);

2
src/ImageSharp/Formats/Png/PngChunk.cs

@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Memory; using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Png namespace SixLabors.ImageSharp.Formats.Png
{ {

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

@ -13,9 +13,9 @@ using System.Text;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats.Png.Filters; using SixLabors.ImageSharp.Formats.Png.Filters;
using SixLabors.ImageSharp.Formats.Png.Zlib; using SixLabors.ImageSharp.Formats.Png.Zlib;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Png namespace SixLabors.ImageSharp.Formats.Png
{ {
@ -188,7 +188,7 @@ namespace SixLabors.ImageSharp.Formats.Png
this.ignoreMetadata = options.IgnoreMetadata; this.ignoreMetadata = options.IgnoreMetadata;
} }
private MemoryManager MemoryManager => this.configuration.MemoryManager; private MemoryAllocator MemoryAllocator => this.configuration.MemoryAllocator;
/// <summary> /// <summary>
/// Decodes the stream to the image. /// Decodes the stream to the image.
@ -410,8 +410,8 @@ namespace SixLabors.ImageSharp.Formats.Png
this.bytesPerSample = this.header.BitDepth / 8; this.bytesPerSample = this.header.BitDepth / 8;
} }
this.previousScanline = this.MemoryManager.AllocateCleanManagedByteBuffer(this.bytesPerScanline); this.previousScanline = this.MemoryAllocator.AllocateCleanManagedByteBuffer(this.bytesPerScanline);
this.scanline = this.configuration.MemoryManager.AllocateCleanManagedByteBuffer(this.bytesPerScanline); this.scanline = this.configuration.MemoryAllocator.AllocateCleanManagedByteBuffer(this.bytesPerScanline);
} }
/// <summary> /// <summary>
@ -531,7 +531,7 @@ namespace SixLabors.ImageSharp.Formats.Png
} }
this.currentRowBytesRead = 0; this.currentRowBytesRead = 0;
Span<byte> scanlineSpan = this.scanline.Span; Span<byte> scanlineSpan = this.scanline.GetSpan();
var filterType = (FilterType)scanlineSpan[0]; var filterType = (FilterType)scanlineSpan[0];
switch (filterType) switch (filterType)
@ -546,17 +546,17 @@ namespace SixLabors.ImageSharp.Formats.Png
case FilterType.Up: case FilterType.Up:
UpFilter.Decode(scanlineSpan, this.previousScanline.Span); UpFilter.Decode(scanlineSpan, this.previousScanline.GetSpan());
break; break;
case FilterType.Average: case FilterType.Average:
AverageFilter.Decode(scanlineSpan, this.previousScanline.Span, this.bytesPerPixel); AverageFilter.Decode(scanlineSpan, this.previousScanline.GetSpan(), this.bytesPerPixel);
break; break;
case FilterType.Paeth: case FilterType.Paeth:
PaethFilter.Decode(scanlineSpan, this.previousScanline.Span, this.bytesPerPixel); PaethFilter.Decode(scanlineSpan, this.previousScanline.GetSpan(), this.bytesPerPixel);
break; break;
default: default:
@ -639,7 +639,7 @@ namespace SixLabors.ImageSharp.Formats.Png
} }
Span<TPixel> rowSpan = image.GetPixelRowSpan(this.currentRow); Span<TPixel> rowSpan = image.GetPixelRowSpan(this.currentRow);
this.ProcessInterlacedDefilteredScanline(this.scanline.Span, rowSpan, Adam7FirstColumn[this.pass], Adam7ColumnIncrement[this.pass]); this.ProcessInterlacedDefilteredScanline(this.scanline.GetSpan(), rowSpan, Adam7FirstColumn[this.pass], Adam7ColumnIncrement[this.pass]);
this.SwapBuffers(); this.SwapBuffers();
@ -727,11 +727,11 @@ namespace SixLabors.ImageSharp.Formats.Png
if (this.header.BitDepth == 16) if (this.header.BitDepth == 16)
{ {
int length = this.header.Width * 3; int length = this.header.Width * 3;
using (IBuffer<byte> compressed = this.configuration.MemoryManager.Allocate<byte>(length)) using (IBuffer<byte> compressed = this.configuration.MemoryAllocator.Allocate<byte>(length))
{ {
// TODO: Should we use pack from vector here instead? // TODO: Should we use pack from vector here instead?
this.From16BitTo8Bit(scanlineBuffer, compressed.Span, length); this.From16BitTo8Bit(scanlineBuffer, compressed.GetSpan(), length);
PixelOperations<TPixel>.Instance.PackFromRgb24Bytes(compressed.Span, rowSpan, this.header.Width); PixelOperations<TPixel>.Instance.PackFromRgb24Bytes(compressed.GetSpan(), rowSpan, this.header.Width);
} }
} }
else else
@ -744,12 +744,12 @@ namespace SixLabors.ImageSharp.Formats.Png
if (this.header.BitDepth == 16) if (this.header.BitDepth == 16)
{ {
int length = this.header.Width * 3; int length = this.header.Width * 3;
using (IBuffer<byte> compressed = this.configuration.MemoryManager.Allocate<byte>(length)) using (IBuffer<byte> compressed = this.configuration.MemoryAllocator.Allocate<byte>(length))
{ {
// TODO: Should we use pack from vector here instead? // TODO: Should we use pack from vector here instead?
this.From16BitTo8Bit(scanlineBuffer, compressed.Span, length); this.From16BitTo8Bit(scanlineBuffer, compressed.GetSpan(), length);
Span<Rgb24> rgb24Span = MemoryMarshal.Cast<byte, Rgb24>(compressed.Span); Span<Rgb24> rgb24Span = MemoryMarshal.Cast<byte, Rgb24>(compressed.GetSpan());
for (int x = 0; x < this.header.Width; x++) for (int x = 0; x < this.header.Width; x++)
{ {
ref Rgb24 rgb24 = ref rgb24Span[x]; ref Rgb24 rgb24 = ref rgb24Span[x];
@ -785,11 +785,11 @@ namespace SixLabors.ImageSharp.Formats.Png
if (this.header.BitDepth == 16) if (this.header.BitDepth == 16)
{ {
int length = this.header.Width * 4; int length = this.header.Width * 4;
using (IBuffer<byte> compressed = this.configuration.MemoryManager.Allocate<byte>(length)) using (IBuffer<byte> compressed = this.configuration.MemoryAllocator.Allocate<byte>(length))
{ {
// TODO: Should we use pack from vector here instead? // TODO: Should we use pack from vector here instead?
this.From16BitTo8Bit(scanlineBuffer, compressed.Span, length); this.From16BitTo8Bit(scanlineBuffer, compressed.GetSpan(), length);
PixelOperations<TPixel>.Instance.PackFromRgba32Bytes(compressed.Span, rowSpan, this.header.Width); PixelOperations<TPixel>.Instance.PackFromRgba32Bytes(compressed.GetSpan(), rowSpan, this.header.Width);
} }
} }
else else
@ -984,9 +984,9 @@ namespace SixLabors.ImageSharp.Formats.Png
if (this.header.BitDepth == 16) if (this.header.BitDepth == 16)
{ {
int length = this.header.Width * 3; int length = this.header.Width * 3;
using (IBuffer<byte> compressed = this.configuration.MemoryManager.Allocate<byte>(length)) using (IBuffer<byte> compressed = this.configuration.MemoryAllocator.Allocate<byte>(length))
{ {
Span<byte> compressedSpan = compressed.Span; Span<byte> compressedSpan = compressed.GetSpan();
// TODO: Should we use pack from vector here instead? // TODO: Should we use pack from vector here instead?
this.From16BitTo8Bit(scanlineBuffer, compressedSpan, length); this.From16BitTo8Bit(scanlineBuffer, compressedSpan, length);
@ -1054,9 +1054,9 @@ namespace SixLabors.ImageSharp.Formats.Png
if (this.header.BitDepth == 16) if (this.header.BitDepth == 16)
{ {
int length = this.header.Width * 4; int length = this.header.Width * 4;
using (IBuffer<byte> compressed = this.configuration.MemoryManager.Allocate<byte>(length)) using (IBuffer<byte> compressed = this.configuration.MemoryAllocator.Allocate<byte>(length))
{ {
Span<byte> compressedSpan = compressed.Span; Span<byte> compressedSpan = compressed.GetSpan();
// TODO: Should we use pack from vector here instead? // TODO: Should we use pack from vector here instead?
this.From16BitTo8Bit(scanlineBuffer, compressedSpan, length); this.From16BitTo8Bit(scanlineBuffer, compressedSpan, length);
@ -1229,7 +1229,7 @@ namespace SixLabors.ImageSharp.Formats.Png
{ {
this.crc.Reset(); this.crc.Reset();
this.crc.Update(this.chunkTypeBuffer); this.crc.Update(this.chunkTypeBuffer);
this.crc.Update(chunk.Data.Span); this.crc.Update(chunk.Data.GetSpan());
if (this.crc.Value != chunk.Crc) if (this.crc.Value != chunk.Crc)
{ {
@ -1273,7 +1273,7 @@ namespace SixLabors.ImageSharp.Formats.Png
private IManagedByteBuffer ReadChunkData(int length) private IManagedByteBuffer ReadChunkData(int length)
{ {
// We rent the buffer here to return it afterwards in Decode() // We rent the buffer here to return it afterwards in Decode()
IManagedByteBuffer buffer = this.configuration.MemoryManager.AllocateCleanManagedByteBuffer(length); IManagedByteBuffer buffer = this.configuration.MemoryAllocator.AllocateCleanManagedByteBuffer(length);
this.currentStream.Read(buffer.Array, 0, length); this.currentStream.Read(buffer.Array, 0, length);

2
src/ImageSharp/Formats/Png/PngEncoder.cs

@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Formats.Png
public void Encode<TPixel>(Image<TPixel> image, Stream stream) public void Encode<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
using (var encoder = new PngEncoderCore(image.GetMemoryManager(), this)) using (var encoder = new PngEncoderCore(image.GetMemoryAllocator(), this))
{ {
encoder.Encode(image, stream); encoder.Encode(image, stream);
} }

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

@ -8,9 +8,9 @@ using System.Linq;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats.Png.Filters; using SixLabors.ImageSharp.Formats.Png.Filters;
using SixLabors.ImageSharp.Formats.Png.Zlib; using SixLabors.ImageSharp.Formats.Png.Zlib;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Quantization; using SixLabors.ImageSharp.Processing.Quantization;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Png namespace SixLabors.ImageSharp.Formats.Png
{ {
@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Formats.Png
/// </summary> /// </summary>
internal sealed class PngEncoderCore : IDisposable internal sealed class PngEncoderCore : IDisposable
{ {
private readonly MemoryManager memoryManager; private readonly MemoryAllocator memoryAllocator;
/// <summary> /// <summary>
/// The maximum block size, defaults at 64k for uncompressed blocks. /// The maximum block size, defaults at 64k for uncompressed blocks.
@ -144,11 +144,11 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="PngEncoderCore"/> class. /// Initializes a new instance of the <see cref="PngEncoderCore"/> class.
/// </summary> /// </summary>
/// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations.</param> /// <param name="memoryAllocator">The <see cref="MemoryAllocator"/> to use for buffer allocations.</param>
/// <param name="options">The options for influencing the encoder</param> /// <param name="options">The options for influencing the encoder</param>
public PngEncoderCore(MemoryManager memoryManager, IPngEncoderOptions options) public PngEncoderCore(MemoryAllocator memoryAllocator, IPngEncoderOptions options)
{ {
this.memoryManager = memoryManager; this.memoryAllocator = memoryAllocator;
this.pngColorType = options.PngColorType; this.pngColorType = options.PngColorType;
this.pngFilterMethod = options.PngFilterMethod; this.pngFilterMethod = options.PngFilterMethod;
this.compressionLevel = options.CompressionLevel; this.compressionLevel = options.CompressionLevel;
@ -283,11 +283,11 @@ namespace SixLabors.ImageSharp.Formats.Png
{ {
if (this.bytesPerPixel == 4) if (this.bytesPerPixel == 4)
{ {
PixelOperations<TPixel>.Instance.ToRgba32Bytes(rowSpan, this.rawScanline.Span, this.width); PixelOperations<TPixel>.Instance.ToRgba32Bytes(rowSpan, this.rawScanline.GetSpan(), this.width);
} }
else else
{ {
PixelOperations<TPixel>.Instance.ToRgb24Bytes(rowSpan, this.rawScanline.Span, this.width); PixelOperations<TPixel>.Instance.ToRgb24Bytes(rowSpan, this.rawScanline.GetSpan(), this.width);
} }
} }
@ -320,23 +320,23 @@ namespace SixLabors.ImageSharp.Formats.Png
switch (this.pngFilterMethod) switch (this.pngFilterMethod)
{ {
case PngFilterMethod.None: case PngFilterMethod.None:
NoneFilter.Encode(this.rawScanline.Span, this.result.Span); NoneFilter.Encode(this.rawScanline.GetSpan(), this.result.GetSpan());
return this.result; return this.result;
case PngFilterMethod.Sub: case PngFilterMethod.Sub:
SubFilter.Encode(this.rawScanline.Span, this.sub.Span, this.bytesPerPixel, out int _); SubFilter.Encode(this.rawScanline.GetSpan(), this.sub.GetSpan(), this.bytesPerPixel, out int _);
return this.sub; return this.sub;
case PngFilterMethod.Up: case PngFilterMethod.Up:
UpFilter.Encode(this.rawScanline.Span, this.previousScanline.Span, this.up.Span, out int _); UpFilter.Encode(this.rawScanline.GetSpan(), this.previousScanline.GetSpan(), this.up.GetSpan(), out int _);
return this.up; return this.up;
case PngFilterMethod.Average: case PngFilterMethod.Average:
AverageFilter.Encode(this.rawScanline.Span, this.previousScanline.Span, this.average.Span, this.bytesPerPixel, out int _); AverageFilter.Encode(this.rawScanline.GetSpan(), this.previousScanline.GetSpan(), this.average.GetSpan(), this.bytesPerPixel, out int _);
return this.average; return this.average;
case PngFilterMethod.Paeth: case PngFilterMethod.Paeth:
PaethFilter.Encode(this.rawScanline.Span, this.previousScanline.Span, this.paeth.Span, this.bytesPerPixel, out int _); PaethFilter.Encode(this.rawScanline.GetSpan(), this.previousScanline.GetSpan(), this.paeth.GetSpan(), this.bytesPerPixel, out int _);
return this.paeth; return this.paeth;
default: default:
@ -354,21 +354,21 @@ namespace SixLabors.ImageSharp.Formats.Png
// Palette images don't compress well with adaptive filtering. // Palette images don't compress well with adaptive filtering.
if (this.pngColorType == PngColorType.Palette || this.bitDepth < 8) if (this.pngColorType == PngColorType.Palette || this.bitDepth < 8)
{ {
NoneFilter.Encode(this.rawScanline.Span, this.result.Span); NoneFilter.Encode(this.rawScanline.GetSpan(), this.result.GetSpan());
return this.result; return this.result;
} }
Span<byte> scanSpan = this.rawScanline.Span; Span<byte> scanSpan = this.rawScanline.GetSpan();
Span<byte> prevSpan = this.previousScanline.Span; Span<byte> prevSpan = this.previousScanline.GetSpan();
// This order, while different to the enumerated order is more likely to produce a smaller sum // This order, while different to the enumerated order is more likely to produce a smaller sum
// early on which shaves a couple of milliseconds off the processing time. // early on which shaves a couple of milliseconds off the processing time.
UpFilter.Encode(scanSpan, prevSpan, this.up.Span, out int currentSum); UpFilter.Encode(scanSpan, prevSpan, this.up.GetSpan(), out int currentSum);
int lowestSum = currentSum; int lowestSum = currentSum;
IManagedByteBuffer actualResult = this.up; IManagedByteBuffer actualResult = this.up;
PaethFilter.Encode(scanSpan, prevSpan, this.paeth.Span, this.bytesPerPixel, out currentSum); PaethFilter.Encode(scanSpan, prevSpan, this.paeth.GetSpan(), this.bytesPerPixel, out currentSum);
if (currentSum < lowestSum) if (currentSum < lowestSum)
{ {
@ -376,7 +376,7 @@ namespace SixLabors.ImageSharp.Formats.Png
actualResult = this.paeth; actualResult = this.paeth;
} }
SubFilter.Encode(scanSpan, this.sub.Span, this.bytesPerPixel, out currentSum); SubFilter.Encode(scanSpan, this.sub.GetSpan(), this.bytesPerPixel, out currentSum);
if (currentSum < lowestSum) if (currentSum < lowestSum)
{ {
@ -384,7 +384,7 @@ namespace SixLabors.ImageSharp.Formats.Png
actualResult = this.sub; actualResult = this.sub;
} }
AverageFilter.Encode(scanSpan, prevSpan, this.average.Span, this.bytesPerPixel, out currentSum); AverageFilter.Encode(scanSpan, prevSpan, this.average.GetSpan(), this.bytesPerPixel, out currentSum);
if (currentSum < lowestSum) if (currentSum < lowestSum)
{ {
@ -460,11 +460,11 @@ namespace SixLabors.ImageSharp.Formats.Png
Rgba32 rgba = default; Rgba32 rgba = default;
bool anyAlpha = false; bool anyAlpha = false;
using (IManagedByteBuffer colorTable = this.memoryManager.AllocateManagedByteBuffer(colorTableLength)) using (IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength))
using (IManagedByteBuffer alphaTable = this.memoryManager.AllocateManagedByteBuffer(pixelCount)) using (IManagedByteBuffer alphaTable = this.memoryAllocator.AllocateManagedByteBuffer(pixelCount))
{ {
Span<byte> colorTableSpan = colorTable.Span; Span<byte> colorTableSpan = colorTable.GetSpan();
Span<byte> alphaTableSpan = alphaTable.Span; Span<byte> alphaTableSpan = alphaTable.GetSpan();
for (byte i = 0; i < pixelCount; i++) for (byte i = 0; i < pixelCount; i++)
{ {
@ -552,16 +552,16 @@ namespace SixLabors.ImageSharp.Formats.Png
this.bytesPerScanline = this.width * this.bytesPerPixel; this.bytesPerScanline = this.width * this.bytesPerPixel;
int resultLength = this.bytesPerScanline + 1; int resultLength = this.bytesPerScanline + 1;
this.previousScanline = this.memoryManager.AllocateCleanManagedByteBuffer(this.bytesPerScanline); this.previousScanline = this.memoryAllocator.AllocateCleanManagedByteBuffer(this.bytesPerScanline);
this.rawScanline = this.memoryManager.AllocateCleanManagedByteBuffer(this.bytesPerScanline); this.rawScanline = this.memoryAllocator.AllocateCleanManagedByteBuffer(this.bytesPerScanline);
this.result = this.memoryManager.AllocateCleanManagedByteBuffer(resultLength); this.result = this.memoryAllocator.AllocateCleanManagedByteBuffer(resultLength);
if (this.pngColorType != PngColorType.Palette) if (this.pngColorType != PngColorType.Palette)
{ {
this.sub = this.memoryManager.AllocateCleanManagedByteBuffer(resultLength); this.sub = this.memoryAllocator.AllocateCleanManagedByteBuffer(resultLength);
this.up = this.memoryManager.AllocateCleanManagedByteBuffer(resultLength); this.up = this.memoryAllocator.AllocateCleanManagedByteBuffer(resultLength);
this.average = this.memoryManager.AllocateCleanManagedByteBuffer(resultLength); this.average = this.memoryAllocator.AllocateCleanManagedByteBuffer(resultLength);
this.paeth = this.memoryManager.AllocateCleanManagedByteBuffer(resultLength); this.paeth = this.memoryAllocator.AllocateCleanManagedByteBuffer(resultLength);
} }
byte[] buffer; byte[] buffer;

6
src/ImageSharp/Image.Decode.cs

@ -4,8 +4,8 @@
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp namespace SixLabors.ImageSharp
{ {
@ -29,12 +29,12 @@ namespace SixLabors.ImageSharp
return null; return null;
} }
using (IManagedByteBuffer buffer = config.MemoryManager.AllocateManagedByteBuffer(maxHeaderSize)) using (IManagedByteBuffer buffer = config.MemoryAllocator.AllocateManagedByteBuffer(maxHeaderSize))
{ {
long startPosition = stream.Position; long startPosition = stream.Position;
stream.Read(buffer.Array, 0, maxHeaderSize); stream.Read(buffer.Array, 0, maxHeaderSize);
stream.Position = startPosition; stream.Position = startPosition;
return config.ImageFormatsManager.FormatDetectors.Select(x => x.DetectFormat(buffer.Span)).LastOrDefault(x => x != null); return config.ImageFormatsManager.FormatDetectors.Select(x => x.DetectFormat(buffer.GetSpan())).LastOrDefault(x => x != null);
} }
} }

167
src/ImageSharp/Image.FromBytes.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System;
using System.IO; using System.IO;
using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
@ -15,7 +16,7 @@ namespace SixLabors.ImageSharp
/// <summary> /// <summary>
/// By reading the header on the provided byte array this calculates the images format. /// By reading the header on the provided byte array this calculates the images format.
/// </summary> /// </summary>
/// <param name="data">The byte array containing image data to read the header from.</param> /// <param name="data">The byte array containing encoded image data to read the header from.</param>
/// <returns>The format or null if none found.</returns> /// <returns>The format or null if none found.</returns>
public static IImageFormat DetectFormat(byte[] data) public static IImageFormat DetectFormat(byte[] data)
{ {
@ -26,7 +27,7 @@ namespace SixLabors.ImageSharp
/// By reading the header on the provided byte array this calculates the images format. /// By reading the header on the provided byte array this calculates the images format.
/// </summary> /// </summary>
/// <param name="config">The configuration.</param> /// <param name="config">The configuration.</param>
/// <param name="data">The byte array containing image data to read the header from.</param> /// <param name="data">The byte array containing encoded image data to read the header from.</param>
/// <returns>The mime type or null if none found.</returns> /// <returns>The mime type or null if none found.</returns>
public static IImageFormat DetectFormat(Configuration config, byte[] data) public static IImageFormat DetectFormat(Configuration config, byte[] data)
{ {
@ -37,30 +38,30 @@ namespace SixLabors.ImageSharp
} }
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given byte array. /// Load a new instance of <see cref="Image{Rgba32}"/> from the given encoded byte array.
/// </summary> /// </summary>
/// <param name="data">The byte array containing image data.</param> /// <param name="data">The byte array containing image data.</param>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns> /// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(byte[] data) => Load<Rgba32>(Configuration.Default, data); public static Image<Rgba32> Load(byte[] data) => Load<Rgba32>(Configuration.Default, data);
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given byte array. /// Load a new instance of <see cref="Image{Rgba32}"/> from the given encoded byte array.
/// </summary> /// </summary>
/// <param name="data">The byte array containing image data.</param> /// <param name="data">The byte array containing encoded image data.</param>
/// <param name="format">The mime type of the decoded image.</param> /// <param name="format">The mime type of the decoded image.</param>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns> /// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(byte[] data, out IImageFormat format) => Load<Rgba32>(Configuration.Default, data, out format); public static Image<Rgba32> Load(byte[] data, out IImageFormat format) => Load<Rgba32>(Configuration.Default, data, out format);
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given byte array. /// Load a new instance of <see cref="Image{Rgba32}"/> from the given encoded byte array.
/// </summary> /// </summary>
/// <param name="config">The config for the decoder.</param> /// <param name="config">The config for the decoder.</param>
/// <param name="data">The byte array containing image data.</param> /// <param name="data">The byte array containing encoded image data.</param>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns> /// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(Configuration config, byte[] data) => Load<Rgba32>(config, data); public static Image<Rgba32> Load(Configuration config, byte[] data) => Load<Rgba32>(config, data);
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given byte array. /// Load a new instance of <see cref="Image{Rgba32}"/> from the given encoded byte array.
/// </summary> /// </summary>
/// <param name="config">The config for the decoder.</param> /// <param name="config">The config for the decoder.</param>
/// <param name="data">The byte array containing image data.</param> /// <param name="data">The byte array containing image data.</param>
@ -69,15 +70,15 @@ namespace SixLabors.ImageSharp
public static Image<Rgba32> Load(Configuration config, byte[] data, out IImageFormat format) => Load<Rgba32>(config, data, out format); public static Image<Rgba32> Load(Configuration config, byte[] data, out IImageFormat format) => Load<Rgba32>(config, data, out format);
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given byte array. /// Load a new instance of <see cref="Image{Rgba32}"/> from the given encoded byte array.
/// </summary> /// </summary>
/// <param name="data">The byte array containing image data.</param> /// <param name="data">The byte array containing encoded image data.</param>
/// <param name="decoder">The decoder.</param> /// <param name="decoder">The decoder.</param>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns> /// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(byte[] data, IImageDecoder decoder) => Load<Rgba32>(data, decoder); public static Image<Rgba32> Load(byte[] data, IImageDecoder decoder) => Load<Rgba32>(data, decoder);
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given byte array. /// Load a new instance of <see cref="Image{Rgba32}"/> from the given encoded byte array.
/// </summary> /// </summary>
/// <param name="config">The config for the decoder.</param> /// <param name="config">The config for the decoder.</param>
/// <param name="data">The byte array containing image data.</param> /// <param name="data">The byte array containing image data.</param>
@ -86,9 +87,9 @@ namespace SixLabors.ImageSharp
public static Image<Rgba32> Load(Configuration config, byte[] data, IImageDecoder decoder) => Load<Rgba32>(config, data, decoder); public static Image<Rgba32> Load(Configuration config, byte[] data, IImageDecoder decoder) => Load<Rgba32>(config, data, decoder);
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given byte array. /// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte array.
/// </summary> /// </summary>
/// <param name="data">The byte array containing image data.</param> /// <param name="data">The byte array containing encoded image data.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns> /// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(byte[] data) public static Image<TPixel> Load<TPixel>(byte[] data)
@ -96,7 +97,7 @@ namespace SixLabors.ImageSharp
=> Load<TPixel>(Configuration.Default, data); => Load<TPixel>(Configuration.Default, data);
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given byte array. /// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte array.
/// </summary> /// </summary>
/// <param name="data">The byte array containing image data.</param> /// <param name="data">The byte array containing image data.</param>
/// <param name="format">The mime type of the decoded image.</param> /// <param name="format">The mime type of the decoded image.</param>
@ -107,10 +108,10 @@ namespace SixLabors.ImageSharp
=> Load<TPixel>(Configuration.Default, data, out format); => Load<TPixel>(Configuration.Default, data, out format);
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given byte array. /// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte array.
/// </summary> /// </summary>
/// <param name="config">The configuration options.</param> /// <param name="config">The configuration options.</param>
/// <param name="data">The byte array containing image data.</param> /// <param name="data">The byte array containing encoded image data.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns> /// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(Configuration config, byte[] data) public static Image<TPixel> Load<TPixel>(Configuration config, byte[] data)
@ -123,11 +124,11 @@ namespace SixLabors.ImageSharp
} }
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given byte array. /// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte array.
/// </summary> /// </summary>
/// <param name="config">The configuration options.</param> /// <param name="config">The configuration options.</param>
/// <param name="data">The byte array containing image data.</param> /// <param name="data">The byte array containing encoded image data.</param>
/// <param name="format">The mime type of the decoded image.</param> /// <param name="format">The <see cref="IImageFormat"/> of the decoded image.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns> /// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(Configuration config, byte[] data, out IImageFormat format) public static Image<TPixel> Load<TPixel>(Configuration config, byte[] data, out IImageFormat format)
@ -140,9 +141,9 @@ namespace SixLabors.ImageSharp
} }
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given byte array. /// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte array.
/// </summary> /// </summary>
/// <param name="data">The byte array containing image data.</param> /// <param name="data">The byte array containing encoded image data.</param>
/// <param name="decoder">The decoder.</param> /// <param name="decoder">The decoder.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns> /// <returns>A new <see cref="Image{TPixel}"/>.</returns>
@ -156,10 +157,10 @@ namespace SixLabors.ImageSharp
} }
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given byte array. /// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte array.
/// </summary> /// </summary>
/// <param name="config">The Configuration.</param> /// <param name="config">The Configuration.</param>
/// <param name="data">The byte array containing image data.</param> /// <param name="data">The byte array containing encoded image data.</param>
/// <param name="decoder">The decoder.</param> /// <param name="decoder">The decoder.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns> /// <returns>A new <see cref="Image{TPixel}"/>.</returns>
@ -171,5 +172,125 @@ namespace SixLabors.ImageSharp
return Load<TPixel>(config, memoryStream, decoder); return Load<TPixel>(config, memoryStream, decoder);
} }
} }
#if !NETSTANDARD1_1
/// <summary>
/// By reading the header on the provided byte array this calculates the images format.
/// </summary>
/// <param name="data">The byte array containing encoded image data to read the header from.</param>
/// <returns>The format or null if none found.</returns>
public static IImageFormat DetectFormat(ReadOnlySpan<byte> data)
{
return DetectFormat(Configuration.Default, data);
}
/// <summary>
/// By reading the header on the provided byte array this calculates the images format.
/// </summary>
/// <param name="config">The configuration.</param>
/// <param name="data">The byte array containing encoded image data to read the header from.</param>
/// <returns>The mime type or null if none found.</returns>
public static unsafe IImageFormat DetectFormat(Configuration config, ReadOnlySpan<byte> data)
{
fixed (byte* ptr = &data.GetPinnableReference())
{
using (var stream = new UnmanagedMemoryStream(ptr, data.Length))
{
return DetectFormat(config, stream);
}
}
}
/// <summary>
/// Load a new instance of <see cref="Image{Rgba32}"/> from the given encoded byte span.
/// </summary>
/// <param name="data">The byte span containing image data.</param>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(ReadOnlySpan<byte> data) => Load<Rgba32>(Configuration.Default, data);
/// <summary>
/// Load a new instance of <see cref="Image{Rgba32}"/> from the given encoded byte span.
/// </summary>
/// <param name="config">The config for the decoder.</param>
/// <param name="data">The byte span containing encoded image data.</param>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(Configuration config, ReadOnlySpan<byte> data) => Load<Rgba32>(config, data);
/// <summary>
/// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte span.
/// </summary>
/// <param name="data">The byte span containing encoded image data.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(ReadOnlySpan<byte> data)
where TPixel : struct, IPixel<TPixel>
=> Load<TPixel>(Configuration.Default, data);
/// <summary>
/// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte span.
/// </summary>
/// <param name="config">The configuration options.</param>
/// <param name="data">The byte span containing encoded image data.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static unsafe Image<TPixel> Load<TPixel>(Configuration config, ReadOnlySpan<byte> data)
where TPixel : struct, IPixel<TPixel>
{
fixed (byte* ptr = &data.GetPinnableReference())
{
using (var stream = new UnmanagedMemoryStream(ptr, data.Length))
{
return Load<TPixel>(config, stream);
}
}
}
/// <summary>
/// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte span.
/// </summary>
/// <param name="config">The Configuration.</param>
/// <param name="data">The byte span containing image data.</param>
/// <param name="decoder">The decoder.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static unsafe Image<TPixel> Load<TPixel>(
Configuration config,
ReadOnlySpan<byte> data,
IImageDecoder decoder)
where TPixel : struct, IPixel<TPixel>
{
fixed (byte* ptr = &data.GetPinnableReference())
{
using (var stream = new UnmanagedMemoryStream(ptr, data.Length))
{
return Load<TPixel>(config, stream, decoder);
}
}
}
/// <summary>
/// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte span.
/// </summary>
/// <param name="config">The configuration options.</param>
/// <param name="data">The byte span containing image data.</param>
/// <param name="format">The <see cref="IImageFormat"/> of the decoded image.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static unsafe Image<TPixel> Load<TPixel>(
Configuration config,
ReadOnlySpan<byte> data,
out IImageFormat format)
where TPixel : struct, IPixel<TPixel>
{
fixed (byte* ptr = &data.GetPinnableReference())
{
using (var stream = new UnmanagedMemoryStream(ptr, data.Length))
{
return Load<TPixel>(config, stream, out format);
}
}
}
#endif
} }
} }

59
src/ImageSharp/Image.WrapMemory.cs

@ -0,0 +1,59 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp
{
/// <content>
/// Adds static methods allowing wrapping an existing memory area as an image.
/// </content>
public static partial class Image
{
// TODO: This is a WIP API, should be public when finished.
/// <summary>
/// Wraps an existing contigous memory area of 'width'x'height' pixels,
/// allowing to view/manipulate it as an ImageSharp <see cref="Image{TPixel}"/> instance.
/// </summary>
/// <typeparam name="TPixel">The pixel type</typeparam>
/// <param name="config">The <see cref="Configuration"/></param>
/// <param name="pixelMemory">The pixel memory</param>
/// <param name="width">The width of the memory image</param>
/// <param name="height">The height of the memory image</param>
/// <param name="metaData">The <see cref="ImageMetaData"/></param>
/// <returns>An <see cref="Image{TPixel}"/> instance</returns>
internal static Image<TPixel> WrapMemory<TPixel>(
Configuration config,
Memory<TPixel> pixelMemory,
int width,
int height,
ImageMetaData metaData)
where TPixel : struct, IPixel<TPixel>
{
var buffer = new ConsumedBuffer<TPixel>(pixelMemory);
return new Image<TPixel>(config, buffer, width, height, metaData);
}
/// <summary>
/// Wraps an existing contigous memory area of 'width'x'height' pixels,
/// allowing to view/manipulate it as an ImageSharp <see cref="Image{TPixel}"/> instance.
/// </summary>
/// <typeparam name="TPixel">The pixel type</typeparam>
/// <param name="pixelMemory">The pixel memory</param>
/// <param name="width">The width of the memory image</param>
/// <param name="height">The height of the memory image</param>
/// <returns>An <see cref="Image{TPixel}"/> instance</returns>
internal static Image<TPixel> WrapMemory<TPixel>(
Memory<TPixel> pixelMemory,
int width,
int height)
where TPixel : struct, IPixel<TPixel>
{
return WrapMemory(Configuration.Default, pixelMemory, width, height, new ImageMetaData());
}
}
}

31
src/ImageSharp/ImageExtensions.Internal.cs

@ -0,0 +1,31 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp
{
/// <content>
/// Contains internal extensions for <see cref="Image{TPixel}"/>
/// </content>
public static partial class ImageExtensions
{
/// <summary>
/// Locks the image providing access to the pixels.
/// <remarks>
/// It is imperative that the accessor is correctly disposed off after use.
/// </remarks>
/// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="image">The image.</param>
/// <returns>
/// The <see cref="Buffer2D{TPixel}" />
/// </returns>
internal static Buffer2D<TPixel> GetRootFramePixelBuffer<TPixel>(this Image<TPixel> image)
where TPixel : struct, IPixel<TPixel>
{
return image.Frames.RootFrame.PixelBuffer;
}
}
}

11
src/ImageSharp/ImageFrameCollection.cs

@ -6,6 +6,7 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp namespace SixLabors.ImageSharp
{ {
@ -29,6 +30,16 @@ namespace SixLabors.ImageSharp
this.frames.Add(new ImageFrame<TPixel>(parent.GetConfiguration(), width, height, backgroundColor)); this.frames.Add(new ImageFrame<TPixel>(parent.GetConfiguration(), width, height, backgroundColor));
} }
internal ImageFrameCollection(Image<TPixel> parent, int width, int height, IBuffer<TPixel> consumedBuffer)
{
Guard.NotNull(parent, nameof(parent));
this.parent = parent;
// Frames are already cloned within the caller
this.frames.Add(new ImageFrame<TPixel>(parent.GetConfiguration(), width, height, consumedBuffer));
}
internal ImageFrameCollection(Image<TPixel> parent, IEnumerable<ImageFrame<TPixel>> frames) internal ImageFrameCollection(Image<TPixel> parent, IEnumerable<ImageFrame<TPixel>> frames)
{ {
Guard.NotNull(parent, nameof(parent)); Guard.NotNull(parent, nameof(parent));

91
src/ImageSharp/ImageFrame{TPixel}.cs

@ -6,9 +6,9 @@ using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp namespace SixLabors.ImageSharp
@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp
/// <param name="height">The height of the image in pixels.</param> /// <param name="height">The height of the image in pixels.</param>
/// <param name="metaData">The meta data.</param> /// <param name="metaData">The meta data.</param>
internal ImageFrame(Configuration configuration, int width, int height, ImageFrameMetaData metaData) internal ImageFrame(Configuration configuration, int width, int height, ImageFrameMetaData metaData)
: this(configuration, width, height, default, metaData) : this(configuration, width, height, default(TPixel), metaData)
{ {
} }
@ -85,12 +85,41 @@ namespace SixLabors.ImageSharp
Guard.NotNull(metaData, nameof(metaData)); Guard.NotNull(metaData, nameof(metaData));
this.configuration = configuration; this.configuration = configuration;
this.MemoryManager = configuration.MemoryManager; this.MemoryAllocator = configuration.MemoryAllocator;
this.PixelBuffer = this.MemoryManager.Allocate2D<TPixel>(width, height, false); this.PixelBuffer = this.MemoryAllocator.Allocate2D<TPixel>(width, height, false);
this.MetaData = metaData; this.MetaData = metaData;
this.Clear(configuration.ParallelOptions, backgroundColor); this.Clear(configuration.ParallelOptions, backgroundColor);
} }
/// <summary>
/// Initializes a new instance of the <see cref="ImageFrame{TPixel}" /> class wrapping an existing buffer.
/// </summary>
internal ImageFrame(Configuration configuration, int width, int height, IBuffer<TPixel> consumedBuffer)
: this(configuration, width, height, consumedBuffer, new ImageFrameMetaData())
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ImageFrame{TPixel}" /> class wrapping an existing buffer.
/// </summary>
internal ImageFrame(
Configuration configuration,
int width,
int height,
IBuffer<TPixel> consumedBuffer,
ImageFrameMetaData metaData)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.MustBeGreaterThan(width, 0, nameof(width));
Guard.MustBeGreaterThan(height, 0, nameof(height));
Guard.NotNull(metaData, nameof(metaData));
this.configuration = configuration;
this.MemoryAllocator = configuration.MemoryAllocator;
this.PixelBuffer = new Buffer2D<TPixel>(consumedBuffer, width, height);
this.MetaData = metaData;
}
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ImageFrame{TPixel}" /> class. /// Initializes a new instance of the <see cref="ImageFrame{TPixel}" /> class.
/// </summary> /// </summary>
@ -102,16 +131,16 @@ namespace SixLabors.ImageSharp
Guard.NotNull(source, nameof(source)); Guard.NotNull(source, nameof(source));
this.configuration = configuration; this.configuration = configuration;
this.MemoryManager = configuration.MemoryManager; this.MemoryAllocator = configuration.MemoryAllocator;
this.PixelBuffer = this.MemoryManager.Allocate2D<TPixel>(source.PixelBuffer.Width, source.PixelBuffer.Height); this.PixelBuffer = this.MemoryAllocator.Allocate2D<TPixel>(source.PixelBuffer.Width, source.PixelBuffer.Height);
source.PixelBuffer.Span.CopyTo(this.PixelBuffer.Span); source.PixelBuffer.GetSpan().CopyTo(this.PixelBuffer.GetSpan());
this.MetaData = source.MetaData.Clone(); this.MetaData = source.MetaData.Clone();
} }
/// <summary> /// <summary>
/// Gets the <see cref="MemoryManager" /> to use for buffer allocations. /// Gets the <see cref="MemoryAllocator" /> to use for buffer allocations.
/// </summary> /// </summary>
public MemoryManager MemoryManager { get; } public MemoryAllocator MemoryAllocator { get; }
/// <summary> /// <summary>
/// Gets the image pixels. Not private as Buffer2D requires an array in its constructor. /// Gets the image pixels. Not private as Buffer2D requires an array in its constructor.
@ -181,27 +210,6 @@ namespace SixLabors.ImageSharp
return ref this.PixelBuffer[x, y]; return ref this.PixelBuffer[x, y];
} }
/// <summary>
/// Locks the image providing access to the pixels.
/// <remarks>
/// It is imperative that the accessor is correctly disposed off after use.
/// </remarks>
/// </summary>
/// <returns>The <see cref="PixelAccessor{TPixel}"/></returns>
internal PixelAccessor<TPixel> Lock()
{
return new PixelAccessor<TPixel>(this);
}
/// <summary>
/// Copies the pixels to a <see cref="PixelAccessor{TPixel}"/> of the same size.
/// </summary>
/// <param name="target">The target pixel buffer accessor.</param>
internal void CopyTo(PixelAccessor<TPixel> target)
{
this.CopyTo(target.PixelBuffer);
}
/// <summary> /// <summary>
/// Copies the pixels to a <see cref="Buffer2D{TPixel}"/> of the same size. /// Copies the pixels to a <see cref="Buffer2D{TPixel}"/> of the same size.
/// </summary> /// </summary>
@ -213,33 +221,18 @@ namespace SixLabors.ImageSharp
throw new ArgumentException("ImageFrame<TPixel>.CopyTo(): target must be of the same size!", nameof(target)); throw new ArgumentException("ImageFrame<TPixel>.CopyTo(): target must be of the same size!", nameof(target));
} }
this.GetPixelSpan().CopyTo(target.Span); this.GetPixelSpan().CopyTo(target.GetSpan());
}
/// <summary>
/// Switches the buffers used by the image and the PixelAccessor meaning that the Image will "own" the buffer from the PixelAccessor and the PixelAccessor will now own the Images buffer.
/// </summary>
/// <param name="pixelSource">The pixel source.</param>
internal void SwapPixelsBuffers(PixelAccessor<TPixel> pixelSource)
{
Guard.NotNull(pixelSource, nameof(pixelSource));
// Push my memory into the accessor (which in turn unpins the old buffer ready for the images use)
Buffer2D<TPixel> newPixels = pixelSource.SwapBufferOwnership(this.PixelBuffer);
this.PixelBuffer = newPixels;
} }
/// <summary> /// <summary>
/// Switches the buffers used by the image and the pixelSource meaning that the Image will "own" the buffer from the pixelSource and the pixelSource will now own the Images buffer. /// Switches the buffers used by the image and the pixelSource meaning that the Image will "own" the buffer from the pixelSource and the pixelSource will now own the Images buffer.
/// </summary> /// </summary>
/// <param name="pixelSource">The pixel source.</param> /// <param name="pixelSource">The pixel source.</param>
internal void SwapPixelsBuffers(ImageFrame<TPixel> pixelSource) internal void SwapOrCopyPixelsBufferFrom(ImageFrame<TPixel> pixelSource)
{ {
Guard.NotNull(pixelSource, nameof(pixelSource)); Guard.NotNull(pixelSource, nameof(pixelSource));
Buffer2D<TPixel> temp = this.PixelBuffer; Buffer2D<TPixel>.SwapOrCopyContent(this.PixelBuffer, pixelSource.PixelBuffer);
this.PixelBuffer = pixelSource.PixelBuffer;
pixelSource.PixelBuffer = temp;
} }
/// <summary> /// <summary>
@ -289,7 +282,7 @@ namespace SixLabors.ImageSharp
{ {
Span<TPixel> sourceRow = this.GetPixelRowSpan(y); Span<TPixel> sourceRow = this.GetPixelRowSpan(y);
Span<TPixel2> targetRow = target.GetPixelRowSpan(y); Span<TPixel2> targetRow = target.GetPixelRowSpan(y);
Span<Vector4> tempRowSpan = tempRowBuffer.Span; Span<Vector4> tempRowSpan = tempRowBuffer.GetSpan();
PixelOperations<TPixel>.Instance.ToScaledVector4(sourceRow, tempRowSpan, sourceRow.Length); PixelOperations<TPixel>.Instance.ToScaledVector4(sourceRow, tempRowSpan, sourceRow.Length);
PixelOperations<TPixel2>.Instance.PackFromScaledVector4(tempRowSpan, targetRow, targetRow.Length); PixelOperations<TPixel2>.Instance.PackFromScaledVector4(tempRowSpan, targetRow, targetRow.Length);

15
src/ImageSharp/ImageSharp.csproj

@ -42,16 +42,19 @@
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.5.1" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' != 'netcoreapp2.1'"> <ItemGroup Condition=" '$(TargetFramework)' != 'netcoreapp2.1'">
<PackageReference Include="System.Buffers" Version="4.5.0" /> <PackageReference Include="System.Buffers" Version="4.5.0" />
<PackageReference Include="System.Memory" Version="4.5.0" /> <PackageReference Include="System.Memory" Version="4.5.1" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.5.0" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.1'">
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.4.0" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' ">
<PackageReference Include="System.IO.UnmanagedMemoryStream" Version="4.3.0" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.1' OR '$(TargetFramework)' == 'netstandard1.3'"> <ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.1' OR '$(TargetFramework)' == 'netstandard1.3'">
<PackageReference Include="System.IO.Compression" Version="4.3.0" /> <PackageReference Include="System.IO.Compression" Version="4.3.0" />
<PackageReference Include="System.Threading.Tasks.Parallel" Version="4.3.0" /> <PackageReference Include="System.Threading.Tasks.Parallel" Version="4.3.0" />

28
src/ImageSharp/Image{TPixel}.cs

@ -10,6 +10,7 @@ using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp namespace SixLabors.ImageSharp
{ {
@ -78,7 +79,28 @@ namespace SixLabors.ImageSharp
this.configuration = configuration ?? Configuration.Default; this.configuration = configuration ?? Configuration.Default;
this.PixelType = new PixelTypeInfo(Unsafe.SizeOf<TPixel>() * 8); this.PixelType = new PixelTypeInfo(Unsafe.SizeOf<TPixel>() * 8);
this.MetaData = metadata ?? new ImageMetaData(); this.MetaData = metadata ?? new ImageMetaData();
this.frames = new ImageFrameCollection<TPixel>(this, width, height, default); this.frames = new ImageFrameCollection<TPixel>(this, width, height, default(TPixel));
}
/// <summary>
/// Initializes a new instance of the <see cref="Image{TPixel}"/> class
/// consuming an external buffer instance.
/// </summary>
internal Image(Configuration configuration, IBuffer<TPixel> consumedBuffer, int width, int height)
: this(configuration, consumedBuffer, width, height, new ImageMetaData())
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Image{TPixel}"/> class
/// consuming an external buffer instance.
/// </summary>
internal Image(Configuration configuration, IBuffer<TPixel> consumedBuffer, int width, int height, ImageMetaData metadata)
{
this.configuration = configuration;
this.PixelType = new PixelTypeInfo(Unsafe.SizeOf<TPixel>() * 8);
this.MetaData = metadata;
this.frames = new ImageFrameCollection<TPixel>(this, width, height, consumedBuffer);
} }
/// <summary> /// <summary>
@ -211,13 +233,13 @@ namespace SixLabors.ImageSharp
/// Switches the buffers used by the image and the pixelSource meaning that the Image will "own" the buffer from the pixelSource and the pixelSource will now own the Images buffer. /// Switches the buffers used by the image and the pixelSource meaning that the Image will "own" the buffer from the pixelSource and the pixelSource will now own the Images buffer.
/// </summary> /// </summary>
/// <param name="pixelSource">The pixel source.</param> /// <param name="pixelSource">The pixel source.</param>
internal void SwapPixelsBuffers(Image<TPixel> pixelSource) internal void SwapOrCopyPixelsBuffersFrom(Image<TPixel> pixelSource)
{ {
Guard.NotNull(pixelSource, nameof(pixelSource)); Guard.NotNull(pixelSource, nameof(pixelSource));
for (int i = 0; i < this.frames.Count; i++) for (int i = 0; i < this.frames.Count; i++)
{ {
this.frames[i].SwapPixelsBuffers(pixelSource.frames[i]); this.frames[i].SwapOrCopyPixelsBufferFrom(pixelSource.frames[i]);
} }
} }
} }

24
src/ImageSharp/Memory/ArrayPoolMemoryManager.Buffer{T}.cs → src/ImageSharp/Memory/ArrayPoolMemoryAllocator.Buffer{T}.cs

@ -5,17 +5,18 @@ using System;
using System.Buffers; using System.Buffers;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Memory namespace SixLabors.Memory
{ {
/// <summary> /// <summary>
/// Contains <see cref="Buffer{T}"/> and <see cref="ManagedByteBuffer"/> /// Contains <see cref="Buffer{T}"/> and <see cref="ManagedByteBuffer"/>
/// </summary> /// </summary>
public partial class ArrayPoolMemoryManager public partial class ArrayPoolMemoryAllocator
{ {
/// <summary> /// <summary>
/// The buffer implementation of <see cref="ArrayPoolMemoryManager"/> /// The buffer implementation of <see cref="ArrayPoolMemoryAllocator"/>.
/// In this implementation <see cref="IBuffer{T}.Memory"/> is owned.
/// </summary> /// </summary>
private class Buffer<T> : IBuffer<T> private class Buffer<T> : ManagedBufferBase<T>
where T : struct where T : struct
{ {
/// <summary> /// <summary>
@ -28,7 +29,7 @@ namespace SixLabors.ImageSharp.Memory
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// By using a weak reference here, we are making sure that array pools and their retained arrays are always GC-ed /// By using a weak reference here, we are making sure that array pools and their retained arrays are always GC-ed
/// after a call to <see cref="ArrayPoolMemoryManager.ReleaseRetainedResources"/>, regardless of having buffer instances still being in use. /// after a call to <see cref="ArrayPoolMemoryAllocator.ReleaseRetainedResources"/>, regardless of having buffer instances still being in use.
/// </remarks> /// </remarks>
private WeakReference<ArrayPool<byte>> sourcePoolReference; private WeakReference<ArrayPool<byte>> sourcePoolReference;
@ -45,12 +46,9 @@ namespace SixLabors.ImageSharp.Memory
protected byte[] Data { get; private set; } protected byte[] Data { get; private set; }
/// <inheritdoc /> /// <inheritdoc />
public Span<T> Span => MemoryMarshal.Cast<byte, T>(this.Data.AsSpan()).Slice(0, this.length); protected override void Dispose(bool disposing)
/// <inheritdoc />
public void Dispose()
{ {
if (this.Data == null || this.sourcePoolReference == null) if (!disposing || this.Data == null || this.sourcePoolReference == null)
{ {
return; return;
} }
@ -63,10 +61,14 @@ namespace SixLabors.ImageSharp.Memory
this.sourcePoolReference = null; this.sourcePoolReference = null;
this.Data = null; this.Data = null;
} }
public override Span<T> GetSpan() => MemoryMarshal.Cast<byte, T>(this.Data.AsSpan()).Slice(0, this.length);
protected override object GetPinnableObject() => this.Data;
} }
/// <summary> /// <summary>
/// The <see cref="IManagedByteBuffer"/> implementation of <see cref="ArrayPoolMemoryManager"/>. /// The <see cref="IManagedByteBuffer"/> implementation of <see cref="ArrayPoolMemoryAllocator"/>.
/// </summary> /// </summary>
private class ManagedByteBuffer : Buffer<byte>, IManagedByteBuffer private class ManagedByteBuffer : Buffer<byte>, IManagedByteBuffer
{ {

20
src/ImageSharp/Memory/ArrayPoolMemoryManager.CommonFactoryMethods.cs → src/ImageSharp/Memory/ArrayPoolMemoryAllocator.CommonFactoryMethods.cs

@ -1,11 +1,11 @@
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Memory namespace SixLabors.Memory
{ {
/// <summary> /// <summary>
/// Contains common factory methods and configuration constants. /// Contains common factory methods and configuration constants.
/// </summary> /// </summary>
public partial class ArrayPoolMemoryManager public partial class ArrayPoolMemoryAllocator
{ {
/// <summary> /// <summary>
/// The default value for: maximum size of pooled arrays in bytes. /// The default value for: maximum size of pooled arrays in bytes.
@ -32,9 +32,9 @@ namespace SixLabors.ImageSharp.Memory
/// This is the default. Should be good for most use cases. /// This is the default. Should be good for most use cases.
/// </summary> /// </summary>
/// <returns>The memory manager</returns> /// <returns>The memory manager</returns>
public static ArrayPoolMemoryManager CreateDefault() public static ArrayPoolMemoryAllocator CreateDefault()
{ {
return new ArrayPoolMemoryManager( return new ArrayPoolMemoryAllocator(
DefaultMaxPooledBufferSizeInBytes, DefaultMaxPooledBufferSizeInBytes,
DefaultBufferSelectorThresholdInBytes, DefaultBufferSelectorThresholdInBytes,
DefaultLargePoolBucketCount, DefaultLargePoolBucketCount,
@ -45,27 +45,27 @@ namespace SixLabors.ImageSharp.Memory
/// For environments with limited memory capabilities. Only small images are pooled, which can result in reduced througput. /// For environments with limited memory capabilities. Only small images are pooled, which can result in reduced througput.
/// </summary> /// </summary>
/// <returns>The memory manager</returns> /// <returns>The memory manager</returns>
public static ArrayPoolMemoryManager CreateWithModeratePooling() public static ArrayPoolMemoryAllocator CreateWithModeratePooling()
{ {
return new ArrayPoolMemoryManager(1024 * 1024, 32 * 1024, 16, 24); return new ArrayPoolMemoryAllocator(1024 * 1024, 32 * 1024, 16, 24);
} }
/// <summary> /// <summary>
/// Only pool small buffers like image rows. /// Only pool small buffers like image rows.
/// </summary> /// </summary>
/// <returns>The memory manager</returns> /// <returns>The memory manager</returns>
public static ArrayPoolMemoryManager CreateWithMinimalPooling() public static ArrayPoolMemoryAllocator CreateWithMinimalPooling()
{ {
return new ArrayPoolMemoryManager(64 * 1024, 32 * 1024, 8, 24); return new ArrayPoolMemoryAllocator(64 * 1024, 32 * 1024, 8, 24);
} }
/// <summary> /// <summary>
/// RAM is not an issue for me, gimme maximum througput! /// RAM is not an issue for me, gimme maximum througput!
/// </summary> /// </summary>
/// <returns>The memory manager</returns> /// <returns>The memory manager</returns>
public static ArrayPoolMemoryManager CreateWithAggressivePooling() public static ArrayPoolMemoryAllocator CreateWithAggressivePooling()
{ {
return new ArrayPoolMemoryManager(128 * 1024 * 1024, 32 * 1024 * 1024, 16, 32); return new ArrayPoolMemoryAllocator(128 * 1024 * 1024, 32 * 1024 * 1024, 16, 32);
} }
} }
} }

24
src/ImageSharp/Memory/ArrayPoolMemoryManager.cs → src/ImageSharp/Memory/ArrayPoolMemoryAllocator.cs

@ -4,12 +4,12 @@
using System.Buffers; using System.Buffers;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Memory namespace SixLabors.Memory
{ {
/// <summary> /// <summary>
/// Implements <see cref="MemoryManager"/> by allocating memory from <see cref="ArrayPool{T}"/>. /// Implements <see cref="MemoryAllocator"/> by allocating memory from <see cref="ArrayPool{T}"/>.
/// </summary> /// </summary>
public partial class ArrayPoolMemoryManager : MemoryManager public partial class ArrayPoolMemoryAllocator : MemoryAllocator
{ {
/// <summary> /// <summary>
/// The <see cref="ArrayPool{T}"/> for small-to-medium buffers which is not kept clean. /// The <see cref="ArrayPool{T}"/> for small-to-medium buffers which is not kept clean.
@ -26,42 +26,42 @@ namespace SixLabors.ImageSharp.Memory
private readonly int maxArraysPerBucketLargePool; private readonly int maxArraysPerBucketLargePool;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ArrayPoolMemoryManager"/> class. /// Initializes a new instance of the <see cref="ArrayPoolMemoryAllocator"/> class.
/// </summary> /// </summary>
public ArrayPoolMemoryManager() public ArrayPoolMemoryAllocator()
: this(DefaultMaxPooledBufferSizeInBytes, DefaultBufferSelectorThresholdInBytes) : this(DefaultMaxPooledBufferSizeInBytes, DefaultBufferSelectorThresholdInBytes)
{ {
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ArrayPoolMemoryManager"/> class. /// Initializes a new instance of the <see cref="ArrayPoolMemoryAllocator"/> class.
/// </summary> /// </summary>
/// <param name="maxPoolSizeInBytes">The maximum size of pooled arrays. Arrays over the thershold are gonna be always allocated.</param> /// <param name="maxPoolSizeInBytes">The maximum size of pooled arrays. Arrays over the thershold are gonna be always allocated.</param>
public ArrayPoolMemoryManager(int maxPoolSizeInBytes) public ArrayPoolMemoryAllocator(int maxPoolSizeInBytes)
: this(maxPoolSizeInBytes, GetLargeBufferThresholdInBytes(maxPoolSizeInBytes)) : this(maxPoolSizeInBytes, GetLargeBufferThresholdInBytes(maxPoolSizeInBytes))
{ {
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ArrayPoolMemoryManager"/> class. /// Initializes a new instance of the <see cref="ArrayPoolMemoryAllocator"/> class.
/// </summary> /// </summary>
/// <param name="maxPoolSizeInBytes">The maximum size of pooled arrays. Arrays over the thershold are gonna be always allocated.</param> /// <param name="maxPoolSizeInBytes">The maximum size of pooled arrays. Arrays over the thershold are gonna be always allocated.</param>
/// <param name="poolSelectorThresholdInBytes">Arrays over this threshold will be pooled in <see cref="largeArrayPool"/> which has less buckets for memory safety.</param> /// <param name="poolSelectorThresholdInBytes">Arrays over this threshold will be pooled in <see cref="largeArrayPool"/> which has less buckets for memory safety.</param>
public ArrayPoolMemoryManager(int maxPoolSizeInBytes, int poolSelectorThresholdInBytes) public ArrayPoolMemoryAllocator(int maxPoolSizeInBytes, int poolSelectorThresholdInBytes)
: this(maxPoolSizeInBytes, poolSelectorThresholdInBytes, DefaultLargePoolBucketCount, DefaultNormalPoolBucketCount) : this(maxPoolSizeInBytes, poolSelectorThresholdInBytes, DefaultLargePoolBucketCount, DefaultNormalPoolBucketCount)
{ {
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ArrayPoolMemoryManager"/> class. /// Initializes a new instance of the <see cref="ArrayPoolMemoryAllocator"/> class.
/// </summary> /// </summary>
/// <param name="maxPoolSizeInBytes">The maximum size of pooled arrays. Arrays over the thershold are gonna be always allocated.</param> /// <param name="maxPoolSizeInBytes">The maximum size of pooled arrays. Arrays over the thershold are gonna be always allocated.</param>
/// <param name="poolSelectorThresholdInBytes">The threshold to pool arrays in <see cref="largeArrayPool"/> which has less buckets for memory safety.</param> /// <param name="poolSelectorThresholdInBytes">The threshold to pool arrays in <see cref="largeArrayPool"/> which has less buckets for memory safety.</param>
/// <param name="maxArraysPerBucketLargePool">Max arrays per bucket for the large array pool</param> /// <param name="maxArraysPerBucketLargePool">Max arrays per bucket for the large array pool</param>
/// <param name="maxArraysPerBucketNormalPool">Max arrays per bucket for the normal array pool</param> /// <param name="maxArraysPerBucketNormalPool">Max arrays per bucket for the normal array pool</param>
public ArrayPoolMemoryManager(int maxPoolSizeInBytes, int poolSelectorThresholdInBytes, int maxArraysPerBucketLargePool, int maxArraysPerBucketNormalPool) public ArrayPoolMemoryAllocator(int maxPoolSizeInBytes, int poolSelectorThresholdInBytes, int maxArraysPerBucketLargePool, int maxArraysPerBucketNormalPool)
{ {
Guard.MustBeGreaterThan(maxPoolSizeInBytes, 0, nameof(maxPoolSizeInBytes)); ImageSharp.Guard.MustBeGreaterThan(maxPoolSizeInBytes, 0, nameof(maxPoolSizeInBytes));
Guard.MustBeLessThanOrEqualTo(poolSelectorThresholdInBytes, maxPoolSizeInBytes, nameof(poolSelectorThresholdInBytes)); Guard.MustBeLessThanOrEqualTo(poolSelectorThresholdInBytes, maxPoolSizeInBytes, nameof(poolSelectorThresholdInBytes));
this.MaxPoolSizeInBytes = maxPoolSizeInBytes; this.MaxPoolSizeInBytes = maxPoolSizeInBytes;

24
src/ImageSharp/Memory/BasicArrayBuffer.cs

@ -1,17 +1,20 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Memory namespace SixLabors.Memory
{ {
/// <summary> /// <summary>
/// Exposes an array through the <see cref="IBuffer{T}"/> interface. /// Wraps an array as an <see cref="IBuffer{T}"/> instance. In this implementation <see cref="IBuffer{T}.Memory"/> is owned.
/// </summary> /// </summary>
internal class BasicArrayBuffer<T> : IBuffer<T> internal class BasicArrayBuffer<T> : ManagedBufferBase<T>
where T : struct where T : struct
{ {
public BasicArrayBuffer(T[] array, int length) public BasicArrayBuffer(T[] array, int length)
{ {
DebugGuard.MustBeLessThanOrEqualTo(length, array.Length, nameof(length)); ImageSharp.DebugGuard.MustBeLessThanOrEqualTo(length, array.Length, nameof(length));
this.Array = array; this.Array = array;
this.Length = length; this.Length = length;
} }
@ -25,8 +28,6 @@ namespace SixLabors.ImageSharp.Memory
public int Length { get; } public int Length { get; }
public Span<T> Span => this.Array.AsSpan(0, this.Length);
/// <summary> /// <summary>
/// Returns a reference to specified element of the buffer. /// Returns a reference to specified element of the buffer.
/// </summary> /// </summary>
@ -39,13 +40,20 @@ namespace SixLabors.ImageSharp.Memory
{ {
DebugGuard.MustBeLessThan(index, this.Length, nameof(index)); DebugGuard.MustBeLessThan(index, this.Length, nameof(index));
Span<T> span = this.Span; Span<T> span = this.GetSpan();
return ref span[index]; return ref span[index];
} }
} }
public void Dispose() protected override void Dispose(bool disposing)
{
}
public override Span<T> GetSpan() => this.Array.AsSpan(0, this.Length);
protected override object GetPinnableObject()
{ {
return this.Array;
} }
} }
} }

5
src/ImageSharp/Memory/BasicByteBuffer.cs

@ -1,4 +1,7 @@
namespace SixLabors.ImageSharp.Memory // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.Memory
{ {
internal class BasicByteBuffer : BasicArrayBuffer<byte>, IManagedByteBuffer internal class BasicByteBuffer : BasicArrayBuffer<byte>, IManagedByteBuffer
{ {

53
src/ImageSharp/Memory/Buffer2DExtensions.cs

@ -5,13 +5,22 @@ using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Memory namespace SixLabors.Memory
{ {
/// <summary> /// <summary>
/// Defines extension methods for <see cref="IBuffer2D{T}"/>. /// Defines extension methods for <see cref="Buffer2D{T}"/>.
/// </summary> /// </summary>
internal static class Buffer2DExtensions internal static class Buffer2DExtensions
{ {
/// <summary>
/// Gets a <see cref="Span{T}"/> to the backing buffer of <paramref name="buffer"/>.
/// </summary>
internal static Span<T> GetSpan<T>(this Buffer2D<T> buffer)
where T : struct
{
return buffer.Buffer.GetSpan();
}
/// <summary> /// <summary>
/// Gets a <see cref="Span{T}"/> to the row 'y' beginning from the pixel at 'x'. /// Gets a <see cref="Span{T}"/> to the row 'y' beginning from the pixel at 'x'.
/// </summary> /// </summary>
@ -21,10 +30,10 @@ namespace SixLabors.ImageSharp.Memory
/// <typeparam name="T">The element type</typeparam> /// <typeparam name="T">The element type</typeparam>
/// <returns>The <see cref="Span{T}"/></returns> /// <returns>The <see cref="Span{T}"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span<T> GetRowSpan<T>(this IBuffer2D<T> buffer, int x, int y) public static Span<T> GetRowSpan<T>(this Buffer2D<T> buffer, int x, int y)
where T : struct where T : struct
{ {
return buffer.Span.Slice((y * buffer.Width) + x, buffer.Width - x); return buffer.GetSpan().Slice((y * buffer.Width) + x, buffer.Width - x);
} }
/// <summary> /// <summary>
@ -35,19 +44,33 @@ namespace SixLabors.ImageSharp.Memory
/// <typeparam name="T">The element type</typeparam> /// <typeparam name="T">The element type</typeparam>
/// <returns>The <see cref="Span{T}"/></returns> /// <returns>The <see cref="Span{T}"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span<T> GetRowSpan<T>(this IBuffer2D<T> buffer, int y) public static Span<T> GetRowSpan<T>(this Buffer2D<T> buffer, int y)
where T : struct
{
return buffer.GetSpan().Slice(y * buffer.Width, buffer.Width);
}
/// <summary>
/// Gets a <see cref="Memory{T}"/> to the row 'y' beginning from the pixel at the first pixel on that row.
/// </summary>
/// <param name="buffer">The buffer</param>
/// <param name="y">The y (row) coordinate</param>
/// <typeparam name="T">The element type</typeparam>
/// <returns>The <see cref="Span{T}"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Memory<T> GetRowMemory<T>(this Buffer2D<T> buffer, int y)
where T : struct where T : struct
{ {
return buffer.Span.Slice(y * buffer.Width, buffer.Width); return buffer.Buffer.Memory.Slice(y * buffer.Width, buffer.Width);
} }
/// <summary> /// <summary>
/// Returns the size of the buffer. /// Returns the size of the buffer.
/// </summary> /// </summary>
/// <typeparam name="T">The element type</typeparam> /// <typeparam name="T">The element type</typeparam>
/// <param name="buffer">The <see cref="IBuffer2D{T}"/></param> /// <param name="buffer">The <see cref="Buffer2D{T}"/></param>
/// <returns>The <see cref="Size{T}"/> of the buffer</returns> /// <returns>The <see cref="Size{T}"/> of the buffer</returns>
public static Size Size<T>(this IBuffer2D<T> buffer) public static Size Size<T>(this Buffer2D<T> buffer)
where T : struct where T : struct
{ {
return new Size(buffer.Width, buffer.Height); return new Size(buffer.Width, buffer.Height);
@ -57,9 +80,9 @@ namespace SixLabors.ImageSharp.Memory
/// Returns a <see cref="Rectangle"/> representing the full area of the buffer. /// Returns a <see cref="Rectangle"/> representing the full area of the buffer.
/// </summary> /// </summary>
/// <typeparam name="T">The element type</typeparam> /// <typeparam name="T">The element type</typeparam>
/// <param name="buffer">The <see cref="IBuffer2D{T}"/></param> /// <param name="buffer">The <see cref="Buffer2D{T}"/></param>
/// <returns>The <see cref="Rectangle"/></returns> /// <returns>The <see cref="Rectangle"/></returns>
public static Rectangle FullRectangle<T>(this IBuffer2D<T> buffer) public static Rectangle FullRectangle<T>(this Buffer2D<T> buffer)
where T : struct where T : struct
{ {
return new Rectangle(0, 0, buffer.Width, buffer.Height); return new Rectangle(0, 0, buffer.Width, buffer.Height);
@ -69,13 +92,13 @@ namespace SixLabors.ImageSharp.Memory
/// Return a <see cref="BufferArea{T}"/> to the subarea represented by 'rectangle' /// Return a <see cref="BufferArea{T}"/> to the subarea represented by 'rectangle'
/// </summary> /// </summary>
/// <typeparam name="T">The element type</typeparam> /// <typeparam name="T">The element type</typeparam>
/// <param name="buffer">The <see cref="IBuffer2D{T}"/></param> /// <param name="buffer">The <see cref="Buffer2D{T}"/></param>
/// <param name="rectangle">The rectangle subarea</param> /// <param name="rectangle">The rectangle subarea</param>
/// <returns>The <see cref="BufferArea{T}"/></returns> /// <returns>The <see cref="BufferArea{T}"/></returns>
public static BufferArea<T> GetArea<T>(this IBuffer2D<T> buffer, Rectangle rectangle) public static BufferArea<T> GetArea<T>(this Buffer2D<T> buffer, Rectangle rectangle)
where T : struct => new BufferArea<T>(buffer, rectangle); where T : struct => new BufferArea<T>(buffer, rectangle);
public static BufferArea<T> GetArea<T>(this IBuffer2D<T> buffer, int x, int y, int width, int height) public static BufferArea<T> GetArea<T>(this Buffer2D<T> buffer, int x, int y, int width, int height)
where T : struct where T : struct
{ {
var rectangle = new Rectangle(x, y, width, height); var rectangle = new Rectangle(x, y, width, height);
@ -86,9 +109,9 @@ namespace SixLabors.ImageSharp.Memory
/// Return a <see cref="BufferArea{T}"/> to the whole area of 'buffer' /// Return a <see cref="BufferArea{T}"/> to the whole area of 'buffer'
/// </summary> /// </summary>
/// <typeparam name="T">The element type</typeparam> /// <typeparam name="T">The element type</typeparam>
/// <param name="buffer">The <see cref="IBuffer2D{T}"/></param> /// <param name="buffer">The <see cref="Buffer2D{T}"/></param>
/// <returns>The <see cref="BufferArea{T}"/></returns> /// <returns>The <see cref="BufferArea{T}"/></returns>
public static BufferArea<T> GetArea<T>(this IBuffer2D<T> buffer) public static BufferArea<T> GetArea<T>(this Buffer2D<T> buffer)
where T : struct => new BufferArea<T>(buffer); where T : struct => new BufferArea<T>(buffer);
} }
} }

48
src/ImageSharp/Memory/Buffer2D{T}.cs

@ -5,14 +5,14 @@ using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Memory namespace SixLabors.Memory
{ {
/// <summary> /// <summary>
/// Represents a buffer of value type objects /// Represents a buffer of value type objects
/// interpreted as a 2D region of <see cref="Width"/> x <see cref="Height"/> elements. /// interpreted as a 2D region of <see cref="Width"/> x <see cref="Height"/> elements.
/// </summary> /// </summary>
/// <typeparam name="T">The value type.</typeparam> /// <typeparam name="T">The value type.</typeparam>
internal class Buffer2D<T> : IBuffer2D<T>, IDisposable internal class Buffer2D<T> : IDisposable
where T : struct where T : struct
{ {
/// <summary> /// <summary>
@ -28,22 +28,25 @@ namespace SixLabors.ImageSharp.Memory
this.Height = height; this.Height = height;
} }
/// <inheritdoc /> /// <summary>
/// Gets the width.
/// </summary>
public int Width { get; private set; } public int Width { get; private set; }
/// <inheritdoc />
public int Height { get; private set; }
/// <summary> /// <summary>
/// Gets the span to the whole area. /// Gets the height.
/// </summary> /// </summary>
public Span<T> Span => this.Buffer.Span; public int Height { get; private set; }
/// <summary> /// <summary>
/// Gets the backing <see cref="IBuffer{T}"/> /// Gets the backing <see cref="IBuffer{T}"/>
/// </summary> /// </summary>
public IBuffer<T> Buffer { get; private set; } public IBuffer<T> Buffer { get; private set; }
public Memory<T> Memory => this.Buffer.Memory;
public Span<T> Span => this.Buffer.GetSpan();
/// <summary> /// <summary>
/// Gets a reference to the element at the specified position. /// Gets a reference to the element at the specified position.
/// </summary> /// </summary>
@ -55,9 +58,9 @@ namespace SixLabors.ImageSharp.Memory
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get get
{ {
DebugGuard.MustBeLessThan(x, this.Width, nameof(x)); ImageSharp.DebugGuard.MustBeLessThan(x, this.Width, nameof(x));
DebugGuard.MustBeLessThan(y, this.Height, nameof(y)); DebugGuard.MustBeLessThan(y, this.Height, nameof(y));
Span<T> span = this.Buffer.Span; Span<T> span = this.Buffer.GetSpan();
return ref span[(this.Width * y) + x]; return ref span[(this.Width * y) + x];
} }
} }
@ -70,13 +73,34 @@ namespace SixLabors.ImageSharp.Memory
this.Buffer?.Dispose(); this.Buffer?.Dispose();
} }
/// <summary>
/// Swaps the contents of 'destination' with 'source' if the buffers are owned (1),
/// copies the contents of 'source' to 'destination' otherwise (2). Buffers should be of same size in case 2!
/// </summary>
public static void SwapOrCopyContent(Buffer2D<T> destination, Buffer2D<T> source)
{
if (source.Buffer.IsMemoryOwner && destination.Buffer.IsMemoryOwner)
{
SwapContents(destination, source);
}
else
{
if (destination.Size() != source.Size())
{
throw new InvalidOperationException("SwapOrCopyContents(): buffers should both owned or the same size!");
}
source.Span.CopyTo(destination.Span);
}
}
/// <summary> /// <summary>
/// Swap the contents (<see cref="Buffer"/>, <see cref="Width"/>, <see cref="Height"/>) of the two buffers. /// Swap the contents (<see cref="Buffer"/>, <see cref="Width"/>, <see cref="Height"/>) of the two buffers.
/// Useful to transfer the contents of a temporary <see cref="Buffer2D{T}"/> to a persistent <see cref="ImageFrame{TPixel}.PixelBuffer"/> /// Useful to transfer the contents of a temporary <see cref="Buffer2D{T}"/> to a persistent <see cref="SixLabors.ImageSharp.ImageFrame{T}.PixelBuffer"/>
/// </summary> /// </summary>
/// <param name="a">The first buffer</param> /// <param name="a">The first buffer</param>
/// <param name="b">The second buffer</param> /// <param name="b">The second buffer</param>
public static void SwapContents(Buffer2D<T> a, Buffer2D<T> b) private static void SwapContents(Buffer2D<T> a, Buffer2D<T> b)
{ {
Size aSize = a.Size(); Size aSize = a.Size();
Size bSize = b.Size(); Size bSize = b.Size();

28
src/ImageSharp/Memory/BufferArea{T}.cs

@ -2,7 +2,7 @@ using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Memory namespace SixLabors.Memory
{ {
/// <summary> /// <summary>
/// Represents a rectangular area inside a 2D memory buffer (<see cref="Buffer2D{T}"/>). /// Represents a rectangular area inside a 2D memory buffer (<see cref="Buffer2D{T}"/>).
@ -18,27 +18,27 @@ namespace SixLabors.ImageSharp.Memory
public readonly Rectangle Rectangle; public readonly Rectangle Rectangle;
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferArea(IBuffer2D<T> destinationBuffer, Rectangle rectangle) public BufferArea(Buffer2D<T> destinationBuffer, Rectangle rectangle)
{ {
DebugGuard.MustBeGreaterThanOrEqualTo(rectangle.X, 0, nameof(rectangle)); ImageSharp.DebugGuard.MustBeGreaterThanOrEqualTo(rectangle.X, 0, nameof(rectangle));
DebugGuard.MustBeGreaterThanOrEqualTo(rectangle.Y, 0, nameof(rectangle)); ImageSharp.DebugGuard.MustBeGreaterThanOrEqualTo(rectangle.Y, 0, nameof(rectangle));
DebugGuard.MustBeLessThanOrEqualTo(rectangle.Width, destinationBuffer.Width, nameof(rectangle)); ImageSharp.DebugGuard.MustBeLessThanOrEqualTo(rectangle.Width, destinationBuffer.Width, nameof(rectangle));
DebugGuard.MustBeLessThanOrEqualTo(rectangle.Height, destinationBuffer.Height, nameof(rectangle)); ImageSharp.DebugGuard.MustBeLessThanOrEqualTo(rectangle.Height, destinationBuffer.Height, nameof(rectangle));
this.DestinationBuffer = destinationBuffer; this.DestinationBuffer = destinationBuffer;
this.Rectangle = rectangle; this.Rectangle = rectangle;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferArea(IBuffer2D<T> destinationBuffer) public BufferArea(Buffer2D<T> destinationBuffer)
: this(destinationBuffer, destinationBuffer.FullRectangle()) : this(destinationBuffer, destinationBuffer.FullRectangle())
{ {
} }
/// <summary> /// <summary>
/// Gets the <see cref="IBuffer2D{T}"/> being pointed by this instance. /// Gets the <see cref="Buffer2D{T}"/> being pointed by this instance.
/// </summary> /// </summary>
public IBuffer2D<T> DestinationBuffer { get; } public Buffer2D<T> DestinationBuffer { get; }
/// <summary> /// <summary>
/// Gets the size of the area. /// Gets the size of the area.
@ -71,7 +71,7 @@ namespace SixLabors.ImageSharp.Memory
/// <param name="x">The position inside a row</param> /// <param name="x">The position inside a row</param>
/// <param name="y">The row index</param> /// <param name="y">The row index</param>
/// <returns>The reference to the value</returns> /// <returns>The reference to the value</returns>
public ref T this[int x, int y] => ref this.DestinationBuffer.Span[this.GetIndexOf(x, y)]; public ref T this[int x, int y] => ref this.DestinationBuffer.GetSpan()[this.GetIndexOf(x, y)];
/// <summary> /// <summary>
/// Gets a reference to the [0,0] element. /// Gets a reference to the [0,0] element.
@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Memory
/// <returns>The reference to the [0,0] element</returns> /// <returns>The reference to the [0,0] element</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref T GetReferenceToOrigin() => public ref T GetReferenceToOrigin() =>
ref this.DestinationBuffer.Span[(this.Rectangle.Y * this.DestinationBuffer.Width) + this.Rectangle.X]; ref this.DestinationBuffer.GetSpan()[(this.Rectangle.Y * this.DestinationBuffer.Width) + this.Rectangle.X];
/// <summary> /// <summary>
/// Gets a span to row 'y' inside this area. /// Gets a span to row 'y' inside this area.
@ -93,7 +93,7 @@ namespace SixLabors.ImageSharp.Memory
int xx = this.Rectangle.X; int xx = this.Rectangle.X;
int width = this.Rectangle.Width; int width = this.Rectangle.Width;
return this.DestinationBuffer.Span.Slice(yy + xx, width); return this.DestinationBuffer.GetSpan().Slice(yy + xx, width);
} }
/// <summary> /// <summary>
@ -119,7 +119,7 @@ namespace SixLabors.ImageSharp.Memory
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferArea<T> GetSubArea(Rectangle rectangle) public BufferArea<T> GetSubArea(Rectangle rectangle)
{ {
DebugGuard.MustBeLessThanOrEqualTo(rectangle.Width, this.Rectangle.Width, nameof(rectangle)); ImageSharp.DebugGuard.MustBeLessThanOrEqualTo(rectangle.Width, this.Rectangle.Width, nameof(rectangle));
DebugGuard.MustBeLessThanOrEqualTo(rectangle.Height, this.Rectangle.Height, nameof(rectangle)); DebugGuard.MustBeLessThanOrEqualTo(rectangle.Height, this.Rectangle.Height, nameof(rectangle));
int x = this.Rectangle.X + rectangle.X; int x = this.Rectangle.X + rectangle.X;
@ -147,7 +147,7 @@ namespace SixLabors.ImageSharp.Memory
// Optimization for when the size of the area is the same as the buffer size. // Optimization for when the size of the area is the same as the buffer size.
if (this.IsFullBufferArea) if (this.IsFullBufferArea)
{ {
this.DestinationBuffer.Span.Clear(); this.DestinationBuffer.GetSpan().Clear();
return; return;
} }

14
src/ImageSharp/Memory/BufferExtensions.cs

@ -6,13 +6,13 @@ using System.IO;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Memory namespace SixLabors.Memory
{ {
internal static class BufferExtensions internal static class BufferExtensions
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Length<T>(this IBuffer<T> buffer) public static int Length<T>(this IBuffer<T> buffer)
where T : struct => buffer.Span.Length; where T : struct => buffer.GetSpan().Length;
/// <summary> /// <summary>
/// Gets a <see cref="Span{T}"/> to an offseted position inside the buffer. /// Gets a <see cref="Span{T}"/> to an offseted position inside the buffer.
@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Memory
public static Span<T> Slice<T>(this IBuffer<T> buffer, int start) public static Span<T> Slice<T>(this IBuffer<T> buffer, int start)
where T : struct where T : struct
{ {
return buffer.Span.Slice(start); return buffer.GetSpan().Slice(start);
} }
/// <summary> /// <summary>
@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.Memory
public static Span<T> Slice<T>(this IBuffer<T> buffer, int start, int length) public static Span<T> Slice<T>(this IBuffer<T> buffer, int start, int length)
where T : struct where T : struct
{ {
return buffer.Span.Slice(start, length); return buffer.GetSpan().Slice(start, length);
} }
/// <summary> /// <summary>
@ -49,12 +49,12 @@ namespace SixLabors.ImageSharp.Memory
public static void Clear<T>(this IBuffer<T> buffer) public static void Clear<T>(this IBuffer<T> buffer)
where T : struct where T : struct
{ {
buffer.Span.Clear(); buffer.GetSpan().Clear();
} }
public static ref T DangerousGetPinnableReference<T>(this IBuffer<T> buffer) public static ref T GetReference<T>(this IBuffer<T> buffer)
where T : struct => where T : struct =>
ref MemoryMarshal.GetReference(buffer.Span); ref MemoryMarshal.GetReference(buffer.GetSpan());
public static void Read(this Stream stream, IManagedByteBuffer buffer) public static void Read(this Stream stream, IManagedByteBuffer buffer)
{ {

34
src/ImageSharp/Memory/ConsumedBuffer.cs

@ -0,0 +1,34 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
namespace SixLabors.Memory
{
/// <summary>
/// A buffer implementation that consumes an existing <see cref="Memory{T}"/> instance.
/// The ownership of the memory remains external.
/// </summary>
/// <typeparam name="T">The value type</typeparam>
internal sealed class ConsumedBuffer<T> : IBuffer<T>
where T : struct
{
public ConsumedBuffer(Memory<T> memory)
{
this.Memory = memory;
}
public Memory<T> Memory { get; }
public bool IsMemoryOwner => false;
public Span<T> GetSpan()
{
return this.Memory.Span;
}
public void Dispose()
{
}
}
}

31
src/ImageSharp/Memory/IBuffer2D{T}.cs

@ -1,31 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
namespace SixLabors.ImageSharp.Memory
{
/// <summary>
/// An interface that represents a pinned buffer of value type objects
/// interpreted as a 2D region of <see cref="Width"/> x <see cref="Height"/> elements.
/// </summary>
/// <typeparam name="T">The value type.</typeparam>
internal interface IBuffer2D<T>
where T : struct
{
/// <summary>
/// Gets the width.
/// </summary>
int Width { get; }
/// <summary>
/// Gets the height.
/// </summary>
int Height { get; }
/// <summary>
/// Gets a <see cref="Span{T}"/> to the backing buffer.
/// </summary>
Span<T> Span { get; }
}
}

27
src/ImageSharp/Memory/IBuffer{T}.cs

@ -2,20 +2,37 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Buffers;
namespace SixLabors.ImageSharp.Memory namespace SixLabors.Memory
{ {
/// <inheritdoc />
/// <summary> /// <summary>
/// Represents a contigous memory buffer of value-type items "promising" a <see cref="Span{T}"/> /// Represents a contigous memory buffer of value-type items.
/// Depending on it's implementation, an <see cref="IBuffer{T}"/> can (1) OWN or (2) CONSUME the <see cref="Memory{T}"/> instance it wraps.
/// For a deeper understanding of the owner/consumer model, read the following docs: <br/>
/// https://gist.github.com/GrabYourPitchforks/4c3e1935fd4d9fa2831dbfcab35dffc6
/// TODO: We need more SOC here! For owned buffers we should use <see cref="IMemoryOwner{T}"/>.
/// For the consumption case we should not use buffers at all. We need to refactor Buffer2D{T} for this.
/// </summary> /// </summary>
/// <typeparam name="T">The value type</typeparam> /// <typeparam name="T">The value type</typeparam>
internal interface IBuffer<T> : IDisposable internal interface IBuffer<T> : IDisposable
where T : struct where T : struct
{ {
/// <summary> /// <summary>
/// Gets the span to the memory "promised" by this buffer /// Gets the <see cref="Memory{T}"/> ownerd/consumed by this buffer.
/// </summary> /// </summary>
Span<T> Span { get; } Memory<T> Memory { get; }
/// <summary>
/// Gets a value indicating whether this instance is owning the <see cref="Memory"/>.
/// </summary>
bool IsMemoryOwner { get; }
/// <summary>
/// Gets the span to the memory "promised" by this buffer when it's OWNED (1).
/// Gets `this.Memory.Span` when the buffer CONSUMED (2).
/// </summary>
/// <returns>The <see cref="Span{T}"/></returns>
Span<T> GetSpan();
} }
} }

2
src/ImageSharp/Memory/IManagedByteBuffer.cs

@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Memory namespace SixLabors.Memory
{ {
/// <summary> /// <summary>
/// Represents a byte buffer backed by a managed array. Useful for interop with classic .NET API-s. /// Represents a byte buffer backed by a managed array. Useful for interop with classic .NET API-s.

43
src/ImageSharp/Memory/ManagedBufferBase.cs

@ -0,0 +1,43 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Buffers;
using System.Runtime.InteropServices;
namespace SixLabors.Memory
{
/// <summary>
/// Provides a base class for <see cref="IBuffer{T}"/> implementations by implementing pinning logic for <see cref="MemoryManager{T}"/> adaption.
/// </summary>
internal abstract class ManagedBufferBase<T> : System.Buffers.MemoryManager<T>, IBuffer<T>
where T : struct
{
private GCHandle pinHandle;
public bool IsMemoryOwner => true;
/// <summary>
/// Gets the object that should be pinned.
/// </summary>
protected abstract object GetPinnableObject();
public override unsafe MemoryHandle Pin(int elementIndex = 0)
{
if (!this.pinHandle.IsAllocated)
{
this.pinHandle = GCHandle.Alloc(this.GetPinnableObject(), GCHandleType.Pinned);
}
void* ptr = (void*)this.pinHandle.AddrOfPinnedObject();
return new MemoryHandle(ptr, this.pinHandle);
}
public override void Unpin()
{
if (this.pinHandle.IsAllocated)
{
this.pinHandle.Free();
}
}
}
}

14
src/ImageSharp/Memory/MemoryManager.cs → src/ImageSharp/Memory/MemoryAllocator.cs

@ -1,12 +1,12 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Memory namespace SixLabors.Memory
{ {
/// <summary> /// <summary>
/// Memory managers are used to allocate memory for image processing operations. /// Memory managers are used to allocate memory for image processing operations.
/// </summary> /// </summary>
public abstract class MemoryManager public abstract class MemoryAllocator
{ {
/// <summary> /// <summary>
/// Allocates an <see cref="IBuffer{T}"/> of size <paramref name="length"/>, optionally /// Allocates an <see cref="IBuffer{T}"/> of size <paramref name="length"/>, optionally
@ -27,16 +27,6 @@ namespace SixLabors.ImageSharp.Memory
/// <returns>The <see cref="IManagedByteBuffer"/></returns> /// <returns>The <see cref="IManagedByteBuffer"/></returns>
internal abstract IManagedByteBuffer AllocateManagedByteBuffer(int length, bool clear); internal abstract IManagedByteBuffer AllocateManagedByteBuffer(int length, bool clear);
/// <summary>
/// Temporal workaround. A method providing a "Buffer" based on a generic array without the 'Unsafe.As()' hackery.
/// Should be replaced with 'Allocate()' as soon as SixLabors.Shapes has Span-based API-s!
/// </summary>
internal BasicArrayBuffer<T> AllocateFake<T>(int length, bool dummy = false)
where T : struct
{
return new BasicArrayBuffer<T>(new T[length]);
}
/// <summary> /// <summary>
/// Releases all retained resources not being in use. /// Releases all retained resources not being in use.
/// Eg: by resetting array pools and letting GC to free the arrays. /// Eg: by resetting array pools and letting GC to free the arrays.

46
src/ImageSharp/Memory/MemoryManagerExtensions.cs → src/ImageSharp/Memory/MemoryAllocatorExtensions.cs

@ -1,11 +1,11 @@
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Memory namespace SixLabors.Memory
{ {
/// <summary> /// <summary>
/// Extension methods for <see cref="MemoryManager"/>. /// Extension methods for <see cref="MemoryAllocator"/>.
/// </summary> /// </summary>
internal static class MemoryManagerExtensions internal static class MemoryAllocatorExtensions
{ {
/// <summary> /// <summary>
/// Allocates a <see cref="IBuffer{T}"/> of size <paramref name="length"/>. /// Allocates a <see cref="IBuffer{T}"/> of size <paramref name="length"/>.
@ -13,67 +13,67 @@ namespace SixLabors.ImageSharp.Memory
/// returning, so it may contain data from an earlier use. /// returning, so it may contain data from an earlier use.
/// </summary> /// </summary>
/// <typeparam name="T">Type of the data stored in the buffer</typeparam> /// <typeparam name="T">Type of the data stored in the buffer</typeparam>
/// <param name="memoryManager">The <see cref="MemoryManager"/></param> /// <param name="memoryAllocator">The <see cref="MemoryAllocator"/></param>
/// <param name="length">Size of the buffer to allocate</param> /// <param name="length">Size of the buffer to allocate</param>
/// <returns>A buffer of values of type <typeparamref name="T"/>.</returns> /// <returns>A buffer of values of type <typeparamref name="T"/>.</returns>
public static IBuffer<T> Allocate<T>(this MemoryManager memoryManager, int length) public static IBuffer<T> Allocate<T>(this MemoryAllocator memoryAllocator, int length)
where T : struct where T : struct
{ {
return memoryManager.Allocate<T>(length, false); return memoryAllocator.Allocate<T>(length, false);
} }
public static IBuffer<T> AllocateClean<T>(this MemoryManager memoryManager, int length) public static IBuffer<T> AllocateClean<T>(this MemoryAllocator memoryAllocator, int length)
where T : struct where T : struct
{ {
return memoryManager.Allocate<T>(length, true); return memoryAllocator.Allocate<T>(length, true);
} }
public static IManagedByteBuffer AllocateManagedByteBuffer(this MemoryManager memoryManager, int length) public static IManagedByteBuffer AllocateManagedByteBuffer(this MemoryAllocator memoryAllocator, int length)
{ {
return memoryManager.AllocateManagedByteBuffer(length, false); return memoryAllocator.AllocateManagedByteBuffer(length, false);
} }
public static IManagedByteBuffer AllocateCleanManagedByteBuffer(this MemoryManager memoryManager, int length) public static IManagedByteBuffer AllocateCleanManagedByteBuffer(this MemoryAllocator memoryAllocator, int length)
{ {
return memoryManager.AllocateManagedByteBuffer(length, true); return memoryAllocator.AllocateManagedByteBuffer(length, true);
} }
public static Buffer2D<T> Allocate2D<T>(this MemoryManager memoryManager, int width, int height, bool clear) public static Buffer2D<T> Allocate2D<T>(this MemoryAllocator memoryAllocator, int width, int height, bool clear)
where T : struct where T : struct
{ {
IBuffer<T> buffer = memoryManager.Allocate<T>(width * height, clear); IBuffer<T> buffer = memoryAllocator.Allocate<T>(width * height, clear);
return new Buffer2D<T>(buffer, width, height); return new Buffer2D<T>(buffer, width, height);
} }
public static Buffer2D<T> Allocate2D<T>(this MemoryManager memoryManager, Size size) public static Buffer2D<T> Allocate2D<T>(this MemoryAllocator memoryAllocator, Size size)
where T : struct => where T : struct =>
Allocate2D<T>(memoryManager, size.Width, size.Height, false); Allocate2D<T>(memoryAllocator, size.Width, size.Height, false);
public static Buffer2D<T> Allocate2D<T>(this MemoryManager memoryManager, int width, int height) public static Buffer2D<T> Allocate2D<T>(this MemoryAllocator memoryAllocator, int width, int height)
where T : struct => where T : struct =>
Allocate2D<T>(memoryManager, width, height, false); Allocate2D<T>(memoryAllocator, width, height, false);
public static Buffer2D<T> AllocateClean2D<T>(this MemoryManager memoryManager, int width, int height) public static Buffer2D<T> AllocateClean2D<T>(this MemoryAllocator memoryAllocator, int width, int height)
where T : struct => where T : struct =>
Allocate2D<T>(memoryManager, width, height, true); Allocate2D<T>(memoryAllocator, width, height, true);
/// <summary> /// <summary>
/// Allocates padded buffers for BMP encoder/decoder. (Replacing old PixelRow/PixelArea) /// Allocates padded buffers for BMP encoder/decoder. (Replacing old PixelRow/PixelArea)
/// </summary> /// </summary>
/// <param name="memoryManager">The <see cref="MemoryManager"/></param> /// <param name="memoryAllocator">The <see cref="MemoryAllocator"/></param>
/// <param name="width">Pixel count in the row</param> /// <param name="width">Pixel count in the row</param>
/// <param name="pixelSizeInBytes">The pixel size in bytes, eg. 3 for RGB</param> /// <param name="pixelSizeInBytes">The pixel size in bytes, eg. 3 for RGB</param>
/// <param name="paddingInBytes">The padding</param> /// <param name="paddingInBytes">The padding</param>
/// <returns>A <see cref="IManagedByteBuffer"/></returns> /// <returns>A <see cref="IManagedByteBuffer"/></returns>
public static IManagedByteBuffer AllocatePaddedPixelRowBuffer( public static IManagedByteBuffer AllocatePaddedPixelRowBuffer(
this MemoryManager memoryManager, this MemoryAllocator memoryAllocator,
int width, int width,
int pixelSizeInBytes, int pixelSizeInBytes,
int paddingInBytes) int paddingInBytes)
{ {
int length = (width * pixelSizeInBytes) + paddingInBytes; int length = (width * pixelSizeInBytes) + paddingInBytes;
return memoryManager.AllocateManagedByteBuffer(length); return memoryAllocator.AllocateManagedByteBuffer(length);
} }
} }
} }

6
src/ImageSharp/Memory/SimpleGcMemoryManager.cs → src/ImageSharp/Memory/SimpleGcMemoryAllocator.cs

@ -1,9 +1,9 @@
namespace SixLabors.ImageSharp.Memory namespace SixLabors.Memory
{ {
/// <summary> /// <summary>
/// Implements <see cref="MemoryManager"/> by newing up arrays by the GC on every allocation requests. /// Implements <see cref="MemoryAllocator"/> by newing up arrays by the GC on every allocation requests.
/// </summary> /// </summary>
public class SimpleGcMemoryManager : MemoryManager public class SimpleGcMemoryAllocator : MemoryAllocator
{ {
/// <inheritdoc /> /// <inheritdoc />
internal override IBuffer<T> Allocate<T>(int length, bool clear) internal override IBuffer<T> Allocate<T>(int length, bool clear)

48
src/ImageSharp/PixelAccessorExtensions.cs

@ -1,48 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp
{
/// <summary>
/// Helper methods fro acccess pixel accessors
/// </summary>
internal static class PixelAccessorExtensions
{
/// <summary>
/// Locks the image providing access to the pixels.
/// <remarks>
/// It is imperative that the accessor is correctly disposed off after use.
/// </remarks>
/// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="frame">The frame.</param>
/// <returns>
/// The <see cref="PixelAccessor{TPixel}" />
/// </returns>
internal static PixelAccessor<TPixel> Lock<TPixel>(this IPixelSource<TPixel> frame)
where TPixel : struct, IPixel<TPixel>
{
return new PixelAccessor<TPixel>(frame);
}
/// <summary>
/// Locks the image providing access to the pixels.
/// <remarks>
/// It is imperative that the accessor is correctly disposed off after use.
/// </remarks>
/// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="image">The image.</param>
/// <returns>
/// The <see cref="PixelAccessor{TPixel}" />
/// </returns>
internal static PixelAccessor<TPixel> Lock<TPixel>(this Image<TPixel> image)
where TPixel : struct, IPixel<TPixel>
{
return image.Frames.RootFrame.Lock();
}
}
}

154
src/ImageSharp/PixelAccessor{TPixel}.cs

@ -1,154 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp
{
/// <summary>
/// Provides per-pixel access to generic <see cref="Image{TPixel}"/> pixels.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal sealed class PixelAccessor<TPixel> : IDisposable, IBuffer2D<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Initializes a new instance of the <see cref="PixelAccessor{TPixel}"/> class.
/// </summary>
/// <param name="image">The image to provide pixel access for.</param>
public PixelAccessor(IPixelSource<TPixel> image)
{
Guard.NotNull(image, nameof(image));
Guard.MustBeGreaterThan(image.PixelBuffer.Width, 0, "image width");
Guard.MustBeGreaterThan(image.PixelBuffer.Height, 0, "image height");
this.SetPixelBufferUnsafe(image.PixelBuffer);
}
/// <summary>
/// Gets the <see cref="Buffer2D{T}"/> containing the pixel data.
/// </summary>
internal Buffer2D<TPixel> PixelBuffer { get; private set; }
/// <summary>
/// Gets the size of a single pixel in the number of bytes.
/// </summary>
public int PixelSize { get; private set; }
/// <summary>
/// Gets the width of one row in the number of bytes.
/// </summary>
public int RowStride { get; private set; }
/// <inheritdoc />
public int Width { get; private set; }
/// <inheritdoc />
public int Height { get; private set; }
/// <inheritdoc />
public Span<TPixel> Span => this.PixelBuffer.Span;
private static PixelOperations<TPixel> Operations => PixelOperations<TPixel>.Instance;
/// <summary>
/// Gets or sets the pixel at the specified position.
/// </summary>
/// <param name="x">The x-coordinate of the pixel. Must be greater than or equal to zero and less than the width of the image.</param>
/// <param name="y">The y-coordinate of the pixel. Must be greater than or equal to zero and less than the height of the image.</param>
/// <returns>The <see typeparam="TPixel"/> at the specified position.</returns>
public TPixel this[int x, int y]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
this.CheckCoordinates(x, y);
return this.Span[(y * this.Width) + x];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
this.CheckCoordinates(x, y);
Span<TPixel> span = this.Span;
span[(y * this.Width) + x] = value;
}
}
/// <inheritdoc />
public void Dispose()
{
}
/// <summary>
/// Resets all the pixels to it's initial value.
/// </summary>
public void Reset()
{
this.PixelBuffer.Buffer.Clear();
}
/// <summary>
/// Sets the pixel buffer in an unsafe manner. This should not be used unless you know what its doing!!!
/// </summary>
/// <param name="pixels">The pixels.</param>
/// <returns>Returns the old pixel data thats has gust been replaced.</returns>
/// <remarks>If <see cref="M:PixelAccessor.PooledMemory"/> is true then caller is responsible for ensuring <see cref="M:PixelDataPool.Return()"/> is called.</remarks>
internal Buffer2D<TPixel> SwapBufferOwnership(Buffer2D<TPixel> pixels)
{
Buffer2D<TPixel> oldPixels = this.PixelBuffer;
this.SetPixelBufferUnsafe(pixels);
return oldPixels;
}
/// <summary>
/// Copies the pixels to another <see cref="PixelAccessor{TPixel}"/> of the same size.
/// </summary>
/// <param name="target">The target pixel buffer accessor.</param>
internal void CopyTo(PixelAccessor<TPixel> target)
{
this.PixelBuffer.Span.CopyTo(target.PixelBuffer.Span);
}
/// <summary>
/// Sets the pixel buffer in an unsafe manor this should not be used unless you know what its doing!!!
/// </summary>
/// <param name="pixels">The pixel buffer</param>
private void SetPixelBufferUnsafe(Buffer2D<TPixel> pixels)
{
this.PixelBuffer = pixels;
this.Width = pixels.Width;
this.Height = pixels.Height;
this.PixelSize = Unsafe.SizeOf<TPixel>();
this.RowStride = this.Width * this.PixelSize;
}
/// <summary>
/// Checks the coordinates to ensure they are within bounds.
/// </summary>
/// <param name="x">The x-coordinate of the pixel. Must be greater than zero and less than the width of the image.</param>
/// <param name="y">The y-coordinate of the pixel. Must be greater than zero and less than the height of the image.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown if the coordinates are not within the bounds of the image.
/// </exception>
[Conditional("DEBUG")]
private void CheckCoordinates(int x, int y)
{
if (x < 0 || x >= this.Width)
{
throw new ArgumentOutOfRangeException(nameof(x), x, $"{x} is outwith the image bounds.");
}
if (y < 0 || y >= this.Height)
{
throw new ArgumentOutOfRangeException(nameof(y), y, $"{y} is outwith the image bounds.");
}
}
}
}

44
src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs

@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
{ {
using System; using System;
using System.Numerics; using System.Numerics;
using SixLabors.ImageSharp.Memory; using SixLabors.Memory;
/// <summary> /// <summary>
@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
} }
/// <inheritdoc /> /// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{ {
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
} }
/// <inheritdoc /> /// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{ {
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -116,7 +116,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
} }
/// <inheritdoc /> /// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{ {
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -155,7 +155,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
} }
/// <inheritdoc /> /// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{ {
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -194,7 +194,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
} }
/// <inheritdoc /> /// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{ {
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -233,7 +233,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
} }
/// <inheritdoc /> /// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{ {
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -272,7 +272,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
} }
/// <inheritdoc /> /// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{ {
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -311,7 +311,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
} }
/// <inheritdoc /> /// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{ {
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -350,7 +350,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
} }
/// <inheritdoc /> /// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{ {
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -389,7 +389,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
} }
/// <inheritdoc /> /// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{ {
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -428,7 +428,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
} }
/// <inheritdoc /> /// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{ {
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -467,7 +467,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
} }
/// <inheritdoc /> /// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{ {
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -506,7 +506,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
} }
/// <inheritdoc /> /// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{ {
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -545,7 +545,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
} }
/// <inheritdoc /> /// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{ {
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -584,7 +584,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
} }
/// <inheritdoc /> /// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{ {
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -623,7 +623,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
} }
/// <inheritdoc /> /// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{ {
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -662,7 +662,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
} }
/// <inheritdoc /> /// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{ {
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -701,7 +701,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
} }
/// <inheritdoc /> /// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{ {
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -740,7 +740,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
} }
/// <inheritdoc /> /// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{ {
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -779,7 +779,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
} }
/// <inheritdoc /> /// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{ {
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -818,7 +818,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
} }
/// <inheritdoc /> /// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{ {
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));

2
src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt

@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
} }
/// <inheritdoc /> /// <inheritdoc />
public override void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) public override void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{ {
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));

6
src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs

@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using SixLabors.ImageSharp.Memory; using SixLabors.Memory;
namespace SixLabors.ImageSharp.PixelFormats namespace SixLabors.ImageSharp.PixelFormats
{ {
@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary> /// <summary>
/// Blend 2 pixels together. /// Blend 2 pixels together.
/// </summary> /// </summary>
/// <param name="memoryManager">The <see cref="MemoryManager"/></param> /// <param name="memoryAllocator">The <see cref="MemoryAllocator"/></param>
/// <param name="destination">The destination span.</param> /// <param name="destination">The destination span.</param>
/// <param name="background">The background span.</param> /// <param name="background">The background span.</param>
/// <param name="source">The source span.</param> /// <param name="source">The source span.</param>
@ -36,6 +36,6 @@ namespace SixLabors.ImageSharp.PixelFormats
/// A value between 0 and 1 indicating the weight of the second source vector. /// A value between 0 and 1 indicating the weight of the second source vector.
/// At amount = 0, "from" is returned, at amount = 1, "to" is returned. /// At amount = 0, "from" is returned, at amount = 1, "to" is returned.
/// </param> /// </param>
public abstract void Blend(MemoryManager memoryManager, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount); public abstract void Blend(MemoryAllocator memoryAllocator, Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount);
} }
} }

2
src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs

@ -5,7 +5,7 @@ using System;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory; using SixLabors.Memory;
namespace SixLabors.ImageSharp.PixelFormats namespace SixLabors.ImageSharp.PixelFormats
{ {

6
src/ImageSharp/Processing/Convolution/Processors/Convolution2DProcessor.cs

@ -5,10 +5,10 @@ using System;
using System.Numerics; using System.Numerics;
using System.Threading.Tasks; using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives; using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Processors; using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Convolution.Processors namespace SixLabors.ImageSharp.Processing.Convolution.Processors
@ -58,7 +58,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
int maxY = endY - 1; int maxY = endY - 1;
int maxX = endX - 1; int maxX = endX - 1;
using (Buffer2D<TPixel> targetPixels = configuration.MemoryManager.Allocate2D<TPixel>(source.Width, source.Height)) using (Buffer2D<TPixel> targetPixels = configuration.MemoryAllocator.Allocate2D<TPixel>(source.Width, source.Height))
{ {
source.CopyTo(targetPixels); source.CopyTo(targetPixels);
@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
} }
}); });
Buffer2D<TPixel>.SwapContents(source.PixelBuffer, targetPixels); Buffer2D<TPixel>.SwapOrCopyContent(source.PixelBuffer, targetPixels);
} }
} }
} }

4
src/ImageSharp/Processing/Convolution/Processors/Convolution2PassProcessor.cs

@ -4,10 +4,10 @@
using System; using System;
using System.Numerics; using System.Numerics;
using System.Threading.Tasks; using System.Threading.Tasks;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives; using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Processors; using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Convolution.Processors namespace SixLabors.ImageSharp.Processing.Convolution.Processors
@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
{ {
ParallelOptions parallelOptions = configuration.ParallelOptions; ParallelOptions parallelOptions = configuration.ParallelOptions;
using (Buffer2D<TPixel> firstPassPixels = configuration.MemoryManager.Allocate2D<TPixel>(source.Size())) using (Buffer2D<TPixel> firstPassPixels = configuration.MemoryAllocator.Allocate2D<TPixel>(source.Size()))
{ {
this.ApplyConvolution(firstPassPixels, source.PixelBuffer, source.Bounds(), this.KernelX, parallelOptions); this.ApplyConvolution(firstPassPixels, source.PixelBuffer, source.Bounds(), this.KernelX, parallelOptions);
this.ApplyConvolution(source.PixelBuffer, firstPassPixels, sourceRectangle, this.KernelY, parallelOptions); this.ApplyConvolution(source.PixelBuffer, firstPassPixels, sourceRectangle, this.KernelY, parallelOptions);

6
src/ImageSharp/Processing/Convolution/Processors/ConvolutionProcessor.cs

@ -5,10 +5,10 @@ using System;
using System.Numerics; using System.Numerics;
using System.Threading.Tasks; using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives; using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Processors; using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Convolution.Processors namespace SixLabors.ImageSharp.Processing.Convolution.Processors
@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
int maxY = endY - 1; int maxY = endY - 1;
int maxX = endX - 1; int maxX = endX - 1;
using (Buffer2D<TPixel> targetPixels = configuration.MemoryManager.Allocate2D<TPixel>(source.Size())) using (Buffer2D<TPixel> targetPixels = configuration.MemoryAllocator.Allocate2D<TPixel>(source.Size()))
{ {
source.CopyTo(targetPixels); source.CopyTo(targetPixels);
@ -96,7 +96,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
} }
}); });
Buffer2D<TPixel>.SwapContents(source.PixelBuffer, targetPixels); Buffer2D<TPixel>.SwapOrCopyContent(source.PixelBuffer, targetPixels);
} }
} }
} }

35
src/ImageSharp/Processing/Convolution/Processors/EdgeDetectorCompassProcessor.cs

@ -3,11 +3,14 @@
using System; using System;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives; using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Filters.Processors; using SixLabors.ImageSharp.Processing.Filters.Processors;
using SixLabors.ImageSharp.Processing.Processors; using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Convolution.Processors namespace SixLabors.ImageSharp.Processing.Convolution.Processors
@ -128,27 +131,35 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
{ {
new ConvolutionProcessor<TPixel>(kernels[i]).Apply(pass, sourceRectangle, configuration); new ConvolutionProcessor<TPixel>(kernels[i]).Apply(pass, sourceRectangle, configuration);
using (PixelAccessor<TPixel> passPixels = pass.Lock()) Buffer2D<TPixel> passPixels = pass.PixelBuffer;
using (PixelAccessor<TPixel> targetPixels = source.Lock()) Buffer2D<TPixel> targetPixels = source.PixelBuffer;
{
Parallel.For( Parallel.For(
minY, minY,
maxY, maxY,
configuration.ParallelOptions, configuration.ParallelOptions,
y => y =>
{ {
int offsetY = y - shiftY; int offsetY = y - shiftY;
ref TPixel passPixelsBase = ref MemoryMarshal.GetReference(passPixels.GetRowSpan(offsetY));
ref TPixel targetPixelsBase = ref MemoryMarshal.GetReference(targetPixels.GetRowSpan(offsetY));
for (int x = minX; x < maxX; x++) for (int x = minX; x < maxX; x++)
{ {
int offsetX = x - shiftX; int offsetX = x - shiftX;
// Grab the max components of the two pixels // Grab the max components of the two pixels
TPixel packed = default(TPixel); ref TPixel currentPassPixel = ref Unsafe.Add(ref passPixelsBase, offsetX);
packed.PackFromVector4(Vector4.Max(passPixels[offsetX, offsetY].ToVector4(), targetPixels[offsetX, offsetY].ToVector4())); ref TPixel currentTargetPixel = ref Unsafe.Add(ref targetPixelsBase, offsetX);
targetPixels[offsetX, offsetY] = packed;
var pixelValue = Vector4.Max(
currentPassPixel.ToVector4(),
currentTargetPixel.ToVector4());
currentTargetPixel.PackFromVector4(pixelValue);
} }
}); });
}
} }
} }
} }

1
src/ImageSharp/Processing/Convolution/Processors/SobelProcessor.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Convolution.Processors namespace SixLabors.ImageSharp.Processing.Convolution.Processors

4
src/ImageSharp/Processing/DefaultInternalImageProcessorContext.cs

@ -2,9 +2,9 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors; using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Processing
} }
/// <inheritdoc/> /// <inheritdoc/>
public MemoryManager MemoryManager => this.source.GetConfiguration().MemoryManager; public MemoryAllocator MemoryAllocator => this.source.GetConfiguration().MemoryAllocator;
/// <inheritdoc/> /// <inheritdoc/>
public Image<TPixel> Apply() public Image<TPixel> Apply()

6
src/ImageSharp/Processing/Effects/Processors/OilPaintingProcessor.cs

@ -5,9 +5,9 @@ using System;
using System.Numerics; using System.Numerics;
using System.Threading.Tasks; using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors; using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Effects.Processors namespace SixLabors.ImageSharp.Processing.Effects.Processors
@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.Processing.Effects.Processors
int radius = this.BrushSize >> 1; int radius = this.BrushSize >> 1;
int levels = this.Levels; int levels = this.Levels;
using (Buffer2D<TPixel> targetPixels = configuration.MemoryManager.Allocate2D<TPixel>(source.Size())) using (Buffer2D<TPixel> targetPixels = configuration.MemoryAllocator.Allocate2D<TPixel>(source.Size()))
{ {
source.CopyTo(targetPixels); source.CopyTo(targetPixels);
@ -134,7 +134,7 @@ namespace SixLabors.ImageSharp.Processing.Effects.Processors
} }
}); });
Buffer2D<TPixel>.SwapContents(source.PixelBuffer, targetPixels); Buffer2D<TPixel>.SwapOrCopyContent(source.PixelBuffer, targetPixels);
} }
} }
} }

6
src/ImageSharp/Processing/IImageProcessingContext{TPixel}.cs

@ -1,9 +1,9 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors; using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
@ -16,10 +16,10 @@ namespace SixLabors.ImageSharp.Processing
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
/// <summary> /// <summary>
/// Gets a reference to the <see cref="MemoryManager" /> used to allocate buffers /// Gets a reference to the <see cref="MemoryAllocator" /> used to allocate buffers
/// for this context. /// for this context.
/// </summary> /// </summary>
MemoryManager MemoryManager { get; } MemoryAllocator MemoryAllocator { get; }
/// <summary> /// <summary>
/// Gets the image dimensions at the current point in the processing pipeline. /// Gets the image dimensions at the current point in the processing pipeline.

12
src/ImageSharp/Processing/Overlays/Processors/BackgroundColorProcessor.cs

@ -4,9 +4,9 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors; using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Overlays.Processors namespace SixLabors.ImageSharp.Processing.Overlays.Processors
@ -66,12 +66,12 @@ namespace SixLabors.ImageSharp.Processing.Overlays.Processors
int width = maxX - minX; int width = maxX - minX;
using (IBuffer<TPixel> colors = source.MemoryManager.Allocate<TPixel>(width)) using (IBuffer<TPixel> colors = source.MemoryAllocator.Allocate<TPixel>(width))
using (IBuffer<float> amount = source.MemoryManager.Allocate<float>(width)) using (IBuffer<float> amount = source.MemoryAllocator.Allocate<float>(width))
{ {
// Be careful! Do not capture colorSpan & amountSpan in the lambda below! // Be careful! Do not capture colorSpan & amountSpan in the lambda below!
Span<TPixel> colorSpan = colors.Span; Span<TPixel> colorSpan = colors.GetSpan();
Span<float> amountSpan = amount.Span; Span<float> amountSpan = amount.GetSpan();
// TODO: Use Span.Fill? // TODO: Use Span.Fill?
for (int i = 0; i < width; i++) for (int i = 0; i < width; i++)
@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.Processing.Overlays.Processors
Span<TPixel> destination = source.GetPixelRowSpan(y - startY).Slice(minX - startX, width); Span<TPixel> destination = source.GetPixelRowSpan(y - startY).Slice(minX - startX, width);
// This switched color & destination in the 2nd and 3rd places because we are applying the target color under the current one // This switched color & destination in the 2nd and 3rd places because we are applying the target color under the current one
blender.Blend(source.MemoryManager, destination, colors.Span, destination, amount.Span); blender.Blend(source.MemoryAllocator, destination, colors.GetSpan(), destination, amount.GetSpan());
}); });
} }
} }

12
src/ImageSharp/Processing/Overlays/Processors/GlowProcessor.cs

@ -5,10 +5,10 @@ using System;
using System.Numerics; using System.Numerics;
using System.Threading.Tasks; using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives; using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Processors; using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Overlays.Processors namespace SixLabors.ImageSharp.Processing.Overlays.Processors
@ -112,10 +112,10 @@ namespace SixLabors.ImageSharp.Processing.Overlays.Processors
} }
int width = maxX - minX; int width = maxX - minX;
using (IBuffer<TPixel> rowColors = source.MemoryManager.Allocate<TPixel>(width)) using (IBuffer<TPixel> rowColors = source.MemoryAllocator.Allocate<TPixel>(width))
{ {
// Be careful! Do not capture rowColorsSpan in the lambda below! // Be careful! Do not capture rowColorsSpan in the lambda below!
Span<TPixel> rowColorsSpan = rowColors.Span; Span<TPixel> rowColorsSpan = rowColors.GetSpan();
for (int i = 0; i < width; i++) for (int i = 0; i < width; i++)
{ {
@ -128,9 +128,9 @@ namespace SixLabors.ImageSharp.Processing.Overlays.Processors
configuration.ParallelOptions, configuration.ParallelOptions,
y => y =>
{ {
using (IBuffer<float> amounts = source.MemoryManager.Allocate<float>(width)) using (IBuffer<float> amounts = source.MemoryAllocator.Allocate<float>(width))
{ {
Span<float> amountsSpan = amounts.Span; Span<float> amountsSpan = amounts.GetSpan();
int offsetY = y - startY; int offsetY = y - startY;
int offsetX = minX - startX; int offsetX = minX - startX;
for (int i = 0; i < width; i++) for (int i = 0; i < width; i++)
@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.Processing.Overlays.Processors
Span<TPixel> destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width); Span<TPixel> destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width);
this.blender.Blend(source.MemoryManager, destination, destination, rowColors.Span, amountsSpan); this.blender.Blend(source.MemoryAllocator, destination, destination, rowColors.GetSpan(), amountsSpan);
} }
}); });
} }

12
src/ImageSharp/Processing/Overlays/Processors/VignetteProcessor.cs

@ -5,10 +5,10 @@ using System;
using System.Numerics; using System.Numerics;
using System.Threading.Tasks; using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives; using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Processors; using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Overlays.Processors namespace SixLabors.ImageSharp.Processing.Overlays.Processors
@ -114,10 +114,10 @@ namespace SixLabors.ImageSharp.Processing.Overlays.Processors
} }
int width = maxX - minX; int width = maxX - minX;
using (IBuffer<TPixel> rowColors = source.MemoryManager.Allocate<TPixel>(width)) using (IBuffer<TPixel> rowColors = source.MemoryAllocator.Allocate<TPixel>(width))
{ {
// Be careful! Do not capture rowColorsSpan in the lambda below! // Be careful! Do not capture rowColorsSpan in the lambda below!
Span<TPixel> rowColorsSpan = rowColors.Span; Span<TPixel> rowColorsSpan = rowColors.GetSpan();
for (int i = 0; i < width; i++) for (int i = 0; i < width; i++)
{ {
@ -130,9 +130,9 @@ namespace SixLabors.ImageSharp.Processing.Overlays.Processors
configuration.ParallelOptions, configuration.ParallelOptions,
y => y =>
{ {
using (IBuffer<float> amounts = source.MemoryManager.Allocate<float>(width)) using (IBuffer<float> amounts = source.MemoryAllocator.Allocate<float>(width))
{ {
Span<float> amountsSpan = amounts.Span; Span<float> amountsSpan = amounts.GetSpan();
int offsetY = y - startY; int offsetY = y - startY;
int offsetX = minX - startX; int offsetX = minX - startX;
for (int i = 0; i < width; i++) for (int i = 0; i < width; i++)
@ -143,7 +143,7 @@ namespace SixLabors.ImageSharp.Processing.Overlays.Processors
Span<TPixel> destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width); Span<TPixel> destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width);
this.blender.Blend(source.MemoryManager, destination, destination, rowColors.Span, amountsSpan); this.blender.Blend(source.MemoryAllocator, destination, destination, rowColors.GetSpan(), amountsSpan);
} }
}); });
} }

2
src/ImageSharp/Processing/Processors/CloningImageProcessor.cs

@ -67,7 +67,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
throw new ImageProcessingException($"An error occurred when processing the image using {this.GetType().Name}. The processor changed the number of frames."); throw new ImageProcessingException($"An error occurred when processing the image using {this.GetType().Name}. The processor changed the number of frames.");
} }
source.SwapPixelsBuffers(cloned); source.SwapOrCopyPixelsBuffersFrom(cloned);
} }
} }

156
src/ImageSharp/Processing/Quantization/FrameQuantizers/WuFrameQuantizer{TPixel}.cs

@ -7,8 +7,8 @@ using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers
{ {
@ -141,17 +141,17 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers
public override QuantizedFrame<TPixel> QuantizeFrame(ImageFrame<TPixel> image) public override QuantizedFrame<TPixel> QuantizeFrame(ImageFrame<TPixel> image)
{ {
Guard.NotNull(image, nameof(image)); Guard.NotNull(image, nameof(image));
MemoryManager memoryManager = image.MemoryManager; MemoryAllocator memoryAllocator = image.MemoryAllocator;
try try
{ {
this.vwt = memoryManager.AllocateClean<long>(TableLength); this.vwt = memoryAllocator.AllocateClean<long>(TableLength);
this.vmr = memoryManager.AllocateClean<long>(TableLength); this.vmr = memoryAllocator.AllocateClean<long>(TableLength);
this.vmg = memoryManager.AllocateClean<long>(TableLength); this.vmg = memoryAllocator.AllocateClean<long>(TableLength);
this.vmb = memoryManager.AllocateClean<long>(TableLength); this.vmb = memoryAllocator.AllocateClean<long>(TableLength);
this.vma = memoryManager.AllocateClean<long>(TableLength); this.vma = memoryAllocator.AllocateClean<long>(TableLength);
this.m2 = memoryManager.AllocateClean<float>(TableLength); this.m2 = memoryAllocator.AllocateClean<float>(TableLength);
this.tag = memoryManager.AllocateClean<byte>(TableLength); this.tag = memoryAllocator.AllocateClean<byte>(TableLength);
return base.QuantizeFrame(image); return base.QuantizeFrame(image);
} }
@ -177,14 +177,14 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers
{ {
this.Mark(ref this.colorCube[k], (byte)k); this.Mark(ref this.colorCube[k], (byte)k);
float weight = Volume(ref this.colorCube[k], this.vwt.Span); float weight = Volume(ref this.colorCube[k], this.vwt.GetSpan());
if (MathF.Abs(weight) > Constants.Epsilon) if (MathF.Abs(weight) > Constants.Epsilon)
{ {
float r = Volume(ref this.colorCube[k], this.vmr.Span); float r = Volume(ref this.colorCube[k], this.vmr.GetSpan());
float g = Volume(ref this.colorCube[k], this.vmg.Span); float g = Volume(ref this.colorCube[k], this.vmg.GetSpan());
float b = Volume(ref this.colorCube[k], this.vmb.Span); float b = Volume(ref this.colorCube[k], this.vmb.GetSpan());
float a = Volume(ref this.colorCube[k], this.vma.Span); float a = Volume(ref this.colorCube[k], this.vma.GetSpan());
ref TPixel color = ref this.palette[k]; ref TPixel color = ref this.palette[k];
color.PackFromVector4(new Vector4(r, g, b, a) / weight / 255F); color.PackFromVector4(new Vector4(r, g, b, a) / weight / 255F);
@ -209,12 +209,12 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers
int index = GetPaletteIndex(r + 1, g + 1, b + 1, a + 1); int index = GetPaletteIndex(r + 1, g + 1, b + 1, a + 1);
Span<long> vwtSpan = this.vwt.Span; Span<long> vwtSpan = this.vwt.GetSpan();
Span<long> vmrSpan = this.vmr.Span; Span<long> vmrSpan = this.vmr.GetSpan();
Span<long> vmgSpan = this.vmg.Span; Span<long> vmgSpan = this.vmg.GetSpan();
Span<long> vmbSpan = this.vmb.Span; Span<long> vmbSpan = this.vmb.GetSpan();
Span<long> vmaSpan = this.vma.Span; Span<long> vmaSpan = this.vma.GetSpan();
Span<float> m2Span = this.m2.Span; Span<float> m2Span = this.m2.GetSpan();
vwtSpan[index]++; vwtSpan[index]++;
vmrSpan[index] += rgba.R; vmrSpan[index] += rgba.R;
@ -246,7 +246,7 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers
} }
} }
this.Get3DMoments(source.MemoryManager); this.Get3DMoments(source.MemoryAllocator);
this.BuildCube(); this.BuildCube();
} }
@ -464,42 +464,42 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers
/// <summary> /// <summary>
/// Converts the histogram into moments so that we can rapidly calculate the sums of the above quantities over any desired box. /// Converts the histogram into moments so that we can rapidly calculate the sums of the above quantities over any desired box.
/// </summary> /// </summary>
private void Get3DMoments(MemoryManager memoryManager) private void Get3DMoments(MemoryAllocator memoryAllocator)
{ {
Span<long> vwtSpan = this.vwt.Span; Span<long> vwtSpan = this.vwt.GetSpan();
Span<long> vmrSpan = this.vmr.Span; Span<long> vmrSpan = this.vmr.GetSpan();
Span<long> vmgSpan = this.vmg.Span; Span<long> vmgSpan = this.vmg.GetSpan();
Span<long> vmbSpan = this.vmb.Span; Span<long> vmbSpan = this.vmb.GetSpan();
Span<long> vmaSpan = this.vma.Span; Span<long> vmaSpan = this.vma.GetSpan();
Span<float> m2Span = this.m2.Span; Span<float> m2Span = this.m2.GetSpan();
using (IBuffer<long> volume = memoryManager.Allocate<long>(IndexCount * IndexAlphaCount)) using (IBuffer<long> volume = memoryAllocator.Allocate<long>(IndexCount * IndexAlphaCount))
using (IBuffer<long> volumeR = memoryManager.Allocate<long>(IndexCount * IndexAlphaCount)) using (IBuffer<long> volumeR = memoryAllocator.Allocate<long>(IndexCount * IndexAlphaCount))
using (IBuffer<long> volumeG = memoryManager.Allocate<long>(IndexCount * IndexAlphaCount)) using (IBuffer<long> volumeG = memoryAllocator.Allocate<long>(IndexCount * IndexAlphaCount))
using (IBuffer<long> volumeB = memoryManager.Allocate<long>(IndexCount * IndexAlphaCount)) using (IBuffer<long> volumeB = memoryAllocator.Allocate<long>(IndexCount * IndexAlphaCount))
using (IBuffer<long> volumeA = memoryManager.Allocate<long>(IndexCount * IndexAlphaCount)) using (IBuffer<long> volumeA = memoryAllocator.Allocate<long>(IndexCount * IndexAlphaCount))
using (IBuffer<float> volume2 = memoryManager.Allocate<float>(IndexCount * IndexAlphaCount)) using (IBuffer<float> volume2 = memoryAllocator.Allocate<float>(IndexCount * IndexAlphaCount))
using (IBuffer<long> area = memoryManager.Allocate<long>(IndexAlphaCount)) using (IBuffer<long> area = memoryAllocator.Allocate<long>(IndexAlphaCount))
using (IBuffer<long> areaR = memoryManager.Allocate<long>(IndexAlphaCount)) using (IBuffer<long> areaR = memoryAllocator.Allocate<long>(IndexAlphaCount))
using (IBuffer<long> areaG = memoryManager.Allocate<long>(IndexAlphaCount)) using (IBuffer<long> areaG = memoryAllocator.Allocate<long>(IndexAlphaCount))
using (IBuffer<long> areaB = memoryManager.Allocate<long>(IndexAlphaCount)) using (IBuffer<long> areaB = memoryAllocator.Allocate<long>(IndexAlphaCount))
using (IBuffer<long> areaA = memoryManager.Allocate<long>(IndexAlphaCount)) using (IBuffer<long> areaA = memoryAllocator.Allocate<long>(IndexAlphaCount))
using (IBuffer<float> area2 = memoryManager.Allocate<float>(IndexAlphaCount)) using (IBuffer<float> area2 = memoryAllocator.Allocate<float>(IndexAlphaCount))
{ {
Span<long> volumeSpan = volume.Span; Span<long> volumeSpan = volume.GetSpan();
Span<long> volumeRSpan = volumeR.Span; Span<long> volumeRSpan = volumeR.GetSpan();
Span<long> volumeGSpan = volumeG.Span; Span<long> volumeGSpan = volumeG.GetSpan();
Span<long> volumeBSpan = volumeB.Span; Span<long> volumeBSpan = volumeB.GetSpan();
Span<long> volumeASpan = volumeA.Span; Span<long> volumeASpan = volumeA.GetSpan();
Span<float> volume2Span = volume2.Span; Span<float> volume2Span = volume2.GetSpan();
Span<long> areaSpan = area.Span; Span<long> areaSpan = area.GetSpan();
Span<long> areaRSpan = areaR.Span; Span<long> areaRSpan = areaR.GetSpan();
Span<long> areaGSpan = areaG.Span; Span<long> areaGSpan = areaG.GetSpan();
Span<long> areaBSpan = areaB.Span; Span<long> areaBSpan = areaB.GetSpan();
Span<long> areaASpan = areaA.Span; Span<long> areaASpan = areaA.GetSpan();
Span<float> area2Span = area2.Span; Span<float> area2Span = area2.GetSpan();
for (int r = 1; r < IndexCount; r++) for (int r = 1; r < IndexCount; r++)
{ {
@ -577,12 +577,12 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers
/// <returns>The <see cref="float"/>.</returns> /// <returns>The <see cref="float"/>.</returns>
private float Variance(ref Box cube) private float Variance(ref Box cube)
{ {
float dr = Volume(ref cube, this.vmr.Span); float dr = Volume(ref cube, this.vmr.GetSpan());
float dg = Volume(ref cube, this.vmg.Span); float dg = Volume(ref cube, this.vmg.GetSpan());
float db = Volume(ref cube, this.vmb.Span); float db = Volume(ref cube, this.vmb.GetSpan());
float da = Volume(ref cube, this.vma.Span); float da = Volume(ref cube, this.vma.GetSpan());
Span<float> m2Span = this.m2.Span; Span<float> m2Span = this.m2.GetSpan();
float xx = float xx =
m2Span[GetPaletteIndex(cube.R1, cube.G1, cube.B1, cube.A1)] m2Span[GetPaletteIndex(cube.R1, cube.G1, cube.B1, cube.A1)]
@ -603,7 +603,7 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers
+ m2Span[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)]; + m2Span[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)];
var vector = new Vector4(dr, dg, db, da); var vector = new Vector4(dr, dg, db, da);
return xx - (Vector4.Dot(vector, vector) / Volume(ref cube, this.vwt.Span)); return xx - (Vector4.Dot(vector, vector) / Volume(ref cube, this.vwt.GetSpan()));
} }
/// <summary> /// <summary>
@ -626,22 +626,22 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers
/// <returns>The <see cref="float"/>.</returns> /// <returns>The <see cref="float"/>.</returns>
private float Maximize(ref Box cube, int direction, int first, int last, out int cut, float wholeR, float wholeG, float wholeB, float wholeA, float wholeW) private float Maximize(ref Box cube, int direction, int first, int last, out int cut, float wholeR, float wholeG, float wholeB, float wholeA, float wholeW)
{ {
long baseR = Bottom(ref cube, direction, this.vmr.Span); long baseR = Bottom(ref cube, direction, this.vmr.GetSpan());
long baseG = Bottom(ref cube, direction, this.vmg.Span); long baseG = Bottom(ref cube, direction, this.vmg.GetSpan());
long baseB = Bottom(ref cube, direction, this.vmb.Span); long baseB = Bottom(ref cube, direction, this.vmb.GetSpan());
long baseA = Bottom(ref cube, direction, this.vma.Span); long baseA = Bottom(ref cube, direction, this.vma.GetSpan());
long baseW = Bottom(ref cube, direction, this.vwt.Span); long baseW = Bottom(ref cube, direction, this.vwt.GetSpan());
float max = 0F; float max = 0F;
cut = -1; cut = -1;
for (int i = first; i < last; i++) for (int i = first; i < last; i++)
{ {
float halfR = baseR + Top(ref cube, direction, i, this.vmr.Span); float halfR = baseR + Top(ref cube, direction, i, this.vmr.GetSpan());
float halfG = baseG + Top(ref cube, direction, i, this.vmg.Span); float halfG = baseG + Top(ref cube, direction, i, this.vmg.GetSpan());
float halfB = baseB + Top(ref cube, direction, i, this.vmb.Span); float halfB = baseB + Top(ref cube, direction, i, this.vmb.GetSpan());
float halfA = baseA + Top(ref cube, direction, i, this.vma.Span); float halfA = baseA + Top(ref cube, direction, i, this.vma.GetSpan());
float halfW = baseW + Top(ref cube, direction, i, this.vwt.Span); float halfW = baseW + Top(ref cube, direction, i, this.vwt.GetSpan());
if (MathF.Abs(halfW) < Constants.Epsilon) if (MathF.Abs(halfW) < Constants.Epsilon)
{ {
@ -685,11 +685,11 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers
/// <returns>Returns a value indicating whether the box has been split.</returns> /// <returns>Returns a value indicating whether the box has been split.</returns>
private bool Cut(ref Box set1, ref Box set2) private bool Cut(ref Box set1, ref Box set2)
{ {
float wholeR = Volume(ref set1, this.vmr.Span); float wholeR = Volume(ref set1, this.vmr.GetSpan());
float wholeG = Volume(ref set1, this.vmg.Span); float wholeG = Volume(ref set1, this.vmg.GetSpan());
float wholeB = Volume(ref set1, this.vmb.Span); float wholeB = Volume(ref set1, this.vmb.GetSpan());
float wholeA = Volume(ref set1, this.vma.Span); float wholeA = Volume(ref set1, this.vma.GetSpan());
float wholeW = Volume(ref set1, this.vwt.Span); float wholeW = Volume(ref set1, this.vwt.GetSpan());
float maxr = this.Maximize(ref set1, 3, set1.R0 + 1, set1.R1, out int cutr, wholeR, wholeG, wholeB, wholeA, wholeW); float maxr = this.Maximize(ref set1, 3, set1.R0 + 1, set1.R1, out int cutr, wholeR, wholeG, wholeB, wholeA, wholeW);
float maxg = this.Maximize(ref set1, 2, set1.G0 + 1, set1.G1, out int cutg, wholeR, wholeG, wholeB, wholeA, wholeW); float maxg = this.Maximize(ref set1, 2, set1.G0 + 1, set1.G1, out int cutg, wholeR, wholeG, wholeB, wholeA, wholeW);
@ -773,7 +773,7 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers
/// <param name="label">A label.</param> /// <param name="label">A label.</param>
private void Mark(ref Box cube, byte label) private void Mark(ref Box cube, byte label)
{ {
Span<byte> tagSpan = this.tag.Span; Span<byte> tagSpan = this.tag.GetSpan();
for (int r = cube.R0 + 1; r <= cube.R1; r++) for (int r = cube.R0 + 1; r <= cube.R1; r++)
{ {
@ -866,7 +866,7 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers
int b = rgba.B >> (8 - IndexBits); int b = rgba.B >> (8 - IndexBits);
int a = rgba.A >> (8 - IndexAlphaBits); int a = rgba.A >> (8 - IndexAlphaBits);
Span<byte> tagSpan = this.tag.Span; Span<byte> tagSpan = this.tag.GetSpan();
return tagSpan[GetPaletteIndex(r + 1, g + 1, b + 1, a + 1)]; return tagSpan[GetPaletteIndex(r + 1, g + 1, b + 1, a + 1)];
} }

8
src/ImageSharp/Processing/Transforms/Processors/AffineTransformProcessor.cs

@ -9,9 +9,9 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Transforms.Resamplers; using SixLabors.ImageSharp.Processing.Transforms.Resamplers;
using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Transforms.Processors namespace SixLabors.ImageSharp.Processing.Transforms.Processors
@ -111,10 +111,10 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
int xLength = (int)MathF.Ceiling((radius.X * 2) + 2); int xLength = (int)MathF.Ceiling((radius.X * 2) + 2);
int yLength = (int)MathF.Ceiling((radius.Y * 2) + 2); int yLength = (int)MathF.Ceiling((radius.Y * 2) + 2);
MemoryManager memoryManager = configuration.MemoryManager; MemoryAllocator memoryAllocator = configuration.MemoryAllocator;
using (Buffer2D<float> yBuffer = memoryManager.Allocate2D<float>(yLength, height)) using (Buffer2D<float> yBuffer = memoryAllocator.Allocate2D<float>(yLength, height))
using (Buffer2D<float> xBuffer = memoryManager.Allocate2D<float>(xLength, height)) using (Buffer2D<float> xBuffer = memoryAllocator.Allocate2D<float>(xLength, height))
{ {
Parallel.For( Parallel.For(
0, 0,

1
src/ImageSharp/Processing/Transforms/Processors/CropProcessor.cs

@ -6,7 +6,6 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives; using SixLabors.Primitives;

10
src/ImageSharp/Processing/Transforms/Processors/FlipProcessor.cs

@ -4,9 +4,9 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors; using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Transforms.Processors namespace SixLabors.ImageSharp.Processing.Transforms.Processors
@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
int height = source.Height; int height = source.Height;
int halfHeight = (int)Math.Ceiling(source.Height * .5F); int halfHeight = (int)Math.Ceiling(source.Height * .5F);
using (Buffer2D<TPixel> targetPixels = configuration.MemoryManager.Allocate2D<TPixel>(source.Size())) using (Buffer2D<TPixel> targetPixels = configuration.MemoryAllocator.Allocate2D<TPixel>(source.Size()))
{ {
Parallel.For( Parallel.For(
0, 0,
@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
altSourceRow.CopyTo(targetRow); altSourceRow.CopyTo(targetRow);
}); });
Buffer2D<TPixel>.SwapContents(source.PixelBuffer, targetPixels); Buffer2D<TPixel>.SwapOrCopyContent(source.PixelBuffer, targetPixels);
} }
} }
@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
int height = source.Height; int height = source.Height;
int halfWidth = (int)Math.Ceiling(width * .5F); int halfWidth = (int)Math.Ceiling(width * .5F);
using (Buffer2D<TPixel> targetPixels = configuration.MemoryManager.Allocate2D<TPixel>(source.Size())) using (Buffer2D<TPixel> targetPixels = configuration.MemoryAllocator.Allocate2D<TPixel>(source.Size()))
{ {
Parallel.For( Parallel.For(
0, 0,
@ -109,7 +109,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
} }
}); });
Buffer2D<TPixel>.SwapContents(source.PixelBuffer, targetPixels); Buffer2D<TPixel>.SwapOrCopyContent(source.PixelBuffer, targetPixels);
} }
} }
} }

8
src/ImageSharp/Processing/Transforms/Processors/ProjectiveTransformProcessor.cs

@ -9,9 +9,9 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Transforms.Resamplers; using SixLabors.ImageSharp.Processing.Transforms.Resamplers;
using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
// TODO: Doesn't work yet! Implement tests + Finish implementation + Document Matrix4x4 behavior // TODO: Doesn't work yet! Implement tests + Finish implementation + Document Matrix4x4 behavior
@ -117,10 +117,10 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
int xLength = (int)MathF.Ceiling((radius.X * 2) + 2); int xLength = (int)MathF.Ceiling((radius.X * 2) + 2);
int yLength = (int)MathF.Ceiling((radius.Y * 2) + 2); int yLength = (int)MathF.Ceiling((radius.Y * 2) + 2);
MemoryManager memoryManager = configuration.MemoryManager; MemoryAllocator memoryAllocator = configuration.MemoryAllocator;
using (Buffer2D<float> yBuffer = memoryManager.Allocate2D<float>(yLength, height)) using (Buffer2D<float> yBuffer = memoryAllocator.Allocate2D<float>(yLength, height))
using (Buffer2D<float> xBuffer = memoryManager.Allocate2D<float>(xLength, height)) using (Buffer2D<float> xBuffer = memoryAllocator.Allocate2D<float>(xLength, height))
{ {
Parallel.For( Parallel.For(
0, 0,

18
src/ImageSharp/Processing/Transforms/Processors/ResizeProcessor.cs

@ -9,9 +9,9 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Transforms.Resamplers; using SixLabors.ImageSharp.Processing.Transforms.Resamplers;
using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Transforms.Processors namespace SixLabors.ImageSharp.Processing.Transforms.Processors
@ -143,12 +143,12 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
/// <summary> /// <summary>
/// Computes the weights to apply at each pixel when resizing. /// Computes the weights to apply at each pixel when resizing.
/// </summary> /// </summary>
/// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations</param> /// <param name="memoryAllocator">The <see cref="MemoryAllocator"/> to use for buffer allocations</param>
/// <param name="destinationSize">The destination size</param> /// <param name="destinationSize">The destination size</param>
/// <param name="sourceSize">The source size</param> /// <param name="sourceSize">The source size</param>
/// <returns>The <see cref="WeightsBuffer"/></returns> /// <returns>The <see cref="WeightsBuffer"/></returns>
// TODO: Made internal to simplify experimenting with weights data. Make it private when finished figuring out how to optimize all the stuff! // TODO: Made internal to simplify experimenting with weights data. Make it private when finished figuring out how to optimize all the stuff!
internal WeightsBuffer PrecomputeWeights(MemoryManager memoryManager, int destinationSize, int sourceSize) internal WeightsBuffer PrecomputeWeights(MemoryAllocator memoryAllocator, int destinationSize, int sourceSize)
{ {
float ratio = (float)sourceSize / destinationSize; float ratio = (float)sourceSize / destinationSize;
float scale = ratio; float scale = ratio;
@ -160,7 +160,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
IResampler sampler = this.Sampler; IResampler sampler = this.Sampler;
float radius = MathF.Ceiling(scale * sampler.Radius); float radius = MathF.Ceiling(scale * sampler.Radius);
var result = new WeightsBuffer(memoryManager, sourceSize, destinationSize); var result = new WeightsBuffer(memoryAllocator, sourceSize, destinationSize);
for (int i = 0; i < destinationSize; i++) for (int i = 0; i < destinationSize; i++)
{ {
@ -226,14 +226,14 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
if (!(this.Sampler is NearestNeighborResampler)) if (!(this.Sampler is NearestNeighborResampler))
{ {
// Since all image frame dimensions have to be the same we can calculate this for all frames. // Since all image frame dimensions have to be the same we can calculate this for all frames.
MemoryManager memoryManager = source.GetMemoryManager(); MemoryAllocator memoryAllocator = source.GetMemoryAllocator();
this.horizontalWeights = this.PrecomputeWeights( this.horizontalWeights = this.PrecomputeWeights(
memoryManager, memoryAllocator,
this.ResizeRectangle.Width, this.ResizeRectangle.Width,
sourceRectangle.Width); sourceRectangle.Width);
this.verticalWeights = this.PrecomputeWeights( this.verticalWeights = this.PrecomputeWeights(
memoryManager, memoryAllocator,
this.ResizeRectangle.Height, this.ResizeRectangle.Height,
sourceRectangle.Height); sourceRectangle.Height);
} }
@ -295,7 +295,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
// First process the columns. Since we are not using multiple threads startY and endY // First process the columns. Since we are not using multiple threads startY and endY
// are the upper and lower bounds of the source rectangle. // are the upper and lower bounds of the source rectangle.
// TODO: Using a transposed variant of 'firstPassPixels' could eliminate the need for the WeightsWindow.ComputeWeightedColumnSum() method, and improve speed! // TODO: Using a transposed variant of 'firstPassPixels' could eliminate the need for the WeightsWindow.ComputeWeightedColumnSum() method, and improve speed!
using (Buffer2D<Vector4> firstPassPixels = source.MemoryManager.Allocate2D<Vector4>(width, source.Height)) using (Buffer2D<Vector4> firstPassPixels = source.MemoryAllocator.Allocate2D<Vector4>(width, source.Height))
{ {
firstPassPixels.Buffer.Clear(); firstPassPixels.Buffer.Clear();
@ -308,7 +308,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
{ {
ref Vector4 firstPassRow = ref MemoryMarshal.GetReference(firstPassPixels.GetRowSpan(y)); ref Vector4 firstPassRow = ref MemoryMarshal.GetReference(firstPassPixels.GetRowSpan(y));
Span<TPixel> sourceRow = source.GetPixelRowSpan(y); Span<TPixel> sourceRow = source.GetPixelRowSpan(y);
Span<Vector4> tempRowSpan = tempRowBuffer.Span; Span<Vector4> tempRowSpan = tempRowBuffer.GetSpan();
PixelOperations<TPixel>.Instance.ToVector4(sourceRow, tempRowSpan, sourceRow.Length); PixelOperations<TPixel>.Instance.ToVector4(sourceRow, tempRowSpan, sourceRow.Length);

8
src/ImageSharp/Processing/Transforms/Processors/WeightsBuffer.cs

@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using SixLabors.ImageSharp.Memory; using SixLabors.Memory;
namespace SixLabors.ImageSharp.Processing.Transforms.Processors namespace SixLabors.ImageSharp.Processing.Transforms.Processors
{ {
@ -16,12 +16,12 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="WeightsBuffer"/> class. /// Initializes a new instance of the <see cref="WeightsBuffer"/> class.
/// </summary> /// </summary>
/// <param name="memoryManager">The MemoryManager to use for allocations.</param> /// <param name="memoryAllocator">The <see cref="MemoryAllocator"/> to use for allocations.</param>
/// <param name="sourceSize">The size of the source window</param> /// <param name="sourceSize">The size of the source window</param>
/// <param name="destinationSize">The size of the destination window</param> /// <param name="destinationSize">The size of the destination window</param>
public WeightsBuffer(MemoryManager memoryManager, int sourceSize, int destinationSize) public WeightsBuffer(MemoryAllocator memoryAllocator, int sourceSize, int destinationSize)
{ {
this.dataBuffer = memoryManager.Allocate2D<float>(sourceSize, destinationSize, true); this.dataBuffer = memoryAllocator.Allocate2D<float>(sourceSize, destinationSize, true);
this.Weights = new WeightsWindow[destinationSize]; this.Weights = new WeightsWindow[destinationSize];
} }

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

@ -5,7 +5,7 @@ using System;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory; using SixLabors.Memory;
namespace SixLabors.ImageSharp.Processing.Transforms.Processors namespace SixLabors.ImageSharp.Processing.Transforms.Processors
{ {
@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref float GetStartReference() public ref float GetStartReference()
{ {
Span<float> span = this.buffer.Span; Span<float> span = this.buffer.GetSpan();
return ref span[this.flatStartIndex]; return ref span[this.flatStartIndex];
} }

48
tests/ImageSharp.Benchmarks/Codecs/CopyPixels.cs

@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory; using SixLabors.Memory;
public class CopyPixels : BenchmarkBase public class CopyPixels : BenchmarkBase
{ {
@ -22,23 +22,21 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
using (var source = new Image<Rgba32>(1024, 768)) using (var source = new Image<Rgba32>(1024, 768))
using (var target = new Image<Rgba32>(1024, 768)) using (var target = new Image<Rgba32>(1024, 768))
{ {
using (PixelAccessor<Rgba32> sourcePixels = source.Lock()) Buffer2D<Rgba32> sourcePixels = source.GetRootFramePixelBuffer();
using (PixelAccessor<Rgba32> targetPixels = target.Lock()) Buffer2D<Rgba32> targetPixels = target.GetRootFramePixelBuffer();
{ Parallel.For(
Parallel.For( 0,
0, source.Height,
source.Height, Configuration.Default.ParallelOptions,
Configuration.Default.ParallelOptions, y =>
y => {
for (int x = 0; x < source.Width; x++)
{ {
for (int x = 0; x < source.Width; x++) targetPixels[x, y] = sourcePixels[x, y];
{ }
targetPixels[x, y] = sourcePixels[x, y]; });
}
});
return targetPixels[0, 0]; return targetPixels[0, 0];
}
} }
} }
@ -48,14 +46,13 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
using (var source = new Image<Rgba32>(1024, 768)) using (var source = new Image<Rgba32>(1024, 768))
using (var target = new Image<Rgba32>(1024, 768)) using (var target = new Image<Rgba32>(1024, 768))
{ {
using (PixelAccessor<Rgba32> sourcePixels = source.Lock()) Buffer2D<Rgba32> sourcePixels = source.GetRootFramePixelBuffer();
using (PixelAccessor<Rgba32> targetPixels = target.Lock()) Buffer2D<Rgba32> targetPixels = target.GetRootFramePixelBuffer();
{ Parallel.For(
Parallel.For( 0,
0, source.Height,
source.Height, Configuration.Default.ParallelOptions,
Configuration.Default.ParallelOptions, y =>
y =>
{ {
Span<Rgba32> sourceRow = sourcePixels.GetRowSpan(y); Span<Rgba32> sourceRow = sourcePixels.GetRowSpan(y);
Span<Rgba32> targetRow = targetPixels.GetRowSpan(y); Span<Rgba32> targetRow = targetPixels.GetRowSpan(y);
@ -66,8 +63,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
} }
}); });
return targetPixels[0, 0]; return targetPixels[0, 0];
}
} }
} }

4
tests/ImageSharp.Benchmarks/Codecs/Jpeg/DoubleBufferedStreams.cs

@ -29,8 +29,8 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
this.stream2 = new MemoryStream(this.buffer); this.stream2 = new MemoryStream(this.buffer);
this.stream3 = new MemoryStream(this.buffer); this.stream3 = new MemoryStream(this.buffer);
this.stream4 = new MemoryStream(this.buffer); this.stream4 = new MemoryStream(this.buffer);
this.reader1 = new DoubleBufferedStreamReader(Configuration.Default.MemoryManager, this.stream2); this.reader1 = new DoubleBufferedStreamReader(Configuration.Default.MemoryAllocator, this.stream2);
this.reader2 = new DoubleBufferedStreamReader(Configuration.Default.MemoryManager, this.stream2); this.reader2 = new DoubleBufferedStreamReader(Configuration.Default.MemoryAllocator, this.stream2);
} }
[GlobalCleanup] [GlobalCleanup]

4
tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs

@ -7,7 +7,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Memory; using SixLabors.Memory;
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortClr))]
public class YCbCrColorConversion public class YCbCrColorConversion
@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
} }
// no need to dispose when buffer is not array owner // no need to dispose when buffer is not array owner
buffers[i] = Configuration.Default.MemoryManager.Allocate2D<float>(values.Length, 1); buffers[i] = Configuration.Default.MemoryAllocator.Allocate2D<float>(values.Length, 1);
} }
return buffers; return buffers;

14
tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs

@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Memory; using SixLabors.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortClr))]
@ -23,8 +23,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[GlobalSetup] [GlobalSetup]
public void Setup() public void Setup()
{ {
this.destination = Configuration.Default.MemoryManager.Allocate<TPixel>(this.Count); this.destination = Configuration.Default.MemoryAllocator.Allocate<TPixel>(this.Count);
this.source = Configuration.Default.MemoryManager.Allocate<Vector4>(this.Count); this.source = Configuration.Default.MemoryAllocator.Allocate<Vector4>(this.Count);
} }
[GlobalCleanup] [GlobalCleanup]
@ -37,8 +37,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[Benchmark(Baseline = true)] [Benchmark(Baseline = true)]
public void PerElement() public void PerElement()
{ {
ref Vector4 s = ref MemoryMarshal.GetReference(this.source.Span); ref Vector4 s = ref MemoryMarshal.GetReference(this.source.GetSpan());
ref TPixel d = ref MemoryMarshal.GetReference(this.destination.Span); ref TPixel d = ref MemoryMarshal.GetReference(this.destination.GetSpan());
for (int i = 0; i < this.Count; i++) for (int i = 0; i < this.Count; i++)
{ {
@ -49,13 +49,13 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[Benchmark] [Benchmark]
public void CommonBulk() public void CommonBulk()
{ {
new PixelOperations<TPixel>().PackFromVector4(this.source.Span, this.destination.Span, this.Count); new PixelOperations<TPixel>().PackFromVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
} }
[Benchmark] [Benchmark]
public void OptimizedBulk() public void OptimizedBulk()
{ {
PixelOperations<TPixel>.Instance.PackFromVector4(this.source.Span, this.destination.Span, this.Count); PixelOperations<TPixel>.Instance.PackFromVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
} }
} }

14
tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs

@ -5,7 +5,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Memory; using SixLabors.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
public abstract class PackFromXyzw<TPixel> public abstract class PackFromXyzw<TPixel>
@ -21,8 +21,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[GlobalSetup] [GlobalSetup]
public void Setup() public void Setup()
{ {
this.destination = Configuration.Default.MemoryManager.Allocate<TPixel>(this.Count); this.destination = Configuration.Default.MemoryAllocator.Allocate<TPixel>(this.Count);
this.source = Configuration.Default.MemoryManager.Allocate<byte>(this.Count * 4); this.source = Configuration.Default.MemoryAllocator.Allocate<byte>(this.Count * 4);
} }
[GlobalCleanup] [GlobalCleanup]
@ -35,8 +35,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[Benchmark(Baseline = true)] [Benchmark(Baseline = true)]
public void PerElement() public void PerElement()
{ {
Span<byte> s = this.source.Span; Span<byte> s = this.source.GetSpan();
Span<TPixel> d = this.destination.Span; Span<TPixel> d = this.destination.GetSpan();
for (int i = 0; i < this.Count; i++) for (int i = 0; i < this.Count; i++)
{ {
@ -50,13 +50,13 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[Benchmark] [Benchmark]
public void CommonBulk() public void CommonBulk()
{ {
new PixelOperations<TPixel>().PackFromRgba32Bytes(this.source.Span, this.destination.Span, this.Count); new PixelOperations<TPixel>().PackFromRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
} }
[Benchmark] [Benchmark]
public void OptimizedBulk() public void OptimizedBulk()
{ {
PixelOperations<TPixel>.Instance.PackFromRgba32Bytes(this.source.Span, this.destination.Span, this.Count); PixelOperations<TPixel>.Instance.PackFromRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
} }
} }

14
tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs

@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Memory; using SixLabors.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
public abstract class ToVector4<TPixel> public abstract class ToVector4<TPixel>
@ -22,8 +22,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[GlobalSetup] [GlobalSetup]
public void Setup() public void Setup()
{ {
this.source = Configuration.Default.MemoryManager.Allocate<TPixel>(this.Count); this.source = Configuration.Default.MemoryAllocator.Allocate<TPixel>(this.Count);
this.destination = Configuration.Default.MemoryManager.Allocate<Vector4>(this.Count); this.destination = Configuration.Default.MemoryAllocator.Allocate<Vector4>(this.Count);
} }
[GlobalCleanup] [GlobalCleanup]
@ -36,8 +36,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[Benchmark(Baseline = true)] [Benchmark(Baseline = true)]
public void PerElement() public void PerElement()
{ {
Span<TPixel> s = this.source.Span; Span<TPixel> s = this.source.GetSpan();
Span<Vector4> d = this.destination.Span; Span<Vector4> d = this.destination.GetSpan();
for (int i = 0; i < this.Count; i++) for (int i = 0; i < this.Count; i++)
{ {
@ -49,13 +49,13 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[Benchmark] [Benchmark]
public void CommonBulk() public void CommonBulk()
{ {
new PixelOperations<TPixel>().ToVector4(this.source.Span, this.destination.Span, this.Count); new PixelOperations<TPixel>().ToVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
} }
[Benchmark] [Benchmark]
public void OptimizedBulk() public void OptimizedBulk()
{ {
PixelOperations<TPixel>.Instance.ToVector4(this.source.Span, this.destination.Span, this.Count); PixelOperations<TPixel>.Instance.ToVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
} }
} }

14
tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs

@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Memory; using SixLabors.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
public abstract class ToXyz<TPixel> public abstract class ToXyz<TPixel>
@ -22,8 +22,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[GlobalSetup] [GlobalSetup]
public void Setup() public void Setup()
{ {
this.source = Configuration.Default.MemoryManager.Allocate<TPixel>(this.Count); this.source = Configuration.Default.MemoryAllocator.Allocate<TPixel>(this.Count);
this.destination = Configuration.Default.MemoryManager.Allocate<byte>(this.Count * 3); this.destination = Configuration.Default.MemoryAllocator.Allocate<byte>(this.Count * 3);
} }
[GlobalCleanup] [GlobalCleanup]
@ -36,8 +36,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[Benchmark(Baseline = true)] [Benchmark(Baseline = true)]
public void PerElement() public void PerElement()
{ {
Span<TPixel> s = this.source.Span; Span<TPixel> s = this.source.GetSpan();
Span<byte> d = this.destination.Span; Span<byte> d = this.destination.GetSpan();
var rgb = default(Rgb24); var rgb = default(Rgb24);
@ -55,13 +55,13 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[Benchmark] [Benchmark]
public void CommonBulk() public void CommonBulk()
{ {
new PixelOperations<TPixel>().ToRgb24Bytes(this.source.Span, this.destination.Span, this.Count); new PixelOperations<TPixel>().ToRgb24Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
} }
[Benchmark] [Benchmark]
public void OptimizedBulk() public void OptimizedBulk()
{ {
PixelOperations<TPixel>.Instance.ToRgb24Bytes(this.source.Span, this.destination.Span, this.Count); PixelOperations<TPixel>.Instance.ToRgb24Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
} }
} }

14
tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs

@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
{ {
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Memory; using SixLabors.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
public abstract class ToXyzw<TPixel> public abstract class ToXyzw<TPixel>
@ -24,8 +24,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[GlobalSetup] [GlobalSetup]
public void Setup() public void Setup()
{ {
this.source = Configuration.Default.MemoryManager.Allocate<TPixel>(this.Count); this.source = Configuration.Default.MemoryAllocator.Allocate<TPixel>(this.Count);
this.destination = Configuration.Default.MemoryManager.Allocate<byte>(this.Count * 4); this.destination = Configuration.Default.MemoryAllocator.Allocate<byte>(this.Count * 4);
} }
[GlobalCleanup] [GlobalCleanup]
@ -38,8 +38,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[Benchmark(Baseline = true)] [Benchmark(Baseline = true)]
public void PerElement() public void PerElement()
{ {
Span<TPixel> s = this.source.Span; Span<TPixel> s = this.source.GetSpan();
Span<byte> d = this.destination.Span; Span<byte> d = this.destination.GetSpan();
var rgba = default(Rgba32); var rgba = default(Rgba32);
@ -58,13 +58,13 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[Benchmark] [Benchmark]
public void CommonBulk() public void CommonBulk()
{ {
new PixelOperations<TPixel>().ToRgba32Bytes(this.source.Span, this.destination.Span, this.Count); new PixelOperations<TPixel>().ToRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
} }
[Benchmark] [Benchmark]
public void OptimizedBulk() public void OptimizedBulk()
{ {
PixelOperations<TPixel>.Instance.ToRgba32Bytes(this.source.Span, this.destination.Span, this.Count); PixelOperations<TPixel>.Instance.ToRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
} }
} }

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save