diff --git a/src/ImageSharp/Formats/WebP/AlphaDecoder.cs b/src/ImageSharp/Formats/WebP/AlphaDecoder.cs
index 3a5f0ca4fc..6737c4d098 100644
--- a/src/ImageSharp/Formats/WebP/AlphaDecoder.cs
+++ b/src/ImageSharp/Formats/WebP/AlphaDecoder.cs
@@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// The first byte of the alpha image stream contains information on ow to decode the stream.
/// Used for allocating memory during decoding.
/// The configuration.
- public AlphaDecoder(int width, int height, byte[] data, byte alphaChunkHeader, MemoryAllocator memoryAllocator, Configuration configuration)
+ public AlphaDecoder(int width, int height, IMemoryOwner data, byte alphaChunkHeader, MemoryAllocator memoryAllocator, Configuration configuration)
{
this.Width = width;
this.Height = height;
@@ -116,7 +116,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
///
/// Gets the (maybe compressed) alpha data.
///
- private byte[] Data { get; }
+ private IMemoryOwner Data { get; }
///
/// Gets the Vp8L decoder which is used to de compress the alpha channel, if needed.
@@ -137,7 +137,8 @@ namespace SixLabors.ImageSharp.Formats.WebP
{
if (this.Compressed is false)
{
- if (this.Data.Length < (this.Width * this.Height))
+ Span dataSpan = this.Data.Memory.Span;
+ if (dataSpan.Length < (this.Width * this.Height))
{
WebPThrowHelper.ThrowImageFormatException("not enough data in the ALPH chunk");
}
@@ -145,11 +146,11 @@ namespace SixLabors.ImageSharp.Formats.WebP
Span alphaSpan = this.Alpha.Memory.Span;
if (this.AlphaFilterType == WebPAlphaFilterType.None)
{
- this.Data.AsSpan(0, this.Width * this.Height).CopyTo(alphaSpan);
+ dataSpan.Slice(0, this.Width * this.Height).CopyTo(alphaSpan);
return;
}
- Span deltas = this.Data.AsSpan();
+ Span deltas = dataSpan;
Span dst = alphaSpan;
Span prev = null;
for (int y = 0; y < this.Height; ++y)
@@ -305,6 +306,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
public void Dispose()
{
this.Vp8LDec?.Dispose();
+ this.Data.Dispose();
this.Alpha?.Dispose();
}
}
diff --git a/src/ImageSharp/Formats/WebP/BitReaderBase.cs b/src/ImageSharp/Formats/WebP/BitReaderBase.cs
index 3a5bf4f4ae..f35368c15a 100644
--- a/src/ImageSharp/Formats/WebP/BitReaderBase.cs
+++ b/src/ImageSharp/Formats/WebP/BitReaderBase.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;
@@ -11,12 +12,12 @@ namespace SixLabors.ImageSharp.Formats.WebP
///
/// Base class for VP8 and VP8L bitreader.
///
- internal abstract class BitReaderBase
+ internal abstract class BitReaderBase : IDisposable
{
///
/// Gets or sets the raw encoded image data.
///
- public byte[] Data { get; set; }
+ public IMemoryOwner Data { get; set; }
///
/// Copies the raw encoded image data from the stream into a byte array.
@@ -26,24 +27,28 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// Used for allocating memory during reading data from the stream.
protected void ReadImageDataFromStream(Stream input, int bytesToRead, MemoryAllocator memoryAllocator)
{
- using (var ms = new MemoryStream())
+ this.Data = memoryAllocator.Allocate(bytesToRead);
+ Span dataSpan = this.Data.Memory.Span;
+
using (IManagedByteBuffer buffer = memoryAllocator.AllocateManagedByteBuffer(4096))
{
Span bufferSpan = buffer.GetSpan();
int read;
while (bytesToRead > 0 && (read = input.Read(buffer.Array, 0, Math.Min(bufferSpan.Length, bytesToRead))) > 0)
{
- ms.Write(buffer.Array, 0, read);
+ buffer.Array.AsSpan(0, read).CopyTo(dataSpan);
bytesToRead -= read;
+ dataSpan = dataSpan.Slice(read);
}
if (bytesToRead > 0)
{
WebPThrowHelper.ThrowImageFormatException("image file has insufficient data");
}
-
- this.Data = ms.ToArray();
}
}
+
+ ///
+ public void Dispose() => this.Data?.Dispose();
}
}
diff --git a/src/ImageSharp/Formats/WebP/Vp8BitReader.cs b/src/ImageSharp/Formats/WebP/Vp8BitReader.cs
index 742125963c..66681b89de 100644
--- a/src/ImageSharp/Formats/WebP/Vp8BitReader.cs
+++ b/src/ImageSharp/Formats/WebP/Vp8BitReader.cs
@@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
-using System;
+using System.Buffers;
using System.Buffers.Binary;
using System.IO;
using System.Runtime.CompilerServices;
@@ -70,10 +70,10 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// The raw encoded image data.
/// The partition length.
/// Start index in the data array. Defaults to 0.
- public Vp8BitReader(byte[] imageData, uint partitionLength, int startPos = 0)
+ public Vp8BitReader(IMemoryOwner imageData, uint partitionLength, int startPos = 0)
{
this.Data = imageData;
- this.ImageDataSize = (uint)imageData.Length;
+ this.ImageDataSize = (uint)imageData.Memory.Length;
this.PartitionLength = partitionLength;
this.InitBitreader(partitionLength, startPos);
}
@@ -184,7 +184,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
{
if (this.pos < this.bufferMax)
{
- ulong inBits = BinaryPrimitives.ReadUInt64LittleEndian(this.Data.AsSpan((int)this.pos, 8));
+ ulong inBits = BinaryPrimitives.ReadUInt64LittleEndian(this.Data.Memory.Span.Slice((int)this.pos, 8));
this.pos += BitsCount >> 3;
ulong bits = this.ByteSwap64(inBits);
bits >>= 64 - BitsCount;
@@ -203,7 +203,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
if (this.pos < this.bufferEnd)
{
this.bits += 8;
- this.value = this.Data[this.pos++] | (this.value << 8);
+ this.value = this.Data.Memory.Span[(int)this.pos++] | (this.value << 8);
}
else if (!this.eof)
{
diff --git a/src/ImageSharp/Formats/WebP/Vp8LBitReader.cs b/src/ImageSharp/Formats/WebP/Vp8LBitReader.cs
index 8990de769c..f90023b89c 100644
--- a/src/ImageSharp/Formats/WebP/Vp8LBitReader.cs
+++ b/src/ImageSharp/Formats/WebP/Vp8LBitReader.cs
@@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
+using System.Buffers;
using System.IO;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory;
@@ -62,18 +63,19 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// Initializes a new instance of the class.
///
/// Lossless compressed image data.
- public Vp8LBitReader(byte[] data)
+ public Vp8LBitReader(IMemoryOwner data)
{
this.Data = data;
- this.len = data.Length;
+ this.len = data.Memory.Length;
this.value = 0;
this.bitPos = 0;
this.Eos = false;
ulong currentValue = 0;
+ System.Span dataSpan = this.Data.Memory.Span;
for (int i = 0; i < 8; ++i)
{
- currentValue |= (ulong)this.Data[i] << (8 * i);
+ currentValue |= (ulong)dataSpan[i] << (8 * i);
}
this.value = currentValue;
@@ -103,9 +105,10 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
ulong currentValue = 0;
+ System.Span dataSpan = this.Data.Memory.Span;
for (int i = 0; i < length; ++i)
{
- currentValue |= (ulong)this.Data[i] << (8 * i);
+ currentValue |= (ulong)dataSpan[i] << (8 * i);
}
this.value = currentValue;
@@ -200,10 +203,11 @@ namespace SixLabors.ImageSharp.Formats.WebP
///
private void ShiftBytes()
{
+ System.Span dataSpan = this.Data.Memory.Span;
while (this.bitPos >= 8 && this.pos < this.len)
{
this.value >>= 8;
- this.value |= (ulong)this.Data[this.pos] << (Lbits - 8);
+ this.value |= (ulong)dataSpan[(int)this.pos] << (Lbits - 8);
++this.pos;
this.bitPos -= 8;
}
diff --git a/src/ImageSharp/Formats/WebP/WebPDecoderCore.cs b/src/ImageSharp/Formats/WebP/WebPDecoderCore.cs
index e6f5dfe3e4..f0060edaf5 100644
--- a/src/ImageSharp/Formats/WebP/WebPDecoderCore.cs
+++ b/src/ImageSharp/Formats/WebP/WebPDecoderCore.cs
@@ -78,7 +78,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
this.currentStream = stream;
uint fileSize = this.ReadImageHeader();
- WebPImageInfo imageInfo = this.ReadVp8Info();
+ using var imageInfo = this.ReadVp8Info();
if (imageInfo.Features != null && imageInfo.Features.Animation)
{
WebPThrowHelper.ThrowNotSupportedException("Animations are not supported");
@@ -186,7 +186,8 @@ namespace SixLabors.ImageSharp.Formats.WebP
// The first two bit of it are reserved and should be 0.
if (imageFeatures >> 6 != 0)
{
- WebPThrowHelper.ThrowImageFormatException("first two bits of the VP8X header are expected to be zero");
+ WebPThrowHelper.ThrowImageFormatException(
+ "first two bits of the VP8X header are expected to be zero");
}
// If bit 3 is set, a ICC Profile Chunk should be present.
@@ -232,12 +233,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
if (features.Animation)
{
// TODO: Animations are not yet supported.
- return new WebPImageInfo()
- {
- Width = width,
- Height = height,
- Features = features
- };
+ return new WebPImageInfo() { Width = width, Height = height, Features = features };
}
// TODO: check if VP8 or VP8L info about the dimensions match VP8X info
@@ -444,8 +440,9 @@ namespace SixLabors.ImageSharp.Formats.WebP
case WebPChunkType.Alpha:
uint alphaChunkSize = this.ReadChunkSize();
features.AlphaChunkHeader = (byte)this.currentStream.ReadByte();
- features.AlphaData = new byte[alphaChunkSize - 1];
- this.currentStream.Read(features.AlphaData, 0, features.AlphaData.Length);
+ var alphaDataSize = (int)(alphaChunkSize - 1);
+ features.AlphaData = this.memoryAllocator.Allocate(alphaDataSize);
+ this.currentStream.Read(features.AlphaData.Memory.Span, 0, alphaDataSize);
break;
}
}
diff --git a/src/ImageSharp/Formats/WebP/WebPFeatures.cs b/src/ImageSharp/Formats/WebP/WebPFeatures.cs
index 3fd0350766..cf1053057c 100644
--- a/src/ImageSharp/Formats/WebP/WebPFeatures.cs
+++ b/src/ImageSharp/Formats/WebP/WebPFeatures.cs
@@ -1,12 +1,15 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
+using System;
+using System.Buffers;
+
namespace SixLabors.ImageSharp.Formats.WebP
{
///
/// Image features of a VP8X image.
///
- internal class WebPFeatures
+ internal class WebPFeatures : IDisposable
{
///
/// Gets or sets a value indicating whether this image has a ICC Profile.
@@ -21,7 +24,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
///
/// Gets or sets the alpha data, if an ALPH chunk is present.
///
- public byte[] AlphaData { get; set; }
+ public IMemoryOwner AlphaData { get; set; }
///
/// Gets or sets the alpha chunk header.
@@ -42,5 +45,11 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// Gets or sets a value indicating whether this image is a animation.
///
public bool Animation { get; set; }
+
+ ///
+ public void Dispose()
+ {
+ this.AlphaData?.Dispose();
+ }
}
}
diff --git a/src/ImageSharp/Formats/WebP/WebPImageInfo.cs b/src/ImageSharp/Formats/WebP/WebPImageInfo.cs
index 19a72c0c28..b7aa4b36a1 100644
--- a/src/ImageSharp/Formats/WebP/WebPImageInfo.cs
+++ b/src/ImageSharp/Formats/WebP/WebPImageInfo.cs
@@ -1,17 +1,19 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
+using System;
+
namespace SixLabors.ImageSharp.Formats.WebP
{
- internal class WebPImageInfo
+ internal class WebPImageInfo : IDisposable
{
///
- /// Gets or sets the bitmap width in pixels (signed integer).
+ /// Gets or sets the bitmap width in pixels.
///
public uint Width { get; set; }
///
- /// Gets or sets the bitmap height in pixels (signed integer).
+ /// Gets or sets the bitmap height in pixels.
///
public uint Height { get; set; }
@@ -53,5 +55,13 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// Gets or sets the VP8 bitreader. Will be null, if its not a lossy image.
///
public Vp8BitReader Vp8BitReader { get; set; } = null;
+
+ ///
+ public void Dispose()
+ {
+ this.Vp8BitReader?.Dispose();
+ this.Vp8LBitReader?.Dispose();
+ this.Features?.AlphaData?.Dispose();
+ }
}
}
diff --git a/src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs b/src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs
index 0b26727d59..a741ad42d3 100644
--- a/src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs
+++ b/src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs
@@ -1195,7 +1195,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
{
uint size = this.bitReader.Remaining - this.bitReader.PartitionLength;
int startIdx = (int)this.bitReader.PartitionLength;
- Span sz = this.bitReader.Data.AsSpan(startIdx);
+ Span sz = this.bitReader.Data.Slice(startIdx);
int sizeLeft = (int)size;
dec.NumPartsMinusOne = (1 << (int)this.bitReader.ReadValue(2)) - 1;
int lastPart = dec.NumPartsMinusOne;