Browse Source

Change WithSeekableStreamAsync() so that it executes synchronous actions after preloading the stream, rather than async actions (since the async actions all ultimately operate synchronously anyway)

pull/2006/head
Dan Kroymann 4 years ago
parent
commit
f874218d0b
  1. 100
      src/ImageSharp/Image.Decode.cs
  2. 18
      src/ImageSharp/Image.FromStream.cs

100
src/ImageSharp/Image.Decode.cs

@ -2,11 +2,8 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
@ -96,20 +93,6 @@ namespace SixLabors.ImageSharp
return format;
}
/// <summary>
/// By reading the header on the provided stream this calculates the images format.
/// </summary>
/// <param name="stream">The image stream to read the header from.</param>
/// <param name="config">The configuration.</param>
/// <returns>The mime type or null if none found.</returns>
private static Task<IImageFormat> InternalDetectFormatAsync(Stream stream, Configuration config)
{
// We are going to cheat here because we know that by this point we have been wrapped in a
// seekable stream then we are free to use sync APIs this is potentially brittle and may
// need a better fix in the future.
return Task.FromResult(InternalDetectFormat(stream, config));
}
/// <summary>
/// By reading the header on the provided stream this calculates the images format.
/// </summary>
@ -126,23 +109,6 @@ namespace SixLabors.ImageSharp
: null;
}
/// <summary>
/// By reading the header on the provided stream this calculates the images format.
/// </summary>
/// <param name="stream">The image stream to read the header from.</param>
/// <param name="config">The configuration.</param>
/// <returns>The decoder and the image format or null if none found.</returns>
private static async Task<(IImageDecoder Decoder, IImageFormat Format)> DiscoverDecoderAsync(Stream stream, Configuration config)
{
IImageFormat format = await InternalDetectFormatAsync(stream, config).ConfigureAwait(false);
IImageDecoder decoder = format != null
? config.ImageFormatsManager.FindDecoder(format)
: null;
return (decoder, format);
}
/// <summary>
/// Decodes the image stream to the current image.
/// </summary>
@ -166,32 +132,6 @@ namespace SixLabors.ImageSharp
return (img, format);
}
/// <summary>
/// Decodes the image stream to the current image.
/// </summary>
/// <param name="stream">The stream.</param>
/// <param name="config">the configuration.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A <see cref="Task{ValueTuple}"/> representing the asynchronous operation.</returns>
private static async Task<(Image<TPixel> Image, IImageFormat Format)> DecodeAsync<TPixel>(
Stream stream,
Configuration config,
CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
{
(IImageDecoder decoder, IImageFormat format) = await DiscoverDecoderAsync(stream, config)
.ConfigureAwait(false);
if (decoder is null)
{
return (null, null);
}
Image<TPixel> img = await decoder.DecodeAsync<TPixel>(config, stream, cancellationToken)
.ConfigureAwait(false);
return (img, format);
}
private static (Image Image, IImageFormat Format) Decode(Stream stream, Configuration config, CancellationToken cancellationToken = default)
{
IImageDecoder decoder = DiscoverDecoder(stream, config, out IImageFormat format);
@ -204,18 +144,6 @@ namespace SixLabors.ImageSharp
return (img, format);
}
private static async Task<(Image Image, IImageFormat Format)> DecodeAsync(Stream stream, Configuration config, CancellationToken cancellationToken)
{
(IImageDecoder decoder, IImageFormat format) = await DiscoverDecoderAsync(stream, config).ConfigureAwait(false);
if (decoder is null)
{
return (null, null);
}
Image img = await decoder.DecodeAsync(config, stream, cancellationToken).ConfigureAwait(false);
return (img, format);
}
/// <summary>
/// Reads the raw image information from the specified stream.
/// </summary>
@ -237,33 +165,5 @@ namespace SixLabors.ImageSharp
IImageInfo info = detector?.Identify(config, stream, cancellationToken);
return (info, format);
}
/// <summary>
/// Reads the raw image information from the specified stream.
/// </summary>
/// <param name="stream">The stream.</param>
/// <param name="config">the configuration.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>
/// A <see cref="Task{ValueTuple}"/> representing the asynchronous operation with the
/// <see cref="IImageInfo"/> property of the returned type set to null if a suitable detector
/// is not found.</returns>
private static async Task<(IImageInfo ImageInfo, IImageFormat Format)> InternalIdentityAsync(Stream stream, Configuration config, CancellationToken cancellationToken)
{
(IImageDecoder decoder, IImageFormat format) = await DiscoverDecoderAsync(stream, config).ConfigureAwait(false);
if (!(decoder is IImageInfoDetector detector))
{
return (null, null);
}
if (detector is null)
{
return (null, format);
}
IImageInfo info = await detector.IdentifyAsync(config, stream, cancellationToken).ConfigureAwait(false);
return (info, format);
}
}
}

18
src/ImageSharp/Image.FromStream.cs

@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp
=> WithSeekableStreamAsync(
configuration,
stream,
(s, _) => InternalDetectFormatAsync(s, configuration),
(s, _) => InternalDetectFormat(s, configuration),
cancellationToken);
/// <summary>
@ -208,7 +208,7 @@ namespace SixLabors.ImageSharp
=> WithSeekableStreamAsync(
configuration,
stream,
(s, ct) => InternalIdentityAsync(s, configuration ?? Configuration.Default, ct),
(s, ct) => InternalIdentity(s, configuration ?? Configuration.Default, ct),
cancellationToken);
/// <summary>
@ -341,7 +341,7 @@ namespace SixLabors.ImageSharp
return WithSeekableStreamAsync(
configuration,
stream,
(s, ct) => decoder.DecodeAsync(configuration, s, ct),
(s, ct) => decoder.Decode(configuration, s, ct),
cancellationToken);
}
@ -468,7 +468,7 @@ namespace SixLabors.ImageSharp
=> WithSeekableStreamAsync(
Configuration.Default,
stream,
(s, ct) => decoder.DecodeAsync<TPixel>(Configuration.Default, s, ct),
(s, ct) => decoder.Decode<TPixel>(Configuration.Default, s, ct),
cancellationToken);
/// <summary>
@ -511,7 +511,7 @@ namespace SixLabors.ImageSharp
=> WithSeekableStreamAsync(
configuration,
stream,
(s, ct) => decoder.DecodeAsync<TPixel>(configuration, s, ct),
(s, ct) => decoder.Decode<TPixel>(configuration, s, ct),
cancellationToken);
/// <summary>
@ -586,7 +586,7 @@ namespace SixLabors.ImageSharp
(Image Image, IImageFormat Format) data = await WithSeekableStreamAsync(
configuration,
stream,
async (s, ct) => await DecodeAsync(s, configuration, ct).ConfigureAwait(false),
(s, ct) => Decode(s, configuration, ct),
cancellationToken)
.ConfigureAwait(false);
@ -629,7 +629,7 @@ namespace SixLabors.ImageSharp
await WithSeekableStreamAsync(
configuration,
stream,
(s, ct) => DecodeAsync<TPixel>(s, configuration, ct),
(s, ct) => Decode<TPixel>(s, configuration, ct),
cancellationToken)
.ConfigureAwait(false);
@ -759,7 +759,7 @@ namespace SixLabors.ImageSharp
private static async Task<T> WithSeekableStreamAsync<T>(
Configuration configuration,
Stream stream,
Func<Stream, CancellationToken, Task<T>> action,
Func<Stream, CancellationToken, T> action,
CancellationToken cancellationToken)
{
Guard.NotNull(configuration, nameof(configuration));
@ -774,7 +774,7 @@ namespace SixLabors.ImageSharp
await stream.CopyToAsync(memoryStream, configuration.StreamProcessingBufferSize, cancellationToken).ConfigureAwait(false);
memoryStream.Position = 0;
return await action(memoryStream, cancellationToken).ConfigureAwait(false);
return action(memoryStream, cancellationToken);
}
}
}

Loading…
Cancel
Save