Browse Source

Add Async APIs to IImageEncoder and IImageDecoder

pull/1574/head
Scott Williams 6 years ago
parent
commit
3a809ec4c5
  1. 32
      src/ImageSharp/Formats/Bmp/BmpDecoder.cs
  2. 41
      src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
  3. 13
      src/ImageSharp/Formats/Bmp/BmpEncoder.cs
  4. 21
      src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
  5. 35
      src/ImageSharp/Formats/Gif/GifDecoder.cs
  6. 35
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs
  7. 9
      src/ImageSharp/Formats/Gif/GifEncoder.cs
  8. 20
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  9. 21
      src/ImageSharp/Formats/IImageDecoder.cs
  10. 12
      src/ImageSharp/Formats/IImageEncoder.cs
  11. 13
      src/ImageSharp/Formats/IImageInfoDetector.cs
  12. 38
      src/ImageSharp/Formats/Jpeg/JpegDecoder.cs
  13. 34
      src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
  14. 23
      src/ImageSharp/Formats/Jpeg/JpegEncoder.cs
  15. 3
      src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
  16. 38
      src/ImageSharp/Formats/Png/PngDecoder.cs
  17. 41
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  18. 16
      src/ImageSharp/Formats/Png/PngEncoder.cs
  19. 20
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  20. 35
      src/ImageSharp/Formats/Tga/TgaDecoder.cs
  21. 38
      src/ImageSharp/Formats/Tga/TgaDecoderCore.cs
  22. 10
      src/ImageSharp/Formats/Tga/TgaEncoder.cs
  23. 19
      src/ImageSharp/Formats/Tga/TgaEncoderCore.cs
  24. 17
      tests/ImageSharp.Tests/TestFormat.cs
  25. 8
      tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs
  26. 12
      tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceDecoder.cs
  27. 15
      tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceEncoder.cs
  28. 32
      tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs

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

@ -2,6 +2,7 @@
// Licensed under the GNU Affero General Public License, Version 3.
using System.IO;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -27,6 +28,26 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// </summary>
public RleSkippedPixelHandling RleSkippedPixelHandling { get; set; } = RleSkippedPixelHandling.Black;
/// <inheritdoc/>
public async Task<Image<TPixel>> DecodeAsync<TPixel>(Configuration configuration, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
Guard.NotNull(stream, nameof(stream));
var decoder = new BmpDecoderCore(configuration, this);
try
{
return await decoder.DecodeAsync<TPixel>(stream).ConfigureAwait(false);
}
catch (InvalidMemoryOperationException ex)
{
Size dims = decoder.Dimensions;
throw new InvalidImageContentException($"Can not decode image. Failed to allocate buffers for possibly degenerate dimensions: {dims.Width}x{dims.Height}. This error can happen for very large RLE bitmaps, which are not supported.", ex);
}
}
/// <inheritdoc/>
public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
@ -50,6 +71,9 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// <inheritdoc />
public Image Decode(Configuration configuration, Stream stream) => this.Decode<Rgba32>(configuration, stream);
/// <inheritdoc />
public async Task<Image> DecodeAsync(Configuration configuration, Stream stream) => await this.DecodeAsync<Rgba32>(configuration, stream).ConfigureAwait(false);
/// <inheritdoc/>
public IImageInfo Identify(Configuration configuration, Stream stream)
{
@ -57,5 +81,13 @@ namespace SixLabors.ImageSharp.Formats.Bmp
return new BmpDecoderCore(configuration, this).Identify(stream);
}
/// <inheritdoc/>
public async Task<IImageInfo> IdentifyAsync(Configuration configuration, Stream stream)
{
Guard.NotNull(stream, nameof(stream));
return await new BmpDecoderCore(configuration, this).IdentifyAsync(stream).ConfigureAwait(false);
}
}
}

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

@ -7,6 +7,7 @@ using System.Buffers.Binary;
using System.IO;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Common.Helpers;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
@ -130,8 +131,32 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// <para><paramref name="stream"/> is null.</para>
/// </exception>
/// <returns>The decoded image.</returns>
public Image<TPixel> Decode<TPixel>(Stream stream)
public async Task<Image<TPixel>> DecodeAsync<TPixel>(Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
// 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<TPixel>(ms);
}
}
/// <summary>
/// Decodes the image from the specified this._stream and sets
/// the data to image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="stream">The stream, where the image should be
/// decoded from. Cannot be null (Nothing in Visual Basic).</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="stream"/> is null.</para>
/// </exception>
/// <returns>The decoded image.</returns>
public Image<TPixel> Decode<TPixel>(Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
try
{
@ -218,6 +243,20 @@ namespace SixLabors.ImageSharp.Formats.Bmp
return new ImageInfo(new PixelTypeInfo(this.infoHeader.BitsPerPixel), this.infoHeader.Width, this.infoHeader.Height, this.metadata);
}
/// <summary>
/// Reads the raw image information from the specified stream.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
public async Task<IImageInfo> IdentifyAsync(Stream stream)
{
using (var ms = new MemoryStream())
{
await stream.CopyToAsync(ms).ConfigureAwait(false);
ms.Position = 0;
return this.Identify(ms);
}
}
/// <summary>
/// Returns the y- value based on the given height.
/// </summary>

13
src/ImageSharp/Formats/Bmp/BmpEncoder.cs

@ -1,7 +1,8 @@
// Copyright (c) Six Labors and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the GNU Affero General Public License, Version 3.
using System.IO;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Quantization;
@ -39,5 +40,13 @@ namespace SixLabors.ImageSharp.Formats.Bmp
var encoder = new BmpEncoderCore(this, image.GetMemoryAllocator());
encoder.Encode(image, stream);
}
/// <inheritdoc/>
public Task EncodeAsync<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
var encoder = new BmpEncoderCore(this, image.GetMemoryAllocator());
return encoder.EncodeAsync(image, stream);
}
}
}
}

21
src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs

@ -5,7 +5,7 @@ using System;
using System.Buffers;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Common.Helpers;
using SixLabors.ImageSharp.Memory;
@ -97,8 +97,25 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="image">The <see cref="ImageFrame{TPixel}"/> to encode from.</param>
/// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param>
public void Encode<TPixel>(Image<TPixel> image, Stream stream)
public async Task EncodeAsync<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
using (var ms = new MemoryStream())
{
this.Encode(image, ms);
ms.Position = 0;
await ms.CopyToAsync(stream).ConfigureAwait(false);
}
}
/// <summary>
/// Encodes the image to the specified stream from the <see cref="ImageFrame{TPixel}"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="image">The <see cref="ImageFrame{TPixel}"/> to encode from.</param>
/// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param>
public void Encode<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
Guard.NotNull(image, nameof(image));
Guard.NotNull(stream, nameof(stream));

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

@ -3,6 +3,7 @@
using System;
using System.IO;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
@ -24,6 +25,27 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// </summary>
public FrameDecodingMode DecodingMode { get; set; } = FrameDecodingMode.All;
/// <inheritdoc/>
public async Task<Image<TPixel>> DecodeAsync<TPixel>(Configuration configuration, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
var decoder = new GifDecoderCore(configuration, this);
try
{
return await decoder.DecodeAsync<TPixel>(stream).ConfigureAwait(false);
}
catch (InvalidMemoryOperationException ex)
{
Size dims = decoder.Dimensions;
GifThrowHelper.ThrowInvalidImageContentException($"Can not decode image. Failed to allocate buffers for possibly degenerate dimensions: {dims.Width}x{dims.Height}.", ex);
// Not reachable, as the previous statement will throw a exception.
return null;
}
}
/// <inheritdoc/>
public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
@ -54,7 +76,20 @@ namespace SixLabors.ImageSharp.Formats.Gif
return decoder.Identify(stream);
}
/// <inheritdoc/>
public async 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);
}
/// <inheritdoc />
public Image Decode(Configuration configuration, Stream stream) => this.Decode<Rgba32>(configuration, stream);
/// <inheritdoc />
public async Task<Image> DecodeAsync(Configuration configuration, Stream stream) => await this.DecodeAsync<Rgba32>(configuration, stream).ConfigureAwait(false);
}
}

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

@ -6,7 +6,7 @@ using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
@ -103,8 +103,25 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="stream">The stream containing image data.</param>
/// <returns>The decoded image</returns>
public Image<TPixel> Decode<TPixel>(Stream stream)
public async Task<Image<TPixel>> DecodeAsync<TPixel>(Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
using (var ms = new MemoryStream())
{
await stream.CopyToAsync(ms).ConfigureAwait(false);
ms.Position = 0;
return this.Decode<TPixel>(ms);
}
}
/// <summary>
/// Decodes the stream to the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="stream">The stream containing image data.</param>
/// <returns>The decoded image</returns>
public Image<TPixel> Decode<TPixel>(Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
Image<TPixel> image = null;
ImageFrame<TPixel> previousFrame = null;
@ -163,6 +180,20 @@ namespace SixLabors.ImageSharp.Formats.Gif
return image;
}
/// <summary>
/// Reads the raw image information from the specified stream.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
public async Task<IImageInfo> IdentifyAsync(Stream stream)
{
using (var ms = new MemoryStream())
{
await stream.CopyToAsync(ms).ConfigureAwait(false);
ms.Position = 0;
return this.Identify(ms);
}
}
/// <summary>
/// Reads the raw image information from the specified stream.
/// </summary>

9
src/ImageSharp/Formats/Gif/GifEncoder.cs

@ -2,6 +2,7 @@
// Licensed under the GNU Affero General Public License, Version 3.
using System.IO;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
@ -38,5 +39,13 @@ namespace SixLabors.ImageSharp.Formats.Gif
var encoder = new GifEncoderCore(image.GetConfiguration(), this);
encoder.Encode(image, stream);
}
/// <inheritdoc/>
public Task EncodeAsync<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
var encoder = new GifEncoderCore(image.GetConfiguration(), this);
return encoder.EncodeAsync(image, stream);
}
}
}

20
src/ImageSharp/Formats/Gif/GifEncoderCore.cs

@ -6,6 +6,7 @@ using System.Buffers;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
@ -74,8 +75,25 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="image">The <see cref="Image{TPixel}"/> to encode from.</param>
/// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param>
public void Encode<TPixel>(Image<TPixel> image, Stream stream)
public async Task EncodeAsync<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
using (var ms = new MemoryStream())
{
this.Encode(image, ms);
ms.Position = 0;
await ms.CopyToAsync(stream).ConfigureAwait(false);
}
}
/// <summary>
/// Encodes the image to the specified stream from the <see cref="Image{TPixel}"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="image">The <see cref="Image{TPixel}"/> to encode from.</param>
/// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param>
public void Encode<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
Guard.NotNull(image, nameof(image));
Guard.NotNull(stream, nameof(stream));

21
src/ImageSharp/Formats/IImageDecoder.cs

@ -2,6 +2,7 @@
// Licensed under the GNU Affero General Public License, Version 3.
using System.IO;
using System.Threading.Tasks;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats
@ -30,5 +31,25 @@ namespace SixLabors.ImageSharp.Formats
/// <returns>The <see cref="Image"/>.</returns>
// TODO: Document ImageFormatExceptions (https://github.com/SixLabors/ImageSharp/issues/1110)
Image Decode(Configuration configuration, Stream stream);
/// <summary>
/// Decodes the image from the specified stream to an <see cref="Image{TPixel}"/> of a specific pixel type.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="configuration">The configuration for the image.</param>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
// TODO: Document ImageFormatExceptions (https://github.com/SixLabors/ImageSharp/issues/1110)
Task<Image<TPixel>> DecodeAsync<TPixel>(Configuration configuration, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>;
/// <summary>
/// Decodes the image from the specified stream to an <see cref="Image"/>.
/// </summary>
/// <param name="configuration">The configuration for the image.</param>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <returns>The <see cref="Image"/>.</returns>
// TODO: Document ImageFormatExceptions (https://github.com/SixLabors/ImageSharp/issues/1110)
Task<Image> DecodeAsync(Configuration configuration, Stream stream);
}
}

12
src/ImageSharp/Formats/IImageEncoder.cs

@ -1,7 +1,8 @@
// Copyright (c) Six Labors and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the GNU Affero General Public License, Version 3.
using System.IO;
using System.Threading.Tasks;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats
@ -19,5 +20,14 @@ namespace SixLabors.ImageSharp.Formats
/// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param>
void Encode<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>;
/// <summary>
/// Encodes the image to the specified stream from the <see cref="Image{TPixel}"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="image">The <see cref="Image{TPixel}"/> to encode from.</param>
/// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param>
Task EncodeAsync<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>;
}
}

13
src/ImageSharp/Formats/IImageInfoDetector.cs

@ -1,7 +1,8 @@
// Copyright (c) Six Labors and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the GNU Affero General Public License, Version 3.
using System.IO;
using System.Threading.Tasks;
namespace SixLabors.ImageSharp.Formats
{
@ -17,5 +18,13 @@ namespace SixLabors.ImageSharp.Formats
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <returns>The <see cref="PixelTypeInfo"/> object</returns>
IImageInfo Identify(Configuration configuration, Stream stream);
/// <summary>
/// Reads the raw image information from the specified stream.
/// </summary>
/// <param name="configuration">The configuration for the image.</param>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <returns>The <see cref="PixelTypeInfo"/> object</returns>
Task<IImageInfo> IdentifyAsync(Configuration configuration, Stream stream);
}
}
}

38
src/ImageSharp/Formats/Jpeg/JpegDecoder.cs

@ -2,6 +2,7 @@
// Licensed under the GNU Affero General Public License, Version 3.
using System.IO;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -17,6 +18,28 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// </summary>
public bool IgnoreMetadata { get; set; }
/// <inheritdoc/>
public async Task<Image<TPixel>> DecodeAsync<TPixel>(Configuration configuration, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
Guard.NotNull(stream, nameof(stream));
using var decoder = new JpegDecoderCore(configuration, this);
try
{
return await decoder.DecodeAsync<TPixel>(stream);
}
catch (InvalidMemoryOperationException ex)
{
(int w, int h) = (decoder.ImageWidth, decoder.ImageHeight);
JpegThrowHelper.ThrowInvalidImageContentException($"Can not decode image. Failed to allocate buffers for possibly degenerate dimensions: {w}x{h}.", ex);
// Not reachable, as the previous statement will throw a exception.
return null;
}
}
/// <inheritdoc/>
public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
@ -43,6 +66,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
public Image Decode(Configuration configuration, Stream stream)
=> this.Decode<Rgba32>(configuration, stream);
/// <inheritdoc />
public async Task<Image> DecodeAsync(Configuration configuration, Stream stream)
=> await this.DecodeAsync<Rgba32>(configuration, stream).ConfigureAwait(false);
/// <inheritdoc/>
public IImageInfo Identify(Configuration configuration, Stream stream)
{
@ -53,5 +80,16 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
return decoder.Identify(stream);
}
}
/// <inheritdoc/>
public async Task<IImageInfo> IdentifyAsync(Configuration configuration, Stream stream)
{
Guard.NotNull(stream, nameof(stream));
using (var decoder = new JpegDecoderCore(configuration, this))
{
return await decoder.IdentifyAsync(stream).ConfigureAwait(false);
}
}
}
}

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

@ -6,6 +6,7 @@ using System.Buffers.Binary;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Common.Helpers;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
@ -218,8 +219,25 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="stream">The stream, where the image should be.</param>
/// <returns>The decoded image.</returns>
public Image<TPixel> Decode<TPixel>(Stream stream)
public async Task<Image<TPixel>> DecodeAsync<TPixel>(Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
using (var ms = new MemoryStream())
{
await stream.CopyToAsync(ms).ConfigureAwait(false);
ms.Position = 0;
return this.Decode<TPixel>(ms);
}
}
/// <summary>
/// Decodes the image from the specified <see cref="Stream"/> and sets the data to image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="stream">The stream, where the image should be.</param>
/// <returns>The decoded image.</returns>
public Image<TPixel> Decode<TPixel>(Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
this.ParseStream(stream);
this.InitExifProfile();
@ -229,6 +247,20 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
return this.PostProcessIntoImage<TPixel>();
}
/// <summary>
/// Reads the raw image information from the specified stream.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
public async Task<IImageInfo> IdentifyAsync(Stream stream)
{
using (var ms = new MemoryStream())
{
await stream.CopyToAsync(ms).ConfigureAwait(false);
ms.Position = 0;
return this.Identify(ms);
}
}
/// <summary>
/// Reads the raw image information from the specified stream.
/// </summary>

23
src/ImageSharp/Formats/Jpeg/JpegEncoder.cs

@ -1,7 +1,8 @@
// Copyright (c) Six Labors and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the GNU Affero General Public License, Version 3.
using System.IO;
using System.Threading.Tasks;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Jpeg
@ -35,5 +36,25 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
var encoder = new JpegEncoderCore(this);
encoder.Encode(image, stream);
}
/// <summary>
/// Encodes the image to the specified stream from the <see cref="Image{TPixel}"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="image">The <see cref="Image{TPixel}"/> to encode from.</param>
/// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param>
public async Task EncodeAsync<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
var encoder = new JpegEncoderCore(this);
// this hack has to be be here because JpegEncoderCore is unsafe
using (var ms = new MemoryStream())
{
encoder.Encode(image, ms);
ms.Position = 0;
await ms.CopyToAsync(stream).ConfigureAwait(false);
}
}
}
}

3
src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs

@ -6,6 +6,7 @@ using System.Buffers.Binary;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Common.Helpers;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
@ -194,7 +195,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// <param name="image">The image to write from.</param>
/// <param name="stream">The stream to write to.</param>
public void Encode<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
Guard.NotNull(image, nameof(image));
Guard.NotNull(stream, nameof(stream));

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

@ -2,6 +2,7 @@
// Licensed under the GNU Affero General Public License, Version 3.
using System.IO;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -34,6 +35,33 @@ namespace SixLabors.ImageSharp.Formats.Png
/// </summary>
public bool IgnoreMetadata { get; set; }
/// <summary>
/// Decodes the image from the specified stream to the <see cref="ImageFrame{TPixel}"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="configuration">The configuration for the image.</param>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <returns>The decoded image.</returns>
public async Task<Image<TPixel>> DecodeAsync<TPixel>(Configuration configuration, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
var decoder = new PngDecoderCore(configuration, this);
try
{
return await decoder.DecodeAsync<TPixel>(stream).ConfigureAwait(false);
}
catch (InvalidMemoryOperationException ex)
{
Size dims = decoder.Dimensions;
PngThrowHelper.ThrowInvalidImageContentException($"Can not decode image. Failed to allocate buffers for possibly degenerate dimensions: {dims.Width}x{dims.Height}.", ex);
// Not reachable, as the previous statement will throw a exception.
return null;
}
}
/// <summary>
/// Decodes the image from the specified stream to the <see cref="ImageFrame{TPixel}"/>.
/// </summary>
@ -68,7 +96,17 @@ namespace SixLabors.ImageSharp.Formats.Png
return decoder.Identify(stream);
}
/// <inheritdoc/>
public async Task<IImageInfo> IdentifyAsync(Configuration configuration, Stream stream)
{
var decoder = new PngDecoderCore(configuration, this);
return await decoder.IdentifyAsync(stream).ConfigureAwait(false);
}
/// <inheritdoc />
public Image Decode(Configuration configuration, Stream stream) => this.Decode<Rgba32>(configuration, stream);
/// <inheritdoc />
public async Task<Image> DecodeAsync(Configuration configuration, Stream stream) => await this.DecodeAsync<Rgba32>(configuration, stream).ConfigureAwait(false);
}
}

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

@ -9,7 +9,7 @@ using System.IO.Compression;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Formats.Png.Chunks;
using SixLabors.ImageSharp.Formats.Png.Filters;
using SixLabors.ImageSharp.Formats.Png.Zlib;
@ -149,8 +149,31 @@ namespace SixLabors.ImageSharp.Formats.Png
/// Thrown if the image is larger than the maximum allowable size.
/// </exception>
/// <returns>The decoded image.</returns>
public Image<TPixel> Decode<TPixel>(Stream stream)
public async Task<Image<TPixel>> DecodeAsync<TPixel>(Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
using (var ms = new MemoryStream())
{
await stream.CopyToAsync(ms).ConfigureAwait(false);
ms.Position = 0;
return this.Decode<TPixel>(ms);
}
}
/// <summary>
/// Decodes the stream to the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="stream">The stream containing image data.</param>
/// <exception cref="ImageFormatException">
/// Thrown if the stream does not contain and end chunk.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown if the image is larger than the maximum allowable size.
/// </exception>
/// <returns>The decoded image.</returns>
public Image<TPixel> Decode<TPixel>(Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
var metadata = new ImageMetadata();
PngMetadata pngMetadata = metadata.GetPngMetadata();
@ -240,6 +263,20 @@ namespace SixLabors.ImageSharp.Formats.Png
}
}
/// <summary>
/// Reads the raw image information from the specified stream.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
public async Task<IImageInfo> IdentifyAsync(Stream stream)
{
using (var ms = new MemoryStream())
{
await stream.CopyToAsync(ms).ConfigureAwait(false);
ms.Position = 0;
return this.Identify(ms);
}
}
/// <summary>
/// Reads the raw image information from the specified stream.
/// </summary>

16
src/ImageSharp/Formats/Png/PngEncoder.cs

@ -2,6 +2,7 @@
// Licensed under the GNU Affero General Public License, Version 3.
using System.IO;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Quantization;
@ -56,5 +57,20 @@ namespace SixLabors.ImageSharp.Formats.Png
encoder.Encode(image, stream);
}
}
/// <summary>
/// Encodes the image to the specified stream from the <see cref="Image{TPixel}"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="image">The <see cref="Image{TPixel}"/> to encode from.</param>
/// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param>
public async Task EncodeAsync<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
using (var encoder = new PngEncoderCore(image.GetMemoryAllocator(), image.GetConfiguration(), new PngEncoderOptions(this)))
{
await encoder.EncodeAsync(image, stream);
}
}
}
}

20
src/ImageSharp/Formats/Png/PngEncoderCore.cs

@ -7,6 +7,7 @@ using System.Buffers.Binary;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats.Png.Chunks;
using SixLabors.ImageSharp.Formats.Png.Filters;
@ -131,8 +132,25 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="image">The <see cref="ImageFrame{TPixel}"/> to encode from.</param>
/// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param>
public void Encode<TPixel>(Image<TPixel> image, Stream stream)
public async Task EncodeAsync<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
using (var ms = new MemoryStream())
{
this.Encode(image, ms);
ms.Position = 0;
await ms.CopyToAsync(stream).ConfigureAwait(false);
}
}
/// <summary>
/// Encodes the image to the specified stream from the <see cref="Image{TPixel}"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="image">The <see cref="ImageFrame{TPixel}"/> to encode from.</param>
/// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param>
public void Encode<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
Guard.NotNull(image, nameof(image));
Guard.NotNull(stream, nameof(stream));

35
src/ImageSharp/Formats/Tga/TgaDecoder.cs

@ -2,6 +2,7 @@
// Licensed under the GNU Affero General Public License, Version 3.
using System.IO;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -12,6 +13,29 @@ namespace SixLabors.ImageSharp.Formats.Tga
/// </summary>
public sealed class TgaDecoder : IImageDecoder, ITgaDecoderOptions, IImageInfoDetector
{
/// <inheritdoc/>
public async Task<Image<TPixel>> DecodeAsync<TPixel>(Configuration configuration, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
Guard.NotNull(stream, nameof(stream));
var decoder = new TgaDecoderCore(configuration, this);
try
{
return await decoder.DecodeAsync<TPixel>(stream).ConfigureAwait(false);
}
catch (InvalidMemoryOperationException ex)
{
Size dims = decoder.Dimensions;
TgaThrowHelper.ThrowInvalidImageContentException($"Can not decode image. Failed to allocate buffers for possibly degenerate dimensions: {dims.Width}x{dims.Height}.", ex);
// Not reachable, as the previous statement will throw a exception.
return null;
}
}
/// <inheritdoc/>
public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
@ -38,6 +62,9 @@ namespace SixLabors.ImageSharp.Formats.Tga
/// <inheritdoc />
public Image Decode(Configuration configuration, Stream stream) => this.Decode<Rgba32>(configuration, stream);
/// <inheritdoc />
public async Task<Image> DecodeAsync(Configuration configuration, Stream stream) => await this.DecodeAsync<Rgba32>(configuration, stream).ConfigureAwait(false);
/// <inheritdoc/>
public IImageInfo Identify(Configuration configuration, Stream stream)
{
@ -45,5 +72,13 @@ namespace SixLabors.ImageSharp.Formats.Tga
return new TgaDecoderCore(configuration, this).Identify(stream);
}
/// <inheritdoc/>
public Task<IImageInfo> IdentifyAsync(Configuration configuration, Stream stream)
{
Guard.NotNull(stream, nameof(stream));
return new TgaDecoderCore(configuration, this).IdentifyAsync(stream);
}
}
}

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

@ -5,7 +5,7 @@ using System;
using System.Buffers;
using System.IO;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
@ -88,8 +88,28 @@ namespace SixLabors.ImageSharp.Formats.Tga
/// <para><paramref name="stream"/> is null.</para>
/// </exception>
/// <returns>The decoded image.</returns>
public Image<TPixel> Decode<TPixel>(Stream stream)
public async Task<Image<TPixel>> DecodeAsync<TPixel>(Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
using (var ms = new MemoryStream())
{
await stream.CopyToAsync(ms).ConfigureAwait(false);
ms.Position = 0;
return this.Decode<TPixel>(ms);
}
}
/// <summary>
/// Decodes the image from the specified stream.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="stream">The stream, where the image should be decoded from. Cannot be null.</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="stream"/> is null.</para>
/// </exception>
/// <returns>The decoded image.</returns>
public Image<TPixel> Decode<TPixel>(Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
try
{
@ -650,6 +670,20 @@ namespace SixLabors.ImageSharp.Formats.Tga
}
}
/// <summary>
/// Reads the raw image information from the specified stream.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
public async Task<IImageInfo> IdentifyAsync(Stream stream)
{
using (var ms = new MemoryStream())
{
await stream.CopyToAsync(ms).ConfigureAwait(false);
ms.Position = 0;
return this.Identify(ms);
}
}
/// <summary>
/// Reads the raw image information from the specified stream.
/// </summary>

10
src/ImageSharp/Formats/Tga/TgaEncoder.cs

@ -2,7 +2,7 @@
// Licensed under the GNU Affero General Public License, Version 3.
using System.IO;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
@ -30,5 +30,13 @@ namespace SixLabors.ImageSharp.Formats.Tga
var encoder = new TgaEncoderCore(this, image.GetMemoryAllocator());
encoder.Encode(image, stream);
}
/// <inheritdoc/>
public Task EncodeAsync<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
var encoder = new TgaEncoderCore(this, image.GetMemoryAllocator());
return encoder.EncodeAsync(image, stream);
}
}
}

19
src/ImageSharp/Formats/Tga/TgaEncoderCore.cs

@ -5,7 +5,7 @@ using System;
using System.Buffers.Binary;
using System.IO;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
@ -55,6 +55,23 @@ namespace SixLabors.ImageSharp.Formats.Tga
this.compression = options.Compression;
}
/// <summary>
/// Encodes the image to the specified stream from the <see cref="ImageFrame{TPixel}"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="image">The <see cref="ImageFrame{TPixel}"/> to encode from.</param>
/// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param>
public async Task EncodeAsync<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
using (var ms = new MemoryStream())
{
this.Encode(image, ms);
ms.Position = 0;
await ms.CopyToAsync(stream).ConfigureAwait(false);
}
}
/// <summary>
/// Encodes the image to the specified stream from the <see cref="ImageFrame{TPixel}"/>.
/// </summary>

17
tests/ImageSharp.Tests/TestFormat.cs

@ -6,7 +6,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
@ -187,7 +187,7 @@ namespace SixLabors.ImageSharp.Tests
}
}
public class TestDecoder : ImageSharp.Formats.IImageDecoder
public class TestDecoder : IImageDecoder
{
private TestFormat testFormat;
@ -219,9 +219,15 @@ namespace SixLabors.ImageSharp.Tests
return this.testFormat.Sample<TPixel>();
}
public Task<Image<TPixel>> DecodeAsync<TPixel>(Configuration config, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
=> Task.FromResult(this.Decode<TPixel>(config, stream));
public bool IsSupportedFileFormat(Span<byte> header) => this.testFormat.IsSupportedFileFormat(header);
public Image Decode(Configuration configuration, Stream stream) => this.Decode<TestPixelForAgnosticDecode>(configuration, stream);
public async Task<Image> DecodeAsync(Configuration configuration, Stream stream) => await this.DecodeAsync<TestPixelForAgnosticDecode>(configuration, stream);
}
public class TestEncoder : ImageSharp.Formats.IImageEncoder
@ -242,6 +248,13 @@ namespace SixLabors.ImageSharp.Tests
{
// TODO record this happened so we can verify it.
}
public Task EncodeAsync<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
// TODO record this happened so we can verify it.
return Task.CompletedTask;
}
}
public struct TestPixelForAgnosticDecode : IPixel<TestPixelForAgnosticDecode>

8
tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs

@ -5,7 +5,7 @@ using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using ImageMagick;
using SixLabors.ImageSharp.Advanced;
@ -49,6 +49,10 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs
}
}
public Task<Image<TPixel>> DecodeAsync<TPixel>(Configuration configuration, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
=> Task.FromResult(this.Decode<TPixel>(configuration, stream));
public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
@ -80,5 +84,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs
}
public Image Decode(Configuration configuration, Stream stream) => this.Decode<Rgba32>(configuration, stream);
public async Task<Image> DecodeAsync(Configuration configuration, Stream stream) => await this.DecodeAsync<Rgba32>(configuration, stream);
}
}

12
tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceDecoder.cs

@ -2,7 +2,8 @@
// Licensed under the GNU Affero General Public License, Version 3.
using System.IO;
using System.Threading.Tasks;
using SixLabors.ImageSharp.ColorSpaces.Conversion;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
@ -13,6 +14,10 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs
{
public static SystemDrawingReferenceDecoder Instance { get; } = new SystemDrawingReferenceDecoder();
public Task<Image<TPixel>> DecodeAsync<TPixel>(Configuration configuration, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
=> Task.FromResult(this.Decode<TPixel>(configuration, stream));
public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
@ -43,6 +48,9 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs
}
}
public Task<IImageInfo> IdentifyAsync(Configuration configuration, Stream stream)
=> Task.FromResult(this.Identify(configuration, stream));
public IImageInfo Identify(Configuration configuration, Stream stream)
{
using (var sourceBitmap = new System.Drawing.Bitmap(stream))
@ -53,5 +61,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs
}
public Image Decode(Configuration configuration, Stream stream) => this.Decode<Rgba32>(configuration, stream);
public async Task<Image> DecodeAsync(Configuration configuration, Stream stream) => await this.DecodeAsync<Rgba32>(configuration, stream);
}
}

15
tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceEncoder.cs

@ -1,9 +1,9 @@
// Copyright (c) Six Labors and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the GNU Affero General Public License, Version 3.
using System.Drawing.Imaging;
using System.IO;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.PixelFormats;
@ -30,5 +30,16 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs
sdBitmap.Save(stream, this.imageFormat);
}
}
public Task EncodeAsync<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
using (System.Drawing.Bitmap sdBitmap = SystemDrawingBridge.To32bppArgbSystemDrawingBitmap(image))
{
sdBitmap.Save(stream, this.imageFormat);
}
return Task.CompletedTask;
}
}
}

32
tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs

@ -4,7 +4,7 @@
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Memory;
@ -349,6 +349,9 @@ namespace SixLabors.ImageSharp.Tests
private static readonly ConcurrentDictionary<string, int> InvocationCounts =
new ConcurrentDictionary<string, int>();
private static readonly ConcurrentDictionary<string, int> InvocationCountsAsync =
new ConcurrentDictionary<string, int>();
private static readonly object Monitor = new object();
private string callerName;
@ -368,15 +371,27 @@ namespace SixLabors.ImageSharp.Tests
return new Image<TPixel>(42, 42);
}
public Task<Image<TPixel>> DecodeAsync<TPixel>(Configuration configuration, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
InvocationCountsAsync[this.callerName]++;
return Task.FromResult(new Image<TPixel>(42, 42));
}
internal static int GetInvocationCount(string callerName) => InvocationCounts[callerName];
internal static int GetInvocationCountAsync(string callerName) => InvocationCountsAsync[callerName];
internal void InitCaller(string name)
{
this.callerName = name;
InvocationCounts[name] = 0;
InvocationCountsAsync[name] = 0;
}
public Image Decode(Configuration configuration, Stream stream) => this.Decode<Rgba32>(configuration, stream);
public async Task<Image> DecodeAsync(Configuration configuration, Stream stream) => await this.DecodeAsync<Rgba32>(configuration, stream);
}
private class TestDecoderWithParameters : IImageDecoder
@ -384,6 +399,9 @@ namespace SixLabors.ImageSharp.Tests
private static readonly ConcurrentDictionary<string, int> InvocationCounts =
new ConcurrentDictionary<string, int>();
private static readonly ConcurrentDictionary<string, int> InvocationCountsAsync =
new ConcurrentDictionary<string, int>();
private static readonly object Monitor = new object();
private string callerName;
@ -407,15 +425,27 @@ namespace SixLabors.ImageSharp.Tests
return new Image<TPixel>(42, 42);
}
public Task<Image<TPixel>> DecodeAsync<TPixel>(Configuration configuration, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
InvocationCountsAsync[this.callerName]++;
return Task.FromResult(new Image<TPixel>(42, 42));
}
internal static int GetInvocationCount(string callerName) => InvocationCounts[callerName];
internal static int GetInvocationCountAsync(string callerName) => InvocationCountsAsync[callerName];
internal void InitCaller(string name)
{
this.callerName = name;
InvocationCounts[name] = 0;
InvocationCountsAsync[name] = 0;
}
public Image Decode(Configuration configuration, Stream stream) => this.Decode<Rgba32>(configuration, stream);
public async Task<Image> DecodeAsync(Configuration configuration, Stream stream) => await this.DecodeAsync<Rgba32>(configuration, stream);
}
}
}

Loading…
Cancel
Save