diff --git a/src/ImageSharp/Image.FromBytes.cs b/src/ImageSharp/Image.FromBytes.cs index 922448c826..7a2e9d736e 100644 --- a/src/ImageSharp/Image.FromBytes.cs +++ b/src/ImageSharp/Image.FromBytes.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Diagnostics.CodeAnalysis; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; @@ -15,18 +16,20 @@ public abstract partial class Image /// By reading the header on the provided byte span this calculates the images format. /// /// The byte span containing encoded image data to read the header from. - /// The format or null if none found. - public static IImageFormat? DetectFormat(ReadOnlySpan data) - => DetectFormat(DecoderOptions.Default, data); + /// The format or null if none found. + /// returns true when format was detected otherwise false. + public static bool TryDetectFormat(ReadOnlySpan data, [NotNullWhen(true)] out IImageFormat? format) + => TryDetectFormat(DecoderOptions.Default, data, out format); /// /// By reading the header on the provided byte span this calculates the images format. /// /// The general decoder options. /// The byte span containing encoded image data to read the header from. + /// The mime type or null if none found. /// The options are null. - /// The mime type or null if none found. - public static IImageFormat? DetectFormat(DecoderOptions options, ReadOnlySpan data) + /// returns true when format was detected otherwise false. + public static bool TryDetectFormat(DecoderOptions options, ReadOnlySpan data, [NotNullWhen(true)] out IImageFormat? format) { Guard.NotNull(options, nameof(options.Configuration)); @@ -34,18 +37,20 @@ public abstract partial class Image int maxHeaderSize = configuration.MaxHeaderSize; if (maxHeaderSize <= 0) { - return null; + format = null; + return false; } foreach (IImageFormatDetector detector in configuration.ImageFormatsManager.FormatDetectors) { - if (detector.TryDetectFormat(data, out IImageFormat? f)) + if (detector.TryDetectFormat(data, out format)) { - return f; + return true; } } - return default; + format = default; + return false; } /// diff --git a/src/ImageSharp/Image.FromFile.cs b/src/ImageSharp/Image.FromFile.cs index 199d450b89..cd27e2882d 100644 --- a/src/ImageSharp/Image.FromFile.cs +++ b/src/ImageSharp/Image.FromFile.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Diagnostics.CodeAnalysis; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; @@ -15,23 +16,25 @@ public abstract partial class Image /// By reading the header on the provided file this calculates the images mime type. /// /// The image file to open and to read the header from. - /// The mime type or null if none found. - public static IImageFormat DetectFormat(string filePath) - => DetectFormat(DecoderOptions.Default, filePath); + /// The mime type or null if none found. + /// returns true when format was detected otherwise false. + 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. /// /// 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. - /// The mime type or null if none found. - public static IImageFormat DetectFormat(DecoderOptions options, string filePath) + /// returns true when format was detected otherwise false. + public static bool TryDetectFormat(DecoderOptions options, string filePath, [NotNullWhen(true)] out IImageFormat? format) { Guard.NotNull(options, nameof(options)); using Stream file = options.Configuration.FileSystem.OpenRead(filePath); - return DetectFormat(options, file); + return TryDetectFormat(options, file, out format); } /// diff --git a/src/ImageSharp/Image.FromStream.cs b/src/ImageSharp/Image.FromStream.cs index 33653434d5..63b9b5c1b9 100644 --- a/src/ImageSharp/Image.FromStream.cs +++ b/src/ImageSharp/Image.FromStream.cs @@ -19,23 +19,28 @@ public abstract partial class Image /// By reading the header on the provided stream this calculates the images format type. /// /// The image stream to read the header from. + /// The format type or null if none found. /// The stream is null. /// The stream is not readable. - /// The format type or null if none found. - public static IImageFormat DetectFormat(Stream stream) - => DetectFormat(DecoderOptions.Default, stream); + /// 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. /// /// The general decoder options. /// The image stream to read the header from. + /// The format type or null if none found. /// The options are null. /// The stream is null. /// The stream is not readable. - /// The format type or null if none found. - public static IImageFormat DetectFormat(DecoderOptions options, Stream stream) - => WithSeekableStream(options, stream, s => InternalDetectFormat(options.Configuration, s)); + /// 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; + } /// /// By reading the header on the provided stream this calculates the images format type. diff --git a/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs b/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs index d276f7eb6d..bfaa2166a3 100644 --- a/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs +++ b/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs @@ -122,7 +122,13 @@ public class ImageFormatManagerTests byte[] invalidImage = { 1, 2, 3 }; - Assert.Equal(Image.DetectFormat(jpegImage), JpegFormat.Instance); - Assert.True(Image.DetectFormat(invalidImage) is null); + bool resultValidImage = Image.TryDetectFormat(jpegImage, out IImageFormat format); + + bool resultInvalidImage = Image.TryDetectFormat(invalidImage, out IImageFormat formatInvalid); + + Assert.True(resultValidImage); + Assert.Equal(format, JpegFormat.Instance); + Assert.False(resultInvalidImage); + Assert.True(formatInvalid is null); } } diff --git a/tests/ImageSharp.Tests/Image/ImageTests.DetectFormat.cs b/tests/ImageSharp.Tests/Image/ImageTests.DetectFormat.cs index 55a9d6f3ee..86ceed73bb 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.DetectFormat.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.DetectFormat.cs @@ -34,8 +34,9 @@ public partial class ImageTests [Fact] public void FromBytes_GlobalConfiguration() { - IImageFormat type = Image.DetectFormat(this.ActualImageSpan); + bool result = Image.TryDetectFormat(this.ActualImageSpan, out IImageFormat type); + Assert.True(result); Assert.Equal(ExpectedGlobalFormat, type); } @@ -47,15 +48,18 @@ public partial class ImageTests Configuration = this.LocalConfiguration }; - IImageFormat type = Image.DetectFormat(options, this.ByteArray); + bool result = Image.TryDetectFormat(options, this.ByteArray, out IImageFormat type); + Assert.True(result); Assert.Equal(this.LocalImageFormat, type); } [Fact] public void FromFileSystemPath_GlobalConfiguration() { - IImageFormat type = Image.DetectFormat(ActualImagePath); + bool result = Image.TryDetectFormat(ActualImagePath, out IImageFormat type); + + Assert.True(result); Assert.Equal(ExpectedGlobalFormat, type); } @@ -67,7 +71,9 @@ public partial class ImageTests Configuration = this.LocalConfiguration }; - IImageFormat type = Image.DetectFormat(options, this.MockFilePath); + bool result = Image.TryDetectFormat(options, this.MockFilePath, out IImageFormat type); + + Assert.True(result); Assert.Equal(this.LocalImageFormat, type); } @@ -76,7 +82,9 @@ public partial class ImageTests { using (var stream = new MemoryStream(this.ActualImageBytes)) { - IImageFormat type = Image.DetectFormat(stream); + bool result = Image.TryDetectFormat(stream, out IImageFormat type); + + Assert.True(result); Assert.Equal(ExpectedGlobalFormat, type); } } @@ -89,7 +97,9 @@ public partial class ImageTests Configuration = this.LocalConfiguration }; - IImageFormat type = Image.DetectFormat(options, this.DataStream); + bool result = Image.TryDetectFormat(options, this.DataStream, out IImageFormat type); + + Assert.True(result); Assert.Equal(this.LocalImageFormat, type); } @@ -101,7 +111,9 @@ public partial class ImageTests Configuration = new() }; - IImageFormat type = Image.DetectFormat(options, this.DataStream); + bool result = Image.TryDetectFormat(options, this.DataStream, out IImageFormat type); + + Assert.False(result); Assert.Null(type); }