Skip to content

Commit bbf3233

Browse files
Merge pull request #1223 from SixLabors/af/FixedCapacityPooledMemoryStream-use-allocator
Use MemoryAllocator in FixedCapacityPooledMemoryStream
2 parents b29bb74 + 481241d commit bbf3233

File tree

10 files changed

+184
-379
lines changed

10 files changed

+184
-379
lines changed

src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs

Lines changed: 14 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
2222
/// <remarks>
2323
/// A useful decoding source example can be found at <see href="https://dxr.mozilla.org/mozilla-central/source/image/decoders/nsBMPDecoder.cpp"/>
2424
/// </remarks>
25-
internal sealed class BmpDecoderCore
25+
internal sealed class BmpDecoderCore : IImageDecoderInternals
2626
{
2727
/// <summary>
2828
/// The default mask for the red part of the color for 16 bit rgb bitmaps.
@@ -89,11 +89,6 @@ internal sealed class BmpDecoderCore
8989
/// </summary>
9090
private BmpInfoHeader infoHeader;
9191

92-
/// <summary>
93-
/// The global configuration.
94-
/// </summary>
95-
private readonly Configuration configuration;
96-
9792
/// <summary>
9893
/// Used for allocating memory during processing operations.
9994
/// </summary>
@@ -111,67 +106,28 @@ internal sealed class BmpDecoderCore
111106
/// <param name="options">The options.</param>
112107
public BmpDecoderCore(Configuration configuration, IBmpDecoderOptions options)
113108
{
114-
this.configuration = configuration;
109+
this.Configuration = configuration;
115110
this.memoryAllocator = configuration.MemoryAllocator;
116111
this.options = options;
117112
}
118113

114+
/// <inheritdoc />
115+
public Configuration Configuration { get; }
116+
119117
/// <summary>
120118
/// Gets the dimensions of the image.
121119
/// </summary>
122120
public Size Dimensions => new Size(this.infoHeader.Width, this.infoHeader.Height);
123121

124-
/// <summary>
125-
/// Decodes the image from the specified this._stream and sets
126-
/// the data to image.
127-
/// </summary>
128-
/// <typeparam name="TPixel">The pixel format.</typeparam>
129-
/// <param name="stream">The stream, where the image should be
130-
/// decoded from. Cannot be null (Nothing in Visual Basic).</param>
131-
/// <exception cref="System.ArgumentNullException">
132-
/// <para><paramref name="stream"/> is null.</para>
133-
/// </exception>
134-
/// <returns>The decoded image.</returns>
135-
public async Task<Image<TPixel>> DecodeAsync<TPixel>(Stream stream)
136-
where TPixel : unmanaged, IPixel<TPixel>
137-
{
138-
// if we can seek then we arn't in a context that errors on async operations
139-
if (stream.CanSeek)
140-
{
141-
return this.Decode<TPixel>(stream);
142-
}
143-
else
144-
{
145-
// cheat for now do async copy of the stream into memory stream and use the sync version
146-
// we should use an array pool backed memorystream implementation
147-
using (var ms = new MemoryStream())
148-
{
149-
await stream.CopyToAsync(ms).ConfigureAwait(false);
150-
ms.Position = 0;
151-
return this.Decode<TPixel>(ms);
152-
}
153-
}
154-
}
155-
156-
/// <summary>
157-
/// Decodes the image from the specified this._stream and sets
158-
/// the data to image.
159-
/// </summary>
160-
/// <typeparam name="TPixel">The pixel format.</typeparam>
161-
/// <param name="stream">The stream, where the image should be
162-
/// decoded from. Cannot be null (Nothing in Visual Basic).</param>
163-
/// <exception cref="System.ArgumentNullException">
164-
/// <para><paramref name="stream"/> is null.</para>
165-
/// </exception>
166-
/// <returns>The decoded image.</returns>
122+
/// <inheritdoc />
167123
public Image<TPixel> Decode<TPixel>(Stream stream)
168-
where TPixel : unmanaged, IPixel<TPixel>
124+
where TPixel : unmanaged, IPixel<TPixel>
169125
{
170126
try
171127
{
172128
int bytesPerColorMapEntry = this.ReadImageHeaders(stream, out bool inverted, out byte[] palette);
173129

174-
var image = new Image<TPixel>(this.configuration, this.infoHeader.Width, this.infoHeader.Height, this.metadata);
130+
var image = new Image<TPixel>(this.Configuration, this.infoHeader.Width, this.infoHeader.Height, this.metadata);
175131

176132
Buffer2D<TPixel> pixels = image.GetRootFramePixelBuffer();
177133

@@ -242,30 +198,13 @@ public Image<TPixel> Decode<TPixel>(Stream stream)
242198
}
243199
}
244200

245-
/// <summary>
246-
/// Reads the raw image information from the specified stream.
247-
/// </summary>
248-
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
201+
/// <inheritdoc />
249202
public IImageInfo Identify(Stream stream)
250203
{
251204
this.ReadImageHeaders(stream, out _, out _);
252205
return new ImageInfo(new PixelTypeInfo(this.infoHeader.BitsPerPixel), this.infoHeader.Width, this.infoHeader.Height, this.metadata);
253206
}
254207

255-
/// <summary>
256-
/// Reads the raw image information from the specified stream.
257-
/// </summary>
258-
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
259-
public async Task<IImageInfo> IdentifyAsync(Stream stream)
260-
{
261-
using (var ms = new FixedCapacityPooledMemoryStream(stream.Length))
262-
{
263-
await stream.CopyToAsync(ms).ConfigureAwait(false);
264-
ms.Position = 0;
265-
return this.Identify(ms);
266-
}
267-
}
268-
269208
/// <summary>
270209
/// Returns the y- value based on the given height.
271210
/// </summary>
@@ -999,7 +938,7 @@ private void ReadRgb24<TPixel>(Buffer2D<TPixel> pixels, int width, int height, b
999938
int newY = Invert(y, height, inverted);
1000939
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
1001940
PixelOperations<TPixel>.Instance.FromBgr24Bytes(
1002-
this.configuration,
941+
this.Configuration,
1003942
row.GetSpan(),
1004943
pixelSpan,
1005944
width);
@@ -1028,7 +967,7 @@ private void ReadRgb32Fast<TPixel>(Buffer2D<TPixel> pixels, int width, int heigh
1028967
int newY = Invert(y, height, inverted);
1029968
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
1030969
PixelOperations<TPixel>.Instance.FromBgra32Bytes(
1031-
this.configuration,
970+
this.Configuration,
1032971
row.GetSpan(),
1033972
pixelSpan,
1034973
width);
@@ -1065,7 +1004,7 @@ private void ReadRgb32Slow<TPixel>(Buffer2D<TPixel> pixels, int width, int heigh
10651004
this.stream.Read(row);
10661005

10671006
PixelOperations<Bgra32>.Instance.FromBgra32Bytes(
1068-
this.configuration,
1007+
this.Configuration,
10691008
row.GetSpan(),
10701009
bgraRowSpan,
10711010
width);
@@ -1101,7 +1040,7 @@ private void ReadRgb32Slow<TPixel>(Buffer2D<TPixel> pixels, int width, int heigh
11011040
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
11021041

11031042
PixelOperations<TPixel>.Instance.FromBgra32Bytes(
1104-
this.configuration,
1043+
this.Configuration,
11051044
row.GetSpan(),
11061045
pixelSpan,
11071046
width);
@@ -1115,7 +1054,7 @@ private void ReadRgb32Slow<TPixel>(Buffer2D<TPixel> pixels, int width, int heigh
11151054
{
11161055
this.stream.Read(row);
11171056
PixelOperations<Bgra32>.Instance.FromBgra32Bytes(
1118-
this.configuration,
1057+
this.Configuration,
11191058
row.GetSpan(),
11201059
bgraRowSpan,
11211060
width);

src/ImageSharp/Formats/Gif/GifDecoderCore.cs

Lines changed: 13 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,13 @@ namespace SixLabors.ImageSharp.Formats.Gif
1717
/// <summary>
1818
/// Performs the gif decoding operation.
1919
/// </summary>
20-
internal sealed class GifDecoderCore
20+
internal sealed class GifDecoderCore : IImageDecoderInternals
2121
{
2222
/// <summary>
2323
/// The temp buffer used to reduce allocations.
2424
/// </summary>
2525
private readonly byte[] buffer = new byte[16];
2626

27-
/// <summary>
28-
/// The global configuration.
29-
/// </summary>
30-
private readonly Configuration configuration;
31-
3227
/// <summary>
3328
/// The currently loaded stream.
3429
/// </summary>
@@ -78,9 +73,12 @@ public GifDecoderCore(Configuration configuration, IGifDecoderOptions options)
7873
{
7974
this.IgnoreMetadata = options.IgnoreMetadata;
8075
this.DecodingMode = options.DecodingMode;
81-
this.configuration = configuration ?? Configuration.Default;
76+
this.Configuration = configuration ?? Configuration.Default;
8277
}
8378

79+
/// <inheritdoc />
80+
public Configuration Configuration { get; }
81+
8482
/// <summary>
8583
/// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded.
8684
/// </summary>
@@ -96,40 +94,11 @@ public GifDecoderCore(Configuration configuration, IGifDecoderOptions options)
9694
/// </summary>
9795
public Size Dimensions => new Size(this.imageDescriptor.Width, this.imageDescriptor.Height);
9896

99-
private MemoryAllocator MemoryAllocator => this.configuration.MemoryAllocator;
100-
101-
/// <summary>
102-
/// Decodes the stream to the image.
103-
/// </summary>
104-
/// <typeparam name="TPixel">The pixel format.</typeparam>
105-
/// <param name="stream">The stream containing image data.</param>
106-
/// <returns>The decoded image</returns>
107-
public async Task<Image<TPixel>> DecodeAsync<TPixel>(Stream stream)
108-
where TPixel : unmanaged, IPixel<TPixel>
109-
{
110-
if (stream.CanSeek)
111-
{
112-
return this.Decode<TPixel>(stream);
113-
}
114-
else
115-
{
116-
using (var ms = new MemoryStream())
117-
{
118-
await stream.CopyToAsync(ms).ConfigureAwait(false);
119-
ms.Position = 0;
120-
return this.Decode<TPixel>(ms);
121-
}
122-
}
123-
}
97+
private MemoryAllocator MemoryAllocator => this.Configuration.MemoryAllocator;
12498

125-
/// <summary>
126-
/// Decodes the stream to the image.
127-
/// </summary>
128-
/// <typeparam name="TPixel">The pixel format.</typeparam>
129-
/// <param name="stream">The stream containing image data.</param>
130-
/// <returns>The decoded image</returns>
99+
/// <inheritdoc />
131100
public Image<TPixel> Decode<TPixel>(Stream stream)
132-
where TPixel : unmanaged, IPixel<TPixel>
101+
where TPixel : unmanaged, IPixel<TPixel>
133102
{
134103
Image<TPixel> image = null;
135104
ImageFrame<TPixel> previousFrame = null;
@@ -188,31 +157,7 @@ public Image<TPixel> Decode<TPixel>(Stream stream)
188157
return image;
189158
}
190159

191-
/// <summary>
192-
/// Reads the raw image information from the specified stream.
193-
/// </summary>
194-
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
195-
public async Task<IImageInfo> IdentifyAsync(Stream stream)
196-
{
197-
if (stream.CanSeek)
198-
{
199-
return this.Identify(stream);
200-
}
201-
else
202-
{
203-
using (var ms = new FixedCapacityPooledMemoryStream(stream.Length))
204-
{
205-
await stream.CopyToAsync(ms).ConfigureAwait(false);
206-
ms.Position = 0;
207-
return this.Identify(ms);
208-
}
209-
}
210-
}
211-
212-
/// <summary>
213-
/// Reads the raw image information from the specified stream.
214-
/// </summary>
215-
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
160+
/// <inheritdoc />
216161
public IImageInfo Identify(Stream stream)
217162
{
218163
try
@@ -410,11 +355,11 @@ private void ReadFrame<TPixel>(ref Image<TPixel> image, ref ImageFrame<TPixel> p
410355
if (this.imageDescriptor.LocalColorTableFlag)
411356
{
412357
int length = this.imageDescriptor.LocalColorTableSize * 3;
413-
localColorTable = this.configuration.MemoryAllocator.AllocateManagedByteBuffer(length, AllocationOptions.Clean);
358+
localColorTable = this.Configuration.MemoryAllocator.AllocateManagedByteBuffer(length, AllocationOptions.Clean);
414359
this.stream.Read(localColorTable.Array, 0, length);
415360
}
416361

417-
indices = this.configuration.MemoryAllocator.Allocate2D<byte>(this.imageDescriptor.Width, this.imageDescriptor.Height, AllocationOptions.Clean);
362+
indices = this.Configuration.MemoryAllocator.Allocate2D<byte>(this.imageDescriptor.Width, this.imageDescriptor.Height, AllocationOptions.Clean);
418363

419364
this.ReadFrameIndices(indices);
420365
ReadOnlySpan<Rgb24> colorTable = MemoryMarshal.Cast<byte, Rgb24>((localColorTable ?? this.globalColorTable).GetSpan());
@@ -438,7 +383,7 @@ private void ReadFrame<TPixel>(ref Image<TPixel> image, ref ImageFrame<TPixel> p
438383
private void ReadFrameIndices(Buffer2D<byte> indices)
439384
{
440385
int dataSize = this.stream.ReadByte();
441-
using var lzwDecoder = new LzwDecoder(this.configuration.MemoryAllocator, this.stream);
386+
using var lzwDecoder = new LzwDecoder(this.Configuration.MemoryAllocator, this.stream);
442387
lzwDecoder.DecodePixels(dataSize, indices);
443388
}
444389

@@ -464,7 +409,7 @@ private void ReadFrameColors<TPixel>(ref Image<TPixel> image, ref ImageFrame<TPi
464409
if (previousFrame is null)
465410
{
466411
// This initializes the image to become fully transparent because the alpha channel is zero.
467-
image = new Image<TPixel>(this.configuration, imageWidth, imageHeight, this.metadata);
412+
image = new Image<TPixel>(this.Configuration, imageWidth, imageHeight, this.metadata);
468413

469414
this.SetFrameMetadata(image.Frames.RootFrame.Metadata);
470415

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Apache License, Version 2.0.
3+
4+
using System.IO;
5+
using SixLabors.ImageSharp.PixelFormats;
6+
7+
namespace SixLabors.ImageSharp.Formats
8+
{
9+
/// <summary>
10+
/// Abstraction for shared internals for ***DecoderCore implementations to be used with <see cref="ImageDecoderUtilities"/>.
11+
/// </summary>
12+
internal interface IImageDecoderInternals
13+
{
14+
/// <summary>
15+
/// Gets the associated configuration.
16+
/// </summary>
17+
Configuration Configuration { get; }
18+
19+
/// <summary>
20+
/// Decodes the image from the specified stream.
21+
/// </summary>
22+
/// <typeparam name="TPixel">The pixel format.</typeparam>
23+
/// <param name="stream">The stream, where the image should be decoded from. Cannot be null.</param>
24+
/// <exception cref="System.ArgumentNullException">
25+
/// <para><paramref name="stream"/> is null.</para>
26+
/// </exception>
27+
/// <returns>The decoded image.</returns>
28+
Image<TPixel> Decode<TPixel>(Stream stream)
29+
where TPixel : unmanaged, IPixel<TPixel>;
30+
31+
/// <summary>
32+
/// Reads the raw image information from the specified stream.
33+
/// </summary>
34+
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
35+
/// <returns>The <see cref="IImageInfo"/>.</returns>
36+
IImageInfo Identify(Stream stream);
37+
}
38+
}

0 commit comments

Comments
 (0)