Browse Source

Use pooled stream for async decode/identify

pull/1574/head
James Jackson-South 6 years ago
parent
commit
089b41e2a9
  1. 4
      src/ImageSharp/Formats/Bmp/BmpDecoder.cs
  2. 3
      src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
  3. 4
      src/ImageSharp/Formats/Gif/GifDecoder.cs
  4. 3
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs
  5. 2
      src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
  6. 23
      src/ImageSharp/Formats/Png/PngDecoder.cs
  7. 3
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  8. 3
      src/ImageSharp/Formats/Tga/TgaDecoderCore.cs
  9. 50
      src/ImageSharp/IO/FixedCapacityPooledMemoryStream.cs
  10. 9
      src/ImageSharp/Image.FromStream.cs
  11. 2
      tests/ImageSharp.Tests/TestUtilities/AsyncStreamWrapper.cs

4
src/ImageSharp/Formats/Bmp/BmpDecoder.cs

@ -83,11 +83,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp
}
/// <inheritdoc/>
public async Task<IImageInfo> IdentifyAsync(Configuration configuration, Stream stream)
public Task<IImageInfo> IdentifyAsync(Configuration configuration, Stream stream)
{
Guard.NotNull(stream, nameof(stream));
return await new BmpDecoderCore(configuration, this).IdentifyAsync(stream).ConfigureAwait(false);
return new BmpDecoderCore(configuration, this).IdentifyAsync(stream);
}
}
}

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

@ -9,6 +9,7 @@ using System.Numerics;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Common.Helpers;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
@ -257,7 +258,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
public async Task<IImageInfo> IdentifyAsync(Stream stream)
{
using (var ms = new MemoryStream())
using (var ms = new FixedCapacityPooledMemoryStream(stream.Length))
{
await stream.CopyToAsync(ms).ConfigureAwait(false);
ms.Position = 0;

4
src/ImageSharp/Formats/Gif/GifDecoder.cs

@ -77,12 +77,12 @@ namespace SixLabors.ImageSharp.Formats.Gif
}
/// <inheritdoc/>
public async Task<IImageInfo> IdentifyAsync(Configuration configuration, Stream stream)
public Task<IImageInfo> IdentifyAsync(Configuration configuration, Stream stream)
{
Guard.NotNull(stream, nameof(stream));
var decoder = new GifDecoderCore(configuration, this);
return await decoder.IdentifyAsync(stream).ConfigureAwait(false);
return decoder.IdentifyAsync(stream);
}
/// <inheritdoc />

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

@ -7,6 +7,7 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
@ -199,7 +200,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
}
else
{
using (var ms = new MemoryStream())
using (var ms = new FixedCapacityPooledMemoryStream(stream.Length))
{
await stream.CopyToAsync(ms).ConfigureAwait(false);
ms.Position = 0;

2
src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs

@ -266,7 +266,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
}
else
{
using (var ms = new MemoryStream())
using (var ms = new FixedCapacityPooledMemoryStream(stream.Length))
{
await stream.CopyToAsync(ms).ConfigureAwait(false);
ms.Position = 0;

23
src/ImageSharp/Formats/Png/PngDecoder.cs

@ -9,25 +9,8 @@ using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Png
{
/// <summary>
/// Encoder for generating an image out of a png encoded stream.
/// Decoder for generating an image out of a png encoded stream.
/// </summary>
/// <remarks>
/// At the moment the following features are supported:
/// <para>
/// <b>Filters:</b> all filters are supported.
/// </para>
/// <para>
/// <b>Pixel formats:</b>
/// <list type="bullet">
/// <item>RGBA (True color) with alpha (8 bit).</item>
/// <item>RGB (True color) without alpha (8 bit).</item>
/// <item>grayscale with alpha (8 bit).</item>
/// <item>grayscale without alpha (8 bit).</item>
/// <item>Palette Index with alpha (8 bit).</item>
/// <item>Palette Index without alpha (8 bit).</item>
/// </list>
/// </para>
/// </remarks>
public sealed class PngDecoder : IImageDecoder, IPngDecoderOptions, IImageInfoDetector
{
/// <summary>
@ -97,10 +80,10 @@ namespace SixLabors.ImageSharp.Formats.Png
}
/// <inheritdoc/>
public async Task<IImageInfo> IdentifyAsync(Configuration configuration, Stream stream)
public Task<IImageInfo> IdentifyAsync(Configuration configuration, Stream stream)
{
var decoder = new PngDecoderCore(configuration, this);
return await decoder.IdentifyAsync(stream).ConfigureAwait(false);
return decoder.IdentifyAsync(stream);
}
/// <inheritdoc />

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

@ -13,6 +13,7 @@ using System.Threading.Tasks;
using SixLabors.ImageSharp.Formats.Png.Chunks;
using SixLabors.ImageSharp.Formats.Png.Filters;
using SixLabors.ImageSharp.Formats.Png.Zlib;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
@ -277,7 +278,7 @@ namespace SixLabors.ImageSharp.Formats.Png
}
else
{
using (var ms = new MemoryStream())
using (var ms = new FixedCapacityPooledMemoryStream(stream.Length))
{
await stream.CopyToAsync(ms).ConfigureAwait(false);
ms.Position = 0;

3
src/ImageSharp/Formats/Tga/TgaDecoderCore.cs

@ -6,6 +6,7 @@ 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;
using SixLabors.ImageSharp.PixelFormats;
@ -689,7 +690,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
}
else
{
using (var ms = new MemoryStream())
using (var ms = new FixedCapacityPooledMemoryStream(stream.Length))
{
await stream.CopyToAsync(ms).ConfigureAwait(false);
ms.Position = 0;

50
src/ImageSharp/IO/FixedCapacityPooledMemoryStream.cs

@ -0,0 +1,50 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System.Buffers;
using System.IO;
namespace SixLabors.ImageSharp.IO
{
/// <summary>
/// A memory stream constructed from a pooled buffer of known length.
/// </summary>
internal sealed class FixedCapacityPooledMemoryStream : MemoryStream
{
private readonly byte[] buffer;
private bool isDisposed;
/// <summary>
/// Initializes a new instance of the <see cref="FixedCapacityPooledMemoryStream"/> class.
/// </summary>
/// <param name="length">The length of the stream buffer to rent.</param>
public FixedCapacityPooledMemoryStream(long length)
: this(RentBuffer(length)) => this.Length = length;
private FixedCapacityPooledMemoryStream(byte[] buffer)
: base(buffer) => this.buffer = buffer;
/// <inheritdoc/>
public override long Length { get; }
/// <inheritdoc/>
protected override void Dispose(bool disposing)
{
if (!this.isDisposed)
{
this.isDisposed = true;
if (disposing)
{
ArrayPool<byte>.Shared.Return(this.buffer);
}
base.Dispose(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<byte>.Shared.Rent((int)length);
}
}

9
src/ImageSharp/Image.FromStream.cs

@ -7,6 +7,7 @@ using System.IO;
using System.Text;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp
@ -674,10 +675,7 @@ namespace SixLabors.ImageSharp
}
// We want to be able to load images from things like HttpContext.Request.Body
// TODO: Should really find a nice way to use a pool for these.
// Investigate readonly version of the linked implementation.
// https://github.com/mgravell/Pipelines.Sockets.Unofficial/compare/mgravell:24482d4...mgravell:6740ea4
using (var memoryStream = new MemoryStream())
using (var memoryStream = new FixedCapacityPooledMemoryStream(stream.Length))
{
stream.CopyTo(memoryStream);
memoryStream.Position = 0;
@ -713,8 +711,7 @@ namespace SixLabors.ImageSharp
return await action(stream).ConfigureAwait(false);
}
// TODO: See above comment.
using (var memoryStream = new MemoryStream())
using (var memoryStream = new FixedCapacityPooledMemoryStream(stream.Length))
{
await stream.CopyToAsync(memoryStream).ConfigureAwait(false);
memoryStream.Position = 0;

2
tests/ImageSharp.Tests/TestUtilities/AsyncStreamWrapper.cs

@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities
public override bool CanWrite => this.inner.CanWrite;
public override long Length => throw new NotSupportedException("The stream is not seekable.");
public override long Length => this.inner.Length;
public override long Position
{

Loading…
Cancel
Save