diff --git a/Directory.Build.props b/Directory.Build.props
index b3e18e5a5a..ff43379ab7 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -26,4 +26,39 @@
true
+
+
+
+ $(DefineConstants);SUPPORTS_CRITICALFINALIZER
+
+
+
+
+ $(DefineConstants);SUPPORTS_CRITICALFINALIZER
+
+
+
+
+ $(DefineConstants);SUPPORTS_CRITICALFINALIZER
+
+
+
+
+ $(DefineConstants);SUPPORTS_CRITICALFINALIZER
+
+
+
+
+ $(DefineConstants);SUPPORTS_CRITICALFINALIZER
+
+
+
+
+
+ $(DefineConstants);SUPPORTS_CRITICALFINALIZER
+ $(DefineConstants);SUPPORTS_GC_MEMORYINFO
+
+
+
+
diff --git a/src/ImageSharp/Common/Extensions/StreamExtensions.cs b/src/ImageSharp/Common/Extensions/StreamExtensions.cs
index f2367d488a..1193eccee3 100644
--- a/src/ImageSharp/Common/Extensions/StreamExtensions.cs
+++ b/src/ImageSharp/Common/Extensions/StreamExtensions.cs
@@ -4,7 +4,6 @@
using System;
using System.Buffers;
using System.IO;
-using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp
{
@@ -72,12 +71,6 @@ public static void Skip(this Stream stream, int count)
}
}
- public static void Read(this Stream stream, IManagedByteBuffer buffer)
- => stream.Read(buffer.Array, 0, buffer.Length());
-
- public static void Write(this Stream stream, IManagedByteBuffer buffer)
- => stream.Write(buffer.Array, 0, buffer.Length());
-
#if !SUPPORTS_SPAN_STREAM
// This is a port of the CoreFX implementation and is MIT Licensed:
// https://github.com/dotnet/corefx/blob/17300169760c61a90cab8d913636c1058a30a8c1/src/Common/src/CoreLib/System/IO/Stream.cs#L742
diff --git a/src/ImageSharp/Common/Helpers/Numerics.cs b/src/ImageSharp/Common/Helpers/Numerics.cs
index db65b84cca..2aacc4ff1c 100644
--- a/src/ImageSharp/Common/Helpers/Numerics.cs
+++ b/src/ImageSharp/Common/Helpers/Numerics.cs
@@ -841,14 +841,12 @@ public static int EvenReduceSum(Vector256 accumulator)
/// Note that by convention, input value 0 returns 0 since Log(0) is undefined.
///
/// The value.
- public static int Log2(uint value)
- {
+ public static int Log2(uint value) =>
#if SUPPORTS_BITOPERATIONS
- return BitOperations.Log2(value);
+ BitOperations.Log2(value);
#else
- return Log2SoftwareFallback(value);
+ Log2SoftwareFallback(value);
#endif
- }
#if !SUPPORTS_BITOPERATIONS
///
@@ -874,9 +872,11 @@ private static int Log2SoftwareFallback(uint value)
value |= value >> 16;
// uint.MaxValue >> 27 is always in range [0 - 31] so we use Unsafe.AddByteOffset to avoid bounds check
+ // - Using deBruijn sequence, k=2, n=5 (2^5=32) : 0b_0000_0111_1100_0100_1010_1100_1101_1101u
+ // - uint|long -> IntPtr cast on 32-bit platforms does expensive overflow checks not needed here
return Unsafe.AddByteOffset(
ref MemoryMarshal.GetReference(Log2DeBruijn),
- (IntPtr)(int)((value * 0x07C4ACDDu) >> 27)); // uint|long -> IntPtr cast on 32-bit platforms does expensive overflow checks not needed here
+ (IntPtr)(int)((value * 0x07C4ACDDu) >> 27));
}
#endif
}
diff --git a/src/ImageSharp/Compression/Zlib/Deflater.cs b/src/ImageSharp/Compression/Zlib/Deflater.cs
index 800c96703e..7ff8342aac 100644
--- a/src/ImageSharp/Compression/Zlib/Deflater.cs
+++ b/src/ImageSharp/Compression/Zlib/Deflater.cs
@@ -222,7 +222,7 @@ public void SetLevel(int level)
/// The number of compressed bytes added to the output, or 0 if either
/// or returns true or length is zero.
///
- public int Deflate(byte[] output, int offset, int length)
+ public int Deflate(Span output, int offset, int length)
{
int origLength = length;
diff --git a/src/ImageSharp/Compression/Zlib/DeflaterEngine.cs b/src/ImageSharp/Compression/Zlib/DeflaterEngine.cs
index d3cfa7c3d1..1418b1fa74 100644
--- a/src/ImageSharp/Compression/Zlib/DeflaterEngine.cs
+++ b/src/ImageSharp/Compression/Zlib/DeflaterEngine.cs
@@ -130,9 +130,9 @@ internal sealed unsafe class DeflaterEngine : IDisposable
/// This array contains the part of the uncompressed stream that
/// is of relevance. The current character is indexed by strstart.
///
- private IManagedByteBuffer windowMemoryOwner;
+ private IMemoryOwner windowMemoryOwner;
private MemoryHandle windowMemoryHandle;
- private readonly byte[] window;
+ private readonly Memory window;
private readonly byte* pinnedWindowPointer;
private int maxChain;
@@ -153,8 +153,8 @@ public DeflaterEngine(MemoryAllocator memoryAllocator, DeflateStrategy strategy)
// Create pinned pointers to the various buffers to allow indexing
// without bounds checks.
- this.windowMemoryOwner = memoryAllocator.AllocateManagedByteBuffer(2 * DeflaterConstants.WSIZE);
- this.window = this.windowMemoryOwner.Array;
+ this.windowMemoryOwner = memoryAllocator.Allocate(2 * DeflaterConstants.WSIZE);
+ this.window = this.windowMemoryOwner.Memory;
this.windowMemoryHandle = this.windowMemoryOwner.Memory.Pin();
this.pinnedWindowPointer = (byte*)this.windowMemoryHandle.Pointer;
@@ -303,7 +303,7 @@ public void SetLevel(int level)
case DeflaterConstants.DEFLATE_STORED:
if (this.strstart > this.blockStart)
{
- this.huffman.FlushStoredBlock(this.window, this.blockStart, this.strstart - this.blockStart, false);
+ this.huffman.FlushStoredBlock(this.window.Span, this.blockStart, this.strstart - this.blockStart, false);
this.blockStart = this.strstart;
}
@@ -313,7 +313,7 @@ public void SetLevel(int level)
case DeflaterConstants.DEFLATE_FAST:
if (this.strstart > this.blockStart)
{
- this.huffman.FlushBlock(this.window, this.blockStart, this.strstart - this.blockStart, false);
+ this.huffman.FlushBlock(this.window.Span, this.blockStart, this.strstart - this.blockStart, false);
this.blockStart = this.strstart;
}
@@ -327,7 +327,7 @@ public void SetLevel(int level)
if (this.strstart > this.blockStart)
{
- this.huffman.FlushBlock(this.window, this.blockStart, this.strstart - this.blockStart, false);
+ this.huffman.FlushBlock(this.window.Span, this.blockStart, this.strstart - this.blockStart, false);
this.blockStart = this.strstart;
}
@@ -362,7 +362,8 @@ public void FillWindow()
more = this.inputEnd - this.inputOff;
}
- Buffer.BlockCopy(this.inputBuf, this.inputOff, this.window, this.strstart + this.lookahead, more);
+ // Buffer.BlockCopy(this.inputBuf, this.inputOff, this.window, this.strstart + this.lookahead, more);
+ Unsafe.CopyBlockUnaligned(ref this.window.Span[this.strstart + this.lookahead], ref this.inputBuf[this.inputOff], (uint)more);
this.inputOff += more;
this.lookahead += more;
@@ -426,7 +427,7 @@ private int InsertString()
private void SlideWindow()
{
- Unsafe.CopyBlockUnaligned(ref this.window[0], ref this.window[DeflaterConstants.WSIZE], DeflaterConstants.WSIZE);
+ Unsafe.CopyBlockUnaligned(ref this.window.Span[0], ref this.window.Span[DeflaterConstants.WSIZE], DeflaterConstants.WSIZE);
this.matchStart -= DeflaterConstants.WSIZE;
this.strstart -= DeflaterConstants.WSIZE;
this.blockStart -= DeflaterConstants.WSIZE;
@@ -663,7 +664,7 @@ private bool DeflateStored(bool flush, bool finish)
lastBlock = false;
}
- this.huffman.FlushStoredBlock(this.window, this.blockStart, storedLength, lastBlock);
+ this.huffman.FlushStoredBlock(this.window.Span, this.blockStart, storedLength, lastBlock);
this.blockStart += storedLength;
return !(lastBlock || storedLength == 0);
}
@@ -683,7 +684,7 @@ private bool DeflateFast(bool flush, bool finish)
if (this.lookahead == 0)
{
// We are flushing everything
- this.huffman.FlushBlock(this.window, this.blockStart, this.strstart - this.blockStart, finish);
+ this.huffman.FlushBlock(this.window.Span, this.blockStart, this.strstart - this.blockStart, finish);
this.blockStart = this.strstart;
return false;
}
@@ -743,7 +744,7 @@ private bool DeflateFast(bool flush, bool finish)
if (this.huffman.IsFull())
{
bool lastBlock = finish && (this.lookahead == 0);
- this.huffman.FlushBlock(this.window, this.blockStart, this.strstart - this.blockStart, lastBlock);
+ this.huffman.FlushBlock(this.window.Span, this.blockStart, this.strstart - this.blockStart, lastBlock);
this.blockStart = this.strstart;
return !lastBlock;
}
@@ -771,7 +772,7 @@ private bool DeflateSlow(bool flush, bool finish)
this.prevAvailable = false;
// We are flushing everything
- this.huffman.FlushBlock(this.window, this.blockStart, this.strstart - this.blockStart, finish);
+ this.huffman.FlushBlock(this.window.Span, this.blockStart, this.strstart - this.blockStart, finish);
this.blockStart = this.strstart;
return false;
}
@@ -846,7 +847,7 @@ private bool DeflateSlow(bool flush, bool finish)
}
bool lastBlock = finish && (this.lookahead == 0) && !this.prevAvailable;
- this.huffman.FlushBlock(this.window, this.blockStart, len, lastBlock);
+ this.huffman.FlushBlock(this.window.Span, this.blockStart, len, lastBlock);
this.blockStart += len;
return !lastBlock;
}
diff --git a/src/ImageSharp/Compression/Zlib/DeflaterHuffman.cs b/src/ImageSharp/Compression/Zlib/DeflaterHuffman.cs
index d6892dfd2d..f901d0f6cb 100644
--- a/src/ImageSharp/Compression/Zlib/DeflaterHuffman.cs
+++ b/src/ImageSharp/Compression/Zlib/DeflaterHuffman.cs
@@ -239,7 +239,7 @@ public void CompressBlock()
/// Count of bytes to write
/// True if this is the last block
[MethodImpl(InliningOptions.ShortMethod)]
- public void FlushStoredBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock)
+ public void FlushStoredBlock(Span stored, int storedOffset, int storedLength, bool lastBlock)
{
this.Pending.WriteBits((DeflaterConstants.STORED_BLOCK << 1) + (lastBlock ? 1 : 0), 3);
this.Pending.AlignToByte();
@@ -256,7 +256,7 @@ public void FlushStoredBlock(byte[] stored, int storedOffset, int storedLength,
/// Index of first byte to flush
/// Count of bytes to flush
/// True if this is the last block
- public void FlushBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock)
+ public void FlushBlock(Span stored, int storedOffset, int storedLength, bool lastBlock)
{
this.literalTree.Frequencies[EofSymbol]++;
@@ -286,13 +286,13 @@ public void FlushBlock(byte[] stored, int storedOffset, int storedLength, bool l
+ this.extraBits;
int static_len = this.extraBits;
- ref byte staticLLengthRef = ref MemoryMarshal.GetReference(StaticLLength);
+ ref byte staticLLengthRef = ref MemoryMarshal.GetReference(StaticLLength);
for (int i = 0; i < LiteralNumber; i++)
{
static_len += this.literalTree.Frequencies[i] * Unsafe.Add(ref staticLLengthRef, i);
}
- ref byte staticDLengthRef = ref MemoryMarshal.GetReference(StaticDLength);
+ ref byte staticDLengthRef = ref MemoryMarshal.GetReference(StaticDLength);
for (int i = 0; i < DistanceNumber; i++)
{
static_len += this.distTree.Frequencies[i] * Unsafe.Add(ref staticDLengthRef, i);
@@ -484,7 +484,7 @@ private sealed class Tree : IDisposable
private IMemoryOwner frequenciesMemoryOwner;
private MemoryHandle frequenciesMemoryHandle;
- private IManagedByteBuffer lengthsMemoryOwner;
+ private IMemoryOwner lengthsMemoryOwner;
private MemoryHandle lengthsMemoryHandle;
public Tree(MemoryAllocator memoryAllocator, int elements, int minCodes, int maxLength)
@@ -498,7 +498,7 @@ public Tree(MemoryAllocator memoryAllocator, int elements, int minCodes, int max
this.frequenciesMemoryHandle = this.frequenciesMemoryOwner.Memory.Pin();
this.Frequencies = (short*)this.frequenciesMemoryHandle.Pointer;
- this.lengthsMemoryOwner = memoryAllocator.AllocateManagedByteBuffer(elements);
+ this.lengthsMemoryOwner = memoryAllocator.Allocate(elements);
this.lengthsMemoryHandle = this.lengthsMemoryOwner.Memory.Pin();
this.Length = (byte*)this.lengthsMemoryHandle.Pointer;
diff --git a/src/ImageSharp/Compression/Zlib/DeflaterOutputStream.cs b/src/ImageSharp/Compression/Zlib/DeflaterOutputStream.cs
index cbbf7ea792..2ebcc5fbc8 100644
--- a/src/ImageSharp/Compression/Zlib/DeflaterOutputStream.cs
+++ b/src/ImageSharp/Compression/Zlib/DeflaterOutputStream.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Buffers;
using System.IO;
using SixLabors.ImageSharp.Memory;
@@ -14,8 +15,7 @@ namespace SixLabors.ImageSharp.Compression.Zlib
internal sealed class DeflaterOutputStream : Stream
{
private const int BufferLength = 512;
- private IManagedByteBuffer memoryOwner;
- private readonly byte[] buffer;
+ private IMemoryOwner bufferOwner;
private Deflater deflater;
private readonly Stream rawStream;
private bool isDisposed;
@@ -29,8 +29,7 @@ internal sealed class DeflaterOutputStream : Stream
public DeflaterOutputStream(MemoryAllocator memoryAllocator, Stream rawStream, int compressionLevel)
{
this.rawStream = rawStream;
- this.memoryOwner = memoryAllocator.AllocateManagedByteBuffer(BufferLength);
- this.buffer = this.memoryOwner.Array;
+ this.bufferOwner = memoryAllocator.Allocate(BufferLength);
this.deflater = new Deflater(memoryAllocator, compressionLevel);
}
@@ -49,15 +48,9 @@ public DeflaterOutputStream(MemoryAllocator memoryAllocator, Stream rawStream, i
///
public override long Position
{
- get
- {
- return this.rawStream.Position;
- }
+ get => this.rawStream.Position;
- set
- {
- throw new NotSupportedException();
- }
+ set => throw new NotSupportedException();
}
///
@@ -91,16 +84,17 @@ public override void Write(byte[] buffer, int offset, int count)
private void Deflate(bool flushing)
{
+ Span bufferSpan = this.bufferOwner.GetSpan();
while (flushing || !this.deflater.IsNeedingInput)
{
- int deflateCount = this.deflater.Deflate(this.buffer, 0, BufferLength);
+ int deflateCount = this.deflater.Deflate(bufferSpan, 0, BufferLength);
if (deflateCount <= 0)
{
break;
}
- this.rawStream.Write(this.buffer, 0, deflateCount);
+ this.rawStream.Write(bufferSpan, 0, deflateCount);
}
if (!this.deflater.IsNeedingInput)
@@ -112,15 +106,16 @@ private void Deflate(bool flushing)
private void Finish()
{
this.deflater.Finish();
+ Span bufferSpan = this.bufferOwner.GetSpan();
while (!this.deflater.IsFinished)
{
- int len = this.deflater.Deflate(this.buffer, 0, BufferLength);
+ int len = this.deflater.Deflate(bufferSpan, 0, BufferLength);
if (len <= 0)
{
break;
}
- this.rawStream.Write(this.buffer, 0, len);
+ this.rawStream.Write(bufferSpan, 0, len);
}
if (!this.deflater.IsFinished)
@@ -140,11 +135,11 @@ protected override void Dispose(bool disposing)
{
this.Finish();
this.deflater.Dispose();
- this.memoryOwner.Dispose();
+ this.bufferOwner.Dispose();
}
this.deflater = null;
- this.memoryOwner = null;
+ this.bufferOwner = null;
this.isDisposed = true;
base.Dispose(disposing);
}
diff --git a/src/ImageSharp/Compression/Zlib/DeflaterPendingBuffer.cs b/src/ImageSharp/Compression/Zlib/DeflaterPendingBuffer.cs
index 36dfd92da2..27a5ba912f 100644
--- a/src/ImageSharp/Compression/Zlib/DeflaterPendingBuffer.cs
+++ b/src/ImageSharp/Compression/Zlib/DeflaterPendingBuffer.cs
@@ -13,9 +13,8 @@ namespace SixLabors.ImageSharp.Compression.Zlib
///
internal sealed unsafe class DeflaterPendingBuffer : IDisposable
{
- private readonly byte[] buffer;
private readonly byte* pinnedBuffer;
- private IManagedByteBuffer bufferMemoryOwner;
+ private IMemoryOwner bufferMemoryOwner;
private MemoryHandle bufferMemoryHandle;
private int start;
@@ -29,8 +28,7 @@ internal sealed unsafe class DeflaterPendingBuffer : IDisposable
/// The memory allocator to use for buffer allocations.
public DeflaterPendingBuffer(MemoryAllocator memoryAllocator)
{
- this.bufferMemoryOwner = memoryAllocator.AllocateManagedByteBuffer(DeflaterConstants.PENDING_BUF_SIZE);
- this.buffer = this.bufferMemoryOwner.Array;
+ this.bufferMemoryOwner = memoryAllocator.Allocate(DeflaterConstants.PENDING_BUF_SIZE);
this.bufferMemoryHandle = this.bufferMemoryOwner.Memory.Pin();
this.pinnedBuffer = (byte*)this.bufferMemoryHandle.Pointer;
}
@@ -70,9 +68,9 @@ public void WriteShort(int value)
/// The offset of first byte to write.
/// The number of bytes to write.
[MethodImpl(InliningOptions.ShortMethod)]
- public void WriteBlock(byte[] block, int offset, int length)
+ public void WriteBlock(Span block, int offset, int length)
{
- Unsafe.CopyBlockUnaligned(ref this.buffer[this.end], ref block[offset], unchecked((uint)length));
+ Unsafe.CopyBlockUnaligned(ref this.pinnedBuffer[this.end], ref block[offset], unchecked((uint)length));
this.end += length;
}
@@ -132,11 +130,11 @@ public void WriteShortMSB(int value)
/// Flushes the pending buffer into the given output array.
/// If the output array is to small, only a partial flush is done.
///
- /// The output array.
+ /// The output span.
/// The offset into output array.
/// The maximum number of bytes to store.
/// The number of bytes flushed.
- public int Flush(byte[] output, int offset, int length)
+ public int Flush(Span output, int offset, int length)
{
if (this.BitCount >= 8)
{
@@ -149,13 +147,13 @@ public int Flush(byte[] output, int offset, int length)
{
length = this.end - this.start;
- Unsafe.CopyBlockUnaligned(ref output[offset], ref this.buffer[this.start], unchecked((uint)length));
+ Unsafe.CopyBlockUnaligned(ref output[offset], ref this.pinnedBuffer[this.start], unchecked((uint)length));
this.start = 0;
this.end = 0;
}
else
{
- Unsafe.CopyBlockUnaligned(ref output[offset], ref this.buffer[this.start], unchecked((uint)length));
+ Unsafe.CopyBlockUnaligned(ref output[offset], ref this.pinnedBuffer[this.start], unchecked((uint)length));
this.start += length;
}
diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs
index 129b3a1aa0..4c433b203a 100644
--- a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs
@@ -4,8 +4,6 @@
using System.IO;
using System.Threading;
using System.Threading.Tasks;
-using SixLabors.ImageSharp.IO;
-using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Bmp
diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
index f6fefda485..e6e60e8040 100644
--- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
@@ -817,31 +817,29 @@ private void ReadRgbPalette(Buffer2D pixels, byte[] colors, int
padding = 4 - padding;
}
- using (IManagedByteBuffer row = this.memoryAllocator.AllocateManagedByteBuffer(arrayWidth + padding, AllocationOptions.Clean))
+ using IMemoryOwner row = this.memoryAllocator.Allocate(arrayWidth + padding, AllocationOptions.Clean);
+ TPixel color = default;
+ Span rowSpan = row.GetSpan();
+
+ for (int y = 0; y < height; y++)
{
- TPixel color = default;
- Span rowSpan = row.GetSpan();
+ int newY = Invert(y, height, inverted);
+ this.stream.Read(rowSpan);
+ int offset = 0;
+ Span pixelRow = pixels.GetRowSpan(newY);
- for (int y = 0; y < height; y++)
+ for (int x = 0; x < arrayWidth; x++)
{
- int newY = Invert(y, height, inverted);
- this.stream.Read(row.Array, 0, row.Length());
- int offset = 0;
- Span pixelRow = pixels.GetRowSpan(newY);
-
- for (int x = 0; x < arrayWidth; x++)
+ int colOffset = x * ppb;
+ for (int shift = 0, newX = colOffset; shift < ppb && newX < width; shift++, newX++)
{
- int colOffset = x * ppb;
- for (int shift = 0, newX = colOffset; shift < ppb && newX < width; shift++, newX++)
- {
- int colorIndex = ((rowSpan[offset] >> (8 - bitsPerPixel - (shift * bitsPerPixel))) & mask) * bytesPerColorMapEntry;
-
- color.FromBgr24(Unsafe.As(ref colors[colorIndex]));
- pixelRow[newX] = color;
- }
+ int colorIndex = ((rowSpan[offset] >> (8 - bitsPerPixel - (shift * bitsPerPixel))) & mask) * bytesPerColorMapEntry;
- offset++;
+ color.FromBgr24(Unsafe.As(ref colors[colorIndex]));
+ pixelRow[newX] = color;
}
+
+ offset++;
}
}
}
@@ -873,29 +871,28 @@ private void ReadRgb16(Buffer2D pixels, int width, int height, b
int greenMaskBits = CountBits((uint)greenMask);
int blueMaskBits = CountBits((uint)blueMask);
- using (IManagedByteBuffer buffer = this.memoryAllocator.AllocateManagedByteBuffer(stride))
+ using IMemoryOwner buffer = this.memoryAllocator.Allocate(stride);
+ Span bufferSpan = buffer.GetSpan();
+ for (int y = 0; y < height; y++)
{
- for (int y = 0; y < height; y++)
- {
- this.stream.Read(buffer.Array, 0, stride);
- int newY = Invert(y, height, inverted);
- Span pixelRow = pixels.GetRowSpan(newY);
+ this.stream.Read(bufferSpan);
+ int newY = Invert(y, height, inverted);
+ Span pixelRow = pixels.GetRowSpan(newY);
- int offset = 0;
- for (int x = 0; x < width; x++)
- {
- short temp = BitConverter.ToInt16(buffer.Array, offset);
+ int offset = 0;
+ for (int x = 0; x < width; x++)
+ {
+ short temp = BinaryPrimitives.ReadInt16LittleEndian(bufferSpan.Slice(offset));
- // Rescale values, so the values range from 0 to 255.
- int r = (redMaskBits == 5) ? GetBytesFrom5BitValue((temp & redMask) >> rightShiftRedMask) : GetBytesFrom6BitValue((temp & redMask) >> rightShiftRedMask);
- int g = (greenMaskBits == 5) ? GetBytesFrom5BitValue((temp & greenMask) >> rightShiftGreenMask) : GetBytesFrom6BitValue((temp & greenMask) >> rightShiftGreenMask);
- int b = (blueMaskBits == 5) ? GetBytesFrom5BitValue((temp & blueMask) >> rightShiftBlueMask) : GetBytesFrom6BitValue((temp & blueMask) >> rightShiftBlueMask);
- var rgb = new Rgb24((byte)r, (byte)g, (byte)b);
+ // Rescale values, so the values range from 0 to 255.
+ int r = (redMaskBits == 5) ? GetBytesFrom5BitValue((temp & redMask) >> rightShiftRedMask) : GetBytesFrom6BitValue((temp & redMask) >> rightShiftRedMask);
+ int g = (greenMaskBits == 5) ? GetBytesFrom5BitValue((temp & greenMask) >> rightShiftGreenMask) : GetBytesFrom6BitValue((temp & greenMask) >> rightShiftGreenMask);
+ int b = (blueMaskBits == 5) ? GetBytesFrom5BitValue((temp & blueMask) >> rightShiftBlueMask) : GetBytesFrom6BitValue((temp & blueMask) >> rightShiftBlueMask);
+ var rgb = new Rgb24((byte)r, (byte)g, (byte)b);
- color.FromRgb24(rgb);
- pixelRow[x] = color;
- offset += 2;
- }
+ color.FromRgb24(rgb);
+ pixelRow[x] = color;
+ offset += 2;
}
}
}
@@ -929,19 +926,19 @@ private void ReadRgb24(Buffer2D pixels, int width, int height, b
{
int padding = CalculatePadding(width, 3);
- using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 3, padding))
+ using IMemoryOwner row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 3, padding);
+ Span rowSpan = row.GetSpan();
+
+ for (int y = 0; y < height; y++)
{
- for (int y = 0; y < height; y++)
- {
- this.stream.Read(row);
- int newY = Invert(y, height, inverted);
- Span pixelSpan = pixels.GetRowSpan(newY);
- PixelOperations.Instance.FromBgr24Bytes(
- this.Configuration,
- row.GetSpan(),
- pixelSpan,
- width);
- }
+ this.stream.Read(rowSpan);
+ int newY = Invert(y, height, inverted);
+ Span pixelSpan = pixels.GetRowSpan(newY);
+ PixelOperations.Instance.FromBgr24Bytes(
+ this.Configuration,
+ rowSpan,
+ pixelSpan,
+ width);
}
}
@@ -958,19 +955,19 @@ private void ReadRgb32Fast(Buffer2D pixels, int width, int heigh
{
int padding = CalculatePadding(width, 4);
- using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 4, padding))
+ using IMemoryOwner row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 4, padding);
+ Span rowSpan = row.GetSpan();
+
+ for (int y = 0; y < height; y++)
{
- for (int y = 0; y < height; y++)
- {
- this.stream.Read(row);
- int newY = Invert(y, height, inverted);
- Span pixelSpan = pixels.GetRowSpan(newY);
- PixelOperations.Instance.FromBgra32Bytes(
- this.Configuration,
- row.GetSpan(),
- pixelSpan,
- width);
- }
+ this.stream.Read(rowSpan);
+ int newY = Invert(y, height, inverted);
+ Span pixelSpan = pixels.GetRowSpan(newY);
+ PixelOperations.Instance.FromBgra32Bytes(
+ this.Configuration,
+ rowSpan,
+ pixelSpan,
+ width);
}
}
@@ -988,86 +985,85 @@ private void ReadRgb32Slow(Buffer2D pixels, int width, int heigh
{
int padding = CalculatePadding(width, 4);
- using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 4, padding))
- using (IMemoryOwner bgraRow = this.memoryAllocator.Allocate(width))
+ using IMemoryOwner row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 4, padding);
+ using IMemoryOwner bgraRow = this.memoryAllocator.Allocate(width);
+ Span rowSpan = row.GetSpan();
+ Span bgraRowSpan = bgraRow.GetSpan();
+ long currentPosition = this.stream.Position;
+ bool hasAlpha = false;
+
+ // Loop though the rows checking each pixel. We start by assuming it's
+ // an BGR0 image. If we hit a non-zero alpha value, then we know it's
+ // actually a BGRA image, and change tactics accordingly.
+ for (int y = 0; y < height; y++)
{
- Span bgraRowSpan = bgraRow.GetSpan();
- long currentPosition = this.stream.Position;
- bool hasAlpha = false;
-
- // Loop though the rows checking each pixel. We start by assuming it's
- // an BGR0 image. If we hit a non-zero alpha value, then we know it's
- // actually a BGRA image, and change tactics accordingly.
- for (int y = 0; y < height; y++)
- {
- this.stream.Read(row);
+ this.stream.Read(rowSpan);
- PixelOperations.Instance.FromBgra32Bytes(
- this.Configuration,
- row.GetSpan(),
- bgraRowSpan,
- width);
+ PixelOperations.Instance.FromBgra32Bytes(
+ this.Configuration,
+ rowSpan,
+ bgraRowSpan,
+ width);
- // Check each pixel in the row to see if it has an alpha value.
- for (int x = 0; x < width; x++)
- {
- Bgra32 bgra = bgraRowSpan[x];
- if (bgra.A > 0)
- {
- hasAlpha = true;
- break;
- }
- }
-
- if (hasAlpha)
+ // Check each pixel in the row to see if it has an alpha value.
+ for (int x = 0; x < width; x++)
+ {
+ Bgra32 bgra = bgraRowSpan[x];
+ if (bgra.A > 0)
{
+ hasAlpha = true;
break;
}
}
- // Reset our stream for a second pass.
- this.stream.Position = currentPosition;
-
- // Process the pixels in bulk taking the raw alpha component value.
if (hasAlpha)
{
- for (int y = 0; y < height; y++)
- {
- this.stream.Read(row);
-
- int newY = Invert(y, height, inverted);
- Span pixelSpan = pixels.GetRowSpan(newY);
-
- PixelOperations.Instance.FromBgra32Bytes(
- this.Configuration,
- row.GetSpan(),
- pixelSpan,
- width);
- }
-
- return;
+ break;
}
+ }
+
+ // Reset our stream for a second pass.
+ this.stream.Position = currentPosition;
- // Slow path. We need to set each alpha component value to fully opaque.
+ // Process the pixels in bulk taking the raw alpha component value.
+ if (hasAlpha)
+ {
for (int y = 0; y < height; y++)
{
- this.stream.Read(row);
- PixelOperations.Instance.FromBgra32Bytes(
- this.Configuration,
- row.GetSpan(),
- bgraRowSpan,
- width);
+ this.stream.Read(rowSpan);
int newY = Invert(y, height, inverted);
Span pixelSpan = pixels.GetRowSpan(newY);
- for (int x = 0; x < width; x++)
- {
- Bgra32 bgra = bgraRowSpan[x];
- bgra.A = byte.MaxValue;
- ref TPixel pixel = ref pixelSpan[x];
- pixel.FromBgra32(bgra);
- }
+ PixelOperations.Instance.FromBgra32Bytes(
+ this.Configuration,
+ rowSpan,
+ pixelSpan,
+ width);
+ }
+
+ return;
+ }
+
+ // Slow path. We need to set each alpha component value to fully opaque.
+ for (int y = 0; y < height; y++)
+ {
+ this.stream.Read(rowSpan);
+ PixelOperations.Instance.FromBgra32Bytes(
+ this.Configuration,
+ rowSpan,
+ bgraRowSpan,
+ width);
+
+ int newY = Invert(y, height, inverted);
+ Span pixelSpan = pixels.GetRowSpan(newY);
+
+ for (int x = 0; x < width; x++)
+ {
+ Bgra32 bgra = bgraRowSpan[x];
+ bgra.A = byte.MaxValue;
+ ref TPixel pixel = ref pixelSpan[x];
+ pixel.FromBgra32(bgra);
}
}
}
@@ -1108,44 +1104,43 @@ private void ReadRgb32BitFields(Buffer2D pixels, int width, int
bool unusualBitMask = bitsRedMask > 8 || bitsGreenMask > 8 || bitsBlueMask > 8 || invMaxValueAlpha > 8;
- using (IManagedByteBuffer buffer = this.memoryAllocator.AllocateManagedByteBuffer(stride))
+ using IMemoryOwner buffer = this.memoryAllocator.Allocate(stride);
+ Span bufferSpan = buffer.GetSpan();
+
+ for (int y = 0; y < height; y++)
{
- for (int y = 0; y < height; y++)
- {
- this.stream.Read(buffer.Array, 0, stride);
- int newY = Invert(y, height, inverted);
- Span pixelRow = pixels.GetRowSpan(newY);
+ this.stream.Read(bufferSpan);
+ int newY = Invert(y, height, inverted);
+ Span pixelRow = pixels.GetRowSpan(newY);
- int offset = 0;
- for (int x = 0; x < width; x++)
+ int offset = 0;
+ for (int x = 0; x < width; x++)
+ {
+ uint temp = BinaryPrimitives.ReadUInt32LittleEndian(bufferSpan.Slice(offset));
+ if (unusualBitMask)
{
- uint temp = BitConverter.ToUInt32(buffer.Array, offset);
-
- if (unusualBitMask)
- {
- uint r = (uint)(temp & redMask) >> rightShiftRedMask;
- uint g = (uint)(temp & greenMask) >> rightShiftGreenMask;
- uint b = (uint)(temp & blueMask) >> rightShiftBlueMask;
- float alpha = alphaMask != 0 ? invMaxValueAlpha * ((uint)(temp & alphaMask) >> rightShiftAlphaMask) : 1.0f;
- var vector4 = new Vector4(
- r * invMaxValueRed,
- g * invMaxValueGreen,
- b * invMaxValueBlue,
- alpha);
- color.FromVector4(vector4);
- }
- else
- {
- byte r = (byte)((temp & redMask) >> rightShiftRedMask);
- byte g = (byte)((temp & greenMask) >> rightShiftGreenMask);
- byte b = (byte)((temp & blueMask) >> rightShiftBlueMask);
- byte a = alphaMask != 0 ? (byte)((temp & alphaMask) >> rightShiftAlphaMask) : (byte)255;
- color.FromRgba32(new Rgba32(r, g, b, a));
- }
-
- pixelRow[x] = color;
- offset += 4;
+ uint r = (uint)(temp & redMask) >> rightShiftRedMask;
+ uint g = (uint)(temp & greenMask) >> rightShiftGreenMask;
+ uint b = (uint)(temp & blueMask) >> rightShiftBlueMask;
+ float alpha = alphaMask != 0 ? invMaxValueAlpha * ((uint)(temp & alphaMask) >> rightShiftAlphaMask) : 1.0f;
+ var vector4 = new Vector4(
+ r * invMaxValueRed,
+ g * invMaxValueGreen,
+ b * invMaxValueBlue,
+ alpha);
+ color.FromVector4(vector4);
}
+ else
+ {
+ byte r = (byte)((temp & redMask) >> rightShiftRedMask);
+ byte g = (byte)((temp & greenMask) >> rightShiftGreenMask);
+ byte b = (byte)((temp & blueMask) >> rightShiftBlueMask);
+ byte a = alphaMask != 0 ? (byte)((temp & alphaMask) >> rightShiftAlphaMask) : (byte)255;
+ color.FromRgba32(new Rgba32(r, g, b, a));
+ }
+
+ pixelRow[x] = color;
+ offset += 4;
}
}
}
diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
index b407ad221f..e9cede671e 100644
--- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
@@ -257,7 +257,7 @@ private void WriteImage(Stream stream, ImageFrame image)
}
}
- private IManagedByteBuffer AllocateRow(int width, int bytesPerPixel) => this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, bytesPerPixel, this.padding);
+ private IMemoryOwner AllocateRow(int width, int bytesPerPixel) => this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, bytesPerPixel, this.padding);
///
/// Writes the 32bit color palette to the stream.
@@ -268,18 +268,18 @@ private void WriteImage(Stream stream, ImageFrame image)
private void Write32Bit(Stream stream, Buffer2D pixels)
where TPixel : unmanaged, IPixel
{
- using (IManagedByteBuffer row = this.AllocateRow(pixels.Width, 4))
+ using IMemoryOwner row = this.AllocateRow(pixels.Width, 4);
+ Span rowSpan = row.GetSpan();
+
+ for (int y = pixels.Height - 1; y >= 0; y--)
{
- for (int y = pixels.Height - 1; y >= 0; y--)
- {
- Span pixelSpan = pixels.GetRowSpan(y);
- PixelOperations.Instance.ToBgra32Bytes(
- this.configuration,
- pixelSpan,
- row.GetSpan(),
- pixelSpan.Length);
- stream.Write(row.Array, 0, row.Length());
- }
+ Span pixelSpan = pixels.GetRowSpan(y);
+ PixelOperations.Instance.ToBgra32Bytes(
+ this.configuration,
+ pixelSpan,
+ row.GetSpan(),
+ pixelSpan.Length);
+ stream.Write(rowSpan);
}
}
@@ -294,18 +294,18 @@ private void Write24Bit(Stream stream, Buffer2D pixels)
{
int width = pixels.Width;
int rowBytesWithoutPadding = width * 3;
- using (IManagedByteBuffer row = this.AllocateRow(width, 3))
+ using IMemoryOwner row = this.AllocateRow(width, 3);
+ Span rowSpan = row.GetSpan();
+
+ for (int y = pixels.Height - 1; y >= 0; y--)
{
- for (int y = pixels.Height - 1; y >= 0; y--)
- {
- Span pixelSpan = pixels.GetRowSpan(y);
- PixelOperations.Instance.ToBgr24Bytes(
- this.configuration,
- pixelSpan,
- row.Slice(0, rowBytesWithoutPadding),
- width);
- stream.Write(row.Array, 0, row.Length());
- }
+ Span pixelSpan = pixels.GetRowSpan(y);
+ PixelOperations.Instance.ToBgr24Bytes(
+ this.configuration,
+ pixelSpan,
+ row.Slice(0, rowBytesWithoutPadding),
+ width);
+ stream.Write(rowSpan);
}
}
@@ -320,20 +320,20 @@ private void Write16Bit(Stream stream, Buffer2D pixels)
{
int width = pixels.Width;
int rowBytesWithoutPadding = width * 2;
- using (IManagedByteBuffer row = this.AllocateRow(width, 2))
+ using IMemoryOwner row = this.AllocateRow(width, 2);
+ Span rowSpan = row.GetSpan();
+
+ for (int y = pixels.Height - 1; y >= 0; y--)
{
- for (int y = pixels.Height - 1; y >= 0; y--)
- {
- Span pixelSpan = pixels.GetRowSpan(y);
+ Span pixelSpan = pixels.GetRowSpan(y);
- PixelOperations.Instance.ToBgra5551Bytes(
- this.configuration,
- pixelSpan,
- row.Slice(0, rowBytesWithoutPadding),
- pixelSpan.Length);
+ PixelOperations.Instance.ToBgra5551Bytes(
+ this.configuration,
+ pixelSpan,
+ row.Slice(0, rowBytesWithoutPadding),
+ pixelSpan.Length);
- stream.Write(row.Array, 0, row.Length());
- }
+ stream.Write(rowSpan);
}
}
@@ -347,17 +347,16 @@ private void Write8Bit(Stream stream, ImageFrame image)
where TPixel : unmanaged, IPixel
{
bool isL8 = typeof(TPixel) == typeof(L8);
- using (IMemoryOwner colorPaletteBuffer = this.memoryAllocator.AllocateManagedByteBuffer(ColorPaletteSize8Bit, AllocationOptions.Clean))
+ using IMemoryOwner colorPaletteBuffer = this.memoryAllocator.Allocate(ColorPaletteSize8Bit, AllocationOptions.Clean);
+ Span colorPalette = colorPaletteBuffer.GetSpan();
+
+ if (isL8)
{
- Span colorPalette = colorPaletteBuffer.GetSpan();
- if (isL8)
- {
- this.Write8BitGray(stream, image, colorPalette);
- }
- else
- {
- this.Write8BitColor(stream, image, colorPalette);
- }
+ this.Write8BitGray(stream, image, colorPalette);
+ }
+ else
+ {
+ this.Write8BitColor(stream, image, colorPalette);
}
}
@@ -441,7 +440,7 @@ private void Write4BitColor(Stream stream, ImageFrame image)
MaxColors = 16
});
using IndexedImageFrame quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(image, image.Bounds());
- using IMemoryOwner colorPaletteBuffer = this.memoryAllocator.AllocateManagedByteBuffer(ColorPaletteSize4Bit, AllocationOptions.Clean);
+ using IMemoryOwner colorPaletteBuffer = this.memoryAllocator.Allocate(ColorPaletteSize4Bit, AllocationOptions.Clean);
Span colorPalette = colorPaletteBuffer.GetSpan();
ReadOnlySpan quantizedColorPalette = quantized.Palette.Span;
@@ -485,7 +484,7 @@ private void Write1BitColor(Stream stream, ImageFrame image)
MaxColors = 2
});
using IndexedImageFrame quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(image, image.Bounds());
- using IMemoryOwner colorPaletteBuffer = this.memoryAllocator.AllocateManagedByteBuffer(ColorPaletteSize1Bit, AllocationOptions.Clean);
+ using IMemoryOwner colorPaletteBuffer = this.memoryAllocator.Allocate(ColorPaletteSize1Bit, AllocationOptions.Clean);
Span colorPalette = colorPaletteBuffer.GetSpan();
ReadOnlySpan quantizedColorPalette = quantized.Palette.Span;
diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
index 2f6b45aff9..c25ac73aaa 100644
--- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
+++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
@@ -2,12 +2,12 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Buffers;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
-using System.Threading.Tasks;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
@@ -33,7 +33,7 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
///
/// The global color table.
///
- private IManagedByteBuffer globalColorTable;
+ private IMemoryOwner globalColorTable;
///
/// The area to restore.
@@ -323,12 +323,12 @@ private void ReadComments()
continue;
}
- using (IManagedByteBuffer commentsBuffer = this.MemoryAllocator.AllocateManagedByteBuffer(length))
- {
- this.stream.Read(commentsBuffer.Array, 0, length);
- string commentPart = GifConstants.Encoding.GetString(commentsBuffer.Array, 0, length);
- stringBuilder.Append(commentPart);
- }
+ using IMemoryOwner commentsBuffer = this.MemoryAllocator.Allocate(length);
+ Span commentsSpan = commentsBuffer.GetSpan();
+ this.stream.Read(commentsSpan);
+
+ string commentPart = GifConstants.Encoding.GetString(commentsSpan);
+ stringBuilder.Append(commentPart);
}
if (stringBuilder.Length > 0)
@@ -348,7 +348,7 @@ private void ReadFrame(ref Image image, ref ImageFrame p
{
this.ReadImageDescriptor();
- IManagedByteBuffer localColorTable = null;
+ IMemoryOwner localColorTable = null;
Buffer2D indices = null;
try
{
@@ -356,8 +356,8 @@ private void ReadFrame(ref Image image, ref ImageFrame p
if (this.imageDescriptor.LocalColorTableFlag)
{
int length = this.imageDescriptor.LocalColorTableSize * 3;
- localColorTable = this.Configuration.MemoryAllocator.AllocateManagedByteBuffer(length, AllocationOptions.Clean);
- this.stream.Read(localColorTable.Array, 0, length);
+ localColorTable = this.Configuration.MemoryAllocator.Allocate(length, AllocationOptions.Clean);
+ this.stream.Read(localColorTable.GetSpan());
}
indices = this.Configuration.MemoryAllocator.Allocate2D(this.imageDescriptor.Width, this.imageDescriptor.Height, AllocationOptions.Clean);
@@ -621,10 +621,10 @@ private void ReadLogicalScreenDescriptorAndGlobalColorTable(BufferedReadStream s
int globalColorTableLength = this.logicalScreenDescriptor.GlobalColorTableSize * 3;
this.gifMetadata.GlobalColorTableLength = globalColorTableLength;
- this.globalColorTable = this.MemoryAllocator.AllocateManagedByteBuffer(globalColorTableLength, AllocationOptions.Clean);
+ this.globalColorTable = this.MemoryAllocator.Allocate(globalColorTableLength, AllocationOptions.Clean);
// Read the global color table data from the stream
- stream.Read(this.globalColorTable.Array, 0, globalColorTableLength);
+ stream.Read(this.globalColorTable.GetSpan());
}
}
}
diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs
index 585f87b3e8..d75a23ebf0 100644
--- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs
+++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs
@@ -475,14 +475,14 @@ private void WriteColorTable(IndexedImageFrame image, Stream str
// The maximum number of colors for the bit depth
int colorTableLength = ColorNumerics.GetColorCountForBitDepth(this.bitDepth) * Unsafe.SizeOf();
- using IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength, AllocationOptions.Clean);
+ using IMemoryOwner colorTable = this.memoryAllocator.Allocate(colorTableLength, AllocationOptions.Clean);
PixelOperations.Instance.ToRgb24Bytes(
this.configuration,
image.Palette.Span,
colorTable.GetSpan(),
image.Palette.Length);
- stream.Write(colorTable.Array, 0, colorTableLength);
+ stream.Write(colorTable.GetSpan());
}
///
diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
index 8571cf0ec3..0a6312e4c7 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Buffers;
using System.Buffers.Binary;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -928,9 +929,10 @@ private void ProcessDefineHuffmanTablesMarker(BufferedReadStream stream, int rem
{
int length = remaining;
- using (IManagedByteBuffer huffmanData = this.Configuration.MemoryAllocator.AllocateManagedByteBuffer(256, AllocationOptions.Clean))
+ using (IMemoryOwner huffmanData = this.Configuration.MemoryAllocator.Allocate(256, AllocationOptions.Clean))
{
- ref byte huffmanDataRef = ref MemoryMarshal.GetReference(huffmanData.GetSpan());
+ Span huffmanDataSpan = huffmanData.GetSpan();
+ ref byte huffmanDataRef = ref MemoryMarshal.GetReference(huffmanDataSpan);
for (int i = 2; i < remaining;)
{
byte huffmanTableSpec = (byte)stream.ReadByte();
@@ -949,9 +951,9 @@ private void ProcessDefineHuffmanTablesMarker(BufferedReadStream stream, int rem
JpegThrowHelper.ThrowInvalidImageContentException("Bad Huffman Table index.");
}
- stream.Read(huffmanData.Array, 0, 16);
+ stream.Read(huffmanDataSpan, 0, 16);
- using (IManagedByteBuffer codeLengths = this.Configuration.MemoryAllocator.AllocateManagedByteBuffer(17, AllocationOptions.Clean))
+ using (IMemoryOwner codeLengths = this.Configuration.MemoryAllocator.Allocate(17, AllocationOptions.Clean))
{
ref byte codeLengthsRef = ref MemoryMarshal.GetReference(codeLengths.GetSpan());
int codeLengthSum = 0;
@@ -968,9 +970,10 @@ private void ProcessDefineHuffmanTablesMarker(BufferedReadStream stream, int rem
JpegThrowHelper.ThrowInvalidImageContentException("Huffman table has excessive length.");
}
- using (IManagedByteBuffer huffmanValues = this.Configuration.MemoryAllocator.AllocateManagedByteBuffer(256, AllocationOptions.Clean))
+ using (IMemoryOwner huffmanValues = this.Configuration.MemoryAllocator.Allocate(256, AllocationOptions.Clean))
{
- stream.Read(huffmanValues.Array, 0, codeLengthSum);
+ Span huffmanValuesSpan = huffmanValues.GetSpan();
+ stream.Read(huffmanValuesSpan, 0, codeLengthSum);
i += 17 + codeLengthSum;
@@ -978,7 +981,7 @@ private void ProcessDefineHuffmanTablesMarker(BufferedReadStream stream, int rem
tableType == 0 ? this.dcHuffmanTables : this.acHuffmanTables,
tableIndex,
codeLengths.GetSpan(),
- huffmanValues.GetSpan());
+ huffmanValuesSpan);
}
}
}
diff --git a/src/ImageSharp/Formats/Png/PngChunk.cs b/src/ImageSharp/Formats/Png/PngChunk.cs
index fd11ba1b6b..7b5f390f12 100644
--- a/src/ImageSharp/Formats/Png/PngChunk.cs
+++ b/src/ImageSharp/Formats/Png/PngChunk.cs
@@ -1,7 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
-using SixLabors.ImageSharp.Memory;
+using System.Buffers;
namespace SixLabors.ImageSharp.Formats.Png
{
@@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Png
///
internal readonly struct PngChunk
{
- public PngChunk(int length, PngChunkType type, IManagedByteBuffer data = null)
+ public PngChunk(int length, PngChunkType type, IMemoryOwner data = null)
{
this.Length = length;
this.Type = type;
@@ -35,7 +35,7 @@ public PngChunk(int length, PngChunkType type, IManagedByteBuffer data = null)
/// Gets the data bytes appropriate to the chunk type, if any.
/// This field can be of zero length or null.
///
- public IManagedByteBuffer Data { get; }
+ public IMemoryOwner Data { get; }
///
/// Gets a value indicating whether the given chunk is critical to decoding
diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
index c2c336c039..309de77f02 100644
--- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Buffers;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.IO;
@@ -84,12 +85,12 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
///
/// Previous scanline processed.
///
- private IManagedByteBuffer previousScanline;
+ private IMemoryOwner previousScanline;
///
/// The current scanline that is being processed.
///
- private IManagedByteBuffer scanline;
+ private IMemoryOwner scanline;
///
/// The index of the current scanline being processed.
@@ -149,7 +150,7 @@ public Image Decode(BufferedReadStream stream, CancellationToken
switch (chunk.Type)
{
case PngChunkType.Header:
- this.ReadHeaderChunk(pngMetadata, chunk.Data.Array);
+ this.ReadHeaderChunk(pngMetadata, chunk.Data.GetSpan());
break;
case PngChunkType.Physical:
this.ReadPhysicalChunk(metadata, chunk.Data.GetSpan());
@@ -167,30 +168,30 @@ public Image Decode(BufferedReadStream stream, CancellationToken
break;
case PngChunkType.Palette:
- var pal = new byte[chunk.Length];
- Buffer.BlockCopy(chunk.Data.Array, 0, pal, 0, chunk.Length);
+ byte[] pal = new byte[chunk.Length];
+ chunk.Data.GetSpan().CopyTo(pal);
this.palette = pal;
break;
case PngChunkType.Transparency:
- var alpha = new byte[chunk.Length];
- Buffer.BlockCopy(chunk.Data.Array, 0, alpha, 0, chunk.Length);
+ byte[] alpha = new byte[chunk.Length];
+ chunk.Data.GetSpan().CopyTo(alpha);
this.paletteAlpha = alpha;
this.AssignTransparentMarkers(alpha, pngMetadata);
break;
case PngChunkType.Text:
- this.ReadTextChunk(pngMetadata, chunk.Data.Array.AsSpan(0, chunk.Length));
+ this.ReadTextChunk(pngMetadata, chunk.Data.GetSpan());
break;
case PngChunkType.CompressedText:
- this.ReadCompressedTextChunk(pngMetadata, chunk.Data.Array.AsSpan(0, chunk.Length));
+ this.ReadCompressedTextChunk(pngMetadata, chunk.Data.GetSpan());
break;
case PngChunkType.InternationalText:
- this.ReadInternationalTextChunk(pngMetadata, chunk.Data.Array.AsSpan(0, chunk.Length));
+ this.ReadInternationalTextChunk(pngMetadata, chunk.Data.GetSpan());
break;
case PngChunkType.Exif:
if (!this.ignoreMetadata)
{
- var exifData = new byte[chunk.Length];
- Buffer.BlockCopy(chunk.Data.Array, 0, exifData, 0, chunk.Length);
+ byte[] exifData = new byte[chunk.Length];
+ chunk.Data.GetSpan().CopyTo(exifData);
metadata.ExifProfile = new ExifProfile(exifData);
}
@@ -239,7 +240,7 @@ public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancella
switch (chunk.Type)
{
case PngChunkType.Header:
- this.ReadHeaderChunk(pngMetadata, chunk.Data.Array);
+ this.ReadHeaderChunk(pngMetadata, chunk.Data.GetSpan());
break;
case PngChunkType.Physical:
this.ReadPhysicalChunk(metadata, chunk.Data.GetSpan());
@@ -251,19 +252,19 @@ public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancella
this.SkipChunkDataAndCrc(chunk);
break;
case PngChunkType.Text:
- this.ReadTextChunk(pngMetadata, chunk.Data.Array.AsSpan(0, chunk.Length));
+ this.ReadTextChunk(pngMetadata, chunk.Data.GetSpan());
break;
case PngChunkType.CompressedText:
- this.ReadCompressedTextChunk(pngMetadata, chunk.Data.Array.AsSpan(0, chunk.Length));
+ this.ReadCompressedTextChunk(pngMetadata, chunk.Data.GetSpan());
break;
case PngChunkType.InternationalText:
- this.ReadInternationalTextChunk(pngMetadata, chunk.Data.Array.AsSpan(0, chunk.Length));
+ this.ReadInternationalTextChunk(pngMetadata, chunk.Data.GetSpan());
break;
case PngChunkType.Exif:
if (!this.ignoreMetadata)
{
- var exifData = new byte[chunk.Length];
- Buffer.BlockCopy(chunk.Data.Array, 0, exifData, 0, chunk.Length);
+ byte[] exifData = new byte[chunk.Length];
+ chunk.Data.GetSpan().CopyTo(exifData);
metadata.ExifProfile = new ExifProfile(exifData);
}
@@ -312,7 +313,7 @@ private static byte ReadByteLittleEndian(ReadOnlySpan buffer, int offset)
/// The number of bits per value.
/// The new array.
/// The resulting array.
- private bool TryScaleUpTo8BitArray(ReadOnlySpan source, int bytesPerScanline, int bits, out IManagedByteBuffer buffer)
+ private bool TryScaleUpTo8BitArray(ReadOnlySpan source, int bytesPerScanline, int bits, out IMemoryOwner buffer)
{
if (bits >= 8)
{
@@ -320,9 +321,9 @@ private bool TryScaleUpTo8BitArray(ReadOnlySpan source, int bytesPerScanli
return false;
}
- buffer = this.memoryAllocator.AllocateManagedByteBuffer(bytesPerScanline * 8 / bits, AllocationOptions.Clean);
+ buffer = this.memoryAllocator.Allocate(bytesPerScanline * 8 / bits, AllocationOptions.Clean);
ref byte sourceRef = ref MemoryMarshal.GetReference(source);
- ref byte resultRef = ref buffer.Array[0];
+ ref byte resultRef = ref MemoryMarshal.GetReference(buffer.GetSpan());
int mask = 0xFF >> (8 - bits);
int resultOffset = 0;
@@ -392,8 +393,8 @@ private void InitializeImage(ImageMetadata metadata, out Image i
this.bytesPerSample = this.header.BitDepth / 8;
}
- this.previousScanline = this.memoryAllocator.AllocateManagedByteBuffer(this.bytesPerScanline, AllocationOptions.Clean);
- this.scanline = this.Configuration.MemoryAllocator.AllocateManagedByteBuffer(this.bytesPerScanline, AllocationOptions.Clean);
+ this.previousScanline = this.memoryAllocator.Allocate(this.bytesPerScanline, AllocationOptions.Clean);
+ this.scanline = this.Configuration.MemoryAllocator.Allocate(this.bytesPerScanline, AllocationOptions.Clean);
}
///
@@ -504,7 +505,7 @@ private void DecodePixelData(DeflateStream compressedStream, ImageFrame<
{
while (this.currentRow < this.header.Height)
{
- int bytesRead = compressedStream.Read(this.scanline.Array, this.currentRowBytesRead, this.bytesPerScanline - this.currentRowBytesRead);
+ int bytesRead = compressedStream.Read(this.scanline.GetSpan(), this.currentRowBytesRead, this.bytesPerScanline - this.currentRowBytesRead);
this.currentRowBytesRead += bytesRead;
if (this.currentRowBytesRead < this.bytesPerScanline)
{
@@ -576,7 +577,7 @@ private void DecodeInterlacedPixelData(DeflateStream compressedStream, I
while (this.currentRow < this.header.Height)
{
- int bytesRead = compressedStream.Read(this.scanline.Array, this.currentRowBytesRead, bytesPerInterlaceScanline - this.currentRowBytesRead);
+ int bytesRead = compressedStream.Read(this.scanline.GetSpan(), this.currentRowBytesRead, bytesPerInterlaceScanline - this.currentRowBytesRead);
this.currentRowBytesRead += bytesRead;
if (this.currentRowBytesRead < bytesPerInterlaceScanline)
{
@@ -653,7 +654,7 @@ private void ProcessDefilteredScanline(ReadOnlySpan defilteredScan
ReadOnlySpan trimmed = defilteredScanline.Slice(1, defilteredScanline.Length - 1);
// Convert 1, 2, and 4 bit pixel data into the 8 bit equivalent.
- ReadOnlySpan scanlineSpan = this.TryScaleUpTo8BitArray(trimmed, this.bytesPerScanline - 1, this.header.BitDepth, out IManagedByteBuffer buffer)
+ ReadOnlySpan scanlineSpan = this.TryScaleUpTo8BitArray(trimmed, this.bytesPerScanline - 1, this.header.BitDepth, out IMemoryOwner buffer)
? buffer.GetSpan()
: trimmed;
@@ -735,7 +736,7 @@ private void ProcessInterlacedDefilteredScanline(ReadOnlySpan defi
ReadOnlySpan trimmed = defilteredScanline.Slice(1, defilteredScanline.Length - 1);
// Convert 1, 2, and 4 bit pixel data into the 8 bit equivalent.
- ReadOnlySpan scanlineSpan = this.TryScaleUpTo8BitArray(trimmed, this.bytesPerScanline, this.header.BitDepth, out IManagedByteBuffer buffer)
+ ReadOnlySpan scanlineSpan = this.TryScaleUpTo8BitArray(trimmed, this.bytesPerScanline, this.header.BitDepth, out IMemoryOwner buffer)
? buffer.GetSpan()
: trimmed;
@@ -1189,12 +1190,12 @@ private void SkipChunkDataAndCrc(in PngChunk chunk)
///
/// The length of the chunk data to read.
[MethodImpl(InliningOptions.ShortMethod)]
- private IManagedByteBuffer ReadChunkData(int length)
+ private IMemoryOwner ReadChunkData(int length)
{
// We rent the buffer here to return it afterwards in Decode()
- IManagedByteBuffer buffer = this.Configuration.MemoryAllocator.AllocateManagedByteBuffer(length, AllocationOptions.Clean);
+ IMemoryOwner buffer = this.Configuration.MemoryAllocator.Allocate(length, AllocationOptions.Clean);
- this.currentStream.Read(buffer.Array, 0, length);
+ this.currentStream.Read(buffer.GetSpan());
return buffer;
}
@@ -1274,7 +1275,7 @@ private bool TryReadTextKeyword(ReadOnlySpan keywordBytes, out string name
private void SwapBuffers()
{
- IManagedByteBuffer temp = this.previousScanline;
+ IMemoryOwner temp = this.previousScanline;
this.previousScanline = this.scanline;
this.scanline = temp;
}
diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
index 7a285eb70b..e3be8fd935 100644
--- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
@@ -80,32 +80,32 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
///
/// The raw data of previous scanline.
///
- private IManagedByteBuffer previousScanline;
+ private IMemoryOwner previousScanline;
///
/// The raw data of current scanline.
///
- private IManagedByteBuffer currentScanline;
+ private IMemoryOwner currentScanline;
///
/// The common buffer for the filters.
///
- private IManagedByteBuffer filterBuffer;
+ private IMemoryOwner filterBuffer;
///
/// The ext buffer for the sub filter, .
///
- private IManagedByteBuffer subFilter;
+ private IMemoryOwner subFilter;
///
/// The ext buffer for the average filter, .
///
- private IManagedByteBuffer averageFilter;
+ private IMemoryOwner averageFilter;
///
/// The ext buffer for the Paeth filter, .
///
- private IManagedByteBuffer paethFilter;
+ private IMemoryOwner paethFilter;
///
/// Initializes a new instance of the class.
@@ -278,21 +278,17 @@ private void CollectGrayscaleBytes(ReadOnlySpan rowSpan)
else
{
// 1, 2, and 4 bit grayscale
- using (IManagedByteBuffer temp = this.memoryAllocator.AllocateManagedByteBuffer(
- rowSpan.Length,
- AllocationOptions.Clean))
- {
- int scaleFactor = 255 / (ColorNumerics.GetColorCountForBitDepth(this.bitDepth) - 1);
- Span tempSpan = temp.GetSpan();
-
- // We need to first create an array of luminance bytes then scale them down to the correct bit depth.
- PixelOperations.Instance.ToL8Bytes(
- this.configuration,
- rowSpan,
- tempSpan,
- rowSpan.Length);
- PngEncoderHelpers.ScaleDownFrom8BitArray(tempSpan, rawScanlineSpan, this.bitDepth, scaleFactor);
- }
+ using IMemoryOwner temp = this.memoryAllocator.Allocate(rowSpan.Length, AllocationOptions.Clean);
+ int scaleFactor = 255 / (ColorNumerics.GetColorCountForBitDepth(this.bitDepth) - 1);
+ Span tempSpan = temp.GetSpan();
+
+ // We need to first create an array of luminance bytes then scale them down to the correct bit depth.
+ PixelOperations.Instance.ToL8Bytes(
+ this.configuration,
+ rowSpan,
+ tempSpan,
+ rowSpan.Length);
+ PngEncoderHelpers.ScaleDownFrom8BitArray(tempSpan, rawScanlineSpan, this.bitDepth, scaleFactor);
}
}
}
@@ -453,7 +449,7 @@ private void CollectPixelBytes(ReadOnlySpan rowSpan, IndexedImag
///
/// Apply filter for the raw scanline.
///
- private IManagedByteBuffer FilterPixelBytes()
+ private IMemoryOwner FilterPixelBytes()
{
switch (this.options.FilterMethod)
{
@@ -490,8 +486,8 @@ private IManagedByteBuffer FilterPixelBytes()
/// The row span.
/// The quantized pixels. Can be null.
/// The row.
- /// The
- private IManagedByteBuffer EncodePixelRow(ReadOnlySpan rowSpan, IndexedImageFrame quantized, int row)
+ /// The
+ private IMemoryOwner EncodePixelRow(ReadOnlySpan rowSpan, IndexedImageFrame quantized, int row)
where TPixel : unmanaged, IPixel
{
this.CollectPixelBytes(rowSpan, quantized, row);
@@ -502,7 +498,7 @@ private IManagedByteBuffer EncodePixelRow(ReadOnlySpan rowSpan,
/// Encodes the indexed pixel data (with palette) for Adam7 interlaced mode.
///
/// The row span.
- private IManagedByteBuffer EncodeAdam7IndexedPixelRow(ReadOnlySpan rowSpan)
+ private IMemoryOwner EncodeAdam7IndexedPixelRow(ReadOnlySpan rowSpan)
{
// CollectPixelBytes
if (this.bitDepth < 8)
@@ -521,8 +517,8 @@ private IManagedByteBuffer EncodeAdam7IndexedPixelRow(ReadOnlySpan rowSpan
/// Applies all PNG filters to the given scanline and returns the filtered scanline that is deemed
/// to be most compressible, using lowest total variation as proxy for compressibility.
///
- /// The
- private IManagedByteBuffer GetOptimalFilteredScanline()
+ /// The
+ private IMemoryOwner GetOptimalFilteredScanline()
{
// Palette images don't compress well with adaptive filtering.
if (this.options.ColorType == PngColorType.Palette || this.bitDepth < 8)
@@ -543,7 +539,7 @@ private IManagedByteBuffer GetOptimalFilteredScanline()
// That way the above comment would actually be true. It used to be anyway...
// If we could use SIMD for none branching filters we could really speed it up.
int lowestSum = currentSum;
- IManagedByteBuffer actualResult = this.filterBuffer;
+ IMemoryOwner actualResult = this.filterBuffer;
PaethFilter.Encode(scanSpan, prevSpan, this.paethFilter.GetSpan(), this.bytesPerPixel, out currentSum);
@@ -612,8 +608,8 @@ private void WritePaletteChunk(Stream stream, IndexedImageFrame
int colorTableLength = paletteLength * Unsafe.SizeOf();
bool hasAlpha = false;
- using IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength);
- using IManagedByteBuffer alphaTable = this.memoryAllocator.AllocateManagedByteBuffer(paletteLength);
+ using IMemoryOwner colorTable = this.memoryAllocator.Allocate(colorTableLength);
+ using IMemoryOwner alphaTable = this.memoryAllocator.Allocate(paletteLength);
ref Rgb24 colorTableRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(colorTable.GetSpan()));
ref byte alphaTableRef = ref MemoryMarshal.GetReference(alphaTable.GetSpan());
@@ -640,12 +636,12 @@ private void WritePaletteChunk(Stream stream, IndexedImageFrame
Unsafe.Add(ref alphaTableRef, i) = alpha;
}
- this.WriteChunk(stream, PngChunkType.Palette, colorTable.Array, 0, colorTableLength);
+ this.WriteChunk(stream, PngChunkType.Palette, colorTable.GetSpan(), 0, colorTableLength);
// Write the transparency data
if (hasAlpha)
{
- this.WriteChunk(stream, PngChunkType.Transparency, alphaTable.Array, 0, paletteLength);
+ this.WriteChunk(stream, PngChunkType.Transparency, alphaTable.GetSpan(), 0, paletteLength);
}
}
@@ -938,9 +934,9 @@ private void AllocateBuffers(int bytesPerScanline, int resultLength)
this.previousScanline?.Dispose();
this.currentScanline?.Dispose();
this.filterBuffer?.Dispose();
- this.previousScanline = this.memoryAllocator.AllocateManagedByteBuffer(bytesPerScanline, AllocationOptions.Clean);
- this.currentScanline = this.memoryAllocator.AllocateManagedByteBuffer(bytesPerScanline, AllocationOptions.Clean);
- this.filterBuffer = this.memoryAllocator.AllocateManagedByteBuffer(resultLength, AllocationOptions.Clean);
+ this.previousScanline = this.memoryAllocator.Allocate(bytesPerScanline, AllocationOptions.Clean);
+ this.currentScanline = this.memoryAllocator.Allocate(bytesPerScanline, AllocationOptions.Clean);
+ this.filterBuffer = this.memoryAllocator.Allocate(resultLength, AllocationOptions.Clean);
}
///
@@ -952,9 +948,9 @@ private void AllocateExtBuffers()
{
int resultLength = this.filterBuffer.Length();
- this.subFilter = this.memoryAllocator.AllocateManagedByteBuffer(resultLength, AllocationOptions.Clean);
- this.averageFilter = this.memoryAllocator.AllocateManagedByteBuffer(resultLength, AllocationOptions.Clean);
- this.paethFilter = this.memoryAllocator.AllocateManagedByteBuffer(resultLength, AllocationOptions.Clean);
+ this.subFilter = this.memoryAllocator.Allocate(resultLength, AllocationOptions.Clean);
+ this.averageFilter = this.memoryAllocator.Allocate(resultLength, AllocationOptions.Clean);
+ this.paethFilter = this.memoryAllocator.Allocate(resultLength, AllocationOptions.Clean);
}
}
@@ -974,10 +970,10 @@ private void EncodePixels(Image pixels, IndexedImageFrame r = this.EncodePixelRow(pixels.GetPixelRowSpan(y), quantized, y);
+ deflateStream.Write(r.GetSpan(), 0, resultLength);
- IManagedByteBuffer temp = this.currentScanline;
+ IMemoryOwner temp = this.currentScanline;
this.currentScanline = this.previousScanline;
this.previousScanline = temp;
}
@@ -1027,10 +1023,10 @@ private void EncodeAdam7Pixels(Image pixels, ZlibDeflateStream d
// encode data
// note: quantized parameter not used
// note: row parameter not used
- IManagedByteBuffer r = this.EncodePixelRow((ReadOnlySpan)destSpan, null, -1);
- deflateStream.Write(r.Array, 0, resultLength);
+ IMemoryOwner r = this.EncodePixelRow((ReadOnlySpan)destSpan, null, -1);
+ deflateStream.Write(r.GetSpan(), 0, resultLength);
- IManagedByteBuffer temp = this.currentScanline;
+ IMemoryOwner temp = this.currentScanline;
this.currentScanline = this.previousScanline;
this.previousScanline = temp;
}
@@ -1080,10 +1076,10 @@ private void EncodeAdam7IndexedPixels(IndexedImageFrame quantize
}
// encode data
- IManagedByteBuffer r = this.EncodeAdam7IndexedPixelRow(destSpan);
- deflateStream.Write(r.Array, 0, resultLength);
+ IMemoryOwner r = this.EncodeAdam7IndexedPixelRow(destSpan);
+ deflateStream.Write(r.GetSpan(), 0, resultLength);
- IManagedByteBuffer temp = this.currentScanline;
+ IMemoryOwner temp = this.currentScanline;
this.currentScanline = this.previousScanline;
this.previousScanline = temp;
}
@@ -1095,7 +1091,8 @@ private void EncodeAdam7IndexedPixels(IndexedImageFrame quantize
/// Writes the chunk end to the stream.
///
/// The containing image data.
- private void WriteEndChunk(Stream stream) => this.WriteChunk(stream, PngChunkType.End, null);
+ private void WriteEndChunk(Stream stream)
+ => this.WriteChunk(stream, PngChunkType.End, null);
///
/// Writes a chunk to the stream.
@@ -1103,7 +1100,8 @@ private void EncodeAdam7IndexedPixels(IndexedImageFrame quantize
/// The to write to.
/// The type of chunk to write.
/// The containing data.
- private void WriteChunk(Stream stream, PngChunkType type, byte[] data) => this.WriteChunk(stream, type, data, 0, data?.Length ?? 0);
+ private void WriteChunk(Stream stream, PngChunkType type, Span data)
+ => this.WriteChunk(stream, type, data, 0, data.Length);
///
/// Writes a chunk of a specified length to the stream at the given offset.
@@ -1113,7 +1111,7 @@ private void EncodeAdam7IndexedPixels(IndexedImageFrame quantize
/// The containing data.
/// The position to offset the data at.
/// The of the data to write.
- private void WriteChunk(Stream stream, PngChunkType type, byte[] data, int offset, int length)
+ private void WriteChunk(Stream stream, PngChunkType type, Span data, int offset, int length)
{
BinaryPrimitives.WriteInt32BigEndian(this.buffer, length);
BinaryPrimitives.WriteUInt32BigEndian(this.buffer.AsSpan(4, 4), (uint)type);
@@ -1122,11 +1120,11 @@ private void WriteChunk(Stream stream, PngChunkType type, byte[] data, int offse
uint crc = Crc32.Calculate(this.buffer.AsSpan(4, 4)); // Write the type buffer
- if (data != null && length > 0)
+ if (length > 0)
{
stream.Write(data, offset, length);
- crc = Crc32.Calculate(crc, data.AsSpan(offset, length));
+ crc = Crc32.Calculate(crc, data.Slice(offset, length));
}
BinaryPrimitives.WriteUInt32BigEndian(this.buffer, crc);
diff --git a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs
index eef6e7362b..ad8f4135f0 100644
--- a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs
+++ b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs
@@ -114,9 +114,10 @@ public Image Decode(BufferedReadStream stream, CancellationToken
int colorMapPixelSizeInBytes = this.fileHeader.CMapDepth / 8;
int colorMapSizeInBytes = this.fileHeader.CMapLength * colorMapPixelSizeInBytes;
- using (IManagedByteBuffer palette = this.memoryAllocator.AllocateManagedByteBuffer(colorMapSizeInBytes, AllocationOptions.Clean))
+ using (IMemoryOwner palette = this.memoryAllocator.Allocate(colorMapSizeInBytes, AllocationOptions.Clean))
{
- this.currentStream.Read(palette.Array, this.fileHeader.CMapStart, colorMapSizeInBytes);
+ Span paletteSpan = palette.GetSpan();
+ this.currentStream.Read(paletteSpan, this.fileHeader.CMapStart, colorMapSizeInBytes);
if (this.fileHeader.ImageType == TgaImageType.RleColorMapped)
{
@@ -124,7 +125,7 @@ public Image Decode(BufferedReadStream stream, CancellationToken
this.fileHeader.Width,
this.fileHeader.Height,
pixels,
- palette.Array,
+ paletteSpan,
colorMapPixelSizeInBytes,
origin);
}
@@ -134,7 +135,7 @@ public Image Decode(BufferedReadStream stream, CancellationToken
this.fileHeader.Width,
this.fileHeader.Height,
pixels,
- palette.Array,
+ paletteSpan,
colorMapPixelSizeInBytes,
origin);
}
@@ -224,7 +225,7 @@ public Image Decode(BufferedReadStream stream, CancellationToken
/// The color palette.
/// Color map size of one entry in bytes.
/// The image origin.
- private void ReadPaletted(int width, int height, Buffer2D pixels, byte[] palette, int colorMapPixelSizeInBytes, TgaImageOrigin origin)
+ private void ReadPaletted(int width, int height, Buffer2D pixels, Span palette, int colorMapPixelSizeInBytes, TgaImageOrigin origin)
where TPixel : unmanaged, IPixel
{
TPixel color = default;
@@ -304,7 +305,7 @@ private void ReadPaletted(int width, int height, Buffer2D pixels
/// The color palette.
/// Color map size of one entry in bytes.
/// The image origin.
- private void ReadPalettedRle(int width, int height, Buffer2D pixels, byte[] palette, int colorMapPixelSizeInBytes, TgaImageOrigin origin)
+ private void ReadPalettedRle(int width, int height, Buffer2D pixels, Span palette, int colorMapPixelSizeInBytes, TgaImageOrigin origin)
where TPixel : unmanaged, IPixel
{
int bytesPerPixel = 1;
@@ -373,22 +374,22 @@ private void ReadMonoChrome(int width, int height, Buffer2D pixe
return;
}
- using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 1, 0))
+ using IMemoryOwner row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 1, 0);
+ Span rowSpan = row.GetSpan();
+ bool invertY = InvertY(origin);
+
+ if (invertY)
{
- bool invertY = InvertY(origin);
- if (invertY)
+ for (int y = height - 1; y >= 0; y--)
{
- for (int y = height - 1; y >= 0; y--)
- {
- this.ReadL8Row(width, pixels, row, y);
- }
+ this.ReadL8Row(width, pixels, rowSpan, y);
}
- else
+ }
+ else
+ {
+ for (int y = 0; y < height; y++)
{
- for (int y = 0; y < height; y++)
- {
- this.ReadL8Row(width, pixels, row, y);
- }
+ this.ReadL8Row(width, pixels, rowSpan, y);
}
}
}
@@ -406,57 +407,56 @@ private void ReadBgra16(int width, int height, Buffer2D pixels,
{
TPixel color = default;
bool invertX = InvertX(origin);
- using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 2, 0))
- {
- for (int y = 0; y < height; y++)
- {
- int newY = InvertY(y, height, origin);
- Span pixelSpan = pixels.GetRowSpan(newY);
-
- if (invertX)
- {
- for (int x = width - 1; x >= 0; x--)
- {
- this.currentStream.Read(this.scratchBuffer, 0, 2);
- if (!this.hasAlpha)
- {
- this.scratchBuffer[1] |= 1 << 7;
- }
+ using IMemoryOwner row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 2, 0);
+ Span rowSpan = row.GetSpan();
- if (this.fileHeader.ImageType == TgaImageType.BlackAndWhite)
- {
- color.FromLa16(Unsafe.As(ref this.scratchBuffer[0]));
- }
- else
- {
- color.FromBgra5551(Unsafe.As(ref this.scratchBuffer[0]));
- }
+ for (int y = 0; y < height; y++)
+ {
+ int newY = InvertY(y, height, origin);
+ Span pixelSpan = pixels.GetRowSpan(newY);
- pixelSpan[x] = color;
- }
- }
- else
+ if (invertX)
+ {
+ for (int x = width - 1; x >= 0; x--)
{
- this.currentStream.Read(row);
- Span rowSpan = row.GetSpan();
-
+ this.currentStream.Read(this.scratchBuffer, 0, 2);
if (!this.hasAlpha)
{
- // We need to set the alpha component value to fully opaque.
- for (int x = 1; x < rowSpan.Length; x += 2)
- {
- rowSpan[x] |= 1 << 7;
- }
+ this.scratchBuffer[1] |= 1 << 7;
}
if (this.fileHeader.ImageType == TgaImageType.BlackAndWhite)
{
- PixelOperations.Instance.FromLa16Bytes(this.Configuration, rowSpan, pixelSpan, width);
+ color.FromLa16(Unsafe.As(ref this.scratchBuffer[0]));
}
else
{
- PixelOperations.Instance.FromBgra5551Bytes(this.Configuration, rowSpan, pixelSpan, width);
+ color.FromBgra5551(Unsafe.As(ref this.scratchBuffer[0]));
}
+
+ pixelSpan[x] = color;
+ }
+ }
+ else
+ {
+ this.currentStream.Read(rowSpan);
+
+ if (!this.hasAlpha)
+ {
+ // We need to set the alpha component value to fully opaque.
+ for (int x = 1; x < rowSpan.Length; x += 2)
+ {
+ rowSpan[x] |= 1 << 7;
+ }
+ }
+
+ if (this.fileHeader.ImageType == TgaImageType.BlackAndWhite)
+ {
+ PixelOperations.Instance.FromLa16Bytes(this.Configuration, rowSpan, pixelSpan, width);
+ }
+ else
+ {
+ PixelOperations.Instance.FromBgra5551Bytes(this.Configuration, rowSpan, pixelSpan, width);
}
}
}
@@ -490,23 +490,22 @@ private void ReadBgr24(int width, int height, Buffer2D pixels, T
return;
}
- using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 3, 0))
- {
- bool invertY = InvertY(origin);
+ using IMemoryOwner row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 3, 0);
+ Span rowSpan = row.GetSpan();
+ bool invertY = InvertY(origin);
- if (invertY)
+ if (invertY)
+ {
+ for (int y = height - 1; y >= 0; y--)
{
- for (int y = height - 1; y >= 0; y--)
- {
- this.ReadBgr24Row(width, pixels, row, y);
- }
+ this.ReadBgr24Row(width, pixels, rowSpan, y);
}
- else
+ }
+ else
+ {
+ for (int y = 0; y < height; y++)
{
- for (int y = 0; y < height; y++)
- {
- this.ReadBgr24Row(width, pixels, row, y);
- }
+ this.ReadBgr24Row(width, pixels, rowSpan, y);
}
}
}
@@ -526,21 +525,21 @@ private void ReadBgra32(int width, int height, Buffer2D pixels,
bool invertX = InvertX(origin);
if (this.tgaMetadata.AlphaChannelBits == 8 && !invertX)
{
- using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 4, 0))
+ using IMemoryOwner row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 4, 0);
+ Span rowSpan = row.GetSpan();
+
+ if (InvertY(origin))
{
- if (InvertY(origin))
+ for (int y = height - 1; y >= 0; y--)
{
- for (int y = height - 1; y >= 0; y--)
- {
- this.ReadBgra32Row(width, pixels, row, y);
- }
+ this.ReadBgra32Row(width, pixels, rowSpan, y);
}
- else
+ }
+ else
+ {
+ for (int y = 0; y < height; y++)
{
- for (int y = 0; y < height; y++)
- {
- this.ReadBgra32Row(width, pixels, row, y);
- }
+ this.ReadBgra32Row(width, pixels, rowSpan, y);
}
}
@@ -652,12 +651,12 @@ public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancella
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void ReadL8Row(int width, Buffer2D pixels, IManagedByteBuffer row, int y)
+ private void ReadL8Row(int width, Buffer2D pixels, Span row, int y)
where TPixel : unmanaged, IPixel
{
this.currentStream.Read(row);
Span pixelSpan = pixels.GetRowSpan(y);
- PixelOperations.Instance.FromL8Bytes(this.Configuration, row.GetSpan(), pixelSpan, width);
+ PixelOperations.Instance.FromL8Bytes(this.Configuration, row, pixelSpan, width);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -679,12 +678,12 @@ private void ReadBgr24Pixel(TPixel color, int x, Span pixelSpan)
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void ReadBgr24Row(int width, Buffer2D pixels, IManagedByteBuffer row, int y)
+ private void ReadBgr24Row(int width, Buffer2D pixels, Span row, int y)
where TPixel : unmanaged, IPixel
{
this.currentStream.Read(row);
Span pixelSpan = pixels.GetRowSpan(y);
- PixelOperations.Instance.FromBgr24Bytes(this.Configuration, row.GetSpan(), pixelSpan, width);
+ PixelOperations.Instance.FromBgr24Bytes(this.Configuration, row, pixelSpan, width);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -698,16 +697,16 @@ private void ReadBgra32Pixel(int x, TPixel color, Span pixelRow)
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void ReadBgra32Row(int width, Buffer2D pixels, IManagedByteBuffer row, int y)
+ private void ReadBgra32Row(int width, Buffer2D pixels, Span row, int y)
where TPixel : unmanaged, IPixel
{
this.currentStream.Read(row);
Span pixelSpan = pixels.GetRowSpan(y);
- PixelOperations.Instance.FromBgra32Bytes(this.Configuration, row.GetSpan(), pixelSpan, width);
+ PixelOperations.Instance.FromBgra32Bytes(this.Configuration, row, pixelSpan, width);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void ReadPalettedBgra16Pixel(byte[] palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span pixelRow)
+ private void ReadPalettedBgra16Pixel(Span palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span pixelRow)
where TPixel : unmanaged, IPixel
{
int colorIndex = this.currentStream.ReadByte();
@@ -716,7 +715,7 @@ private void ReadPalettedBgra16Pixel(byte[] palette, int colorMapPixelSi
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void ReadPalettedBgra16Pixel(byte[] palette, int index, int colorMapPixelSizeInBytes, ref TPixel color)
+ private void ReadPalettedBgra16Pixel(Span palette, int index, int colorMapPixelSizeInBytes, ref TPixel color)
where TPixel : unmanaged, IPixel