diff --git a/src/ImageSharp/Image.Decode.cs b/src/ImageSharp/Image.Decode.cs
index 683590fd1a..bc44cd8cab 100644
--- a/src/ImageSharp/Image.Decode.cs
+++ b/src/ImageSharp/Image.Decode.cs
@@ -4,6 +4,7 @@
using System;
using System.IO;
using System.Linq;
+using System.Threading;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Memory;
@@ -156,9 +157,10 @@ namespace SixLabors.ImageSharp
///
/// The stream.
/// the configuration.
+ /// The token to monitor for cancellation requests.
/// The pixel format.
/// A representing the asynchronous operation.
- private static async Task<(Image Image, IImageFormat Format)> DecodeAsync(Stream stream, Configuration config)
+ private static async Task<(Image Image, IImageFormat Format)> DecodeAsync(Stream stream, Configuration config, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel
{
(IImageDecoder decoder, IImageFormat format) = await DiscoverDecoderAsync(stream, config).ConfigureAwait(false);
@@ -183,7 +185,7 @@ namespace SixLabors.ImageSharp
return (img, format);
}
- private static async Task<(Image Image, IImageFormat Format)> DecodeAsync(Stream stream, Configuration config)
+ 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)
@@ -221,11 +223,12 @@ namespace SixLabors.ImageSharp
///
/// The stream.
/// the configuration.
+ /// The token to monitor for cancellation requests.
///
/// A representing the asynchronous operation with the
/// property of the returned type set to null if a suitable detector
/// is not found.
- private static async Task<(IImageInfo ImageInfo, IImageFormat Format)> InternalIdentityAsync(Stream stream, Configuration config)
+ 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);
diff --git a/src/ImageSharp/Image.FromFile.cs b/src/ImageSharp/Image.FromFile.cs
index a078f2db98..7dc06b3ca9 100644
--- a/src/ImageSharp/Image.FromFile.cs
+++ b/src/ImageSharp/Image.FromFile.cs
@@ -3,6 +3,7 @@
using System;
using System.IO;
+using System.Threading;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.PixelFormats;
@@ -136,13 +137,26 @@ namespace SixLabors.ImageSharp
/// Image format not recognised.
/// Image contains invalid content.
/// A representing the asynchronous operation.
- public static async Task LoadAsync(Configuration configuration, string path)
+ public static Task LoadAsync(Configuration configuration, string path)
+ => LoadAsync(configuration, path, default(CancellationToken));
+
+ ///
+ /// Create a new instance of the class from the given file.
+ ///
+ /// The configuration for the decoder.
+ /// The file path to the image.
+ /// The token to monitor for cancellation requests.
+ /// The configuration is null.
+ /// The path is null.
+ /// Image format not recognised.
+ /// Image contains invalid content.
+ /// A representing the asynchronous operation.
+ public static async Task LoadAsync(Configuration configuration, string path, CancellationToken cancellationToken)
{
- using (Stream stream = configuration.FileSystem.OpenRead(path))
- {
- (Image img, _) = await LoadWithFormatAsync(configuration, stream).ConfigureAwait(false);
- return img;
- }
+ using Stream stream = configuration.FileSystem.OpenRead(path);
+ (Image img, _) = await LoadWithFormatAsync(configuration, stream, cancellationToken)
+ .ConfigureAwait(false);
+ return img;
}
///
@@ -181,14 +195,28 @@ namespace SixLabors.ImageSharp
/// Image contains invalid content.
/// A representing the asynchronous operation.
public static Task LoadAsync(Configuration configuration, string path, IImageDecoder decoder)
+ => LoadAsync(configuration, path, decoder, default);
+
+ ///
+ /// Create a new instance of the class from the given file.
+ ///
+ /// The Configuration.
+ /// The file path to the image.
+ /// The decoder.
+ /// The token to monitor for cancellation requests.
+ /// The configuration is null.
+ /// The path is null.
+ /// The decoder is null.
+ /// Image format not recognised.
+ /// Image contains invalid content.
+ /// A representing the asynchronous operation.
+ public static Task LoadAsync(Configuration configuration, string path, IImageDecoder decoder, CancellationToken cancellationToken)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.NotNull(path, nameof(path));
- using (Stream stream = configuration.FileSystem.OpenRead(path))
- {
- return LoadAsync(configuration, stream, decoder);
- }
+ using Stream stream = configuration.FileSystem.OpenRead(path);
+ return LoadAsync(configuration, stream, decoder, cancellationToken);
}
///
diff --git a/src/ImageSharp/Image.FromStream.cs b/src/ImageSharp/Image.FromStream.cs
index beec0b1880..d005873cad 100644
--- a/src/ImageSharp/Image.FromStream.cs
+++ b/src/ImageSharp/Image.FromStream.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
+using System.Threading;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Memory;
@@ -62,7 +63,8 @@ namespace SixLabors.ImageSharp
=> WithSeekableStreamAsync(
configuration,
stream,
- s => InternalDetectFormatAsync(s, configuration));
+ (s, _) => InternalDetectFormatAsync(s, configuration),
+ default);
///
/// Reads the raw image information from the specified stream without fully decoding it.
@@ -192,7 +194,29 @@ namespace SixLabors.ImageSharp
=> WithSeekableStreamAsync(
configuration,
stream,
- s => InternalIdentityAsync(s, configuration ?? Configuration.Default));
+ (s, ct) => InternalIdentityAsync(s, configuration ?? Configuration.Default, ct),
+ default);
+
+ ///
+ /// Reads the raw image information from the specified stream without fully decoding it.
+ ///
+ /// The configuration.
+ /// The image stream to read the information from.
+ /// The token to monitor for cancellation requests.
+ /// The configuration is null.
+ /// The stream is null.
+ /// The stream is not readable.
+ /// Image contains invalid content.
+ ///
+ /// The representing the asyncronous operation with the parameter type
+ /// property set to null if suitable info detector is not found.
+ ///
+ public static Task<(IImageInfo ImageInfo, IImageFormat Format)> IdentifyWithFormatAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken)
+ => WithSeekableStreamAsync(
+ configuration,
+ stream,
+ (s, ct) => InternalIdentityAsync(s, configuration ?? Configuration.Default, ct),
+ cancellationToken);
///
/// Decode a new instance of the class from the given stream.
@@ -310,12 +334,31 @@ namespace SixLabors.ImageSharp
/// Image contains invalid content.
/// A representing the asynchronous operation.
public static Task LoadAsync(Configuration configuration, Stream stream, IImageDecoder decoder)
+ => LoadAsync(configuration, stream, decoder, default);
+
+ ///
+ /// Decode a new instance of the class from the given stream.
+ /// The pixel format is selected by the decoder.
+ ///
+ /// The configuration for the decoder.
+ /// The stream containing image information.
+ /// The decoder.
+ /// The token to monitor for cancellation requests.
+ /// The configuration is null.
+ /// The stream is null.
+ /// The decoder is null.
+ /// The stream is not readable.
+ /// Image format not recognised.
+ /// Image contains invalid content.
+ /// A representing the asynchronous operation.
+ public static Task LoadAsync(Configuration configuration, Stream stream, IImageDecoder decoder, CancellationToken cancellationToken)
{
Guard.NotNull(decoder, nameof(decoder));
return WithSeekableStreamAsync(
configuration,
stream,
- s => decoder.DecodeAsync(configuration, s));
+ (s, ct) => decoder.DecodeAsync(configuration, s),
+ cancellationToken);
}
///
@@ -348,6 +391,25 @@ namespace SixLabors.ImageSharp
return fmt.Image;
}
+ ///
+ /// Decode a new instance of the class from the given stream.
+ ///
+ /// The configuration for the decoder.
+ /// The stream containing image information.
+ /// The token to monitor for cancellation requests.
+ /// The configuration is null.
+ /// The stream is null.
+ /// The stream is not readable.
+ /// Image format not recognised.
+ /// Image contains invalid content.
+ /// A representing the asynchronous operation.
+ public static async Task LoadAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken)
+ {
+ (Image Image, IImageFormat Format) fmt = await LoadWithFormatAsync(configuration, stream, cancellationToken)
+ .ConfigureAwait(false);
+ return fmt.Image;
+ }
+
///
/// Create a new instance of the class from the given stream.
///
@@ -432,11 +494,28 @@ namespace SixLabors.ImageSharp
/// The pixel format.
/// A representing the asynchronous operation.
public static Task> LoadAsync(Stream stream, IImageDecoder decoder)
+ where TPixel : unmanaged, IPixel
+ => LoadAsync(stream, decoder, default);
+
+ ///
+ /// Create a new instance of the class from the given stream.
+ ///
+ /// The stream containing image information.
+ /// The decoder.
+ /// The token to monitor for cancellation requests.
+ /// The stream is null.
+ /// The stream is not readable.
+ /// Image format not recognised.
+ /// Image contains invalid content.
+ /// The pixel format.
+ /// A representing the asynchronous operation.
+ public static Task> LoadAsync(Stream stream, IImageDecoder decoder, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel
=> WithSeekableStreamAsync(
Configuration.Default,
stream,
- s => decoder.DecodeAsync(Configuration.Default, s));
+ (s, ct) => decoder.DecodeAsync(Configuration.Default, s),
+ cancellationToken);
///
/// Create a new instance of the class from the given stream.
@@ -468,12 +547,38 @@ namespace SixLabors.ImageSharp
/// Image contains invalid content.
/// The pixel format.
/// A representing the asynchronous operation.
- public static Task> LoadAsync(Configuration configuration, Stream stream, IImageDecoder decoder)
+ public static Task> LoadAsync(
+ Configuration configuration,
+ Stream stream,
+ IImageDecoder decoder)
+ where TPixel : unmanaged, IPixel
+ => LoadAsync(configuration, stream, decoder, default);
+
+ ///
+ /// Create a new instance of the class from the given stream.
+ ///
+ /// The Configuration.
+ /// The stream containing image information.
+ /// The decoder.
+ /// The token to monitor for cancellation requests.
+ /// The configuration is null.
+ /// The stream is null.
+ /// The stream is not readable.
+ /// Image format not recognised.
+ /// Image contains invalid content.
+ /// The pixel format.
+ /// A representing the asynchronous operation.
+ public static Task> LoadAsync(
+ Configuration configuration,
+ Stream stream,
+ IImageDecoder decoder,
+ CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel
=> WithSeekableStreamAsync(
configuration,
stream,
- s => decoder.DecodeAsync(configuration, s));
+ (s, ct) => decoder.DecodeAsync(configuration, s),
+ cancellationToken);
///
/// Create a new instance of the class from the given stream.
@@ -538,12 +643,30 @@ namespace SixLabors.ImageSharp
/// Image format not recognised.
/// Image contains invalid content.
/// A representing the asynchronous operation.
- public static async Task<(Image Image, IImageFormat Format)> LoadWithFormatAsync(Configuration configuration, Stream stream)
+ public static Task<(Image Image, IImageFormat Format)> LoadWithFormatAsync(
+ Configuration configuration,
+ Stream stream)
+ => LoadWithFormatAsync(configuration, stream, default);
+
+ ///
+ /// Create a new instance of the class from the given stream.
+ ///
+ /// The configuration options.
+ /// The stream containing image information.
+ /// The token to monitor for cancellation requests.
+ /// The configuration is null.
+ /// The stream is null.
+ /// The stream is not readable.
+ /// Image format not recognised.
+ /// Image contains invalid content.
+ /// A representing the asynchronous operation.
+ public static async Task<(Image Image, IImageFormat Format)> LoadWithFormatAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken)
{
(Image Image, IImageFormat Format) data = await WithSeekableStreamAsync(
configuration,
stream,
- async s => await DecodeAsync(s, configuration).ConfigureAwait(false))
+ async (s, ct) => await DecodeAsync(s, configuration, ct).ConfigureAwait(false),
+ cancellationToken)
.ConfigureAwait(false);
if (data.Image != null)
@@ -574,14 +697,33 @@ namespace SixLabors.ImageSharp
/// Image contains invalid content.
/// The pixel format.
/// A representing the asynchronous operation.
- public static async Task<(Image Image, IImageFormat Format)> LoadWithFormatAsync(Configuration configuration, Stream stream)
+ public static Task<(Image Image, IImageFormat Format)> LoadWithFormatAsync(
+ Configuration configuration, Stream stream)
+ where TPixel : unmanaged, IPixel
+ => LoadWithFormatAsync(configuration, stream, default);
+
+ ///
+ /// Create a new instance of the class from the given stream.
+ ///
+ /// The configuration options.
+ /// The stream containing image information.
+ /// The token to monitor for cancellation requests.
+ /// The configuration is null.
+ /// The stream is null.
+ /// The stream is not readable.
+ /// Image format not recognised.
+ /// Image contains invalid content.
+ /// The pixel format.
+ /// A representing the asynchronous operation.
+ public static async Task<(Image Image, IImageFormat Format)> LoadWithFormatAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel
{
(Image Image, IImageFormat Format) data =
await WithSeekableStreamAsync(
configuration,
stream,
- s => DecodeAsync(s, configuration))
+ (s, ct) => DecodeAsync(s, configuration, ct),
+ cancellationToken)
.ConfigureAwait(false);
if (data.Image != null)
@@ -612,10 +754,28 @@ namespace SixLabors.ImageSharp
/// Image contains invalid content.
/// The pixel format.
/// A representing the asynchronous operation.
- public static async Task> LoadAsync(Configuration configuration, Stream stream)
+ public static Task> LoadAsync(Configuration configuration, Stream stream)
+ where TPixel : unmanaged, IPixel
+ => LoadAsync(configuration, stream, default(CancellationToken));
+
+ ///
+ /// Create a new instance of the class from the given stream.
+ ///
+ /// The configuration options.
+ /// The stream containing image information.
+ /// The token to monitor for cancellation requests.
+ /// The configuration is null.
+ /// The stream is null.
+ /// The stream is not readable.
+ /// Image format not recognised.
+ /// Image contains invalid content.
+ /// The pixel format.
+ /// A representing the asynchronous operation.
+ public static async Task> LoadAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel
{
- (Image img, _) = await LoadWithFormatAsync(configuration, stream).ConfigureAwait(false);
+ (Image img, _) = await LoadWithFormatAsync(configuration, stream, cancellationToken)
+ .ConfigureAwait(false);
return img;
}
@@ -700,11 +860,13 @@ namespace SixLabors.ImageSharp
/// The configuration.
/// The input stream.
/// The action to perform.
+ /// The cancellation token.
/// The .
private static async Task WithSeekableStreamAsync(
Configuration configuration,
Stream stream,
- Func> action)
+ Func> action,
+ CancellationToken cancellationToken)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.NotNull(stream, nameof(stream));
@@ -725,14 +887,14 @@ namespace SixLabors.ImageSharp
stream.Position = 0;
}
- return await action(stream).ConfigureAwait(false);
+ return await action(stream, cancellationToken).ConfigureAwait(false);
}
using MemoryStream memoryStream = configuration.MemoryAllocator.AllocateFixedCapacityMemoryStream(stream.Length);
- await stream.CopyToAsync(memoryStream).ConfigureAwait(false);
+ await stream.CopyToAsync(memoryStream, cancellationToken).ConfigureAwait(false);
memoryStream.Position = 0;
- return await action(memoryStream).ConfigureAwait(false);
+ return await action(memoryStream, cancellationToken).ConfigureAwait(false);
}
}
}