diff --git a/src/ImageSharp/Image.FromFile.cs b/src/ImageSharp/Image.FromFile.cs
index 7d94e1bebc..1058dd19c0 100644
--- a/src/ImageSharp/Image.FromFile.cs
+++ b/src/ImageSharp/Image.FromFile.cs
@@ -80,6 +80,125 @@ namespace SixLabors.ImageSharp
}
}
+ ///
+ /// Reads the raw image information from the specified stream without fully decoding it.
+ ///
+ /// The image file to open and to read the header from.
+ /// The configuration is null.
+ ///
+ /// The representing the asynchronous operation with the parameter type
+ /// property set to null if suitable info detector is not found.
+ ///
+ public static Task IdentifyAsync(string filePath)
+ => IdentifyAsync(Configuration.Default, filePath, default);
+
+ ///
+ /// Reads the raw image information from the specified stream without fully decoding it.
+ ///
+ /// The configuration.
+ /// The image file to open and to read the header from.
+ /// The configuration is null.
+ ///
+ /// The representing the asynchronous operation with the parameter type
+ /// property set to null if suitable info detector is not found.
+ ///
+ public static Task IdentifyAsync(Configuration configuration, string filePath)
+ => IdentifyAsync(configuration, filePath, default);
+
+ ///
+ /// Reads the raw image information from the specified stream without fully decoding it.
+ ///
+ /// The image file to open and to read the header from.
+ /// The token to monitor for cancellation requests.
+ /// The configuration is null.
+ ///
+ /// The representing the asynchronous operation with the parameter type
+ /// property set to null if suitable info detector is not found.
+ ///
+ public static Task IdentifyAsync(string filePath, CancellationToken cancellationToken)
+ => IdentifyAsync(Configuration.Default, filePath, cancellationToken);
+
+ ///
+ /// Reads the raw image information from the specified stream without fully decoding it.
+ ///
+ /// The configuration.
+ /// The image file to open and to read the header from.
+ /// The token to monitor for cancellation requests.
+ /// The configuration is null.
+ ///
+ /// The representing the asynchronous operation with the parameter type
+ /// property set to null if suitable info detector is not found.
+ ///
+ public static async Task IdentifyAsync(Configuration configuration, string filePath, CancellationToken cancellationToken)
+ {
+ (IImageInfo ImageInfo, IImageFormat Format) res = await IdentifyWithFormatAsync(configuration, filePath, cancellationToken);
+ return res.ImageInfo;
+ }
+
+ ///
+ /// Reads the raw image information from the specified stream without fully decoding it.
+ ///
+ /// The image file to open and to read the header from.
+ /// The configuration is null.
+ ///
+ /// The representing the asynchronous operation with the parameter type
+ /// property set to null if suitable info detector is not found.
+ ///
+ public static Task<(IImageInfo ImageInfo, IImageFormat Format)> IdentifyWithFormatAsync(string filePath)
+ => IdentifyWithFormatAsync(Configuration.Default, filePath, default);
+
+ ///
+ /// Reads the raw image information from the specified stream without fully decoding it.
+ ///
+ /// The image file to open and to read the header from.
+ /// The token to monitor for cancellation requests.
+ /// The configuration is null.
+ ///
+ /// The representing the asynchronous operation with the parameter type
+ /// property set to null if suitable info detector is not found.
+ ///
+ public static Task<(IImageInfo ImageInfo, IImageFormat Format)> IdentifyWithFormatAsync(
+ string filePath,
+ CancellationToken cancellationToken)
+ => IdentifyWithFormatAsync(Configuration.Default, filePath, cancellationToken);
+
+ ///
+ /// Reads the raw image information from the specified stream without fully decoding it.
+ ///
+ /// The configuration.
+ /// The image file to open and to read the header from.
+ /// The configuration is null.
+ ///
+ /// The representing the asynchronous 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,
+ string filePath)
+ => IdentifyWithFormatAsync(configuration, filePath, default);
+
+ ///
+ /// Reads the raw image information from the specified stream without fully decoding it.
+ ///
+ /// The configuration.
+ /// The image file to open and to read the header from.
+ /// The token to monitor for cancellation requests.
+ /// The configuration is null.
+ ///
+ /// The representing the asynchronous operation with the parameter type
+ /// property set to null if suitable info detector is not found.
+ ///
+ public static async Task<(IImageInfo ImageInfo, IImageFormat Format)> IdentifyWithFormatAsync(
+ Configuration configuration,
+ string filePath,
+ CancellationToken cancellationToken)
+ {
+ Guard.NotNull(configuration, nameof(configuration));
+ using Stream stream = configuration.FileSystem.OpenRead(filePath);
+ return await IdentifyWithFormatAsync(configuration, stream, cancellationToken)
+ .ConfigureAwait(false);
+ }
+
///
/// Create a new instance of the class from the given file.
///
@@ -182,6 +301,20 @@ namespace SixLabors.ImageSharp
}
}
+ ///
+ /// Create a new instance of the class from the given file.
+ ///
+ /// The file path to the image.
+ /// The decoder.
+ /// 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(string path, IImageDecoder decoder)
+ => LoadAsync(Configuration.Default, path, decoder, default);
+
///
/// Create a new instance of the class from the given file.
///
@@ -197,6 +330,22 @@ namespace SixLabors.ImageSharp
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 file path to the image.
+ /// The decoder.
+ /// The configuration is null.
+ /// The path is null.
+ /// The decoder is null.
+ /// Image format not recognised.
+ /// Image contains invalid content.
+ /// The pixel format.
+ /// A representing the asynchronous operation.
+ public static Task> LoadAsync(string path, IImageDecoder decoder)
+ where TPixel : unmanaged, IPixel
+ => LoadAsync(Configuration.Default, path, decoder, default);
+
///
/// Create a new instance of the class from the given file.
///
@@ -260,6 +409,20 @@ namespace SixLabors.ImageSharp
return LoadAsync(configuration, stream, decoder, cancellationToken);
}
+ ///
+ /// Create a new instance of the class from the given file.
+ ///
+ /// The file path to the image.
+ /// The configuration is null.
+ /// The path is null.
+ /// Image format not recognised.
+ /// Image contains invalid content.
+ /// The pixel format.
+ /// A representing the asynchronous operation.
+ public static Task> LoadAsync(string path)
+ where TPixel : unmanaged, IPixel
+ => LoadAsync(Configuration.Default, path, default(CancellationToken));
+
///
/// Create a new instance of the class from the given file.
///
diff --git a/src/ImageSharp/Image.FromStream.cs b/src/ImageSharp/Image.FromStream.cs
index 58d6640a06..ac6eec282b 100644
--- a/src/ImageSharp/Image.FromStream.cs
+++ b/src/ImageSharp/Image.FromStream.cs
@@ -135,9 +135,26 @@ namespace SixLabors.ImageSharp
/// A representing the asynchronous operation or null if
/// a suitable detector is not found.
///
- public static async Task IdentifyAsync(Configuration configuration, Stream stream)
+ public static Task IdentifyAsync(Configuration configuration, Stream stream)
+ => IdentifyAsync(configuration, stream, 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.
+ ///
+ /// A representing the asynchronous operation or null if
+ /// a suitable detector is not found.
+ ///
+ public static async Task IdentifyAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken)
{
- (IImageInfo ImageInfo, IImageFormat Format) res = await IdentifyWithFormatAsync(configuration, stream).ConfigureAwait(false);
+ (IImageInfo ImageInfo, IImageFormat Format) res = await IdentifyWithFormatAsync(configuration, stream, cancellationToken).ConfigureAwait(false);
return res.ImageInfo;
}
@@ -197,6 +214,24 @@ namespace SixLabors.ImageSharp
(s, ct) => InternalIdentityAsync(s, configuration ?? Configuration.Default, ct),
default);
+ ///
+ /// Reads the raw image information from the specified stream without fully decoding it.
+ ///
+ /// 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 asynchronous operation with the parameter type
+ /// property set to null if suitable info detector is not found.
+ ///
+ public static Task<(IImageInfo ImageInfo, IImageFormat Format)> IdentifyWithFormatAsync(
+ Stream stream,
+ CancellationToken cancellationToken)
+ => IdentifyWithFormatAsync(Configuration.Default, stream, cancellationToken);
+
///
/// Reads the raw image information from the specified stream without fully decoding it.
///
@@ -208,7 +243,7 @@ namespace SixLabors.ImageSharp
/// The stream is not readable.
/// Image contains invalid content.
///
- /// The representing the asyncronous operation with the parameter type
+ /// The representing the asynchronous 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)
diff --git a/tests/ImageSharp.Tests/Image/ImageTests.Decode_Cancellation.cs b/tests/ImageSharp.Tests/Image/ImageTests.Decode_Cancellation.cs
index 4e278ad35f..317a5129c4 100644
--- a/tests/ImageSharp.Tests/Image/ImageTests.Decode_Cancellation.cs
+++ b/tests/ImageSharp.Tests/Image/ImageTests.Decode_Cancellation.cs
@@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Tests
[Theory]
[InlineData(false)]
[InlineData(true)]
- public async Task LoadAsync_Specific_Stream_WhenCancelledDuringRead(bool isInputStreamSeekable)
+ public async Task LoadAsync_Specific_Stream(bool isInputStreamSeekable)
{
this.isTestStreamSeekable = isInputStreamSeekable;
_ = Task.Factory.StartNew(this.DoCancel, TaskCreationOptions.LongRunning);
@@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.Tests
[Theory]
[InlineData(false)]
[InlineData(true)]
- public async Task LoadAsync_Agnostic_Stream_WhenCancelledDuringRead(bool isInputStreamSeekable)
+ public async Task LoadAsync_Agnostic_Stream(bool isInputStreamSeekable)
{
this.isTestStreamSeekable = isInputStreamSeekable;
_ = Task.Factory.StartNew(this.DoCancel, TaskCreationOptions.LongRunning);
@@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Tests
}
[Fact]
- public async Task LoadAsync_Agnostic_Path_WhenCancelledDuringRead()
+ public async Task LoadAsync_Agnostic_Path()
{
this.isTestStreamSeekable = true;
_ = Task.Factory.StartNew(this.DoCancel, TaskCreationOptions.LongRunning);
@@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.Tests
}
[Fact]
- public async Task LoadAsync_Specific_Path_WhenCancelledDuringRead()
+ public async Task LoadAsync_Specific_Path()
{
this.isTestStreamSeekable = true;
_ = Task.Factory.StartNew(this.DoCancel, TaskCreationOptions.LongRunning);
@@ -64,6 +64,54 @@ namespace SixLabors.ImageSharp.Tests
await Assert.ThrowsAsync(() => Image.LoadAsync(this.TopLevelConfiguration, this.MockFilePath, this.cts.Token));
}
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task IdentifyAsync_Stream(bool isInputStreamSeekable)
+ {
+ this.isTestStreamSeekable = isInputStreamSeekable;
+ _ = Task.Factory.StartNew(this.DoCancel, TaskCreationOptions.LongRunning);
+
+ await Assert.ThrowsAsync(() => Image.IdentifyAsync(this.TopLevelConfiguration, this.DataStream, this.cts.Token));
+ }
+
+ [Fact]
+ public async Task IdentifyAsync_CustomConfiguration_Path()
+ {
+ this.isTestStreamSeekable = true;
+ _ = Task.Factory.StartNew(this.DoCancel, TaskCreationOptions.LongRunning);
+
+ await Assert.ThrowsAsync(() => Image.IdentifyAsync(this.TopLevelConfiguration, this.MockFilePath, this.cts.Token));
+ }
+
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task IdentifyWithFormatAsync_CustomConfiguration_Stream(bool isInputStreamSeekable)
+ {
+ this.isTestStreamSeekable = isInputStreamSeekable;
+ _ = Task.Factory.StartNew(this.DoCancel, TaskCreationOptions.LongRunning);
+
+ await Assert.ThrowsAsync(() => Image.IdentifyWithFormatAsync(this.TopLevelConfiguration, this.DataStream, this.cts.Token));
+ }
+
+ [Fact]
+ public async Task IdentifyWithFormatAsync_CustomConfiguration_Path()
+ {
+ this.isTestStreamSeekable = true;
+ _ = Task.Factory.StartNew(this.DoCancel, TaskCreationOptions.LongRunning);
+
+ await Assert.ThrowsAsync(() => Image.IdentifyWithFormatAsync(this.TopLevelConfiguration, this.MockFilePath, this.cts.Token));
+ }
+
+ [Fact]
+ public async Task IdentifyWithFormatAsync_DefaultConfiguration_Stream()
+ {
+ _ = Task.Factory.StartNew(this.DoCancel, TaskCreationOptions.LongRunning);
+
+ await Assert.ThrowsAsync(() => Image.IdentifyWithFormatAsync(this.DataStream, this.cts.Token));
+ }
+
private async Task DoCancel()
{
// wait until we reach the middle of the steam
diff --git a/tests/ImageSharp.Tests/Image/ImageTests.Identify.cs b/tests/ImageSharp.Tests/Image/ImageTests.Identify.cs
index 6784f96e86..e5b35ffd23 100644
--- a/tests/ImageSharp.Tests/Image/ImageTests.Identify.cs
+++ b/tests/ImageSharp.Tests/Image/ImageTests.Identify.cs
@@ -19,6 +19,8 @@ namespace SixLabors.ImageSharp.Tests
{
private static readonly string ActualImagePath = TestFile.GetInputFileFullPath(TestImages.Bmp.F);
+ private static readonly Size ExpectedImageSize = new Size(108, 202);
+
private byte[] ActualImageBytes => TestFile.Create(TestImages.Bmp.F).Bytes;
private IImageInfo LocalImageInfo => this.localImageInfoMock.Object;
@@ -33,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests
{
IImageInfo info = Image.Identify(this.ActualImageBytes, out IImageFormat type);
- Assert.NotNull(info);
+ Assert.Equal(ExpectedImageSize, info.Size());
Assert.Equal(ExpectedGlobalFormat, type);
}
@@ -131,13 +133,46 @@ namespace SixLabors.ImageSharp.Tests
using (var stream = new MemoryStream(this.ActualImageBytes))
{
var asyncStream = new AsyncStreamWrapper(stream, () => false);
- (IImageInfo ImageInfo, IImageFormat Format) info = await Image.IdentifyWithFormatAsync(asyncStream);
+ (IImageInfo ImageInfo, IImageFormat Format) res = await Image.IdentifyWithFormatAsync(asyncStream);
- Assert.NotNull(info.ImageInfo);
- Assert.Equal(ExpectedGlobalFormat, info.Format);
+ Assert.Equal(ExpectedImageSize, res.ImageInfo.Size());
+ Assert.Equal(ExpectedGlobalFormat, res.Format);
}
}
+ [Fact]
+ public async Task FromPathAsync_CustomConfiguration()
+ {
+ IImageInfo info = await Image.IdentifyAsync(this.LocalConfiguration, this.MockFilePath);
+ Assert.Equal(this.LocalImageInfo, info);
+ }
+
+ [Fact]
+ public async Task IdentifyWithFormatAsync_FromPath_CustomConfiguration()
+ {
+ (IImageInfo ImageInfo, IImageFormat Format) info = await Image.IdentifyWithFormatAsync(this.LocalConfiguration, this.MockFilePath);
+ Assert.NotNull(info.ImageInfo);
+ Assert.Equal(this.LocalImageFormat, info.Format);
+ }
+
+ [Fact]
+ public async Task IdentifyWithFormatAsync_FromPath_GlobalConfiguration()
+ {
+ (IImageInfo ImageInfo, IImageFormat Format) res = await Image.IdentifyWithFormatAsync(ActualImagePath);
+
+ Assert.Equal(ExpectedImageSize, res.ImageInfo.Size());
+ Assert.Equal(ExpectedGlobalFormat, res.Format);
+ }
+
+ [Fact]
+ public async Task FromPathAsync_GlobalConfiguration()
+ {
+ IImageInfo info = await Image.IdentifyAsync(ActualImagePath);
+
+ Assert.Equal(ExpectedImageSize, info.Size());
+ }
+
+
[Fact]
public async Task FromStreamAsync_CustomConfiguration()
{
diff --git a/tests/ImageSharp.Tests/Image/ImageTests.Load_FileSystemPath_UseDefaultConfiguration.cs b/tests/ImageSharp.Tests/Image/ImageTests.Load_FileSystemPath_UseDefaultConfiguration.cs
index 1689c1dea7..a5034e43b0 100644
--- a/tests/ImageSharp.Tests/Image/ImageTests.Load_FileSystemPath_UseDefaultConfiguration.cs
+++ b/tests/ImageSharp.Tests/Image/ImageTests.Load_FileSystemPath_UseDefaultConfiguration.cs
@@ -25,102 +25,80 @@ namespace SixLabors.ImageSharp.Tests
[Fact]
public void Path_Specific()
{
- using (var img = Image.Load(this.Path))
- {
- VerifyDecodedImage(img);
- }
+ using var img = Image.Load(this.Path);
+ VerifyDecodedImage(img);
}
[Fact]
public void Path_Agnostic()
{
- using (var img = Image.Load(this.Path))
- {
- VerifyDecodedImage(img);
- }
+ using var img = Image.Load(this.Path);
+ VerifyDecodedImage(img);
}
[Fact]
public async Task Path_Agnostic_Async()
{
- using (var img = await Image.LoadAsync(this.Path))
- {
- VerifyDecodedImage(img);
- }
+ using var img = await Image.LoadAsync(this.Path);
+ VerifyDecodedImage(img);
}
[Fact]
public async Task Path_Specific_Async()
{
- using (var img = await Image.LoadAsync(Configuration.Default, this.Path))
- {
- VerifyDecodedImage(img);
- }
+ using var img = await Image.LoadAsync(this.Path);
+ VerifyDecodedImage(img);
}
[Fact]
public async Task Path_Agnostic_Configuration_Async()
{
- using (var img = await Image.LoadAsync(Configuration.Default, this.Path))
- {
- VerifyDecodedImage(img);
- }
+ using var img = await Image.LoadAsync(this.Path);
+ VerifyDecodedImage(img);
}
[Fact]
public void Path_Decoder_Specific()
{
- using (var img = Image.Load(this.Path, new BmpDecoder()))
- {
- VerifyDecodedImage(img);
- }
+ using var img = Image.Load(this.Path, new BmpDecoder());
+ VerifyDecodedImage(img);
}
[Fact]
public void Path_Decoder_Agnostic()
{
- using (var img = Image.Load(this.Path, new BmpDecoder()))
- {
- VerifyDecodedImage(img);
- }
+ using var img = Image.Load(this.Path, new BmpDecoder());
+ VerifyDecodedImage(img);
}
[Fact]
public async Task Path_Decoder_Agnostic_Async()
{
- using (var img = await Image.LoadAsync(Configuration.Default, this.Path, new BmpDecoder()))
- {
- VerifyDecodedImage(img);
- }
+ using var img = await Image.LoadAsync(this.Path, new BmpDecoder());
+ VerifyDecodedImage(img);
}
[Fact]
public async Task Path_Decoder_Specific_Async()
{
- using (var img = await Image.LoadAsync(Configuration.Default, this.Path, new BmpDecoder()))
- {
- VerifyDecodedImage(img);
- }
+ using var img = await Image.LoadAsync(this.Path, new BmpDecoder());
+ VerifyDecodedImage(img);
}
[Fact]
public void Path_OutFormat_Specific()
{
- using (var img = Image.Load(this.Path, out IImageFormat format))
- {
- VerifyDecodedImage(img);
- Assert.IsType(format);
- }
+ using var img = Image.Load(this.Path, out IImageFormat format);
+ VerifyDecodedImage(img);
+ Assert.IsType(format);
}
[Fact]
public void Path_OutFormat_Agnostic()
{
- using (var img = Image.Load(this.Path, out IImageFormat format))
- {
- VerifyDecodedImage(img);
- Assert.IsType(format);
- }
+ using var img = Image.Load(this.Path, out IImageFormat format);
+ VerifyDecodedImage(img);
+ Assert.IsType(format);
}
[Fact]
@@ -142,6 +120,20 @@ namespace SixLabors.ImageSharp.Tests
Image.Load((string)null);
});
}
+
+ [Fact]
+ public Task Async_WhenFileNotFound_Throws()
+ {
+ return Assert.ThrowsAsync(
+ () => Image.LoadAsync(Guid.NewGuid().ToString()));
+ }
+
+ [Fact]
+ public Task Async_WhenPathIsNull_Throws()
+ {
+ return Assert.ThrowsAsync(
+ () => Image.LoadAsync((string)null));
+ }
}
}
}
diff --git a/tests/ImageSharp.Tests/TestFormat.cs b/tests/ImageSharp.Tests/TestFormat.cs
index 18f0876d02..5a380f7832 100644
--- a/tests/ImageSharp.Tests/TestFormat.cs
+++ b/tests/ImageSharp.Tests/TestFormat.cs
@@ -197,7 +197,7 @@ namespace SixLabors.ImageSharp.Tests
}
}
- public class TestDecoder : IImageDecoder
+ public class TestDecoder : IImageDecoder, IImageInfoDetector
{
private TestFormat testFormat;
@@ -243,6 +243,12 @@ namespace SixLabors.ImageSharp.Tests
public async Task DecodeAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken)
=> await this.DecodeAsync(configuration, stream, cancellationToken);
+
+ public IImageInfo Identify(Configuration configuration, Stream stream) =>
+ this.IdentifyAsync(configuration, stream, default).GetAwaiter().GetResult();
+
+ public async Task IdentifyAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken)
+ => await this.DecodeImpl(configuration, stream, cancellationToken);
}
public class TestEncoder : ImageSharp.Formats.IImageEncoder