From e2872c1064811e75e772cb818287669505b050f5 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Sun, 1 Jan 2023 11:40:28 +0100 Subject: [PATCH 01/10] Remove nullable disable * FormatDetecot * ImageFormatManager * DecoderUtilities (Not needed) --- src/ImageSharp/Advanced/AdvancedImageExtensions.cs | 4 ++-- .../Formats/Bmp/BmpImageFormatDetector.cs | 3 +-- .../Formats/Gif/GifImageFormatDetector.cs | 3 +-- src/ImageSharp/Formats/IImageFormatDetector.cs | 2 +- src/ImageSharp/Formats/ImageDecoderUtilities.cs | 1 - src/ImageSharp/Formats/ImageFormatManager.cs | 13 ++++++------- .../Formats/Jpeg/JpegImageFormatDetector.cs | 3 +-- .../Formats/Pbm/PbmImageFormatDetector.cs | 3 +-- .../Formats/Png/PngImageFormatDetector.cs | 3 +-- .../Formats/Tga/TgaImageFormatDetector.cs | 3 +-- .../Formats/Tiff/TiffImageFormatDetector.cs | 3 +-- .../Formats/Webp/WebpImageFormatDetector.cs | 3 +-- src/ImageSharp/Image.FromBytes.cs | 7 +++---- src/ImageSharp/Image{TPixel}.cs | 4 +--- 14 files changed, 21 insertions(+), 34 deletions(-) diff --git a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs index 10267c8ef7..da0c7f60cf 100644 --- a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs +++ b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs @@ -27,7 +27,7 @@ public static class AdvancedImageExtensions Guard.NotNull(filePath, nameof(filePath)); string ext = Path.GetExtension(filePath); - IImageFormat format = source.GetConfiguration().ImageFormatsManager.FindFormatByFileExtension(ext); + IImageFormat? format = source.GetConfiguration().ImageFormatsManager.FindFormatByFileExtension(ext); if (format is null) { StringBuilder sb = new(); @@ -40,7 +40,7 @@ public static class AdvancedImageExtensions throw new NotSupportedException(sb.ToString()); } - IImageEncoder encoder = source.GetConfiguration().ImageFormatsManager.FindEncoder(format); + IImageEncoder? encoder = source.GetConfiguration().ImageFormatsManager.FindEncoder(format); if (encoder is null) { diff --git a/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs b/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs index 4957b7ba73..162c8ed399 100644 --- a/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs @@ -1,6 +1,5 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable using System.Buffers.Binary; @@ -15,7 +14,7 @@ public sealed class BmpImageFormatDetector : IImageFormatDetector public int HeaderSize => 2; /// - public IImageFormat DetectFormat(ReadOnlySpan header) + public IImageFormat? DetectFormat(ReadOnlySpan header) { return this.IsSupportedFileFormat(header) ? BmpFormat.Instance : null; } diff --git a/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs b/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs index c826765009..db3d429046 100644 --- a/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs @@ -1,6 +1,5 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable namespace SixLabors.ImageSharp.Formats.Gif; @@ -13,7 +12,7 @@ public sealed class GifImageFormatDetector : IImageFormatDetector public int HeaderSize => 6; /// - public IImageFormat DetectFormat(ReadOnlySpan header) + public IImageFormat? DetectFormat(ReadOnlySpan header) { return this.IsSupportedFileFormat(header) ? GifFormat.Instance : null; } diff --git a/src/ImageSharp/Formats/IImageFormatDetector.cs b/src/ImageSharp/Formats/IImageFormatDetector.cs index 17f565d2b2..e1bdc41f8f 100644 --- a/src/ImageSharp/Formats/IImageFormatDetector.cs +++ b/src/ImageSharp/Formats/IImageFormatDetector.cs @@ -19,5 +19,5 @@ public interface IImageFormatDetector /// /// The containing the file header. /// returns the mime type of detected otherwise returns null - IImageFormat DetectFormat(ReadOnlySpan header); + IImageFormat? DetectFormat(ReadOnlySpan header); } diff --git a/src/ImageSharp/Formats/ImageDecoderUtilities.cs b/src/ImageSharp/Formats/ImageDecoderUtilities.cs index 50635dbefb..2a5b91b094 100644 --- a/src/ImageSharp/Formats/ImageDecoderUtilities.cs +++ b/src/ImageSharp/Formats/ImageDecoderUtilities.cs @@ -1,6 +1,5 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.Memory; diff --git a/src/ImageSharp/Formats/ImageFormatManager.cs b/src/ImageSharp/Formats/ImageFormatManager.cs index dc09bb6a13..85424e7b8c 100644 --- a/src/ImageSharp/Formats/ImageFormatManager.cs +++ b/src/ImageSharp/Formats/ImageFormatManager.cs @@ -1,6 +1,5 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable using System.Collections.Concurrent; @@ -93,7 +92,7 @@ public class ImageFormatManager /// /// The extension to discover /// The if found otherwise null - public IImageFormat FindFormatByFileExtension(string extension) + public IImageFormat? FindFormatByFileExtension(string extension) { Guard.NotNullOrWhiteSpace(extension, nameof(extension)); @@ -110,7 +109,7 @@ public class ImageFormatManager /// /// The mime-type to discover /// The if found; otherwise null - public IImageFormat FindFormatByMimeType(string mimeType) + public IImageFormat? FindFormatByMimeType(string mimeType) => this.imageFormats.FirstOrDefault(x => x.MimeTypes.Contains(mimeType, StringComparer.OrdinalIgnoreCase)); /// @@ -160,11 +159,11 @@ public class ImageFormatManager /// /// The format to discover /// The if found otherwise null - public IImageDecoder FindDecoder(IImageFormat format) + public IImageDecoder? FindDecoder(IImageFormat format) { Guard.NotNull(format, nameof(format)); - return this.mimeTypeDecoders.TryGetValue(format, out IImageDecoder decoder) + return this.mimeTypeDecoders.TryGetValue(format, out IImageDecoder? decoder) ? decoder : null; } @@ -174,11 +173,11 @@ public class ImageFormatManager /// /// The format to discover /// The if found otherwise null - public IImageEncoder FindEncoder(IImageFormat format) + public IImageEncoder? FindEncoder(IImageFormat format) { Guard.NotNull(format, nameof(format)); - return this.mimeTypeEncoders.TryGetValue(format, out IImageEncoder encoder) + return this.mimeTypeEncoders.TryGetValue(format, out IImageEncoder? encoder) ? encoder : null; } diff --git a/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs b/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs index 54e1b28ee3..3bf7346ff3 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs @@ -1,6 +1,5 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable namespace SixLabors.ImageSharp.Formats.Jpeg; @@ -13,7 +12,7 @@ public sealed class JpegImageFormatDetector : IImageFormatDetector public int HeaderSize => 11; /// - public IImageFormat DetectFormat(ReadOnlySpan header) + public IImageFormat? DetectFormat(ReadOnlySpan header) => this.IsSupportedFileFormat(header) ? JpegFormat.Instance : null; private bool IsSupportedFileFormat(ReadOnlySpan header) diff --git a/src/ImageSharp/Formats/Pbm/PbmImageFormatDetector.cs b/src/ImageSharp/Formats/Pbm/PbmImageFormatDetector.cs index 01ad9c62be..021cff2670 100644 --- a/src/ImageSharp/Formats/Pbm/PbmImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Pbm/PbmImageFormatDetector.cs @@ -1,6 +1,5 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable namespace SixLabors.ImageSharp.Formats.Pbm; @@ -17,7 +16,7 @@ public sealed class PbmImageFormatDetector : IImageFormatDetector public int HeaderSize => 2; /// - public IImageFormat DetectFormat(ReadOnlySpan header) => IsSupportedFileFormat(header) ? PbmFormat.Instance : null; + public IImageFormat? DetectFormat(ReadOnlySpan header) => IsSupportedFileFormat(header) ? PbmFormat.Instance : null; private static bool IsSupportedFileFormat(ReadOnlySpan header) { diff --git a/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs b/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs index a389428070..2e20668248 100644 --- a/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs @@ -1,6 +1,5 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable using System.Buffers.Binary; @@ -15,7 +14,7 @@ public sealed class PngImageFormatDetector : IImageFormatDetector public int HeaderSize => 8; /// - public IImageFormat DetectFormat(ReadOnlySpan header) + public IImageFormat? DetectFormat(ReadOnlySpan header) { return this.IsSupportedFileFormat(header) ? PngFormat.Instance : null; } diff --git a/src/ImageSharp/Formats/Tga/TgaImageFormatDetector.cs b/src/ImageSharp/Formats/Tga/TgaImageFormatDetector.cs index 82246f3474..13d4e784c9 100644 --- a/src/ImageSharp/Formats/Tga/TgaImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Tga/TgaImageFormatDetector.cs @@ -1,6 +1,5 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable namespace SixLabors.ImageSharp.Formats.Tga; @@ -13,7 +12,7 @@ public sealed class TgaImageFormatDetector : IImageFormatDetector public int HeaderSize => 16; /// - public IImageFormat DetectFormat(ReadOnlySpan header) + public IImageFormat? DetectFormat(ReadOnlySpan header) { return this.IsSupportedFileFormat(header) ? TgaFormat.Instance : null; } diff --git a/src/ImageSharp/Formats/Tiff/TiffImageFormatDetector.cs b/src/ImageSharp/Formats/Tiff/TiffImageFormatDetector.cs index c48014024f..9af6a659e3 100644 --- a/src/ImageSharp/Formats/Tiff/TiffImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Tiff/TiffImageFormatDetector.cs @@ -1,6 +1,5 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable namespace SixLabors.ImageSharp.Formats.Tiff; @@ -13,7 +12,7 @@ public sealed class TiffImageFormatDetector : IImageFormatDetector public int HeaderSize => 8; /// - public IImageFormat DetectFormat(ReadOnlySpan header) + public IImageFormat? DetectFormat(ReadOnlySpan header) { if (this.IsSupportedFileFormat(header)) { diff --git a/src/ImageSharp/Formats/Webp/WebpImageFormatDetector.cs b/src/ImageSharp/Formats/Webp/WebpImageFormatDetector.cs index 9b52492aaa..3b30a2cfb5 100644 --- a/src/ImageSharp/Formats/Webp/WebpImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Webp/WebpImageFormatDetector.cs @@ -1,6 +1,5 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable namespace SixLabors.ImageSharp.Formats.Webp; @@ -13,7 +12,7 @@ public sealed class WebpImageFormatDetector : IImageFormatDetector public int HeaderSize => 12; /// - public IImageFormat DetectFormat(ReadOnlySpan header) + public IImageFormat? DetectFormat(ReadOnlySpan header) => this.IsSupportedFileFormat(header) ? WebpFormat.Instance : null; private bool IsSupportedFileFormat(ReadOnlySpan header) diff --git a/src/ImageSharp/Image.FromBytes.cs b/src/ImageSharp/Image.FromBytes.cs index 2ea2b9d432..0d36e397c1 100644 --- a/src/ImageSharp/Image.FromBytes.cs +++ b/src/ImageSharp/Image.FromBytes.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.PixelFormats; @@ -17,7 +16,7 @@ public abstract partial class Image /// /// 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) + public static IImageFormat? DetectFormat(ReadOnlySpan data) => DetectFormat(DecoderOptions.Default, data); /// @@ -27,7 +26,7 @@ public abstract partial class Image /// The byte span containing encoded image data to read the header from. /// The options are null. /// The mime type or null if none found. - public static IImageFormat DetectFormat(DecoderOptions options, ReadOnlySpan data) + public static IImageFormat? DetectFormat(DecoderOptions options, ReadOnlySpan data) { Guard.NotNull(options, nameof(options.Configuration)); @@ -40,7 +39,7 @@ public abstract partial class Image foreach (IImageFormatDetector detector in configuration.ImageFormatsManager.FormatDetectors) { - IImageFormat f = detector.DetectFormat(data); + IImageFormat? f = detector.DetectFormat(data); if (f != null) { diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index 01dd727fc0..31fd015096 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable -using System.Buffers; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Advanced; @@ -420,7 +418,7 @@ public sealed class Image : Image { Guard.NotNull(frames, nameof(frames)); - ImageFrame rootFrame = frames.FirstOrDefault(); + ImageFrame? rootFrame = frames.FirstOrDefault(); if (rootFrame == null) { From 8ba26b99356f6bf16a5ab78ed9cdee608339cfc0 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Sun, 1 Jan 2023 11:46:45 +0100 Subject: [PATCH 02/10] Remove nullable disable from CloningImageProcessor --- .../Processing/Processors/CloningImageProcessor{TPixel}.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/CloningImageProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/CloningImageProcessor{TPixel}.cs index 1cf8f35795..aa000a10e7 100644 --- a/src/ImageSharp/Processing/Processors/CloningImageProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/CloningImageProcessor{TPixel}.cs @@ -1,6 +1,5 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable using SixLabors.ImageSharp.PixelFormats; @@ -73,7 +72,7 @@ public abstract class CloningImageProcessor : ICloningImageProcessor clone = default; + Image? clone = default; try { clone = ((ICloningImageProcessor)this).CloneAndExecute(); From 9b91a9e5a32e8631723a45079792c6e8c09e9e67 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Sun, 1 Jan 2023 12:03:11 +0100 Subject: [PATCH 03/10] Remove nullable disable and fix Equals --- .../Processors/Convolution/ConvolutionProcessorHelpers.cs | 3 +-- .../Processors/Convolution/Kernels/EdgeDetector2DKernel.cs | 3 +-- .../Convolution/Kernels/EdgeDetectorCompassKernel.cs | 3 +-- .../Processors/Convolution/Kernels/EdgeDetectorKernel.cs | 3 +-- .../Convolution/Parameters/BokehBlurParameters.cs | 3 +-- .../Processing/Processors/Dithering/ErrorDither.cs | 7 +++---- .../Processing/Processors/Dithering/OrderedDither.cs | 7 +++---- .../Processors/Dithering/PaletteDitherProcessor{TPixel}.cs | 5 ++--- 8 files changed, 13 insertions(+), 21 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessorHelpers.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessorHelpers.cs index df18baf839..411dbe50cb 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessorHelpers.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessorHelpers.cs @@ -1,6 +1,5 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable namespace SixLabors.ImageSharp.Processing.Processors.Convolution; @@ -99,7 +98,7 @@ internal static class ConvolutionProcessorHelpers /// The resulting 1D row vector, if possible. /// The resulting 1D column vector, if possible. /// Whether or not was linearly separable. - public static bool TryGetLinearlySeparableComponents(this DenseMatrix matrix, out float[] row, out float[] column) + public static bool TryGetLinearlySeparableComponents(this DenseMatrix matrix, out float[]? row, out float[]? column) { int height = matrix.Rows; int width = matrix.Columns; diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernels/EdgeDetector2DKernel.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernels/EdgeDetector2DKernel.cs index f03555bbaa..d900b2746a 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Kernels/EdgeDetector2DKernel.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Kernels/EdgeDetector2DKernel.cs @@ -1,6 +1,5 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable namespace SixLabors.ImageSharp.Processing.Processors.Convolution; @@ -88,7 +87,7 @@ public readonly struct EdgeDetector2DKernel : IEquatable => !(left == right); /// - public override bool Equals(object obj) + public override bool Equals(object? obj) => obj is EdgeDetector2DKernel kernel && this.Equals(kernel); /// diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernels/EdgeDetectorCompassKernel.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernels/EdgeDetectorCompassKernel.cs index d476ed9231..0c456eb88e 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Kernels/EdgeDetectorCompassKernel.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Kernels/EdgeDetectorCompassKernel.cs @@ -1,6 +1,5 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable namespace SixLabors.ImageSharp.Processing.Processors.Convolution; @@ -135,7 +134,7 @@ public readonly struct EdgeDetectorCompassKernel : IEquatable !(left == right); /// - public override bool Equals(object obj) => obj is EdgeDetectorCompassKernel kernel && this.Equals(kernel); + public override bool Equals(object? obj) => obj is EdgeDetectorCompassKernel kernel && this.Equals(kernel); /// public bool Equals(EdgeDetectorCompassKernel other) => this.North.Equals(other.North) && this.NorthWest.Equals(other.NorthWest) && this.West.Equals(other.West) && this.SouthWest.Equals(other.SouthWest) && this.South.Equals(other.South) && this.SouthEast.Equals(other.SouthEast) && this.East.Equals(other.East) && this.NorthEast.Equals(other.NorthEast); diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernels/EdgeDetectorKernel.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernels/EdgeDetectorKernel.cs index 9022dd044a..42a0c1cfe8 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Kernels/EdgeDetectorKernel.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Kernels/EdgeDetectorKernel.cs @@ -1,6 +1,5 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable namespace SixLabors.ImageSharp.Processing.Processors.Convolution; @@ -64,7 +63,7 @@ public readonly struct EdgeDetectorKernel : IEquatable => !(left == right); /// - public override bool Equals(object obj) + public override bool Equals(object? obj) => obj is EdgeDetectorKernel kernel && this.Equals(kernel); /// diff --git a/src/ImageSharp/Processing/Processors/Convolution/Parameters/BokehBlurParameters.cs b/src/ImageSharp/Processing/Processors/Convolution/Parameters/BokehBlurParameters.cs index 15ff8560e1..cb92dce4a7 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Parameters/BokehBlurParameters.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Parameters/BokehBlurParameters.cs @@ -1,6 +1,5 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable namespace SixLabors.ImageSharp.Processing.Processors.Convolution.Parameters; @@ -37,7 +36,7 @@ internal readonly struct BokehBlurParameters : IEquatable } /// - public override bool Equals(object obj) => obj is BokehBlurParameters other && this.Equals(other); + public override bool Equals(object? obj) => obj is BokehBlurParameters other && this.Equals(other); /// public override int GetHashCode() diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs index 5706f2d992..3a869a0a28 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs @@ -1,6 +1,5 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable using System.Numerics; using System.Runtime.CompilerServices; @@ -212,7 +211,7 @@ public readonly partial struct ErrorDither : IDither, IEquatable, I } /// - public override bool Equals(object obj) + public override bool Equals(object? obj) => obj is ErrorDither dither && this.Equals(dither); /// @@ -220,8 +219,8 @@ public readonly partial struct ErrorDither : IDither, IEquatable, I => this.offset == other.offset && this.matrix.Equals(other.matrix); /// - public bool Equals(IDither other) - => this.Equals((object)other); + public bool Equals(IDither? other) + => this.Equals((object?)other); /// public override int GetHashCode() diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs index b96427934d..1a02e7a221 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs @@ -1,6 +1,5 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Memory; @@ -200,7 +199,7 @@ public readonly partial struct OrderedDither : IDither, IEquatable - public override bool Equals(object obj) + public override bool Equals(object? obj) => obj is OrderedDither dither && this.Equals(dither); /// @@ -209,8 +208,8 @@ public readonly partial struct OrderedDither : IDither, IEquatable this.thresholdMatrix.Equals(other.thresholdMatrix) && this.modulusX == other.modulusX && this.modulusY == other.modulusY; /// - public bool Equals(IDither other) - => this.Equals((object)other); + public bool Equals(IDither? other) + => this.Equals((object?)other); /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs index b95bbe3793..abf283e6c1 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs @@ -1,6 +1,5 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable using System.Buffers; using System.Diagnostics.CodeAnalysis; @@ -19,7 +18,7 @@ internal sealed class PaletteDitherProcessor : ImageProcessor { private readonly DitherProcessor ditherProcessor; private readonly IDither dither; - private IMemoryOwner paletteOwner; + private IMemoryOwner? paletteOwner; private bool isDisposed; /// @@ -62,7 +61,7 @@ internal sealed class PaletteDitherProcessor : ImageProcessor this.isDisposed = true; if (disposing) { - this.paletteOwner.Dispose(); + this.paletteOwner?.Dispose(); this.ditherProcessor.Dispose(); } From b8e20f5331668fd8312aee97784c25b4607d9002 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Sun, 1 Jan 2023 12:20:20 +0100 Subject: [PATCH 04/10] Remove nullable disable from ResizeHelper --- .../Processing/Processors/Transforms/Resize/ResizeHelper.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeHelper.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeHelper.cs index 6e7384cbdd..d03a694ba5 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeHelper.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeHelper.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -#nullable disable +using System.Diagnostics.CodeAnalysis; using System.Numerics; namespace SixLabors.ImageSharp.Processing.Processors.Transforms; @@ -422,6 +422,7 @@ internal static class ResizeHelper return (new Size(Sanitize(width), Sanitize(height)), new Rectangle(targetX, targetY, Sanitize(targetWidth), Sanitize(targetHeight))); } + [DoesNotReturn] private static void ThrowInvalid(string message) => throw new InvalidOperationException(message); private static int Sanitize(int input) => Math.Max(1, input); From bd990f0035fd2b6f703bde91745b7950a0627a5f Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Sun, 1 Jan 2023 13:05:50 +0100 Subject: [PATCH 05/10] Update shared infrastructure --- shared-infrastructure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-infrastructure b/shared-infrastructure index bf398a9b6b..9a82679e92 160000 --- a/shared-infrastructure +++ b/shared-infrastructure @@ -1 +1 @@ -Subproject commit bf398a9b6bb6d0acfe0525ee109276b4ef74646c +Subproject commit 9a82679e92df9476725fd2a2038604fd412af56c From 89212131ce04f7d92f43faf7ffd485456f722581 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Sun, 1 Jan 2023 13:42:57 +0100 Subject: [PATCH 06/10] Fix tests after update of SharedInfrastructure --- .../Image/ImageFrameCollectionTests.Generic.cs | 6 +++--- .../Image/ImageFrameCollectionTests.NonGeneric.cs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.Generic.cs b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.Generic.cs index 5e435ee9bb..fba19065b0 100644 --- a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.Generic.cs +++ b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.Generic.cs @@ -38,7 +38,7 @@ public abstract partial class ImageFrameCollectionTests using ImageFrame addedFrame = this.Collection.AddFrame((ImageFrame)null); }); - Assert.StartsWith("Parameter \"frame\" must be not null.", ex.Message); + Assert.StartsWith("Value cannot be null. (Parameter 'frame')", ex.Message); } [Fact] @@ -52,7 +52,7 @@ public abstract partial class ImageFrameCollectionTests using ImageFrame addedFrame = this.Collection.AddFrame(data); }); - Assert.StartsWith("Parameter \"source\" must be not null.", ex.Message); + Assert.StartsWith("Value cannot be null. (Parameter 'source')", ex.Message); } [Fact] @@ -89,7 +89,7 @@ public abstract partial class ImageFrameCollectionTests using ImageFrame insertedFrame = this.Collection.InsertFrame(1, null); }); - Assert.StartsWith("Parameter \"frame\" must be not null.", ex.Message); + Assert.StartsWith("Value cannot be null. (Parameter 'frame')", ex.Message); } [Fact] diff --git a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs index 60290a7eda..bc22806c3c 100644 --- a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs +++ b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs @@ -77,7 +77,7 @@ public abstract partial class ImageFrameCollectionTests ArgumentNullException ex = Assert.Throws( () => this.Collection.AddFrame(null)); - Assert.StartsWith("Parameter \"source\" must be not null.", ex.Message); + Assert.StartsWith("Value cannot be null. (Parameter 'source')", ex.Message); } [Fact] @@ -95,7 +95,7 @@ public abstract partial class ImageFrameCollectionTests ArgumentNullException ex = Assert.Throws( () => this.Collection.InsertFrame(1, null)); - Assert.StartsWith("Parameter \"source\" must be not null.", ex.Message); + Assert.StartsWith("Value cannot be null. (Parameter 'source')", ex.Message); } [Fact] From 0f9efeb25ca52c578b09c8ec46c2544ae8800e47 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Wed, 4 Jan 2023 12:23:53 +0100 Subject: [PATCH 07/10] Rewrite to TryFindFormatByFileExtension --- .../Advanced/AdvancedImageExtensions.cs | 3 +- src/ImageSharp/Formats/ImageFormatManager.cs | 11 +- .../Image/ImageTests.DetectFormat.cs | 10 +- .../Image/ImageTests.Identify.cs | 107 +++++++----------- .../Image/ImageTests.SaveAsync.cs | 4 +- .../Image/LargeImageIntegrationTests.cs | 4 +- .../TestUtilities/TestEnvironment.Formats.cs | 5 +- 7 files changed, 67 insertions(+), 77 deletions(-) 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( From 06e249584bdb50800f98145616346c3cb3f11f03 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Wed, 4 Jan 2023 12:44:29 +0100 Subject: [PATCH 08/10] Rewrite to TryDetectFormat --- src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs | 10 +++++++--- src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs | 7 +++++-- src/ImageSharp/Formats/IImageFormatDetector.cs | 7 +++++-- .../Formats/Jpeg/JpegImageFormatDetector.cs | 9 +++++++-- src/ImageSharp/Formats/Pbm/PbmImageFormatDetector.cs | 8 +++++++- src/ImageSharp/Formats/Png/PngImageFormatDetector.cs | 6 ++++-- src/ImageSharp/Formats/Tga/TgaImageFormatDetector.cs | 7 +++++-- .../Formats/Tiff/TiffImageFormatDetector.cs | 12 +++++------- .../Formats/Webp/WebpImageFormatDetector.cs | 9 +++++++-- src/ImageSharp/Image.Decode.cs | 3 +-- src/ImageSharp/Image.FromBytes.cs | 4 +--- .../Image/MockImageFormatDetector.cs | 7 +++++-- tests/ImageSharp.Tests/TestFormat.cs | 10 ++++------ 13 files changed, 63 insertions(+), 36 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs b/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs index 162c8ed399..01dd3157ef 100644 --- a/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Buffers.Binary; +using System.Diagnostics.CodeAnalysis; namespace SixLabors.ImageSharp.Formats.Bmp; @@ -14,9 +15,11 @@ public sealed class BmpImageFormatDetector : IImageFormatDetector public int HeaderSize => 2; /// - public IImageFormat? DetectFormat(ReadOnlySpan header) + public bool TryDetectFormat(ReadOnlySpan header, [NotNullWhen(true)] out IImageFormat? format) { - return this.IsSupportedFileFormat(header) ? BmpFormat.Instance : null; + format = this.IsSupportedFileFormat(header) ? BmpFormat.Instance : null; + + return format != null; } private bool IsSupportedFileFormat(ReadOnlySpan header) @@ -24,7 +27,8 @@ public sealed class BmpImageFormatDetector : IImageFormatDetector if (header.Length >= this.HeaderSize) { short fileTypeMarker = BinaryPrimitives.ReadInt16LittleEndian(header); - return fileTypeMarker == BmpConstants.TypeMarkers.Bitmap || fileTypeMarker == BmpConstants.TypeMarkers.BitmapArray; + return fileTypeMarker == BmpConstants.TypeMarkers.Bitmap || + fileTypeMarker == BmpConstants.TypeMarkers.BitmapArray; } return false; diff --git a/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs b/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs index db3d429046..ffda8075af 100644 --- a/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs @@ -1,6 +1,8 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Diagnostics.CodeAnalysis; + namespace SixLabors.ImageSharp.Formats.Gif; /// @@ -12,9 +14,10 @@ public sealed class GifImageFormatDetector : IImageFormatDetector public int HeaderSize => 6; /// - public IImageFormat? DetectFormat(ReadOnlySpan header) + public bool TryDetectFormat(ReadOnlySpan header, [NotNullWhen(true)] out IImageFormat? format) { - return this.IsSupportedFileFormat(header) ? GifFormat.Instance : null; + format = this.IsSupportedFileFormat(header) ? GifFormat.Instance : null; + return format != null; } private bool IsSupportedFileFormat(ReadOnlySpan header) diff --git a/src/ImageSharp/Formats/IImageFormatDetector.cs b/src/ImageSharp/Formats/IImageFormatDetector.cs index e1bdc41f8f..86750a7106 100644 --- a/src/ImageSharp/Formats/IImageFormatDetector.cs +++ b/src/ImageSharp/Formats/IImageFormatDetector.cs @@ -1,6 +1,8 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Diagnostics.CodeAnalysis; + namespace SixLabors.ImageSharp.Formats; /// @@ -18,6 +20,7 @@ public interface IImageFormatDetector /// Detect mimetype /// /// The containing the file header. - /// returns the mime type of detected otherwise returns null - IImageFormat? DetectFormat(ReadOnlySpan header); + /// The mime type of detected otherwise returns null + /// returns true when format was detected otherwise false. + bool TryDetectFormat(ReadOnlySpan header, [NotNullWhen(true)] out IImageFormat? format); } diff --git a/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs b/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs index 3bf7346ff3..4daf9fd97b 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs @@ -1,6 +1,8 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Diagnostics.CodeAnalysis; + namespace SixLabors.ImageSharp.Formats.Jpeg; /// @@ -12,8 +14,11 @@ public sealed class JpegImageFormatDetector : IImageFormatDetector public int HeaderSize => 11; /// - public IImageFormat? DetectFormat(ReadOnlySpan header) - => this.IsSupportedFileFormat(header) ? JpegFormat.Instance : null; + public bool TryDetectFormat(ReadOnlySpan header, [NotNullWhen(true)] out IImageFormat? format) + { + format = this.IsSupportedFileFormat(header) ? JpegFormat.Instance : null; + return format != null; + } private bool IsSupportedFileFormat(ReadOnlySpan header) => header.Length >= this.HeaderSize diff --git a/src/ImageSharp/Formats/Pbm/PbmImageFormatDetector.cs b/src/ImageSharp/Formats/Pbm/PbmImageFormatDetector.cs index 021cff2670..a50a2ddb69 100644 --- a/src/ImageSharp/Formats/Pbm/PbmImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Pbm/PbmImageFormatDetector.cs @@ -1,6 +1,8 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Diagnostics.CodeAnalysis; + namespace SixLabors.ImageSharp.Formats.Pbm; /// @@ -16,7 +18,11 @@ public sealed class PbmImageFormatDetector : IImageFormatDetector public int HeaderSize => 2; /// - public IImageFormat? DetectFormat(ReadOnlySpan header) => IsSupportedFileFormat(header) ? PbmFormat.Instance : null; + public bool TryDetectFormat(ReadOnlySpan header, [NotNullWhen(true)] out IImageFormat? format) + { + format = IsSupportedFileFormat(header) ? PbmFormat.Instance : null; + return format != null; + } private static bool IsSupportedFileFormat(ReadOnlySpan header) { diff --git a/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs b/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs index 2e20668248..1b574d49bb 100644 --- a/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Buffers.Binary; +using System.Diagnostics.CodeAnalysis; namespace SixLabors.ImageSharp.Formats.Png; @@ -14,9 +15,10 @@ public sealed class PngImageFormatDetector : IImageFormatDetector public int HeaderSize => 8; /// - public IImageFormat? DetectFormat(ReadOnlySpan header) + public bool TryDetectFormat(ReadOnlySpan header, [NotNullWhen(true)] out IImageFormat? format) { - return this.IsSupportedFileFormat(header) ? PngFormat.Instance : null; + format = this.IsSupportedFileFormat(header) ? PngFormat.Instance : null; + return format != null; } private bool IsSupportedFileFormat(ReadOnlySpan header) diff --git a/src/ImageSharp/Formats/Tga/TgaImageFormatDetector.cs b/src/ImageSharp/Formats/Tga/TgaImageFormatDetector.cs index 13d4e784c9..ad76bc3fbd 100644 --- a/src/ImageSharp/Formats/Tga/TgaImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Tga/TgaImageFormatDetector.cs @@ -1,6 +1,8 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Diagnostics.CodeAnalysis; + namespace SixLabors.ImageSharp.Formats.Tga; /// @@ -12,9 +14,10 @@ public sealed class TgaImageFormatDetector : IImageFormatDetector public int HeaderSize => 16; /// - public IImageFormat? DetectFormat(ReadOnlySpan header) + public bool TryDetectFormat(ReadOnlySpan header, [NotNullWhen(true)] out IImageFormat? format) { - return this.IsSupportedFileFormat(header) ? TgaFormat.Instance : null; + format = this.IsSupportedFileFormat(header) ? TgaFormat.Instance : null; + return format != null; } private bool IsSupportedFileFormat(ReadOnlySpan header) diff --git a/src/ImageSharp/Formats/Tiff/TiffImageFormatDetector.cs b/src/ImageSharp/Formats/Tiff/TiffImageFormatDetector.cs index 9af6a659e3..6382037ed3 100644 --- a/src/ImageSharp/Formats/Tiff/TiffImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Tiff/TiffImageFormatDetector.cs @@ -1,6 +1,8 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Diagnostics.CodeAnalysis; + namespace SixLabors.ImageSharp.Formats.Tiff; /// @@ -12,14 +14,10 @@ public sealed class TiffImageFormatDetector : IImageFormatDetector public int HeaderSize => 8; /// - public IImageFormat? DetectFormat(ReadOnlySpan header) + public bool TryDetectFormat(ReadOnlySpan header, [NotNullWhen(true)] out IImageFormat? format) { - if (this.IsSupportedFileFormat(header)) - { - return TiffFormat.Instance; - } - - return null; + format = this.IsSupportedFileFormat(header) ? TiffFormat.Instance : null; + return format != null; } private bool IsSupportedFileFormat(ReadOnlySpan header) diff --git a/src/ImageSharp/Formats/Webp/WebpImageFormatDetector.cs b/src/ImageSharp/Formats/Webp/WebpImageFormatDetector.cs index 3b30a2cfb5..2b91aa95fe 100644 --- a/src/ImageSharp/Formats/Webp/WebpImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Webp/WebpImageFormatDetector.cs @@ -1,6 +1,8 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Diagnostics.CodeAnalysis; + namespace SixLabors.ImageSharp.Formats.Webp; /// @@ -12,8 +14,11 @@ public sealed class WebpImageFormatDetector : IImageFormatDetector public int HeaderSize => 12; /// - public IImageFormat? DetectFormat(ReadOnlySpan header) - => this.IsSupportedFileFormat(header) ? WebpFormat.Instance : null; + public bool TryDetectFormat(ReadOnlySpan header, [NotNullWhen(true)] out IImageFormat? format) + { + format = this.IsSupportedFileFormat(header) ? WebpFormat.Instance : null; + return format != null; + } private bool IsSupportedFileFormat(ReadOnlySpan header) => header.Length >= this.HeaderSize && IsRiffContainer(header) && IsWebpFile(header); diff --git a/src/ImageSharp/Image.Decode.cs b/src/ImageSharp/Image.Decode.cs index 806a0f471b..a556cbceb3 100644 --- a/src/ImageSharp/Image.Decode.cs +++ b/src/ImageSharp/Image.Decode.cs @@ -82,8 +82,7 @@ public abstract partial class Image { if (formatDetector.HeaderSize <= headerSize) { - IImageFormat attemptFormat = formatDetector.DetectFormat(headersBuffer); - if (attemptFormat != null) + if (formatDetector.TryDetectFormat(headersBuffer, out IImageFormat attemptFormat)) { format = attemptFormat; } diff --git a/src/ImageSharp/Image.FromBytes.cs b/src/ImageSharp/Image.FromBytes.cs index 0d36e397c1..922448c826 100644 --- a/src/ImageSharp/Image.FromBytes.cs +++ b/src/ImageSharp/Image.FromBytes.cs @@ -39,9 +39,7 @@ public abstract partial class Image foreach (IImageFormatDetector detector in configuration.ImageFormatsManager.FormatDetectors) { - IImageFormat? f = detector.DetectFormat(data); - - if (f != null) + if (detector.TryDetectFormat(data, out IImageFormat? f)) { return f; } diff --git a/tests/ImageSharp.Tests/Image/MockImageFormatDetector.cs b/tests/ImageSharp.Tests/Image/MockImageFormatDetector.cs index d0576c828b..8564eaa5bb 100644 --- a/tests/ImageSharp.Tests/Image/MockImageFormatDetector.cs +++ b/tests/ImageSharp.Tests/Image/MockImageFormatDetector.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Diagnostics.CodeAnalysis; using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.Tests; @@ -19,8 +20,10 @@ public class MockImageFormatDetector : IImageFormatDetector public int HeaderSize => 1; - public IImageFormat DetectFormat(ReadOnlySpan header) + public bool TryDetectFormat(ReadOnlySpan header, [NotNullWhen(true)] out IImageFormat? format) { - return this.localImageFormatMock; + format = this.localImageFormatMock; + + return true; } } diff --git a/tests/ImageSharp.Tests/TestFormat.cs b/tests/ImageSharp.Tests/TestFormat.cs index f3176f16c5..bfad231949 100644 --- a/tests/ImageSharp.Tests/TestFormat.cs +++ b/tests/ImageSharp.Tests/TestFormat.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Diagnostics.CodeAnalysis; using System.Numerics; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; @@ -174,14 +175,11 @@ public class TestFormat : IImageFormatConfigurationModule, IImageFormat public int HeaderSize => this.testFormat.HeaderSize; - public IImageFormat DetectFormat(ReadOnlySpan header) + public bool TryDetectFormat(ReadOnlySpan header, [NotNullWhen(true)] out IImageFormat? format) { - if (this.testFormat.IsSupportedFileFormat(header)) - { - return this.testFormat; - } + format = this.testFormat.IsSupportedFileFormat(header) ? this.testFormat : null; - return null; + return format != null; } public TestHeader(TestFormat testFormat) => this.testFormat = testFormat; From 9debbe17ac120cbe220f08be8559388b3a367052 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Mon, 9 Jan 2023 07:01:23 +0100 Subject: [PATCH 09/10] Add NotNullWhen to TryGetLinearlySeparableComponents --- .../Processors/Convolution/ConvolutionProcessorHelpers.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessorHelpers.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessorHelpers.cs index 411dbe50cb..4aefa0daef 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessorHelpers.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessorHelpers.cs @@ -1,6 +1,8 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Diagnostics.CodeAnalysis; + namespace SixLabors.ImageSharp.Processing.Processors.Convolution; internal static class ConvolutionProcessorHelpers @@ -98,7 +100,7 @@ internal static class ConvolutionProcessorHelpers /// The resulting 1D row vector, if possible. /// The resulting 1D column vector, if possible. /// Whether or not was linearly separable. - public static bool TryGetLinearlySeparableComponents(this DenseMatrix matrix, out float[]? row, out float[]? column) + public static bool TryGetLinearlySeparableComponents(this DenseMatrix matrix, [NotNullWhen(true)] out float[]? row, [NotNullWhen(true)] out float[]? column) { int height = matrix.Rows; int width = matrix.Columns; From 4a5f525d7a778b691f4992db0950ae85762dad6b Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Mon, 9 Jan 2023 07:32:11 +0100 Subject: [PATCH 10/10] Convert DetectFormat to the Try pattern --- src/ImageSharp/Image.FromBytes.cs | 23 +++++++++------- src/ImageSharp/Image.FromFile.cs | 15 ++++++----- src/ImageSharp/Image.FromStream.cs | 17 +++++++----- .../Formats/ImageFormatManagerTests.cs | 10 +++++-- .../Image/ImageTests.DetectFormat.cs | 26 ++++++++++++++----- 5 files changed, 61 insertions(+), 30 deletions(-) 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); }