diff --git a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs index da0c7f60cf..4fa07931ed 100644 --- a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs +++ b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs @@ -27,8 +27,7 @@ public static class AdvancedImageExtensions Guard.NotNull(filePath, nameof(filePath)); string ext = Path.GetExtension(filePath); - IImageFormat? format = source.GetConfiguration().ImageFormatsManager.FindFormatByFileExtension(ext); - if (format is null) + if (!source.GetConfiguration().ImageFormatsManager.TryFindFormatByFileExtension(ext, out IImageFormat? format)) { StringBuilder sb = new(); sb.AppendLine(CultureInfo.InvariantCulture, $"No encoder was found for extension '{ext}'. Registered encoders include:"); diff --git a/src/ImageSharp/Formats/ImageFormatManager.cs b/src/ImageSharp/Formats/ImageFormatManager.cs index 85424e7b8c..d058e80c9b 100644 --- a/src/ImageSharp/Formats/ImageFormatManager.cs +++ b/src/ImageSharp/Formats/ImageFormatManager.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Collections.Concurrent; +using System.Diagnostics.CodeAnalysis; namespace SixLabors.ImageSharp.Formats; @@ -91,8 +92,9 @@ public class ImageFormatManager /// For the specified file extensions type find the e . /// /// The extension to discover - /// The if found otherwise null - public IImageFormat? FindFormatByFileExtension(string extension) + /// The if found otherwise null + /// False if no format was found + public bool TryFindFormatByFileExtension(string extension, [NotNullWhen(true)] out IImageFormat? format) { Guard.NotNullOrWhiteSpace(extension, nameof(extension)); @@ -101,7 +103,10 @@ public class ImageFormatManager extension = extension[1..]; } - return this.imageFormats.FirstOrDefault(x => x.FileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase)); + format = this.imageFormats.FirstOrDefault(x => + x.FileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase)); + + return format != null; } /// diff --git a/tests/ImageSharp.Tests/Image/ImageTests.DetectFormat.cs b/tests/ImageSharp.Tests/Image/ImageTests.DetectFormat.cs index 271a4a08e8..55a9d6f3ee 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.DetectFormat.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.DetectFormat.cs @@ -22,8 +22,14 @@ public partial class ImageTests private IImageFormat LocalImageFormat => this.localImageFormatMock.Object; - private static readonly IImageFormat ExpectedGlobalFormat = - Configuration.Default.ImageFormatsManager.FindFormatByFileExtension("bmp"); + private static IImageFormat ExpectedGlobalFormat + { + get + { + Configuration.Default.ImageFormatsManager.TryFindFormatByFileExtension("bmp", out IImageFormat format); + return format!; + } + } [Fact] public void FromBytes_GlobalConfiguration() diff --git a/tests/ImageSharp.Tests/Image/ImageTests.Identify.cs b/tests/ImageSharp.Tests/Image/ImageTests.Identify.cs index bec58f56bd..49c9562531 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.Identify.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.Identify.cs @@ -25,8 +25,15 @@ public partial class ImageTests private IImageFormat LocalImageFormat => this.localImageFormatMock.Object; - private static readonly IImageFormat ExpectedGlobalFormat = - Configuration.Default.ImageFormatsManager.FindFormatByFileExtension("bmp"); + private static IImageFormat ExpectedGlobalFormat + { + get + { + Configuration.Default.ImageFormatsManager.TryFindFormatByFileExtension("bmp", out var format); + return format!; + } + } + [Fact] public void FromBytes_GlobalConfiguration() @@ -40,10 +47,7 @@ public partial class ImageTests [Fact] public void FromBytes_CustomConfiguration() { - DecoderOptions options = new() - { - Configuration = this.LocalConfiguration - }; + DecoderOptions options = new() { Configuration = this.LocalConfiguration }; IImageInfo info = Image.Identify(options, this.ByteArray, out IImageFormat type); @@ -63,10 +67,7 @@ public partial class ImageTests [Fact] public void FromFileSystemPath_CustomConfiguration() { - DecoderOptions options = new() - { - Configuration = this.LocalConfiguration - }; + DecoderOptions options = new() { Configuration = this.LocalConfiguration }; IImageInfo info = Image.Identify(options, this.MockFilePath, out IImageFormat type); @@ -119,10 +120,7 @@ public partial class ImageTests [Fact] public void FromStream_CustomConfiguration() { - DecoderOptions options = new() - { - Configuration = this.LocalConfiguration - }; + DecoderOptions options = new() { Configuration = this.LocalConfiguration }; IImageInfo info = Image.Identify(options, this.DataStream, out IImageFormat type); @@ -133,10 +131,7 @@ public partial class ImageTests [Fact] public void FromStream_CustomConfiguration_NoFormat() { - DecoderOptions options = new() - { - Configuration = this.LocalConfiguration - }; + DecoderOptions options = new() { Configuration = this.LocalConfiguration }; IImageInfo info = Image.Identify(options, this.DataStream); @@ -146,10 +141,7 @@ public partial class ImageTests [Fact] public void WhenNoMatchingFormatFound_ReturnsNull() { - DecoderOptions options = new() - { - Configuration = new() - }; + DecoderOptions options = new() { Configuration = new() }; IImageInfo info = Image.Identify(options, this.DataStream, out IImageFormat type); @@ -164,18 +156,15 @@ public partial class ImageTests using var zipFile = new ZipArchive(new MemoryStream( new byte[] { - 0x50, 0x4B, 0x03, 0x04, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0xAF, - 0x94, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x6D, 0x79, 0x73, 0x74, 0x65, 0x72, - 0x79, 0x50, 0x4B, 0x01, 0x02, 0x3F, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x77, 0xAF, 0x94, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6D, - 0x79, 0x73, 0x74, 0x65, 0x72, 0x79, 0x0A, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x46, 0x82, 0xFF, 0x91, 0x27, 0xF6, - 0xD7, 0x01, 0x55, 0xA1, 0xF9, 0x91, 0x27, 0xF6, 0xD7, 0x01, 0x55, 0xA1, - 0xF9, 0x91, 0x27, 0xF6, 0xD7, 0x01, 0x50, 0x4B, 0x05, 0x06, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x59, 0x00, 0x00, 0x00, 0x25, 0x00, + 0x50, 0x4B, 0x03, 0x04, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0xAF, 0x94, 0x53, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x6D, 0x79, + 0x73, 0x74, 0x65, 0x72, 0x79, 0x50, 0x4B, 0x01, 0x02, 0x3F, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x77, 0xAF, 0x94, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x6D, 0x79, 0x73, 0x74, 0x65, 0x72, 0x79, 0x0A, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x46, 0x82, 0xFF, 0x91, 0x27, 0xF6, 0xD7, 0x01, 0x55, 0xA1, + 0xF9, 0x91, 0x27, 0xF6, 0xD7, 0x01, 0x55, 0xA1, 0xF9, 0x91, 0x27, 0xF6, 0xD7, 0x01, 0x50, 0x4B, + 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x59, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00 })); using Stream stream = zipFile.Entries[0].Open(); @@ -236,18 +225,15 @@ public partial class ImageTests using var zipFile = new ZipArchive(new MemoryStream( new byte[] { - 0x50, 0x4B, 0x03, 0x04, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0xAF, - 0x94, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x6D, 0x79, 0x73, 0x74, 0x65, 0x72, - 0x79, 0x50, 0x4B, 0x01, 0x02, 0x3F, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x77, 0xAF, 0x94, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6D, - 0x79, 0x73, 0x74, 0x65, 0x72, 0x79, 0x0A, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x46, 0x82, 0xFF, 0x91, 0x27, 0xF6, - 0xD7, 0x01, 0x55, 0xA1, 0xF9, 0x91, 0x27, 0xF6, 0xD7, 0x01, 0x55, 0xA1, - 0xF9, 0x91, 0x27, 0xF6, 0xD7, 0x01, 0x50, 0x4B, 0x05, 0x06, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x59, 0x00, 0x00, 0x00, 0x25, 0x00, + 0x50, 0x4B, 0x03, 0x04, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0xAF, 0x94, 0x53, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x6D, 0x79, + 0x73, 0x74, 0x65, 0x72, 0x79, 0x50, 0x4B, 0x01, 0x02, 0x3F, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x77, 0xAF, 0x94, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x6D, 0x79, 0x73, 0x74, 0x65, 0x72, 0x79, 0x0A, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x46, 0x82, 0xFF, 0x91, 0x27, 0xF6, 0xD7, 0x01, 0x55, 0xA1, + 0xF9, 0x91, 0x27, 0xF6, 0xD7, 0x01, 0x55, 0xA1, 0xF9, 0x91, 0x27, 0xF6, 0xD7, 0x01, 0x50, 0x4B, + 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x59, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00 })); using Stream stream = zipFile.Entries[0].Open(); @@ -258,10 +244,7 @@ public partial class ImageTests [Fact] public async Task FromPathAsync_CustomConfiguration() { - DecoderOptions options = new() - { - Configuration = this.LocalConfiguration - }; + DecoderOptions options = new() { Configuration = this.LocalConfiguration }; IImageInfo info = await Image.IdentifyAsync(options, this.MockFilePath); Assert.Equal(this.LocalImageInfo, info); @@ -270,12 +253,10 @@ public partial class ImageTests [Fact] public async Task IdentifyWithFormatAsync_FromPath_CustomConfiguration() { - DecoderOptions options = new() - { - Configuration = this.LocalConfiguration - }; + DecoderOptions options = new() { Configuration = this.LocalConfiguration }; - (IImageInfo ImageInfo, IImageFormat Format) info = await Image.IdentifyWithFormatAsync(options, this.MockFilePath); + (IImageInfo ImageInfo, IImageFormat Format) info = + await Image.IdentifyWithFormatAsync(options, this.MockFilePath); Assert.NotNull(info.ImageInfo); Assert.Equal(this.LocalImageFormat, info.Format); } @@ -300,13 +281,11 @@ public partial class ImageTests [Fact] public async Task FromStreamAsync_CustomConfiguration() { - DecoderOptions options = new() - { - Configuration = this.LocalConfiguration - }; + DecoderOptions options = new() { Configuration = this.LocalConfiguration }; var asyncStream = new AsyncStreamWrapper(this.DataStream, () => false); - (IImageInfo ImageInfo, IImageFormat Format) info = await Image.IdentifyWithFormatAsync(options, asyncStream); + (IImageInfo ImageInfo, IImageFormat Format) + info = await Image.IdentifyWithFormatAsync(options, asyncStream); Assert.Equal(this.LocalImageInfo, info.ImageInfo); Assert.Equal(this.LocalImageFormat, info.Format); @@ -315,13 +294,11 @@ public partial class ImageTests [Fact] public async Task WhenNoMatchingFormatFoundAsync_ReturnsNull() { - DecoderOptions options = new() - { - Configuration = new() - }; + DecoderOptions options = new() { Configuration = new() }; var asyncStream = new AsyncStreamWrapper(this.DataStream, () => false); - (IImageInfo ImageInfo, IImageFormat Format) info = await Image.IdentifyWithFormatAsync(options, asyncStream); + (IImageInfo ImageInfo, IImageFormat Format) + info = await Image.IdentifyWithFormatAsync(options, asyncStream); Assert.Null(info.ImageInfo); } diff --git a/tests/ImageSharp.Tests/Image/ImageTests.SaveAsync.cs b/tests/ImageSharp.Tests/Image/ImageTests.SaveAsync.cs index 1ceadb964d..3627ba2a65 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.SaveAsync.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.SaveAsync.cs @@ -77,8 +77,8 @@ public partial class ImageTests using (var image = new Image(5, 5)) { string ext = Path.GetExtension(filename); - IImageFormat format = image.GetConfiguration().ImageFormatsManager.FindFormatByFileExtension(ext); - Assert.Equal(mimeType, format.DefaultMimeType); + image.GetConfiguration().ImageFormatsManager.TryFindFormatByFileExtension(ext, out IImageFormat format); + Assert.Equal(mimeType, format!.DefaultMimeType); using (var stream = new MemoryStream()) { diff --git a/tests/ImageSharp.Tests/Image/LargeImageIntegrationTests.cs b/tests/ImageSharp.Tests/Image/LargeImageIntegrationTests.cs index b65719228c..7309185c79 100644 --- a/tests/ImageSharp.Tests/Image/LargeImageIntegrationTests.cs +++ b/tests/ImageSharp.Tests/Image/LargeImageIntegrationTests.cs @@ -55,8 +55,8 @@ public class LargeImageIntegrationTests Configuration configuration = Configuration.Default.Clone(); configuration.PreferContiguousImageBuffers = true; - IImageEncoder encoder = configuration.ImageFormatsManager.FindEncoder( - configuration.ImageFormatsManager.FindFormatByFileExtension(formatInner)); + configuration.ImageFormatsManager.TryFindFormatByFileExtension(formatInner, out IImageFormat format); + IImageEncoder encoder = configuration.ImageFormatsManager.FindEncoder(format!); string dir = TestEnvironment.CreateOutputDirectory(".Temp"); string path = Path.Combine(dir, $"{Guid.NewGuid()}.{formatInner}"); using (Image temp = new(2048, 2048)) diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs index 68c1664a8f..f44ae5b23f 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.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.Formats.Bmp; using SixLabors.ImageSharp.Formats.Gif; @@ -36,7 +37,9 @@ public static partial class TestEnvironment { string extension = Path.GetExtension(filePath); - return Configuration.ImageFormatsManager.FindFormatByFileExtension(extension); + Configuration.ImageFormatsManager.TryFindFormatByFileExtension(extension, out IImageFormat format); + + return format; } private static void ConfigureCodecs(