diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
index e37144bd58..4b14061cf8 100644
--- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
@@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
///
/// A useful decoding source example can be found at
///
- internal sealed class BmpDecoderCore
+ internal sealed class BmpDecoderCore : IImageDecoderInternals
{
///
/// The default mask for the red part of the color for 16 bit rgb bitmaps.
@@ -89,11 +89,6 @@ internal sealed class BmpDecoderCore
///
private BmpInfoHeader infoHeader;
- ///
- /// The global configuration.
- ///
- private readonly Configuration configuration;
-
///
/// Used for allocating memory during processing operations.
///
@@ -111,67 +106,28 @@ internal sealed class BmpDecoderCore
/// The options.
public BmpDecoderCore(Configuration configuration, IBmpDecoderOptions options)
{
- this.configuration = configuration;
+ this.Configuration = configuration;
this.memoryAllocator = configuration.MemoryAllocator;
this.options = options;
}
+ ///
+ public Configuration Configuration { get; }
+
///
/// Gets the dimensions of the image.
///
public Size Dimensions => new Size(this.infoHeader.Width, this.infoHeader.Height);
- ///
- /// Decodes the image from the specified this._stream and sets
- /// the data to image.
- ///
- /// The pixel format.
- /// The stream, where the image should be
- /// decoded from. Cannot be null (Nothing in Visual Basic).
- ///
- /// is null.
- ///
- /// The decoded image.
- public async Task> DecodeAsync(Stream stream)
- where TPixel : unmanaged, IPixel
- {
- // if we can seek then we arn't in a context that errors on async operations
- if (stream.CanSeek)
- {
- return this.Decode(stream);
- }
- else
- {
- // cheat for now do async copy of the stream into memory stream and use the sync version
- // we should use an array pool backed memorystream implementation
- using (var ms = new MemoryStream())
- {
- await stream.CopyToAsync(ms).ConfigureAwait(false);
- ms.Position = 0;
- return this.Decode(ms);
- }
- }
- }
-
- ///
- /// Decodes the image from the specified this._stream and sets
- /// the data to image.
- ///
- /// The pixel format.
- /// The stream, where the image should be
- /// decoded from. Cannot be null (Nothing in Visual Basic).
- ///
- /// is null.
- ///
- /// The decoded image.
+ ///
public Image Decode(Stream stream)
- where TPixel : unmanaged, IPixel
+ where TPixel : unmanaged, IPixel
{
try
{
int bytesPerColorMapEntry = this.ReadImageHeaders(stream, out bool inverted, out byte[] palette);
- var image = new Image(this.configuration, this.infoHeader.Width, this.infoHeader.Height, this.metadata);
+ var image = new Image(this.Configuration, this.infoHeader.Width, this.infoHeader.Height, this.metadata);
Buffer2D pixels = image.GetRootFramePixelBuffer();
@@ -242,30 +198,13 @@ public Image Decode(Stream stream)
}
}
- ///
- /// Reads the raw image information from the specified stream.
- ///
- /// The containing image data.
+ ///
public IImageInfo Identify(Stream stream)
{
this.ReadImageHeaders(stream, out _, out _);
return new ImageInfo(new PixelTypeInfo(this.infoHeader.BitsPerPixel), this.infoHeader.Width, this.infoHeader.Height, this.metadata);
}
- ///
- /// Reads the raw image information from the specified stream.
- ///
- /// The containing image data.
- public async Task IdentifyAsync(Stream stream)
- {
- using (var ms = new FixedCapacityPooledMemoryStream(stream.Length))
- {
- await stream.CopyToAsync(ms).ConfigureAwait(false);
- ms.Position = 0;
- return this.Identify(ms);
- }
- }
-
///
/// Returns the y- value based on the given height.
///
@@ -999,7 +938,7 @@ private void ReadRgb24(Buffer2D pixels, int width, int height, b
int newY = Invert(y, height, inverted);
Span pixelSpan = pixels.GetRowSpan(newY);
PixelOperations.Instance.FromBgr24Bytes(
- this.configuration,
+ this.Configuration,
row.GetSpan(),
pixelSpan,
width);
@@ -1028,7 +967,7 @@ private void ReadRgb32Fast(Buffer2D pixels, int width, int heigh
int newY = Invert(y, height, inverted);
Span pixelSpan = pixels.GetRowSpan(newY);
PixelOperations.Instance.FromBgra32Bytes(
- this.configuration,
+ this.Configuration,
row.GetSpan(),
pixelSpan,
width);
@@ -1065,7 +1004,7 @@ private void ReadRgb32Slow(Buffer2D pixels, int width, int heigh
this.stream.Read(row);
PixelOperations.Instance.FromBgra32Bytes(
- this.configuration,
+ this.Configuration,
row.GetSpan(),
bgraRowSpan,
width);
@@ -1101,7 +1040,7 @@ private void ReadRgb32Slow(Buffer2D pixels, int width, int heigh
Span pixelSpan = pixels.GetRowSpan(newY);
PixelOperations.Instance.FromBgra32Bytes(
- this.configuration,
+ this.Configuration,
row.GetSpan(),
pixelSpan,
width);
@@ -1115,7 +1054,7 @@ private void ReadRgb32Slow(Buffer2D pixels, int width, int heigh
{
this.stream.Read(row);
PixelOperations.Instance.FromBgra32Bytes(
- this.configuration,
+ this.Configuration,
row.GetSpan(),
bgraRowSpan,
width);
diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
index 8f8426780d..e4c98799ba 100644
--- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
+++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
@@ -17,18 +17,13 @@ namespace SixLabors.ImageSharp.Formats.Gif
///
/// Performs the gif decoding operation.
///
- internal sealed class GifDecoderCore
+ internal sealed class GifDecoderCore : IImageDecoderInternals
{
///
/// The temp buffer used to reduce allocations.
///
private readonly byte[] buffer = new byte[16];
- ///
- /// The global configuration.
- ///
- private readonly Configuration configuration;
-
///
/// The currently loaded stream.
///
@@ -78,9 +73,12 @@ public GifDecoderCore(Configuration configuration, IGifDecoderOptions options)
{
this.IgnoreMetadata = options.IgnoreMetadata;
this.DecodingMode = options.DecodingMode;
- this.configuration = configuration ?? Configuration.Default;
+ this.Configuration = configuration ?? Configuration.Default;
}
+ ///
+ public Configuration Configuration { get; }
+
///
/// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded.
///
@@ -96,40 +94,11 @@ public GifDecoderCore(Configuration configuration, IGifDecoderOptions options)
///
public Size Dimensions => new Size(this.imageDescriptor.Width, this.imageDescriptor.Height);
- private MemoryAllocator MemoryAllocator => this.configuration.MemoryAllocator;
-
- ///
- /// Decodes the stream to the image.
- ///
- /// The pixel format.
- /// The stream containing image data.
- /// The decoded image
- public async Task> DecodeAsync(Stream stream)
- where TPixel : unmanaged, IPixel
- {
- if (stream.CanSeek)
- {
- return this.Decode(stream);
- }
- else
- {
- using (var ms = new MemoryStream())
- {
- await stream.CopyToAsync(ms).ConfigureAwait(false);
- ms.Position = 0;
- return this.Decode(ms);
- }
- }
- }
+ private MemoryAllocator MemoryAllocator => this.Configuration.MemoryAllocator;
- ///
- /// Decodes the stream to the image.
- ///
- /// The pixel format.
- /// The stream containing image data.
- /// The decoded image
+ ///
public Image Decode(Stream stream)
- where TPixel : unmanaged, IPixel
+ where TPixel : unmanaged, IPixel
{
Image image = null;
ImageFrame previousFrame = null;
@@ -188,31 +157,7 @@ public Image Decode(Stream stream)
return image;
}
- ///
- /// Reads the raw image information from the specified stream.
- ///
- /// The containing image data.
- public async Task IdentifyAsync(Stream stream)
- {
- if (stream.CanSeek)
- {
- return this.Identify(stream);
- }
- else
- {
- using (var ms = new FixedCapacityPooledMemoryStream(stream.Length))
- {
- await stream.CopyToAsync(ms).ConfigureAwait(false);
- ms.Position = 0;
- return this.Identify(ms);
- }
- }
- }
-
- ///
- /// Reads the raw image information from the specified stream.
- ///
- /// The containing image data.
+ ///
public IImageInfo Identify(Stream stream)
{
try
@@ -410,11 +355,11 @@ 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);
+ localColorTable = this.Configuration.MemoryAllocator.AllocateManagedByteBuffer(length, AllocationOptions.Clean);
this.stream.Read(localColorTable.Array, 0, length);
}
- indices = this.configuration.MemoryAllocator.Allocate2D(this.imageDescriptor.Width, this.imageDescriptor.Height, AllocationOptions.Clean);
+ indices = this.Configuration.MemoryAllocator.Allocate2D(this.imageDescriptor.Width, this.imageDescriptor.Height, AllocationOptions.Clean);
this.ReadFrameIndices(indices);
ReadOnlySpan colorTable = MemoryMarshal.Cast((localColorTable ?? this.globalColorTable).GetSpan());
@@ -438,7 +383,7 @@ private void ReadFrame(ref Image image, ref ImageFrame p
private void ReadFrameIndices(Buffer2D indices)
{
int dataSize = this.stream.ReadByte();
- using var lzwDecoder = new LzwDecoder(this.configuration.MemoryAllocator, this.stream);
+ using var lzwDecoder = new LzwDecoder(this.Configuration.MemoryAllocator, this.stream);
lzwDecoder.DecodePixels(dataSize, indices);
}
@@ -464,7 +409,7 @@ private void ReadFrameColors(ref Image image, ref ImageFrame(this.configuration, imageWidth, imageHeight, this.metadata);
+ image = new Image(this.Configuration, imageWidth, imageHeight, this.metadata);
this.SetFrameMetadata(image.Frames.RootFrame.Metadata);
diff --git a/src/ImageSharp/Formats/IImageDecoderInternals.cs b/src/ImageSharp/Formats/IImageDecoderInternals.cs
new file mode 100644
index 0000000000..3ab9123530
--- /dev/null
+++ b/src/ImageSharp/Formats/IImageDecoderInternals.cs
@@ -0,0 +1,38 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System.IO;
+using SixLabors.ImageSharp.PixelFormats;
+
+namespace SixLabors.ImageSharp.Formats
+{
+ ///
+ /// Abstraction for shared internals for ***DecoderCore implementations to be used with .
+ ///
+ internal interface IImageDecoderInternals
+ {
+ ///
+ /// Gets the associated configuration.
+ ///
+ Configuration Configuration { get; }
+
+ ///
+ /// Decodes the image from the specified stream.
+ ///
+ /// The pixel format.
+ /// The stream, where the image should be decoded from. Cannot be null.
+ ///
+ /// is null.
+ ///
+ /// The decoded image.
+ Image Decode(Stream stream)
+ where TPixel : unmanaged, IPixel;
+
+ ///
+ /// Reads the raw image information from the specified stream.
+ ///
+ /// The containing image data.
+ /// The .
+ IImageInfo Identify(Stream stream);
+ }
+}
diff --git a/src/ImageSharp/Formats/ImageDecoderUtilities.cs b/src/ImageSharp/Formats/ImageDecoderUtilities.cs
new file mode 100644
index 0000000000..6bb9116cda
--- /dev/null
+++ b/src/ImageSharp/Formats/ImageDecoderUtilities.cs
@@ -0,0 +1,55 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System.IO;
+using System.Threading.Tasks;
+using SixLabors.ImageSharp.Memory;
+using SixLabors.ImageSharp.PixelFormats;
+
+namespace SixLabors.ImageSharp.Formats
+{
+ internal static class ImageDecoderUtilities
+ {
+ ///
+ /// Reads the raw image information from the specified stream.
+ ///
+ /// The decoder.
+ /// The containing image data.
+ public static async Task IdentifyAsync(this IImageDecoderInternals decoder, Stream stream)
+ {
+ if (stream.CanSeek)
+ {
+ return decoder.Identify(stream);
+ }
+
+ using MemoryStream ms = decoder.Configuration.MemoryAllocator.AllocateFixedCapacityMemoryStream(stream.Length);
+ await stream.CopyToAsync(ms).ConfigureAwait(false);
+ ms.Position = 0;
+ return decoder.Identify(ms);
+ }
+
+ ///
+ /// Decodes the image from the specified stream.
+ ///
+ /// The pixel format.
+ /// The decoder.
+ /// The stream, where the image should be decoded from. Cannot be null.
+ ///
+ /// is null.
+ ///
+ /// The decoded image.
+ public static async Task> DecodeAsync(this IImageDecoderInternals decoder, Stream stream)
+ where TPixel : unmanaged, IPixel
+ {
+ if (stream.CanSeek)
+ {
+ return decoder.Decode(stream);
+ }
+
+ using MemoryStream ms = decoder.Configuration.MemoryAllocator.AllocateFixedCapacityMemoryStream(stream.Length);
+ await stream.CopyToAsync(ms).ConfigureAwait(false);
+ ms.Position = 0;
+ return decoder.Decode(ms);
+ }
+ }
+}
diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
index af1a705d44..f8151141ca 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
@@ -25,18 +25,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// Originally ported from
/// with additional fixes for both performance and common encoding errors.
///
- internal sealed class JpegDecoderCore : IRawJpegData
+ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
{
///
/// The only supported precision
///
private readonly int[] supportedPrecisions = { 8, 12 };
- ///
- /// The global configuration
- ///
- private readonly Configuration configuration;
-
///
/// The buffer used to temporarily store bytes read from the stream.
///
@@ -109,10 +104,13 @@ internal sealed class JpegDecoderCore : IRawJpegData
/// The options.
public JpegDecoderCore(Configuration configuration, IJpegDecoderOptions options)
{
- this.configuration = configuration ?? Configuration.Default;
+ this.Configuration = configuration ?? Configuration.Default;
this.IgnoreMetadata = options.IgnoreMetadata;
}
+ ///
+ public Configuration Configuration { get; }
+
///
/// Gets the frame
///
@@ -213,38 +211,9 @@ public static JpegFileMarker FindNextFileMarker(byte[] marker, DoubleBufferedStr
return new JpegFileMarker(marker[1], stream.Position - 2, true);
}
- ///
- /// Decodes the image from the specified and sets the data to image.
- ///
- /// The pixel format.
- /// The stream, where the image should be.
- /// The decoded image.
- public async Task> DecodeAsync(Stream stream)
- where TPixel : unmanaged, IPixel
- {
- if (stream.CanSeek)
- {
- return this.Decode(stream);
- }
- else
- {
- using (var ms = new MemoryStream())
- {
- await stream.CopyToAsync(ms).ConfigureAwait(false);
- ms.Position = 0;
- return this.Decode(ms);
- }
- }
- }
-
- ///
- /// Decodes the image from the specified and sets the data to image.
- ///
- /// The pixel format.
- /// The stream, where the image should be.
- /// The decoded image.
+ ///
public Image Decode(Stream stream)
- where TPixel : unmanaged, IPixel
+ where TPixel : unmanaged, IPixel
{
this.ParseStream(stream);
this.InitExifProfile();
@@ -254,31 +223,7 @@ public Image Decode(Stream stream)
return this.PostProcessIntoImage();
}
- ///
- /// Reads the raw image information from the specified stream.
- ///
- /// The containing image data.
- public async Task IdentifyAsync(Stream stream)
- {
- if (stream.CanSeek)
- {
- return this.Identify(stream);
- }
- else
- {
- using (var ms = new FixedCapacityPooledMemoryStream(stream.Length))
- {
- await stream.CopyToAsync(ms).ConfigureAwait(false);
- ms.Position = 0;
- return this.Identify(ms);
- }
- }
- }
-
- ///
- /// Reads the raw image information from the specified stream.
- ///
- /// The containing image data.
+ ///
public IImageInfo Identify(Stream stream)
{
this.ParseStream(stream, true);
@@ -298,7 +243,7 @@ public IImageInfo Identify(Stream stream)
public void ParseStream(Stream stream, bool metadataOnly = false)
{
this.Metadata = new ImageMetadata();
- this.InputStream = new DoubleBufferedStreamReader(this.configuration.MemoryAllocator, stream);
+ this.InputStream = new DoubleBufferedStreamReader(this.Configuration.MemoryAllocator, stream);
// Check for the Start Of Image marker.
this.InputStream.Read(this.markerBuffer, 0, 2);
@@ -937,7 +882,7 @@ private void ProcessStartOfFrameMarker(int remaining, in JpegFileMarker frameMar
maxV = v;
}
- var component = new JpegComponent(this.configuration.MemoryAllocator, this.Frame, this.temp[index], h, v, this.temp[index + 2], i);
+ var component = new JpegComponent(this.Configuration.MemoryAllocator, this.Frame, this.temp[index], h, v, this.temp[index + 2], i);
this.Frame.Components[i] = component;
this.Frame.ComponentIds[i] = component.Id;
@@ -962,7 +907,7 @@ private void ProcessDefineHuffmanTablesMarker(int remaining)
{
int length = remaining;
- using (IManagedByteBuffer huffmanData = this.configuration.MemoryAllocator.AllocateManagedByteBuffer(256, AllocationOptions.Clean))
+ using (IManagedByteBuffer huffmanData = this.Configuration.MemoryAllocator.AllocateManagedByteBuffer(256, AllocationOptions.Clean))
{
ref byte huffmanDataRef = ref MemoryMarshal.GetReference(huffmanData.GetSpan());
for (int i = 2; i < remaining;)
@@ -985,7 +930,7 @@ private void ProcessDefineHuffmanTablesMarker(int remaining)
this.InputStream.Read(huffmanData.Array, 0, 16);
- using (IManagedByteBuffer codeLengths = this.configuration.MemoryAllocator.AllocateManagedByteBuffer(17, AllocationOptions.Clean))
+ using (IManagedByteBuffer codeLengths = this.Configuration.MemoryAllocator.AllocateManagedByteBuffer(17, AllocationOptions.Clean))
{
ref byte codeLengthsRef = ref MemoryMarshal.GetReference(codeLengths.GetSpan());
int codeLengthSum = 0;
@@ -1002,7 +947,7 @@ private void ProcessDefineHuffmanTablesMarker(int remaining)
JpegThrowHelper.ThrowInvalidImageContentException("Huffman table has excessive length.");
}
- using (IManagedByteBuffer huffmanValues = this.configuration.MemoryAllocator.AllocateManagedByteBuffer(256, AllocationOptions.Clean))
+ using (IManagedByteBuffer huffmanValues = this.Configuration.MemoryAllocator.AllocateManagedByteBuffer(256, AllocationOptions.Clean))
{
this.InputStream.Read(huffmanValues.Array, 0, codeLengthSum);
@@ -1129,12 +1074,12 @@ private Image PostProcessIntoImage()
}
var image = Image.CreateUninitialized(
- this.configuration,
+ this.Configuration,
this.ImageWidth,
this.ImageHeight,
this.Metadata);
- using (var postProcessor = new JpegImagePostProcessor(this.configuration, this))
+ using (var postProcessor = new JpegImagePostProcessor(this.Configuration, this))
{
postProcessor.PostProcess(image.Frames.RootFrame);
}
diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
index bb8589de49..e2b0e50fcc 100644
--- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
@@ -24,18 +24,13 @@ namespace SixLabors.ImageSharp.Formats.Png
///
/// Performs the png decoding operation.
///
- internal sealed class PngDecoderCore
+ internal sealed class PngDecoderCore : IImageDecoderInternals
{
///
/// Reusable buffer.
///
private readonly byte[] buffer = new byte[4];
- ///
- /// The global configuration.
- ///
- private readonly Configuration configuration;
-
///
/// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded.
///
@@ -123,60 +118,22 @@ internal sealed class PngDecoderCore
/// The decoder options.
public PngDecoderCore(Configuration configuration, IPngDecoderOptions options)
{
- this.configuration = configuration ?? Configuration.Default;
- this.memoryAllocator = this.configuration.MemoryAllocator;
+ this.Configuration = configuration ?? Configuration.Default;
+ this.memoryAllocator = this.Configuration.MemoryAllocator;
this.ignoreMetadata = options.IgnoreMetadata;
}
+ ///
+ public Configuration Configuration { get; }
+
///
/// Gets the dimensions of the image.
///
public Size Dimensions => new Size(this.header.Width, this.header.Height);
- ///
- /// Decodes the stream to the image.
- ///
- /// The pixel format.
- /// The stream containing image data.
- ///
- /// Thrown if the stream does not contain and end chunk.
- ///
- ///
- /// Thrown if the image is larger than the maximum allowable size.
- ///
- /// The decoded image.
- public async Task> DecodeAsync(Stream stream)
- where TPixel : unmanaged, IPixel
- {
- if (stream.CanSeek)
- {
- return this.Decode(stream);
- }
- else
- {
- using (var ms = new MemoryStream())
- {
- await stream.CopyToAsync(ms).ConfigureAwait(false);
- ms.Position = 0;
- return this.Decode(ms);
- }
- }
- }
-
- ///
- /// Decodes the stream to the image.
- ///
- /// The pixel format.
- /// The stream containing image data.
- ///
- /// Thrown if the stream does not contain and end chunk.
- ///
- ///
- /// Thrown if the image is larger than the maximum allowable size.
- ///
- /// The decoded image.
+ ///
public Image Decode(Stream stream)
- where TPixel : unmanaged, IPixel
+ where TPixel : unmanaged, IPixel
{
var metadata = new ImageMetadata();
PngMetadata pngMetadata = metadata.GetPngMetadata();
@@ -266,31 +223,7 @@ public Image Decode(Stream stream)
}
}
- ///
- /// Reads the raw image information from the specified stream.
- ///
- /// The containing image data.
- public async Task IdentifyAsync(Stream stream)
- {
- if (stream.CanSeek)
- {
- return this.Identify(stream);
- }
- else
- {
- using (var ms = new FixedCapacityPooledMemoryStream(stream.Length))
- {
- await stream.CopyToAsync(ms).ConfigureAwait(false);
- ms.Position = 0;
- return this.Identify(ms);
- }
- }
- }
-
- ///
- /// Reads the raw image information from the specified stream.
- ///
- /// The containing image data.
+ ///
public IImageInfo Identify(Stream stream)
{
var metadata = new ImageMetadata();
@@ -446,7 +379,7 @@ private void InitializeImage(ImageMetadata metadata, out Image i
where TPixel : unmanaged, IPixel
{
image = Image.CreateUninitialized(
- this.configuration,
+ this.Configuration,
this.header.Width,
this.header.Height,
metadata);
@@ -460,7 +393,7 @@ private void InitializeImage(ImageMetadata metadata, out Image i
}
this.previousScanline = this.memoryAllocator.AllocateManagedByteBuffer(this.bytesPerScanline, AllocationOptions.Clean);
- this.scanline = this.configuration.MemoryAllocator.AllocateManagedByteBuffer(this.bytesPerScanline, AllocationOptions.Clean);
+ this.scanline = this.Configuration.MemoryAllocator.AllocateManagedByteBuffer(this.bytesPerScanline, AllocationOptions.Clean);
}
///
@@ -759,7 +692,7 @@ private void ProcessDefilteredScanline(ReadOnlySpan defilteredScan
case PngColorType.Rgb:
PngScanlineProcessor.ProcessRgbScanline(
- this.configuration,
+ this.Configuration,
this.header,
scanlineSpan,
rowSpan,
@@ -773,7 +706,7 @@ private void ProcessDefilteredScanline(ReadOnlySpan defilteredScan
case PngColorType.RgbWithAlpha:
PngScanlineProcessor.ProcessRgbaScanline(
- this.configuration,
+ this.Configuration,
this.header,
scanlineSpan,
rowSpan,
@@ -1258,7 +1191,7 @@ private void SkipChunkDataAndCrc(in PngChunk chunk)
private IManagedByteBuffer ReadChunkData(int length)
{
// We rent the buffer here to return it afterwards in Decode()
- IManagedByteBuffer buffer = this.configuration.MemoryAllocator.AllocateManagedByteBuffer(length, AllocationOptions.Clean);
+ IManagedByteBuffer buffer = this.Configuration.MemoryAllocator.AllocateManagedByteBuffer(length, AllocationOptions.Clean);
this.currentStream.Read(buffer.Array, 0, length);
diff --git a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs
index ae8946173b..3f6d721f6a 100644
--- a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs
+++ b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs
@@ -5,7 +5,6 @@
using System.Buffers;
using System.IO;
using System.Runtime.CompilerServices;
-using System.Threading.Tasks;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
@@ -16,7 +15,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
///
/// Performs the tga decoding operation.
///
- internal sealed class TgaDecoderCore
+ internal sealed class TgaDecoderCore : IImageDecoderInternals
{
///
/// A scratch buffer to reduce allocations.
@@ -38,11 +37,6 @@ internal sealed class TgaDecoderCore
///
private TgaFileHeader fileHeader;
- ///
- /// The global configuration.
- ///
- private readonly Configuration configuration;
-
///
/// Used for allocating memory during processing operations.
///
@@ -70,54 +64,22 @@ internal sealed class TgaDecoderCore
/// The options.
public TgaDecoderCore(Configuration configuration, ITgaDecoderOptions options)
{
- this.configuration = configuration;
+ this.Configuration = configuration;
this.memoryAllocator = configuration.MemoryAllocator;
this.options = options;
}
+ ///
+ public Configuration Configuration { get; }
+
///
/// Gets the dimensions of the image.
///
public Size Dimensions => new Size(this.fileHeader.Width, this.fileHeader.Height);
- ///
- /// Decodes the image from the specified stream.
- ///
- /// The pixel format.
- /// The stream, where the image should be decoded from. Cannot be null.
- ///
- /// is null.
- ///
- /// The decoded image.
- public async Task> DecodeAsync(Stream stream)
- where TPixel : unmanaged, IPixel
- {
- if (stream.CanSeek)
- {
- return this.Decode(stream);
- }
- else
- {
- using (var ms = new MemoryStream())
- {
- await stream.CopyToAsync(ms).ConfigureAwait(false);
- ms.Position = 0;
- return this.Decode(ms);
- }
- }
- }
-
- ///
- /// Decodes the image from the specified stream.
- ///
- /// The pixel format.
- /// The stream, where the image should be decoded from. Cannot be null.
- ///
- /// is null.
- ///
- /// The decoded image.
+ ///
public Image Decode(Stream stream)
- where TPixel : unmanaged, IPixel
+ where TPixel : unmanaged, IPixel
{
try
{
@@ -135,7 +97,7 @@ public Image Decode(Stream stream)
throw new UnknownImageFormatException("Width or height cannot be 0");
}
- var image = Image.CreateUninitialized(this.configuration, this.fileHeader.Width, this.fileHeader.Height, this.metadata);
+ var image = Image.CreateUninitialized(this.Configuration, this.fileHeader.Width, this.fileHeader.Height, this.metadata);
Buffer2D pixels = image.GetRootFramePixelBuffer();
if (this.fileHeader.ColorMapType == 1)
@@ -489,11 +451,11 @@ private void ReadBgra16(int width, int height, Buffer2D pixels,
if (this.fileHeader.ImageType == TgaImageType.BlackAndWhite)
{
- PixelOperations.Instance.FromLa16Bytes(this.configuration, rowSpan, pixelSpan, width);
+ PixelOperations.Instance.FromLa16Bytes(this.Configuration, rowSpan, pixelSpan, width);
}
else
{
- PixelOperations.Instance.FromBgra5551Bytes(this.configuration, rowSpan, pixelSpan, width);
+ PixelOperations.Instance.FromBgra5551Bytes(this.Configuration, rowSpan, pixelSpan, width);
}
}
}
@@ -678,31 +640,7 @@ private void ReadRle(int width, int height, Buffer2D pixels, int
}
}
- ///
- /// Reads the raw image information from the specified stream.
- ///
- /// The containing image data.
- public async Task IdentifyAsync(Stream stream)
- {
- if (stream.CanSeek)
- {
- return this.Identify(stream);
- }
- else
- {
- using (var ms = new FixedCapacityPooledMemoryStream(stream.Length))
- {
- await stream.CopyToAsync(ms).ConfigureAwait(false);
- ms.Position = 0;
- return this.Identify(ms);
- }
- }
- }
-
- ///
- /// Reads the raw image information from the specified stream.
- ///
- /// The containing image data.
+ ///
public IImageInfo Identify(Stream stream)
{
this.ReadFileHeader(stream);
@@ -719,7 +657,7 @@ private void ReadL8Row(int width, Buffer2D pixels, IManagedByteB
{
this.currentStream.Read(row);
Span pixelSpan = pixels.GetRowSpan(y);
- PixelOperations.Instance.FromL8Bytes(this.configuration, row.GetSpan(), pixelSpan, width);
+ PixelOperations.Instance.FromL8Bytes(this.Configuration, row.GetSpan(), pixelSpan, width);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -746,7 +684,7 @@ private void ReadBgr24Row(int width, Buffer2D pixels, IManagedBy
{
this.currentStream.Read(row);
Span pixelSpan = pixels.GetRowSpan(y);
- PixelOperations.Instance.FromBgr24Bytes(this.configuration, row.GetSpan(), pixelSpan, width);
+ PixelOperations.Instance.FromBgr24Bytes(this.Configuration, row.GetSpan(), pixelSpan, width);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -765,7 +703,7 @@ private void ReadBgra32Row(int width, Buffer2D pixels, IManagedB
{
this.currentStream.Read(row);
Span pixelSpan = pixels.GetRowSpan(y);
- PixelOperations.Instance.FromBgra32Bytes(this.configuration, row.GetSpan(), pixelSpan, width);
+ PixelOperations.Instance.FromBgra32Bytes(this.Configuration, row.GetSpan(), pixelSpan, width);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
diff --git a/src/ImageSharp/IO/FixedCapacityPooledMemoryStream.cs b/src/ImageSharp/IO/FixedCapacityPooledMemoryStream.cs
index 878fcc53a7..6953b0e102 100644
--- a/src/ImageSharp/IO/FixedCapacityPooledMemoryStream.cs
+++ b/src/ImageSharp/IO/FixedCapacityPooledMemoryStream.cs
@@ -3,6 +3,7 @@
using System.Buffers;
using System.IO;
+using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.IO
{
@@ -11,18 +12,19 @@ namespace SixLabors.ImageSharp.IO
///
internal sealed class FixedCapacityPooledMemoryStream : MemoryStream
{
- private readonly byte[] buffer;
+ private readonly IManagedByteBuffer buffer;
private bool isDisposed;
///
/// Initializes a new instance of the class.
///
/// The length of the stream buffer to rent.
- public FixedCapacityPooledMemoryStream(long length)
- : this(RentBuffer(length)) => this.Length = length;
+ /// The allocator to rent the buffer from.
+ public FixedCapacityPooledMemoryStream(long length, MemoryAllocator allocator)
+ : this(RentBuffer(length, allocator)) => this.Length = length;
- private FixedCapacityPooledMemoryStream(byte[] buffer)
- : base(buffer) => this.buffer = buffer;
+ private FixedCapacityPooledMemoryStream(IManagedByteBuffer buffer)
+ : base(buffer.Array) => this.buffer = buffer;
///
public override long Length { get; }
@@ -36,7 +38,7 @@ protected override void Dispose(bool disposing)
if (disposing)
{
- ArrayPool.Shared.Return(this.buffer);
+ this.buffer.Dispose();
}
base.Dispose(disposing);
@@ -45,6 +47,10 @@ protected override void Dispose(bool disposing)
// In the extrememly unlikely event someone ever gives us a stream
// with length longer than int.MaxValue then we'll use something else.
- private static byte[] RentBuffer(long length) => ArrayPool.Shared.Rent((int)length);
+ private static IManagedByteBuffer RentBuffer(long length, MemoryAllocator allocator)
+ {
+ Guard.MustBeBetweenOrEqualTo(length, 0, int.MaxValue, nameof(length));
+ return allocator.AllocateManagedByteBuffer((int)length);
+ }
}
}
diff --git a/src/ImageSharp/Image.FromStream.cs b/src/ImageSharp/Image.FromStream.cs
index 499f5ac195..d3fd35d5fc 100644
--- a/src/ImageSharp/Image.FromStream.cs
+++ b/src/ImageSharp/Image.FromStream.cs
@@ -8,6 +8,7 @@
using System.Threading.Tasks;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.IO;
+using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp
@@ -675,7 +676,7 @@ private static T WithSeekableStream(Configuration configuration, Stream strea
}
// We want to be able to load images from things like HttpContext.Request.Body
- using (var memoryStream = new FixedCapacityPooledMemoryStream(stream.Length))
+ using (MemoryStream memoryStream = configuration.MemoryAllocator.AllocateFixedCapacityMemoryStream(stream.Length))
{
stream.CopyTo(memoryStream);
memoryStream.Position = 0;
@@ -711,7 +712,7 @@ private static async Task WithSeekableStreamAsync(
return await action(stream).ConfigureAwait(false);
}
- using (var memoryStream = new FixedCapacityPooledMemoryStream(stream.Length))
+ using (MemoryStream memoryStream = configuration.MemoryAllocator.AllocateFixedCapacityMemoryStream(stream.Length))
{
await stream.CopyToAsync(memoryStream).ConfigureAwait(false);
memoryStream.Position = 0;
diff --git a/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs b/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs
index 45463c76fb..9a56390d89 100644
--- a/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs
+++ b/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs
@@ -2,6 +2,8 @@
// Licensed under the Apache License, Version 2.0.
using System.Buffers;
+using System.IO;
+using SixLabors.ImageSharp.IO;
namespace SixLabors.ImageSharp.Memory
{
@@ -98,5 +100,8 @@ internal static MemoryGroup AllocateGroup(
AllocationOptions options = AllocationOptions.None)
where T : struct
=> MemoryGroup.Allocate(memoryAllocator, totalLength, bufferAlignment, options);
+
+ internal static MemoryStream AllocateFixedCapacityMemoryStream(this MemoryAllocator allocator, long length) =>
+ new FixedCapacityPooledMemoryStream(length, allocator);
}
}