From 0aa12a4602a6f2fc1c1d3a063d1b8a15806086a8 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 14 Jan 2023 09:33:18 +1000 Subject: [PATCH] Refactor Identify and DetectFormat and fix tests --- src/ImageSharp/Common/Attempt{T}.cs | 24 ++ src/ImageSharp/Formats/ImageDecoder.cs | 18 +- src/ImageSharp/Image.Decode.cs | 79 +++---- src/ImageSharp/Image.FromBytes.cs | 49 ++-- src/ImageSharp/Image.FromFile.cs | 134 +++++------ src/ImageSharp/Image.FromStream.cs | 210 +++++++----------- .../Formats/Bmp/BmpDecoderTests.cs | 16 +- .../Formats/Bmp/BmpMetadataTests.cs | 33 ++- .../Formats/GeneralFormatTests.cs | 12 +- .../Formats/Gif/GifDecoderTests.cs | 18 +- .../Formats/Pbm/PbmMetadataTests.cs | 23 +- .../Formats/Png/PngDecoderTests.cs | 18 +- .../Formats/Png/PngMetadataTests.cs | 46 ++-- .../Formats/Tga/TgaFileHeaderTests.cs | 6 +- .../Formats/Tiff/BigTiffDecoderTests.cs | 50 ++--- .../Formats/Tiff/TiffDecoderTests.cs | 40 ++-- .../Formats/Tiff/TiffMetadataTests.cs | 28 +-- .../Formats/WebP/WebpDecoderTests.cs | 14 +- .../Image/ImageTests.Decode_Cancellation.cs | 2 +- .../Image/ImageTests.DetectFormat.cs | 55 +++-- .../Image/ImageTests.Identify.cs | 152 +++++++------ .../Image/ImageTests.ImageLoadTestBase.cs | 14 +- .../Image/ImageTests.WrapMemory.cs | 3 +- .../Image/MockImageFormatDetector.cs | 8 +- 24 files changed, 524 insertions(+), 528 deletions(-) create mode 100644 src/ImageSharp/Common/Attempt{T}.cs diff --git a/src/ImageSharp/Common/Attempt{T}.cs b/src/ImageSharp/Common/Attempt{T}.cs new file mode 100644 index 0000000000..a243dffd1f --- /dev/null +++ b/src/ImageSharp/Common/Attempt{T}.cs @@ -0,0 +1,24 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Diagnostics.CodeAnalysis; + +namespace SixLabors.ImageSharp; + +/// +/// A wrapper for nullable values that correctly handles the return type based on the result. +/// +/// The type of nullable value. +public readonly struct Attempt +{ + /// + /// Gets a value indicating whether the attempted return was successful. + /// + [MemberNotNullWhen(returnValue: true, member: nameof(Value))] + public bool Success => this.Value is not null; + + /// + /// Gets the value when the attempted return is successful; otherwise, the default value for the type. + /// + public T? Value { get; init; } +} diff --git a/src/ImageSharp/Formats/ImageDecoder.cs b/src/ImageSharp/Formats/ImageDecoder.cs index bc2620c7fb..dfb3761977 100644 --- a/src/ImageSharp/Formats/ImageDecoder.cs +++ b/src/ImageSharp/Formats/ImageDecoder.cs @@ -84,12 +84,18 @@ public abstract class ImageDecoder : IImageDecoder } /// - public Task IdentifyAsync(DecoderOptions options, Stream stream, CancellationToken cancellationToken = default) - => WithSeekableMemoryStreamAsync( - options, - stream, - (s, ct) => this.Identify(options, s, ct), - cancellationToken); + public async Task IdentifyAsync(DecoderOptions options, Stream stream, CancellationToken cancellationToken = default) + { + ImageInfo info = await WithSeekableMemoryStreamAsync( + options, + stream, + (s, ct) => this.Identify(options, s, ct), + cancellationToken).ConfigureAwait(false); + + this.SetDecoderFormat(options.Configuration, info); + + return info; + } /// /// Decodes the image from the specified stream to an of a specific pixel type. diff --git a/src/ImageSharp/Image.Decode.cs b/src/ImageSharp/Image.Decode.cs index d549fabee5..9a28440601 100644 --- a/src/ImageSharp/Image.Decode.cs +++ b/src/ImageSharp/Image.Decode.cs @@ -1,6 +1,5 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Memory; @@ -45,7 +44,7 @@ public abstract partial class Image /// The general configuration. /// The image stream to read the header from. /// The mime type or null if none found. - private static IImageFormat InternalDetectFormat(Configuration configuration, Stream stream) + private static IImageFormat? InternalDetectFormat(Configuration configuration, Stream stream) { // We take a minimum of the stream length vs the max header size and always check below // to ensure that only formats that headers fit within the given buffer length are tested. @@ -77,15 +76,12 @@ public abstract partial class Image // Does the given stream contain enough data to fit in the header for the format // and does that data match the format specification? // Individual formats should still check since they are public. - IImageFormat format = null; + IImageFormat? format = null; foreach (IImageFormatDetector formatDetector in configuration.ImageFormatsManager.FormatDetectors) { - if (formatDetector.HeaderSize <= headerSize) + if (formatDetector.HeaderSize <= headerSize && formatDetector.TryDetectFormat(headersBuffer, out IImageFormat? attemptFormat)) { - if (formatDetector.TryDetectFormat(headersBuffer, out IImageFormat attemptFormat)) - { - format = attemptFormat; - } + format = attemptFormat; } } @@ -97,13 +93,11 @@ public abstract partial class Image /// /// The general decoder options. /// The image stream to read the header from. - /// The IImageFormat. - /// The image format or null if none found. - private static IImageDecoder DiscoverDecoder(DecoderOptions options, Stream stream, out IImageFormat format) + /// The or . + private static IImageDecoder? DiscoverDecoder(DecoderOptions options, Stream stream) { - format = InternalDetectFormat(options.Configuration, stream); - - return format != null + IImageFormat? format = InternalDetectFormat(options.Configuration, stream); + return format is not null ? options.Configuration.ImageFormatsManager.FindDecoder(format) : null; } @@ -117,60 +111,56 @@ public abstract partial class Image /// /// A new . /// - private static (Image Image, IImageFormat Format) Decode(DecoderOptions options, Stream stream) + private static Image? Decode(DecoderOptions options, Stream stream) where TPixel : unmanaged, IPixel { - IImageDecoder decoder = DiscoverDecoder(options, stream, out IImageFormat format); + IImageDecoder? decoder = DiscoverDecoder(options, stream); if (decoder is null) { - return (null, null); + return null; } - Image img = decoder.Decode(options, stream); - return (img, format); + return decoder.Decode(options, stream); } - private static async Task<(Image Image, IImageFormat Format)> DecodeAsync( + private static async Task?> DecodeAsync( DecoderOptions options, Stream stream, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { - IImageDecoder decoder = DiscoverDecoder(options, stream, out IImageFormat format); + IImageDecoder? decoder = DiscoverDecoder(options, stream); if (decoder is null) { - return (null, null); + return null; } - Image img = await decoder.DecodeAsync(options, stream, cancellationToken).ConfigureAwait(false); - return (img, format); + return await decoder.DecodeAsync(options, stream, cancellationToken).ConfigureAwait(false); } - private static (Image Image, IImageFormat Format) Decode(DecoderOptions options, Stream stream) + private static Image? Decode(DecoderOptions options, Stream stream) { - IImageDecoder decoder = DiscoverDecoder(options, stream, out IImageFormat format); + IImageDecoder? decoder = DiscoverDecoder(options, stream); if (decoder is null) { - return (null, null); + return null; } - Image img = decoder.Decode(options, stream); - return (img, format); + return decoder.Decode(options, stream); } - private static async Task<(Image Image, IImageFormat Format)> DecodeAsync( + private static async Task DecodeAsync( DecoderOptions options, Stream stream, CancellationToken cancellationToken) { - IImageDecoder decoder = DiscoverDecoder(options, stream, out IImageFormat format); + IImageDecoder? decoder = DiscoverDecoder(options, stream); if (decoder is null) { - return (null, null); + return null; } - Image img = await decoder.DecodeAsync(options, stream, cancellationToken).ConfigureAwait(false); - return (img, format); + return await decoder.DecodeAsync(options, stream, cancellationToken).ConfigureAwait(false); } /// @@ -181,11 +171,15 @@ public abstract partial class Image /// /// The or null if a suitable info detector is not found. /// - private static (ImageInfo ImageInfo, IImageFormat Format) InternalIdentify(DecoderOptions options, Stream stream) + private static ImageInfo? InternalIdentify(DecoderOptions options, Stream stream) { - IImageDecoder decoder = DiscoverDecoder(options, stream, out IImageFormat format); - ImageInfo info = decoder?.Identify(options, stream); - return (info, format); + IImageDecoder? decoder = DiscoverDecoder(options, stream); + if (decoder is null) + { + return null; + } + + return decoder.Identify(options, stream); } /// @@ -197,19 +191,18 @@ public abstract partial class Image /// /// The or null if a suitable info detector is not found. /// - private static async Task<(ImageInfo ImageInfo, IImageFormat Format)> InternalIdentifyAsync( + private static async Task InternalIdentifyAsync( DecoderOptions options, Stream stream, CancellationToken cancellationToken) { - IImageDecoder decoder = DiscoverDecoder(options, stream, out IImageFormat format); + IImageDecoder? decoder = DiscoverDecoder(options, stream); if (decoder is null) { - return (null, null); + return null; } - ImageInfo info = await decoder.IdentifyAsync(options, stream, cancellationToken).ConfigureAwait(false); - return (info, format); + return await decoder.IdentifyAsync(options, stream, cancellationToken).ConfigureAwait(false); } } diff --git a/src/ImageSharp/Image.FromBytes.cs b/src/ImageSharp/Image.FromBytes.cs index a6c73c61ec..9218128340 100644 --- a/src/ImageSharp/Image.FromBytes.cs +++ b/src/ImageSharp/Image.FromBytes.cs @@ -55,46 +55,41 @@ public abstract partial class Image /// /// Reads the raw image information from the specified stream without fully decoding it. - /// - /// The byte span containing encoded image data to read the header from. - /// The data is null. - /// The data is not readable. - /// - /// The or null if suitable info detector not found. - /// - public static ImageInfo Identify(ReadOnlySpan data) => Identify(data, out IImageFormat _); - - /// - /// Reads the raw image information from the specified stream without fully decoding it. + /// A return value indicates whether the operation succeeded. /// /// The byte array containing encoded image data to read the header from. - /// The format type of the decoded image. + /// + /// When this method returns, contains the raw image information; + /// otherwise, the default value for the type of the parameter. + /// This parameter is passed uninitialized. + /// + /// if the information can be read; otherwise, /// The data is null. /// The data is not readable. - /// - /// The or null if suitable info detector not found. - /// - public static ImageInfo Identify(ReadOnlySpan data, out IImageFormat format) - => Identify(DecoderOptions.Default, data, out format); + public static bool TryIdentify(ReadOnlySpan data, [NotNullWhen(true)] out ImageInfo? info) + => TryIdentify(DecoderOptions.Default, data, out info); /// /// Reads the raw image information from the specified span of bytes without fully decoding it. + /// A return value indicates whether the operation succeeded. /// /// The general decoder options. /// The byte span containing encoded image data to read the header from. - /// The format type of the decoded image. + /// + /// When this method returns, contains the raw image information; + /// otherwise, the default value for the type of the parameter. + /// This parameter is passed uninitialized. + /// + /// if the information can be read; otherwise, /// The configuration is null. /// The data is null. /// The data is not readable. - /// - /// The or null if suitable info detector is not found. - /// - public static unsafe ImageInfo Identify(DecoderOptions options, ReadOnlySpan data, out IImageFormat format) + public static unsafe bool TryIdentify(DecoderOptions options, ReadOnlySpan data, [NotNullWhen(true)] out ImageInfo? info) { fixed (byte* ptr = data) { - using var stream = new UnmanagedMemoryStream(ptr, data.Length); - return Identify(options, stream, out format); + using UnmanagedMemoryStream stream = new(ptr, data.Length); + return TryIdentify(options, stream, out info); } } @@ -141,7 +136,7 @@ public abstract partial class Image { fixed (byte* ptr = data) { - using var stream = new UnmanagedMemoryStream(ptr, data.Length); + using UnmanagedMemoryStream stream = new(ptr, data.Length); return Load(options, stream); } } @@ -166,7 +161,7 @@ public abstract partial class Image { fixed (byte* ptr = data) { - using var stream = new UnmanagedMemoryStream(ptr, data.Length); + using UnmanagedMemoryStream stream = new(ptr, data.Length); return Load(options, stream, out format); } } @@ -222,7 +217,7 @@ public abstract partial class Image { fixed (byte* ptr = data) { - using var stream = new UnmanagedMemoryStream(ptr, data.Length); + using UnmanagedMemoryStream stream = new(ptr, data.Length); return Load(options, stream, out format); } } diff --git a/src/ImageSharp/Image.FromFile.cs b/src/ImageSharp/Image.FromFile.cs index 1f17b698d6..515d8408c2 100644 --- a/src/ImageSharp/Image.FromFile.cs +++ b/src/ImageSharp/Image.FromFile.cs @@ -13,22 +13,32 @@ namespace SixLabors.ImageSharp; public abstract partial class Image { /// - /// By reading the header on the provided file this calculates the images mime type. + /// Detects the encoded image format type from the specified file. + /// A return value indicates whether the operation succeeded. /// /// The image file to open and to read the header from. - /// The mime type or null if none found. - /// returns true when format was detected otherwise false. + /// + /// When this method returns, contains the format that matches the given file; + /// otherwise, the default value for the type of the parameter. + /// This parameter is passed uninitialized. + /// + /// if a match is found; otherwise, public static bool TryDetectFormat(string filePath, [NotNullWhen(true)] out IImageFormat? format) => TryDetectFormat(DecoderOptions.Default, filePath, out format); /// - /// By reading the header on the provided file this calculates the images mime type. + /// Detects the encoded image format type from the specified file. + /// A return value indicates whether the operation succeeded. /// /// The general decoder options. /// The image file to open and to read the header from. - /// The mime type or null if none found. - /// The configuration is null. - /// returns true when format was detected otherwise false. + /// + /// When this method returns, contains the format that matches the given file; + /// otherwise, the default value for the type of the parameter. + /// This parameter is passed uninitialized. + /// + /// if a match is found; otherwise, + /// The options are null. public static bool TryDetectFormat(DecoderOptions options, string filePath, [NotNullWhen(true)] out IImageFormat? format) { Guard.NotNull(options, nameof(options)); @@ -38,112 +48,106 @@ public abstract partial class Image } /// - /// Reads the raw image information from the specified stream without fully decoding it. + /// Detects the encoded image format type from the specified file. + /// A return value indicates whether the operation succeeded. /// /// The image file to open and to read the header from. - /// - /// The or null if suitable info detector not found. - /// - public static ImageInfo Identify(string filePath) - => Identify(filePath, out IImageFormat _); - - /// - /// 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 format type of the decoded image. - /// - /// The or null if suitable info detector not found. - /// - public static ImageInfo Identify(string filePath, out IImageFormat format) - => Identify(DecoderOptions.Default, filePath, out format); + /// The token to monitor for cancellation requests. + /// A representing the asynchronous operation. + public static Task> TryDetectFormatAsync( + string filePath, + CancellationToken cancellationToken = default) + => TryDetectFormatAsync(DecoderOptions.Default, filePath, cancellationToken); /// - /// Reads the raw image information from the specified stream without fully decoding it. + /// Detects the encoded image format type from the specified file. + /// A return value indicates whether the operation succeeded. /// /// The general decoder options. /// The image file to open and to read the header from. - /// The format type of the decoded image. - /// The configuration is null. - /// - /// The or null if suitable info detector is not found. - /// - public static ImageInfo Identify(DecoderOptions options, string filePath, out IImageFormat format) + /// The token to monitor for cancellation requests. + /// The options are null. + /// A representing the asynchronous operation. + public static async Task> TryDetectFormatAsync( + DecoderOptions options, + string filePath, + CancellationToken cancellationToken = default) { Guard.NotNull(options, nameof(options)); - using Stream file = options.Configuration.FileSystem.OpenRead(filePath); - return Identify(options, file, out format); + + using Stream stream = options.Configuration.FileSystem.OpenRead(filePath); + return await TryDetectFormatAsync(options, stream, cancellationToken).ConfigureAwait(false); } /// - /// Reads the raw image information from the specified stream without fully decoding it. + /// Reads the raw image information from the specified file path without fully decoding it. + /// A return value indicates whether the operation succeeded. /// /// 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 = default) - => IdentifyAsync(DecoderOptions.Default, filePath, cancellationToken); + /// + /// When this method returns, contains the raw image information; + /// otherwise, the default value for the type of the parameter. + /// This parameter is passed uninitialized. + /// + /// if the information can be read; otherwise, + public static bool TryIdentify(string filePath, [NotNullWhen(true)] out ImageInfo? info) + => TryIdentify(DecoderOptions.Default, filePath, out info); /// - /// Reads the raw image information from the specified stream without fully decoding it. + /// Reads the raw image information from the specified file path without fully decoding it. + /// A return value indicates whether the operation succeeded. /// /// The general decoder options. /// 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( - DecoderOptions options, - string filePath, - CancellationToken cancellationToken = default) + /// + /// When this method returns, contains the raw image information; + /// otherwise, the default value for the type of the parameter. + /// This parameter is passed uninitialized. + /// + /// if the information can be read; otherwise, + /// The options are null. + public static bool TryIdentify(DecoderOptions options, string filePath, [NotNullWhen(true)] out ImageInfo? info) { - (ImageInfo ImageInfo, IImageFormat Format) res = - await IdentifyWithFormatAsync(options, filePath, cancellationToken).ConfigureAwait(false); - return res.ImageInfo; + Guard.NotNull(options, nameof(options)); + + using Stream stream = options.Configuration.FileSystem.OpenRead(filePath); + return TryIdentify(options, stream, out info); } /// /// Reads the raw image information from the specified stream without fully decoding it. + /// A return value indicates whether the operation succeeded. /// /// 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. + /// The representing the asynchronous operation. /// - public static Task<(ImageInfo ImageInfo, IImageFormat Format)> IdentifyWithFormatAsync( + public static Task> TryIdentifyAsync( string filePath, CancellationToken cancellationToken = default) - => IdentifyWithFormatAsync(DecoderOptions.Default, filePath, cancellationToken); + => TryIdentifyAsync(DecoderOptions.Default, filePath, cancellationToken); /// /// Reads the raw image information from the specified stream without fully decoding it. + /// A return value indicates whether the operation succeeded. /// /// The general decoder options. /// 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. + /// The representing the asynchronous operation. /// - public static async Task<(ImageInfo ImageInfo, IImageFormat Format)> IdentifyWithFormatAsync( + public static async Task> TryIdentifyAsync( DecoderOptions options, string filePath, CancellationToken cancellationToken = default) { Guard.NotNull(options, nameof(options)); using Stream stream = options.Configuration.FileSystem.OpenRead(filePath); - return await IdentifyWithFormatAsync(options, stream, cancellationToken) - .ConfigureAwait(false); + return await TryIdentifyAsync(options, stream, cancellationToken).ConfigureAwait(false); } /// diff --git a/src/ImageSharp/Image.FromStream.cs b/src/ImageSharp/Image.FromStream.cs index fc6e14b2eb..fa9285ef3a 100644 --- a/src/ImageSharp/Image.FromStream.cs +++ b/src/ImageSharp/Image.FromStream.cs @@ -16,45 +16,59 @@ namespace SixLabors.ImageSharp; public abstract partial class Image { /// - /// By reading the header on the provided stream this calculates the images format type. + /// Detects the encoded image format type from the specified stream. + /// A return value indicates whether the operation succeeded. /// /// The image stream to read the header from. - /// The format type or null if none found. + /// + /// When this method returns, contains the format that matches the given stream; + /// otherwise, the default value for the type of the parameter. + /// This parameter is passed uninitialized. + /// + /// if a match is found; otherwise, /// The stream is null. /// The stream is not readable. - /// returns true when format was detected otherwise false. public static bool TryDetectFormat(Stream stream, [NotNullWhen(true)] out IImageFormat? format) => TryDetectFormat(DecoderOptions.Default, stream, out format); /// - /// By reading the header on the provided stream this calculates the images format type. + /// Detects the encoded image format type from the specified stream. + /// A return value indicates whether the operation succeeded. /// /// The general decoder options. /// The image stream to read the header from. - /// The format type or null if none found. + /// + /// When this method returns, contains the format that matches the given stream; + /// otherwise, the default value for the type of the parameter. + /// This parameter is passed uninitialized. + /// + /// if a match is found; otherwise, /// The options are null. /// The stream is null. /// The stream is not readable. - /// returns true when format was detected otherwise false. public static bool TryDetectFormat(DecoderOptions options, Stream stream, [NotNullWhen(true)] out IImageFormat? format) { format = WithSeekableStream(options, stream, s => InternalDetectFormat(options.Configuration, s)); - return format != null; + return format is not null; } /// - /// By reading the header on the provided stream this calculates the images format type. + /// Detects the encoded image format type from the specified stream. + /// A return value indicates whether the operation succeeded. /// /// The image stream to read the header from. /// The token to monitor for cancellation requests. /// The stream is null. /// The stream is not readable. - /// A representing the asynchronous operation or null if none is found. - public static Task DetectFormatAsync(Stream stream, CancellationToken cancellationToken = default) - => DetectFormatAsync(DecoderOptions.Default, stream, cancellationToken); + /// A representing the asynchronous operation. + public static Task> TryDetectFormatAsync( + Stream stream, + CancellationToken cancellationToken = default) + => TryDetectFormatAsync(DecoderOptions.Default, stream, cancellationToken); /// - /// By reading the header on the provided stream this calculates the images format type. + /// Detects the encoded image format type from the specified stream. + /// A return value indicates whether the operation succeeded. /// /// The general decoder options. /// The image stream to read the header from. @@ -62,117 +76,63 @@ public abstract partial class Image /// The options are null. /// The stream is null. /// The stream is not readable. - /// A representing the asynchronous operation. - public static Task DetectFormatAsync(DecoderOptions options, Stream stream, CancellationToken cancellationToken = default) - => WithSeekableStreamAsync( + /// A representing the asynchronous operation. + public static async Task> TryDetectFormatAsync( + DecoderOptions options, + Stream stream, + CancellationToken cancellationToken = default) + { + IImageFormat? format = await WithSeekableStreamAsync( options, stream, (s, _) => Task.FromResult(InternalDetectFormat(options.Configuration, s)), - cancellationToken); - - /// - /// Reads the raw image information from the specified stream without fully decoding it. - /// - /// The image stream to read the header from. - /// The stream is null. - /// The stream is not readable. - /// Image contains invalid content. - /// - /// The or null if a suitable info detector is not found. - /// - public static ImageInfo Identify(Stream stream) - => Identify(stream, out IImageFormat _); + cancellationToken).ConfigureAwait(false); - /// - /// Reads the raw image information from the specified stream without fully decoding it. - /// - /// The image stream to read the header from. - /// The token to monitor for cancellation requests. - /// 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 Task IdentifyAsync(Stream stream, CancellationToken cancellationToken = default) - => IdentifyAsync(DecoderOptions.Default, stream, cancellationToken); + return new() { Value = format }; + } /// /// Reads the raw image information from the specified stream without fully decoding it. + /// A return value indicates whether the operation succeeded. /// /// The image stream to read the header from. - /// The format type of the decoded image. + /// + /// When this method returns, contains the raw image information; + /// otherwise, the default value for the type of the parameter. + /// This parameter is passed uninitialized. + /// + /// if the information can be read; otherwise, /// The stream is null. /// The stream is not readable. /// Image contains invalid content. - /// - /// The or null if a suitable info detector is not found. - /// - public static ImageInfo Identify(Stream stream, out IImageFormat format) - => Identify(DecoderOptions.Default, stream, out format); + public static bool TryIdentify(Stream stream, [NotNullWhen(true)] out ImageInfo? info) + => TryIdentify(DecoderOptions.Default, stream, out info); /// /// Reads the raw image information from the specified stream without fully decoding it. + /// A return value indicates whether the operation succeeded. /// /// The general decoder options. /// The image stream to read the information from. + /// + /// When this method returns, contains the raw image information; + /// otherwise, the default value for the type of the parameter. + /// This parameter is passed uninitialized. + /// + /// if the information can be read; otherwise, /// The options are null. /// The stream is null. /// The stream is not readable. /// Image contains invalid content. - /// - /// The or null if a suitable info detector is not found. - /// - public static ImageInfo Identify(DecoderOptions options, Stream stream) - => Identify(options, stream, out _); - - /// - /// Reads the raw image information from the specified stream without fully decoding it. - /// - /// The general decoder options. - /// The image stream to read the information from. - /// The token to monitor for cancellation requests. - /// The options are 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( - DecoderOptions options, - Stream stream, - CancellationToken cancellationToken = default) + public static bool TryIdentify(DecoderOptions options, Stream stream, [NotNullWhen(true)] out ImageInfo? info) { - (ImageInfo ImageInfo, IImageFormat Format) res = await IdentifyWithFormatAsync(options, stream, cancellationToken).ConfigureAwait(false); - return res.ImageInfo; - } - - /// - /// Reads the raw image information from the specified stream without fully decoding it. - /// - /// The general decoder options. - /// The image stream to read the information from. - /// The format type of the decoded image. - /// The options are null. - /// The stream is null. - /// The stream is not readable. - /// Image contains invalid content. - /// - /// The or null if a suitable info detector is not found. - /// - public static ImageInfo Identify(DecoderOptions options, Stream stream, out IImageFormat format) - { - (ImageInfo ImageInfo, IImageFormat Format) data = WithSeekableStream(options, stream, s => InternalIdentify(options, s)); - - format = data.Format; - return data.ImageInfo; + info = WithSeekableStream(options, stream, s => InternalIdentify(options, s)); + return info is not null; } /// /// Reads the raw image information from the specified stream without fully decoding it. + /// A return value indicates whether the operation succeeded. /// /// The image stream to read the information from. /// The token to monitor for cancellation requests. @@ -181,16 +141,16 @@ public abstract partial class Image /// 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. + /// The representing the asynchronous operation. /// - public static Task<(ImageInfo ImageInfo, IImageFormat Format)> IdentifyWithFormatAsync( + public static Task> TryIdentifyAsync( Stream stream, CancellationToken cancellationToken = default) - => IdentifyWithFormatAsync(DecoderOptions.Default, stream, cancellationToken); + => TryIdentifyAsync(DecoderOptions.Default, stream, cancellationToken); /// /// Reads the raw image information from the specified stream without fully decoding it. + /// A return value indicates whether the operation succeeded. /// /// The general decoder options. /// The image stream to read the information from. @@ -200,18 +160,21 @@ public abstract partial class Image /// 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. + /// The representing the asynchronous operation. /// - public static Task<(ImageInfo ImageInfo, IImageFormat Format)> IdentifyWithFormatAsync( + public static async Task> TryIdentifyAsync( DecoderOptions options, Stream stream, CancellationToken cancellationToken = default) - => WithSeekableStreamAsync( + { + ImageInfo? info = await WithSeekableStreamAsync( options, stream, (s, ct) => InternalIdentifyAsync(options, s, ct), - cancellationToken); + cancellationToken).ConfigureAwait(false); + + return new() { Value = info }; + } /// /// Decode a new instance of the class from the given stream. @@ -387,16 +350,15 @@ public abstract partial class Image public static Image Load(DecoderOptions options, Stream stream, out IImageFormat format) where TPixel : unmanaged, IPixel { - (Image Image, IImageFormat Format) data = WithSeekableStream(options, stream, s => Decode(options, s)); + Image? image = WithSeekableStream(options, stream, s => Decode(options, s)); - format = data.Format; - - if (data.Image is null) + if (image is null) { ThrowNotLoaded(options); } - return data.Image; + format = image.Metadata.DecodedImageFormat!; + return image; } /// @@ -416,16 +378,15 @@ public abstract partial class Image Stream stream, CancellationToken cancellationToken = default) { - (Image Image, IImageFormat Format) data = - await WithSeekableStreamAsync(options, stream, (s, ct) => DecodeAsync(options, s, ct), cancellationToken) - .ConfigureAwait(false); + Image? image = await WithSeekableStreamAsync(options, stream, (s, ct) => DecodeAsync(options, s, ct), cancellationToken) + .ConfigureAwait(false); - if (data.Image is null) + if (image is null) { ThrowNotLoaded(options); } - return data; + return new(image, image.Metadata.DecodedImageFormat!); } /// @@ -447,16 +408,15 @@ public abstract partial class Image CancellationToken cancellationToken = default) where TPixel : unmanaged, IPixel { - (Image Image, IImageFormat Format) data = - await WithSeekableStreamAsync(options, stream, (s, ct) => DecodeAsync(options, s, ct), cancellationToken) - .ConfigureAwait(false); + Image? image = await WithSeekableStreamAsync(options, stream, (s, ct) => DecodeAsync(options, s, ct), cancellationToken) + .ConfigureAwait(false); - if (data.Image is null) + if (image is null) { ThrowNotLoaded(options); } - return data; + return new(image, image.Metadata.DecodedImageFormat!); } /// @@ -498,16 +458,14 @@ public abstract partial class Image /// A new . public static Image Load(DecoderOptions options, Stream stream, out IImageFormat format) { - (Image img, IImageFormat fmt) = WithSeekableStream(options, stream, s => Decode(options, s)); - - format = fmt; - - if (img is null) + Image? image = WithSeekableStream(options, stream, s => Decode(options, s)); + if (image is null) { ThrowNotLoaded(options); } - return img; + format = image.Metadata.DecodedImageFormat!; + return image; } /// diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs index bfe490efa0..035481e015 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs @@ -473,9 +473,9 @@ public class BmpDecoderTests [InlineData(Bit1Pal1, 1)] public void Identify_DetectsCorrectPixelType(string imagePath, int expectedPixelSize) { - var testFile = TestFile.Create(imagePath); - using var stream = new MemoryStream(testFile.Bytes, false); - ImageInfo imageInfo = Image.Identify(stream); + TestFile testFile = TestFile.Create(imagePath); + using MemoryStream stream = new(testFile.Bytes, false); + Image.TryIdentify(stream, out ImageInfo imageInfo); Assert.NotNull(imageInfo); Assert.Equal(expectedPixelSize, imageInfo.PixelType?.BitsPerPixel); } @@ -491,9 +491,9 @@ public class BmpDecoderTests [InlineData(RLE8Inverted, 491, 272)] public void Identify_DetectsCorrectWidthAndHeight(string imagePath, int expectedWidth, int expectedHeight) { - var testFile = TestFile.Create(imagePath); - using var stream = new MemoryStream(testFile.Bytes, false); - ImageInfo imageInfo = Image.Identify(stream); + TestFile testFile = TestFile.Create(imagePath); + using MemoryStream stream = new(testFile.Bytes, false); + Image.TryIdentify(stream, out ImageInfo imageInfo); Assert.NotNull(imageInfo); Assert.Equal(expectedWidth, imageInfo.Width); Assert.Equal(expectedHeight, imageInfo.Height); @@ -503,8 +503,8 @@ public class BmpDecoderTests [MemberData(nameof(RatioFiles))] public void Decode_VerifyRatio(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit) { - var testFile = TestFile.Create(imagePath); - using var stream = new MemoryStream(testFile.Bytes, false); + TestFile testFile = TestFile.Create(imagePath); + using MemoryStream stream = new(testFile.Bytes, false); using Image image = BmpDecoder.Instance.Decode(DecoderOptions.Default, stream); ImageMetadata meta = image.Metadata; Assert.Equal(xResolution, meta.HorizontalResolution); diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpMetadataTests.cs index 712c7d8bf4..1aef3e7481 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpMetadataTests.cs @@ -14,8 +14,9 @@ public class BmpMetadataTests [Fact] public void CloneIsDeep() { - var meta = new BmpMetadata { BitsPerPixel = BmpBitsPerPixel.Pixel24, InfoHeaderType = BmpInfoHeaderType.Os2Version2 }; - var clone = (BmpMetadata)meta.DeepClone(); + BmpMetadata meta = new() + { BitsPerPixel = BmpBitsPerPixel.Pixel24, InfoHeaderType = BmpInfoHeaderType.Os2Version2 }; + BmpMetadata clone = (BmpMetadata)meta.DeepClone(); clone.BitsPerPixel = BmpBitsPerPixel.Pixel32; clone.InfoHeaderType = BmpInfoHeaderType.WinVersion2; @@ -35,15 +36,13 @@ public class BmpMetadataTests [InlineData(Os2v2, BmpInfoHeaderType.Os2Version2)] public void Identify_DetectsCorrectBitmapInfoHeaderType(string imagePath, BmpInfoHeaderType expectedInfoHeaderType) { - var testFile = TestFile.Create(imagePath); - using (var stream = new MemoryStream(testFile.Bytes, false)) - { - ImageInfo imageInfo = Image.Identify(stream); - Assert.NotNull(imageInfo); - BmpMetadata bitmapMetadata = imageInfo.Metadata.GetBmpMetadata(); - Assert.NotNull(bitmapMetadata); - Assert.Equal(expectedInfoHeaderType, bitmapMetadata.InfoHeaderType); - } + TestFile testFile = TestFile.Create(imagePath); + using MemoryStream stream = new(testFile.Bytes, false); + Image.TryIdentify(stream, out ImageInfo imageInfo); + Assert.NotNull(imageInfo); + BmpMetadata bitmapMetadata = imageInfo.Metadata.GetBmpMetadata(); + Assert.NotNull(bitmapMetadata); + Assert.Equal(expectedInfoHeaderType, bitmapMetadata.InfoHeaderType); } [Theory] @@ -51,12 +50,10 @@ public class BmpMetadataTests public void Decoder_CanReadColorProfile(TestImageProvider provider) where TPixel : unmanaged, IPixel { - using (Image image = provider.GetImage(BmpDecoder.Instance)) - { - ImageSharp.Metadata.ImageMetadata metaData = image.Metadata; - Assert.NotNull(metaData); - Assert.NotNull(metaData.IccProfile); - Assert.Equal(16, metaData.IccProfile.Entries.Length); - } + using Image image = provider.GetImage(BmpDecoder.Instance); + ImageSharp.Metadata.ImageMetadata metaData = image.Metadata; + Assert.NotNull(metaData); + Assert.NotNull(metaData.IccProfile); + Assert.Equal(16, metaData.IccProfile.Entries.Length); } } diff --git a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs index 95040e5d66..400af5e450 100644 --- a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs +++ b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs @@ -7,7 +7,6 @@ using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Quantization; -using SixLabors.ImageSharp.Tests.TestUtilities; namespace SixLabors.ImageSharp.Tests.Formats; @@ -257,15 +256,11 @@ public class GeneralFormatTests image.Save(memoryStream, format); memoryStream.Position = 0; - ImageInfo imageInfo = Image.Identify(memoryStream); + Image.TryIdentify(memoryStream, out ImageInfo imageInfo); Assert.Equal(imageInfo.Width, width); Assert.Equal(imageInfo.Height, height); - memoryStream.Position = 0; - - imageInfo = Image.Identify(memoryStream, out IImageFormat detectedFormat); - - Assert.Equal(format, detectedFormat); + Assert.Equal(format, imageInfo.Metadata.DecodedImageFormat); } [Fact] @@ -274,10 +269,9 @@ public class GeneralFormatTests byte[] invalid = new byte[10]; using MemoryStream memoryStream = new(invalid); - ImageInfo imageInfo = Image.Identify(memoryStream, out IImageFormat format); + Image.TryIdentify(memoryStream, out ImageInfo imageInfo); Assert.Null(imageInfo); - Assert.Null(format); } private static IImageFormat GetFormat(string format) diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs index 9ddae6645c..589baa613d 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs @@ -59,13 +59,13 @@ public class GifDecoderTests [Fact] public unsafe void Decode_NonTerminatedFinalFrame() { - var testFile = TestFile.Create(TestImages.Gif.Rings); + TestFile testFile = TestFile.Create(TestImages.Gif.Rings); int length = testFile.Bytes.Length - 2; fixed (byte* data = testFile.Bytes.AsSpan(0, length)) { - using var stream = new UnmanagedMemoryStream(data, length); + using UnmanagedMemoryStream stream = new(data, length); using Image image = GifDecoder.Instance.Decode(DecoderOptions.Default, stream); Assert.Equal((200, 200), (image.Width, image.Height)); } @@ -120,9 +120,13 @@ public class GifDecoderTests [InlineData(TestImages.Gif.Trans, 8)] public void DetectPixelSize(string imagePath, int expectedPixelSize) { - var testFile = TestFile.Create(imagePath); - using var stream = new MemoryStream(testFile.Bytes, false); - Assert.Equal(expectedPixelSize, Image.Identify(stream)?.PixelType?.BitsPerPixel); + TestFile testFile = TestFile.Create(imagePath); + using MemoryStream stream = new(testFile.Bytes, false); + + Image.TryIdentify(stream, out ImageInfo imageInfo); + + Assert.NotNull(imageInfo); + Assert.Equal(expectedPixelSize, imageInfo.PixelType.BitsPerPixel); } [Theory] @@ -155,9 +159,9 @@ public class GifDecoderTests [Fact] public void CanDecodeIntermingledImages() { - using (var kumin1 = Image.Load(TestFile.Create(TestImages.Gif.Kumin).Bytes)) + using (Image kumin1 = Image.Load(TestFile.Create(TestImages.Gif.Kumin).Bytes)) using (Image.Load(TestFile.Create(TestImages.Png.Icon).Bytes)) - using (var kumin2 = Image.Load(TestFile.Create(TestImages.Gif.Kumin).Bytes)) + using (Image kumin2 = Image.Load(TestFile.Create(TestImages.Gif.Kumin).Bytes)) { for (int i = 0; i < kumin1.Frames.Count; i++) { diff --git a/tests/ImageSharp.Tests/Formats/Pbm/PbmMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Pbm/PbmMetadataTests.cs index 826d16e740..b4c39293d4 100644 --- a/tests/ImageSharp.Tests/Formats/Pbm/PbmMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmMetadataTests.cs @@ -13,8 +13,9 @@ public class PbmMetadataTests [Fact] public void CloneIsDeep() { - var meta = new PbmMetadata { ColorType = PbmColorType.Grayscale }; - var clone = (PbmMetadata)meta.DeepClone(); + PbmMetadata meta = new() + { ColorType = PbmColorType.Grayscale }; + PbmMetadata clone = (PbmMetadata)meta.DeepClone(); clone.ColorType = PbmColorType.Rgb; clone.ComponentType = PbmComponentType.Short; @@ -33,9 +34,9 @@ public class PbmMetadataTests [InlineData(RgbPlain, PbmEncoding.Plain)] public void Identify_DetectsCorrectEncoding(string imagePath, PbmEncoding expectedEncoding) { - var testFile = TestFile.Create(imagePath); - using var stream = new MemoryStream(testFile.Bytes, false); - ImageInfo imageInfo = Image.Identify(stream); + TestFile testFile = TestFile.Create(imagePath); + using MemoryStream stream = new(testFile.Bytes, false); + Image.TryIdentify(stream, out ImageInfo imageInfo); Assert.NotNull(imageInfo); PbmMetadata bitmapMetadata = imageInfo.Metadata.GetPbmMetadata(); Assert.NotNull(bitmapMetadata); @@ -52,9 +53,9 @@ public class PbmMetadataTests [InlineData(RgbPlain, PbmColorType.Rgb)] public void Identify_DetectsCorrectColorType(string imagePath, PbmColorType expectedColorType) { - var testFile = TestFile.Create(imagePath); - using var stream = new MemoryStream(testFile.Bytes, false); - ImageInfo imageInfo = Image.Identify(stream); + TestFile testFile = TestFile.Create(imagePath); + using MemoryStream stream = new(testFile.Bytes, false); + Image.TryIdentify(stream, out ImageInfo imageInfo); Assert.NotNull(imageInfo); PbmMetadata bitmapMetadata = imageInfo.Metadata.GetPbmMetadata(); Assert.NotNull(bitmapMetadata); @@ -71,9 +72,9 @@ public class PbmMetadataTests [InlineData(RgbPlain, PbmComponentType.Byte)] public void Identify_DetectsCorrectComponentType(string imagePath, PbmComponentType expectedComponentType) { - var testFile = TestFile.Create(imagePath); - using var stream = new MemoryStream(testFile.Bytes, false); - ImageInfo imageInfo = Image.Identify(stream); + TestFile testFile = TestFile.Create(imagePath); + using MemoryStream stream = new(testFile.Bytes, false); + Image.TryIdentify(stream, out ImageInfo imageInfo); Assert.NotNull(imageInfo); PbmMetadata bitmapMetadata = imageInfo.Metadata.GetPbmMetadata(); Assert.NotNull(bitmapMetadata); diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index ea958df37b..85849cdff0 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -82,7 +82,7 @@ public partial class PngDecoderTests public void Decode_NonGeneric_CreatesCorrectImageType(string path, Type type) { string file = Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, path); - using var image = Image.Load(file); + using Image image = Image.Load(file); Assert.IsType(type, image); } @@ -304,9 +304,13 @@ public partial class PngDecoderTests [InlineData(TestImages.Png.Rgb48BppInterlaced, 48)] public void Identify(string imagePath, int expectedPixelSize) { - var testFile = TestFile.Create(imagePath); - using var stream = new MemoryStream(testFile.Bytes, false); - Assert.Equal(expectedPixelSize, Image.Identify(stream)?.PixelType?.BitsPerPixel); + TestFile testFile = TestFile.Create(imagePath); + using MemoryStream stream = new(testFile.Bytes, false); + + Image.TryIdentify(stream, out ImageInfo imageInfo); + + Assert.NotNull(imageInfo); + Assert.Equal(expectedPixelSize, imageInfo.PixelType.BitsPerPixel); } [Theory] @@ -502,9 +506,9 @@ public partial class PngDecoderTests [InlineData(TestImages.Png.Issue2209IndexedWithTransparency)] public void Issue2209_Identify_HasTransparencyIsTrue(string imagePath) { - var testFile = TestFile.Create(imagePath); - using var stream = new MemoryStream(testFile.Bytes, false); - ImageInfo imageInfo = Image.Identify(stream); + TestFile testFile = TestFile.Create(imagePath); + using MemoryStream stream = new(testFile.Bytes, false); + Image.TryIdentify(stream, out ImageInfo imageInfo); PngMetadata metadata = imageInfo.Metadata.GetPngMetadata(); Assert.True(metadata.HasTransparency); } diff --git a/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs index 03de88a249..351b44ee02 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs @@ -23,7 +23,7 @@ public class PngMetadataTests [Fact] public void CloneIsDeep() { - var meta = new PngMetadata + PngMetadata meta = new() { BitDepth = PngBitDepth.Bit16, ColorType = PngColorType.GrayscaleWithAlpha, @@ -32,7 +32,7 @@ public class PngMetadataTests TextData = new List { new PngTextData("name", "value", "foo", "bar") } }; - var clone = (PngMetadata)meta.DeepClone(); + PngMetadata clone = (PngMetadata)meta.DeepClone(); clone.BitDepth = PngBitDepth.Bit2; clone.ColorType = PngColorType.Palette; @@ -63,7 +63,7 @@ public class PngMetadataTests where TPixel : unmanaged, IPixel { using Image input = provider.GetImage(PngDecoder.Instance); - using var memoryStream = new MemoryStream(); + using MemoryStream memoryStream = new(); input.Save(memoryStream, new PngEncoder()); memoryStream.Position = 0; @@ -93,13 +93,13 @@ public class PngMetadataTests where TPixel : unmanaged, IPixel { using Image input = provider.GetImage(PngDecoder.Instance); - using var memoryStream = new MemoryStream(); + using MemoryStream memoryStream = new(); // This will be a zTXt chunk. - var expectedText = new PngTextData("large-text", new string('c', 100), string.Empty, string.Empty); + PngTextData expectedText = new("large-text", new string('c', 100), string.Empty, string.Empty); // This will be a iTXt chunk. - var expectedTextNoneLatin = new PngTextData("large-text-non-latin", new string('Ф', 100), "language-tag", "translated-keyword"); + PngTextData expectedTextNoneLatin = new("large-text-non-latin", new string('Ф', 100), "language-tag", "translated-keyword"); PngMetadata inputMetadata = input.Metadata.GetFormatMetadata(PngFormat.Instance); inputMetadata.TextData.Add(expectedText); inputMetadata.TextData.Add(expectedTextNoneLatin); @@ -153,7 +153,7 @@ public class PngMetadataTests SkipMetadata = false }; - var testFile = TestFile.Create(TestImages.Png.Blur); + TestFile testFile = TestFile.Create(TestImages.Png.Blur); using Image image = testFile.CreateRgba32Image(PngDecoder.Instance, options); PngMetadata meta = image.Metadata.GetFormatMetadata(PngFormat.Instance); @@ -172,7 +172,7 @@ public class PngMetadataTests SkipMetadata = true }; - var testFile = TestFile.Create(TestImages.Png.PngWithMetadata); + TestFile testFile = TestFile.Create(TestImages.Png.PngWithMetadata); using Image image = testFile.CreateRgba32Image(PngDecoder.Instance, options); PngMetadata meta = image.Metadata.GetFormatMetadata(PngFormat.Instance); @@ -183,8 +183,8 @@ public class PngMetadataTests [MemberData(nameof(RatioFiles))] public void Decode_VerifyRatio(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit) { - var testFile = TestFile.Create(imagePath); - using var stream = new MemoryStream(testFile.Bytes, false); + TestFile testFile = TestFile.Create(imagePath); + using MemoryStream stream = new(testFile.Bytes, false); using Image image = PngDecoder.Instance.Decode(DecoderOptions.Default, stream); ImageMetadata meta = image.Metadata; Assert.Equal(xResolution, meta.HorizontalResolution); @@ -201,11 +201,11 @@ public class PngMetadataTests ImageSharp.Metadata.Profiles.Icc.IccProfile expectedProfile = input.Metadata.IccProfile; byte[] expectedProfileBytes = expectedProfile.ToByteArray(); - using var memStream = new MemoryStream(); + using MemoryStream memStream = new(); input.Save(memStream, new PngEncoder()); memStream.Position = 0; - using var output = Image.Load(memStream); + using Image output = Image.Load(memStream); ImageSharp.Metadata.Profiles.Icc.IccProfile actualProfile = output.Metadata.IccProfile; byte[] actualProfileBytes = actualProfile.ToByteArray(); @@ -217,8 +217,8 @@ public class PngMetadataTests [MemberData(nameof(RatioFiles))] public void Identify_VerifyRatio(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit) { - var testFile = TestFile.Create(imagePath); - using var stream = new MemoryStream(testFile.Bytes, false); + TestFile testFile = TestFile.Create(imagePath); + using MemoryStream stream = new(testFile.Bytes, false); ImageInfo image = PngDecoder.Instance.Identify(DecoderOptions.Default, stream); ImageMetadata meta = image.Metadata; Assert.Equal(xResolution, meta.HorizontalResolution); @@ -230,9 +230,9 @@ public class PngMetadataTests [InlineData(TestImages.Png.PngWithMetadata)] public void Identify_ReadsTextData(string imagePath) { - var testFile = TestFile.Create(imagePath); - using var stream = new MemoryStream(testFile.Bytes, false); - ImageInfo imageInfo = Image.Identify(stream); + TestFile testFile = TestFile.Create(imagePath); + using MemoryStream stream = new(testFile.Bytes, false); + Image.TryIdentify(stream, out ImageInfo imageInfo); Assert.NotNull(imageInfo); PngMetadata meta = imageInfo.Metadata.GetFormatMetadata(PngFormat.Instance); VerifyTextDataIsPresent(meta); @@ -242,9 +242,9 @@ public class PngMetadataTests [InlineData(TestImages.Png.PngWithMetadata)] public void Identify_ReadsExifData(string imagePath) { - var testFile = TestFile.Create(imagePath); - using var stream = new MemoryStream(testFile.Bytes, false); - ImageInfo imageInfo = Image.Identify(stream); + TestFile testFile = TestFile.Create(imagePath); + using MemoryStream stream = new(testFile.Bytes, false); + Image.TryIdentify(stream, out ImageInfo imageInfo); Assert.NotNull(imageInfo); Assert.NotNull(imageInfo.Metadata.ExifProfile); ExifProfile exif = imageInfo.Metadata.ExifProfile; @@ -279,9 +279,9 @@ public class PngMetadataTests [InlineData(TestImages.Png.Issue1875)] public void Identify_ReadsLegacyExifData(string imagePath) { - var testFile = TestFile.Create(imagePath); - using var stream = new MemoryStream(testFile.Bytes, false); - ImageInfo imageInfo = Image.Identify(stream); + TestFile testFile = TestFile.Create(imagePath); + using MemoryStream stream = new(testFile.Bytes, false); + Image.TryIdentify(stream, out ImageInfo imageInfo); Assert.NotNull(imageInfo); Assert.NotNull(imageInfo.Metadata.ExifProfile); diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaFileHeaderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaFileHeaderTests.cs index d34c051f8f..5910a86ac1 100644 --- a/tests/ImageSharp.Tests/Formats/Tga/TgaFileHeaderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tga/TgaFileHeaderTests.cs @@ -22,7 +22,7 @@ public class TgaFileHeaderTests [InlineData(new byte[] { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 0, 0, 0, 32, 8 })] // invalid height public void ImageLoad_WithNoValidTgaHeaderBytes_Throws_UnknownImageFormatException(byte[] data) { - using var stream = new MemoryStream(data); + using MemoryStream stream = new(data); Assert.Throws(() => { @@ -39,9 +39,9 @@ public class TgaFileHeaderTests [InlineData(new byte[] { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 124, 0, 124, 0, 24, 32 }, 124, 124, TgaBitsPerPixel.Pixel24)] public void Identify_WithValidData_Works(byte[] data, int width, int height, TgaBitsPerPixel bitsPerPixel) { - using var stream = new MemoryStream(data); + using MemoryStream stream = new(data); - ImageInfo info = Image.Identify(stream); + Image.TryIdentify(stream, out ImageInfo info); TgaMetadata tgaData = info.Metadata.GetTgaMetadata(); Assert.Equal(bitsPerPixel, tgaData.BitsPerPixel); Assert.Equal(width, info.Width); diff --git a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs index bc8fe35a4a..de7e747200 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs @@ -60,23 +60,21 @@ public class BigTiffDecoderTests : TiffDecoderBaseTester [InlineData(MinIsBlack, 1, 32, 32, 96, 96, PixelResolutionUnit.PixelsPerInch)] public void Identify(string imagePath, int expectedPixelSize, int expectedWidth, int expectedHeight, double expectedHResolution, double expectedVResolution, PixelResolutionUnit expectedResolutionUnit) { - var testFile = TestFile.Create(imagePath); - using (var stream = new MemoryStream(testFile.Bytes, false)) - { - ImageInfo info = Image.Identify(stream); - - Assert.Equal(expectedPixelSize, info.PixelType?.BitsPerPixel); - Assert.Equal(expectedWidth, info.Width); - Assert.Equal(expectedHeight, info.Height); - Assert.NotNull(info.Metadata); - Assert.Equal(expectedHResolution, info.Metadata.HorizontalResolution); - Assert.Equal(expectedVResolution, info.Metadata.VerticalResolution); - Assert.Equal(expectedResolutionUnit, info.Metadata.ResolutionUnits); - - TiffMetadata tiffmeta = info.Metadata.GetTiffMetadata(); - Assert.NotNull(tiffmeta); - Assert.Equal(TiffFormatType.BigTIFF, tiffmeta.FormatType); - } + TestFile testFile = TestFile.Create(imagePath); + using MemoryStream stream = new(testFile.Bytes, false); + Image.TryIdentify(stream, out ImageInfo info); + + Assert.Equal(expectedPixelSize, info.PixelType?.BitsPerPixel); + Assert.Equal(expectedWidth, info.Width); + Assert.Equal(expectedHeight, info.Height); + Assert.NotNull(info.Metadata); + Assert.Equal(expectedHResolution, info.Metadata.HorizontalResolution); + Assert.Equal(expectedVResolution, info.Metadata.VerticalResolution); + Assert.Equal(expectedResolutionUnit, info.Metadata.ResolutionUnits); + + TiffMetadata tiffmeta = info.Metadata.GetTiffMetadata(); + Assert.NotNull(tiffmeta); + Assert.Equal(TiffFormatType.BigTIFF, tiffmeta.FormatType); } [Theory] @@ -84,19 +82,17 @@ public class BigTiffDecoderTests : TiffDecoderBaseTester [InlineData(BigTIFFMotorola, ImageSharp.ByteOrder.BigEndian)] public void ByteOrder(string imagePath, ByteOrder expectedByteOrder) { - var testFile = TestFile.Create(imagePath); - using (var stream = new MemoryStream(testFile.Bytes, false)) - { - ImageInfo info = Image.Identify(stream); + TestFile testFile = TestFile.Create(imagePath); + using MemoryStream stream = new(testFile.Bytes, false); + Image.TryIdentify(stream, out ImageInfo info); - Assert.NotNull(info.Metadata); - Assert.Equal(expectedByteOrder, info.Metadata.GetTiffMetadata().ByteOrder); + Assert.NotNull(info.Metadata); + Assert.Equal(expectedByteOrder, info.Metadata.GetTiffMetadata().ByteOrder); - stream.Seek(0, SeekOrigin.Begin); + stream.Seek(0, SeekOrigin.Begin); - using var img = Image.Load(stream); - Assert.Equal(expectedByteOrder, img.Metadata.GetTiffMetadata().ByteOrder); - } + using Image img = Image.Load(stream); + Assert.Equal(expectedByteOrder, img.Metadata.GetTiffMetadata().ByteOrder); } [Theory] diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index 60bc44dedd..26f006b34b 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -30,19 +30,17 @@ public class TiffDecoderTests : TiffDecoderBaseTester [InlineData(Flower4BitPalette, 4, 73, 43, 72, 72, PixelResolutionUnit.PixelsPerInch)] public void Identify(string imagePath, int expectedPixelSize, int expectedWidth, int expectedHeight, double expectedHResolution, double expectedVResolution, PixelResolutionUnit expectedResolutionUnit) { - var testFile = TestFile.Create(imagePath); - using (var stream = new MemoryStream(testFile.Bytes, false)) - { - ImageInfo info = Image.Identify(stream); - - Assert.Equal(expectedPixelSize, info.PixelType?.BitsPerPixel); - Assert.Equal(expectedWidth, info.Width); - Assert.Equal(expectedHeight, info.Height); - Assert.NotNull(info.Metadata); - Assert.Equal(expectedHResolution, info.Metadata.HorizontalResolution); - Assert.Equal(expectedVResolution, info.Metadata.VerticalResolution); - Assert.Equal(expectedResolutionUnit, info.Metadata.ResolutionUnits); - } + TestFile testFile = TestFile.Create(imagePath); + using MemoryStream stream = new(testFile.Bytes, false); + Image.TryIdentify(stream, out ImageInfo info); + + Assert.Equal(expectedPixelSize, info.PixelType?.BitsPerPixel); + Assert.Equal(expectedWidth, info.Width); + Assert.Equal(expectedHeight, info.Height); + Assert.NotNull(info.Metadata); + Assert.Equal(expectedHResolution, info.Metadata.HorizontalResolution); + Assert.Equal(expectedVResolution, info.Metadata.VerticalResolution); + Assert.Equal(expectedResolutionUnit, info.Metadata.ResolutionUnits); } [Theory] @@ -51,18 +49,16 @@ public class TiffDecoderTests : TiffDecoderBaseTester public void ByteOrder(string imagePath, ByteOrder expectedByteOrder) { TestFile testFile = TestFile.Create(imagePath); - using (var stream = new MemoryStream(testFile.Bytes, false)) - { - ImageInfo info = Image.Identify(stream); + using MemoryStream stream = new(testFile.Bytes, false); + Image.TryIdentify(stream, out ImageInfo info); - Assert.NotNull(info.Metadata); - Assert.Equal(expectedByteOrder, info.Metadata.GetTiffMetadata().ByteOrder); + Assert.NotNull(info.Metadata); + Assert.Equal(expectedByteOrder, info.Metadata.GetTiffMetadata().ByteOrder); - stream.Seek(0, SeekOrigin.Begin); + stream.Seek(0, SeekOrigin.Begin); - using Image img = Image.Load(stream); - Assert.Equal(expectedByteOrder, img.Metadata.GetTiffMetadata().ByteOrder); - } + using Image img = Image.Load(stream); + Assert.Equal(expectedByteOrder, img.Metadata.GetTiffMetadata().ByteOrder); } [Theory] diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs index 6cf1bbc366..4d5f66503c 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs @@ -27,12 +27,12 @@ public class TiffMetadataTests [Fact] public void TiffMetadata_CloneIsDeep() { - var meta = new TiffMetadata + TiffMetadata meta = new() { ByteOrder = ByteOrder.BigEndian, }; - var clone = (TiffMetadata)meta.DeepClone(); + TiffMetadata clone = (TiffMetadata)meta.DeepClone(); clone.ByteOrder = ByteOrder.LittleEndian; @@ -46,10 +46,10 @@ public class TiffMetadataTests { using Image image = provider.GetImage(TiffDecoder.Instance); TiffFrameMetadata meta = image.Frames.RootFrame.Metadata.GetTiffMetadata(); - var cloneSameAsSampleMetaData = (TiffFrameMetadata)meta.DeepClone(); + TiffFrameMetadata cloneSameAsSampleMetaData = (TiffFrameMetadata)meta.DeepClone(); VerifyExpectedTiffFrameMetaDataIsPresent(cloneSameAsSampleMetaData); - var clone = (TiffFrameMetadata)meta.DeepClone(); + TiffFrameMetadata clone = (TiffFrameMetadata)meta.DeepClone(); clone.BitsPerPixel = TiffBitsPerPixel.Bit8; clone.Compression = TiffCompression.None; @@ -77,10 +77,10 @@ public class TiffMetadataTests [InlineData(RgbUncompressed, 24)] public void Identify_DetectsCorrectBitPerPixel(string imagePath, int expectedBitsPerPixel) { - var testFile = TestFile.Create(imagePath); - using var stream = new MemoryStream(testFile.Bytes, false); + TestFile testFile = TestFile.Create(imagePath); + using MemoryStream stream = new(testFile.Bytes, false); - ImageInfo imageInfo = Image.Identify(stream); + Image.TryIdentify(stream, out ImageInfo imageInfo); Assert.NotNull(imageInfo); TiffMetadata tiffMetadata = imageInfo.Metadata.GetTiffMetadata(); @@ -93,10 +93,10 @@ public class TiffMetadataTests [InlineData(LittleEndianByteOrder, ByteOrder.LittleEndian)] public void Identify_DetectsCorrectByteOrder(string imagePath, ByteOrder expectedByteOrder) { - var testFile = TestFile.Create(imagePath); - using var stream = new MemoryStream(testFile.Bytes, false); + TestFile testFile = TestFile.Create(imagePath); + using MemoryStream stream = new(testFile.Bytes, false); - ImageInfo imageInfo = Image.Identify(stream); + Image.TryIdentify(stream, out ImageInfo imageInfo); Assert.NotNull(imageInfo); TiffMetadata tiffMetadata = imageInfo.Metadata.GetTiffMetadata(); @@ -173,7 +173,7 @@ public class TiffMetadataTests Assert.Equal("Copyright", exifProfile.GetValue(ExifTag.Copyright).Value); Assert.Equal(4, exifProfile.GetValue(ExifTag.Rating).Value); Assert.Equal(75, exifProfile.GetValue(ExifTag.RatingPercent).Value); - var expectedResolution = new Rational(10, 1, simplify: false); + Rational expectedResolution = new(10, 1, simplify: false); Assert.Equal(expectedResolution, exifProfile.GetValue(ExifTag.XResolution).Value); Assert.Equal(expectedResolution, exifProfile.GetValue(ExifTag.YResolution).Value); Assert.Equal(new Number[] { 8u }, exifProfile.GetValue(ExifTag.StripOffsets)?.Value, new NumberComparer()); @@ -242,13 +242,13 @@ public class TiffMetadataTests Assert.Equal(TiffBitsPerPixel.Bit4, frameMetaInput.BitsPerPixel); // Save to Tiff - var tiffEncoder = new TiffEncoder() { PhotometricInterpretation = TiffPhotometricInterpretation.Rgb }; - using var ms = new MemoryStream(); + TiffEncoder tiffEncoder = new() { PhotometricInterpretation = TiffPhotometricInterpretation.Rgb }; + using MemoryStream ms = new(); image.Save(ms, tiffEncoder); // Assert ms.Position = 0; - using var encodedImage = Image.Load(ms); + using Image encodedImage = Image.Load(ms); ImageMetadata encodedImageMetaData = encodedImage.Metadata; ImageFrame rootFrameEncodedImage = encodedImage.Frames.RootFrame; diff --git a/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs index 150c67d4f4..4d5d2aefdd 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs @@ -39,9 +39,9 @@ public class WebpDecoderTests int expectedHeight, int expectedBitsPerPixel) { - var testFile = TestFile.Create(imagePath); - using var stream = new MemoryStream(testFile.Bytes, false); - ImageInfo imageInfo = Image.Identify(stream); + TestFile testFile = TestFile.Create(imagePath); + using MemoryStream stream = new(testFile.Bytes, false); + Image.TryIdentify(stream, out ImageInfo imageInfo); Assert.NotNull(imageInfo); Assert.Equal(expectedWidth, imageInfo.Width); Assert.Equal(expectedHeight, imageInfo.Height); @@ -419,7 +419,7 @@ public class WebpDecoderTests private static void RunDecodeLossyWithHorizontalFilter() { - var provider = TestImageProvider.File(TestImageLossyHorizontalFilterPath); + TestImageProvider provider = TestImageProvider.File(TestImageLossyHorizontalFilterPath); using Image image = provider.GetImage(WebpDecoder.Instance); image.DebugSave(provider); image.CompareToOriginal(provider, ReferenceDecoder); @@ -427,7 +427,7 @@ public class WebpDecoderTests private static void RunDecodeLossyWithVerticalFilter() { - var provider = TestImageProvider.File(TestImageLossyVerticalFilterPath); + TestImageProvider provider = TestImageProvider.File(TestImageLossyVerticalFilterPath); using Image image = provider.GetImage(WebpDecoder.Instance); image.DebugSave(provider); image.CompareToOriginal(provider, ReferenceDecoder); @@ -435,7 +435,7 @@ public class WebpDecoderTests private static void RunDecodeLossyWithSimpleFilterTest() { - var provider = TestImageProvider.File(TestImageLossySimpleFilterPath); + TestImageProvider provider = TestImageProvider.File(TestImageLossySimpleFilterPath); using Image image = provider.GetImage(WebpDecoder.Instance); image.DebugSave(provider); image.CompareToOriginal(provider, ReferenceDecoder); @@ -443,7 +443,7 @@ public class WebpDecoderTests private static void RunDecodeLossyWithComplexFilterTest() { - var provider = TestImageProvider.File(TestImageLossyComplexFilterPath); + TestImageProvider provider = TestImageProvider.File(TestImageLossyComplexFilterPath); using Image image = provider.GetImage(WebpDecoder.Instance); image.DebugSave(provider); image.CompareToOriginal(provider, ReferenceDecoder); diff --git a/tests/ImageSharp.Tests/Image/ImageTests.Decode_Cancellation.cs b/tests/ImageSharp.Tests/Image/ImageTests.Decode_Cancellation.cs index d8d9f4fe2a..d4a77d2c12 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.Decode_Cancellation.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.Decode_Cancellation.cs @@ -34,7 +34,7 @@ public partial class ImageTests { using FileStream fs = File.OpenRead(TestFile.GetInputFileFullPath(file)); CancellationToken preCancelled = new(canceled: true); - await Assert.ThrowsAnyAsync(async () => await Image.IdentifyAsync(fs, preCancelled)); + await Assert.ThrowsAnyAsync(async () => await Image.TryIdentifyAsync(fs, preCancelled)); } private static TheoryData CreateLoadData() diff --git a/tests/ImageSharp.Tests/Image/ImageTests.DetectFormat.cs b/tests/ImageSharp.Tests/Image/ImageTests.DetectFormat.cs index 86ceed73bb..5a5f595ac7 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.DetectFormat.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.DetectFormat.cs @@ -16,9 +16,9 @@ public partial class ImageTests { private static readonly string ActualImagePath = TestFile.GetInputFileFullPath(TestImages.Bmp.F); - private byte[] ActualImageBytes => TestFile.Create(TestImages.Bmp.F).Bytes; + private static byte[] ActualImageBytes => TestFile.Create(TestImages.Bmp.F).Bytes; - private ReadOnlySpan ActualImageSpan => this.ActualImageBytes.AsSpan(); + private static ReadOnlySpan ActualImageSpan => ActualImageBytes.AsSpan(); private IImageFormat LocalImageFormat => this.localImageFormatMock.Object; @@ -34,7 +34,7 @@ public partial class ImageTests [Fact] public void FromBytes_GlobalConfiguration() { - bool result = Image.TryDetectFormat(this.ActualImageSpan, out IImageFormat type); + bool result = Image.TryDetectFormat(ActualImageSpan, out IImageFormat type); Assert.True(result); Assert.Equal(ExpectedGlobalFormat, type); @@ -63,6 +63,15 @@ public partial class ImageTests Assert.Equal(ExpectedGlobalFormat, type); } + [Fact] + public async Task FromFileSystemPathAsync_GlobalConfiguration() + { + Attempt attempt = await Image.TryDetectFormatAsync(ActualImagePath); + + Assert.True(attempt.Success); + Assert.Equal(ExpectedGlobalFormat, attempt.Value); + } + [Fact] public void FromFileSystemPath_CustomConfiguration() { @@ -78,15 +87,27 @@ public partial class ImageTests } [Fact] - public void FromStream_GlobalConfiguration() + public async Task FromFileSystemPathAsync_CustomConfiguration() { - using (var stream = new MemoryStream(this.ActualImageBytes)) + DecoderOptions options = new() { - bool result = Image.TryDetectFormat(stream, out IImageFormat type); + Configuration = this.LocalConfiguration + }; - Assert.True(result); - Assert.Equal(ExpectedGlobalFormat, type); - } + Attempt attempt = await Image.TryDetectFormatAsync(options, this.MockFilePath); + + Assert.True(attempt.Success); + Assert.Equal(this.LocalImageFormat, attempt.Value); + } + + [Fact] + public void FromStream_GlobalConfiguration() + { + using MemoryStream stream = new(ActualImageBytes); + bool result = Image.TryDetectFormat(stream, out IImageFormat type); + + Assert.True(result); + Assert.Equal(ExpectedGlobalFormat, type); } [Fact] @@ -120,11 +141,9 @@ public partial class ImageTests [Fact] public async Task FromStreamAsync_GlobalConfiguration() { - using (var stream = new MemoryStream(this.ActualImageBytes)) - { - IImageFormat type = await Image.DetectFormatAsync(new AsyncStreamWrapper(stream, () => false)); - Assert.Equal(ExpectedGlobalFormat, type); - } + using MemoryStream stream = new(ActualImageBytes); + Attempt attempt = await Image.TryDetectFormatAsync(new AsyncStreamWrapper(stream, () => false)); + Assert.Equal(ExpectedGlobalFormat, attempt.Value); } [Fact] @@ -135,8 +154,8 @@ public partial class ImageTests Configuration = this.LocalConfiguration }; - IImageFormat type = await Image.DetectFormatAsync(options, new AsyncStreamWrapper(this.DataStream, () => false)); - Assert.Equal(this.LocalImageFormat, type); + Attempt attempt = await Image.TryDetectFormatAsync(options, new AsyncStreamWrapper(this.DataStream, () => false)); + Assert.Equal(this.LocalImageFormat, attempt.Value); } [Fact] @@ -147,8 +166,8 @@ public partial class ImageTests Configuration = new() }; - IImageFormat type = await Image.DetectFormatAsync(options, new AsyncStreamWrapper(this.DataStream, () => false)); - Assert.Null(type); + Attempt attempt = await Image.TryDetectFormatAsync(options, new AsyncStreamWrapper(this.DataStream, () => false)); + Assert.Null(attempt.Value); } } } diff --git a/tests/ImageSharp.Tests/Image/ImageTests.Identify.cs b/tests/ImageSharp.Tests/Image/ImageTests.Identify.cs index 83aeed5bdc..e9b61232ac 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.Identify.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.Identify.cs @@ -27,7 +27,7 @@ public partial class ImageTests { get { - Configuration.Default.ImageFormatsManager.TryFindFormatByFileExtension("bmp", out var format); + Configuration.Default.ImageFormatsManager.TryFindFormatByFileExtension("bmp", out IImageFormat format); return format!; } } @@ -35,30 +35,27 @@ public partial class ImageTests [Fact] public void FromBytes_GlobalConfiguration() { - ImageInfo info = Image.Identify(ActualImageBytes, out IImageFormat type); - + Image.TryIdentify(ActualImageBytes, out ImageInfo info); Assert.Equal(ExpectedImageSize, info.Size()); - Assert.Equal(ExpectedGlobalFormat, type); + Assert.Equal(ExpectedGlobalFormat, info.Metadata.DecodedImageFormat); } [Fact] public void FromBytes_CustomConfiguration() { DecoderOptions options = new() { Configuration = this.LocalConfiguration }; - - ImageInfo info = Image.Identify(options, this.ByteArray, out IImageFormat type); + Image.TryIdentify(options, this.ByteArray, out ImageInfo info); Assert.Equal(this.LocalImageInfo, info); - Assert.Equal(this.LocalImageFormat, type); } [Fact] public void FromFileSystemPath_GlobalConfiguration() { - ImageInfo info = Image.TryIdentify(ActualImagePath, out IImageFormat type); + Image.TryIdentify(ActualImagePath, out ImageInfo info); Assert.NotNull(info); - Assert.Equal(ExpectedGlobalFormat, type); + Assert.Equal(ExpectedGlobalFormat, info.Metadata.DecodedImageFormat); } [Fact] @@ -66,27 +63,26 @@ public partial class ImageTests { DecoderOptions options = new() { Configuration = this.LocalConfiguration }; - ImageInfo info = Image.Identify(options, this.MockFilePath, out IImageFormat type); + Image.TryIdentify(options, this.MockFilePath, out ImageInfo info); Assert.Equal(this.LocalImageInfo, info); - Assert.Equal(this.LocalImageFormat, type); } [Fact] public void FromStream_GlobalConfiguration() { - using var stream = new MemoryStream(ActualImageBytes); - ImageInfo info = Image.Identify(stream, out IImageFormat type); + using MemoryStream stream = new(ActualImageBytes); + Image.TryIdentify(stream, out ImageInfo info); Assert.NotNull(info); - Assert.Equal(ExpectedGlobalFormat, type); + Assert.Equal(ExpectedGlobalFormat, info.Metadata.DecodedImageFormat); } [Fact] public void FromStream_GlobalConfiguration_NoFormat() { - using var stream = new MemoryStream(ActualImageBytes); - ImageInfo info = Image.Identify(stream); + using MemoryStream stream = new(ActualImageBytes); + Image.TryIdentify(stream, out ImageInfo info); Assert.NotNull(info); } @@ -94,22 +90,22 @@ public partial class ImageTests [Fact] public void FromNonSeekableStream_GlobalConfiguration() { - using var stream = new MemoryStream(ActualImageBytes); - using var nonSeekableStream = new NonSeekableStream(stream); + using MemoryStream stream = new(ActualImageBytes); + using NonSeekableStream nonSeekableStream = new(stream); - ImageInfo info = Image.Identify(nonSeekableStream, out IImageFormat type); + Image.TryIdentify(nonSeekableStream, out ImageInfo info); Assert.NotNull(info); - Assert.Equal(ExpectedGlobalFormat, type); + Assert.Equal(ExpectedGlobalFormat, info.Metadata.DecodedImageFormat); } [Fact] public void FromNonSeekableStream_GlobalConfiguration_NoFormat() { - using var stream = new MemoryStream(ActualImageBytes); - using var nonSeekableStream = new NonSeekableStream(stream); + using MemoryStream stream = new(ActualImageBytes); + using NonSeekableStream nonSeekableStream = new(stream); - ImageInfo info = Image.Identify(nonSeekableStream); + Image.TryIdentify(nonSeekableStream, out ImageInfo info); Assert.NotNull(info); } @@ -119,10 +115,9 @@ public partial class ImageTests { DecoderOptions options = new() { Configuration = this.LocalConfiguration }; - ImageInfo info = Image.Identify(options, this.DataStream, out IImageFormat type); + Image.TryIdentify(options, this.DataStream, out ImageInfo info); Assert.Equal(this.LocalImageInfo, info); - Assert.Equal(this.LocalImageFormat, type); } [Fact] @@ -130,7 +125,7 @@ public partial class ImageTests { DecoderOptions options = new() { Configuration = this.LocalConfiguration }; - ImageInfo info = Image.TryIdentify(options, this.DataStream); + Image.TryIdentify(options, this.DataStream, out ImageInfo info); Assert.Equal(this.LocalImageInfo, info); } @@ -140,17 +135,15 @@ public partial class ImageTests { DecoderOptions options = new() { Configuration = new() }; - ImageInfo info = Image.Identify(options, this.DataStream, out IImageFormat type); - + Assert.False(Image.TryIdentify(options, this.DataStream, out ImageInfo info)); Assert.Null(info); - Assert.Null(type); } [Fact] public void FromStream_ZeroLength_ReturnsNull() { // https://github.com/SixLabors/ImageSharp/issues/1903 - using var zipFile = new ZipArchive(new MemoryStream( + using ZipArchive zipFile = new(new MemoryStream( new byte[] { 0x50, 0x4B, 0x03, 0x04, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0xAF, 0x94, 0x53, 0x00, 0x00, @@ -165,61 +158,67 @@ public partial class ImageTests 0x00, 0x00, 0x00, 0x00 })); using Stream stream = zipFile.Entries[0].Open(); - ImageInfo info = Image.Identify(stream); + + Assert.False(Image.TryIdentify(stream, out ImageInfo info)); Assert.Null(info); } [Fact] public async Task FromStreamAsync_GlobalConfiguration_NoFormat() { - using var stream = new MemoryStream(ActualImageBytes); - var asyncStream = new AsyncStreamWrapper(stream, () => false); - ImageInfo info = await Image.IdentifyAsync(asyncStream); + using MemoryStream stream = new(ActualImageBytes); + AsyncStreamWrapper asyncStream = new(stream, () => false); - Assert.NotNull(info); + Attempt attempt = await Image.TryIdentifyAsync(asyncStream); + + Assert.True(attempt.Success); + Assert.NotNull(attempt.Value); } [Fact] public async Task FromStreamAsync_GlobalConfiguration() { - using var stream = new MemoryStream(ActualImageBytes); - var asyncStream = new AsyncStreamWrapper(stream, () => false); - (ImageInfo ImageInfo, IImageFormat Format) res = await Image.TryIdentifyAsync(asyncStream); + using MemoryStream stream = new(ActualImageBytes); + AsyncStreamWrapper asyncStream = new(stream, () => false); + Attempt attempt = await Image.TryIdentifyAsync(asyncStream); - Assert.Equal(ExpectedImageSize, res.ImageInfo.Size()); - Assert.Equal(ExpectedGlobalFormat, res.Format); + Assert.True(attempt.Success); + Assert.Equal(ExpectedImageSize, attempt.Value.Size()); + Assert.Equal(ExpectedGlobalFormat, attempt.Value.Metadata.DecodedImageFormat); } [Fact] public async Task FromNonSeekableStreamAsync_GlobalConfiguration_NoFormat() { - using var stream = new MemoryStream(ActualImageBytes); - using var nonSeekableStream = new NonSeekableStream(stream); + using MemoryStream stream = new(ActualImageBytes); + using NonSeekableStream nonSeekableStream = new(stream); - var asyncStream = new AsyncStreamWrapper(nonSeekableStream, () => false); - ImageInfo info = await Image.IdentifyAsync(asyncStream); + AsyncStreamWrapper asyncStream = new(nonSeekableStream, () => false); + Attempt attempt = await Image.TryIdentifyAsync(asyncStream); - Assert.NotNull(info); + Assert.True(attempt.Success); + Assert.NotNull(attempt.Value); } [Fact] public async Task FromNonSeekableStreamAsync_GlobalConfiguration() { - using var stream = new MemoryStream(ActualImageBytes); - using var nonSeekableStream = new NonSeekableStream(stream); + using MemoryStream stream = new(ActualImageBytes); + using NonSeekableStream nonSeekableStream = new(stream); - var asyncStream = new AsyncStreamWrapper(nonSeekableStream, () => false); - (ImageInfo ImageInfo, IImageFormat Format) res = await Image.TryIdentifyAsync(asyncStream); + AsyncStreamWrapper asyncStream = new(nonSeekableStream, () => false); + Attempt attempt = await Image.TryIdentifyAsync(asyncStream); - Assert.Equal(ExpectedImageSize, res.ImageInfo.Size()); - Assert.Equal(ExpectedGlobalFormat, res.Format); + Assert.True(attempt.Success); + Assert.Equal(ExpectedImageSize, attempt.Value.Size()); + Assert.Equal(ExpectedGlobalFormat, attempt.Value.Metadata.DecodedImageFormat); } [Fact] public async Task FromStreamAsync_ZeroLength_ReturnsNull() { // https://github.com/SixLabors/ImageSharp/issues/1903 - using var zipFile = new ZipArchive(new MemoryStream( + using ZipArchive zipFile = new(new MemoryStream( new byte[] { 0x50, 0x4B, 0x03, 0x04, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0xAF, 0x94, 0x53, 0x00, 0x00, @@ -234,8 +233,11 @@ public partial class ImageTests 0x00, 0x00, 0x00, 0x00 })); using Stream stream = zipFile.Entries[0].Open(); - ImageInfo info = await Image.IdentifyAsync(stream); - Assert.Null(info); + + Attempt attempt = await Image.TryIdentifyAsync(stream); + + Assert.False(attempt.Success); + Assert.Null(attempt.Value); } [Fact] @@ -243,8 +245,10 @@ public partial class ImageTests { DecoderOptions options = new() { Configuration = this.LocalConfiguration }; - ImageInfo info = await Image.IdentifyAsync(options, this.MockFilePath); - Assert.Equal(this.LocalImageInfo, info); + Attempt attempt = await Image.TryIdentifyAsync(options, this.MockFilePath); + + Assert.True(attempt.Success); + Assert.Equal(this.LocalImageInfo, attempt.Value); } [Fact] @@ -252,27 +256,28 @@ public partial class ImageTests { DecoderOptions options = new() { Configuration = this.LocalConfiguration }; - (ImageInfo ImageInfo, IImageFormat Format) info = - await Image.TryIdentifyAsync(options, this.MockFilePath); - Assert.NotNull(info.ImageInfo); - Assert.Equal(this.LocalImageFormat, info.Format); + Attempt attempt = await Image.TryIdentifyAsync(options, this.MockFilePath); + + Assert.True(attempt.Success); + Assert.NotNull(attempt.Value); } [Fact] public async Task IdentifyWithFormatAsync_FromPath_GlobalConfiguration() { - (ImageInfo ImageInfo, IImageFormat Format) res = await Image.TryIdentifyAsync(ActualImagePath); + Attempt attempt = await Image.TryIdentifyAsync(ActualImagePath); - Assert.Equal(ExpectedImageSize, res.ImageInfo.Size()); - Assert.Equal(ExpectedGlobalFormat, res.Format); + Assert.Equal(ExpectedImageSize, attempt.Value.Size()); + Assert.Equal(ExpectedGlobalFormat, attempt.Value.Metadata.DecodedImageFormat); } [Fact] public async Task FromPathAsync_GlobalConfiguration() { - ImageInfo info = await Image.IdentifyAsync(ActualImagePath); + Attempt attempt = await Image.TryIdentifyAsync(ActualImagePath); - Assert.Equal(ExpectedImageSize, info.Size()); + Assert.True(attempt.Success); + Assert.Equal(ExpectedImageSize, attempt.Value.Size()); } [Fact] @@ -280,12 +285,11 @@ public partial class ImageTests { DecoderOptions options = new() { Configuration = this.LocalConfiguration }; - var asyncStream = new AsyncStreamWrapper(this.DataStream, () => false); - (ImageInfo ImageInfo, IImageFormat Format) - info = await Image.TryIdentifyAsync(options, asyncStream); + AsyncStreamWrapper asyncStream = new(this.DataStream, () => false); + Attempt attempt = await Image.TryIdentifyAsync(options, asyncStream); - Assert.Equal(this.LocalImageInfo, info.ImageInfo); - Assert.Equal(this.LocalImageFormat, info.Format); + Assert.True(attempt.Success); + Assert.Equal(this.LocalImageInfo, attempt.Value); } [Fact] @@ -293,11 +297,11 @@ public partial class ImageTests { DecoderOptions options = new() { Configuration = new() }; - var asyncStream = new AsyncStreamWrapper(this.DataStream, () => false); - (ImageInfo ImageInfo, IImageFormat Format) - info = await Image.TryIdentifyAsync(options, asyncStream); + AsyncStreamWrapper asyncStream = new(this.DataStream, () => false); + Attempt attempt = await Image.TryIdentifyAsync(options, asyncStream); - Assert.Null(info.ImageInfo); + Assert.False(attempt.Success); + Assert.Null(attempt.Value); } } } diff --git a/tests/ImageSharp.Tests/Image/ImageTests.ImageLoadTestBase.cs b/tests/ImageSharp.Tests/Image/ImageTests.ImageLoadTestBase.cs index 235ea2d92c..4d3e4128fa 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.ImageLoadTestBase.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.ImageLoadTestBase.cs @@ -51,18 +51,22 @@ public partial class ImageTests protected byte[] ByteArray => ((MemoryStream)this.DataStream).ToArray(); - protected ImageInfo LocalImageInfo => new( - this.localImageInfoMock.Object.PixelType, - this.localImageInfoMock.Object.Width, - this.localImageInfoMock.Object.Height, - this.localImageInfoMock.Object.Metadata); + protected ImageInfo LocalImageInfo { get; } protected ImageLoadTestBase() { + // TODO: Remove all this mocking. It's too complicated and we can now use fakes. this.localStreamReturnImageRgba32 = new Image(1, 1); this.localStreamReturnImageAgnostic = new Image(1, 1); this.localImageInfoMock = new Mock(); + + this.LocalImageInfo = new( + this.localImageInfoMock.Object.PixelType, + this.localImageInfoMock.Object.Width, + this.localImageInfoMock.Object.Height, + this.localImageInfoMock.Object.Metadata); + this.localImageFormatMock = new Mock(); this.localDecoder = new Mock(); diff --git a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs index b62f3ebd80..3239c57b1a 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs @@ -294,7 +294,6 @@ public partial class ImageTests } } - [Fact] public unsafe void WrapMemory_Throws_OnTooLessWrongSize() { @@ -307,7 +306,7 @@ public partial class ImageTests { try { - using (var image = Image.WrapMemory(cfg, ptr, 24, 5, 5, metaData)); + using var image = Image.WrapMemory(cfg, ptr, 24, 5, 5, metaData); } catch (Exception e) { diff --git a/tests/ImageSharp.Tests/Image/MockImageFormatDetector.cs b/tests/ImageSharp.Tests/Image/MockImageFormatDetector.cs index 8564eaa5bb..b372adaaf9 100644 --- a/tests/ImageSharp.Tests/Image/MockImageFormatDetector.cs +++ b/tests/ImageSharp.Tests/Image/MockImageFormatDetector.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Diagnostics.CodeAnalysis; @@ -11,12 +11,10 @@ namespace SixLabors.ImageSharp.Tests; /// public class MockImageFormatDetector : IImageFormatDetector { - private IImageFormat localImageFormatMock; + private readonly IImageFormat localImageFormatMock; public MockImageFormatDetector(IImageFormat imageFormat) - { - this.localImageFormatMock = imageFormat; - } + => this.localImageFormatMock = imageFormat; public int HeaderSize => 1;