Browse Source

Refactor Load APIs

pull/2317/head
James Jackson-South 3 years ago
parent
commit
f421701333
  1. 18
      src/ImageSharp/Advanced/AdvancedImageExtensions.cs
  2. 17
      src/ImageSharp/Formats/ImageDecoder.cs
  3. 64
      src/ImageSharp/Formats/ImageExtensions.Save.cs
  4. 51
      src/ImageSharp/Formats/ImageFormatManager.cs
  5. 91
      src/ImageSharp/Image.Decode.cs
  6. 166
      src/ImageSharp/Image.FromBytes.cs
  7. 255
      src/ImageSharp/Image.FromFile.cs
  8. 291
      src/ImageSharp/Image.FromStream.cs
  9. 2
      src/ImageSharp/Image.LoadPixelData.cs
  10. 4
      src/ImageSharp/ImageExtensions.cs
  11. 72
      tests/ImageSharp.Tests/Formats/Bmp/ImageExtensionsTest.cs
  12. 9
      tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs
  13. 72
      tests/ImageSharp.Tests/Formats/Gif/ImageExtensionsTest.cs
  14. 8
      tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs
  15. 72
      tests/ImageSharp.Tests/Formats/Jpg/ImageExtensionsTest.cs
  16. 42
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs
  17. 10
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs
  18. 72
      tests/ImageSharp.Tests/Formats/Pbm/ImageExtensionsTest.cs
  19. 72
      tests/ImageSharp.Tests/Formats/Png/ImageExtensionsTest.cs
  20. 72
      tests/ImageSharp.Tests/Formats/Tga/ImageExtensionsTest.cs
  21. 2
      tests/ImageSharp.Tests/Formats/Tga/TgaFileHeaderTests.cs
  22. 72
      tests/ImageSharp.Tests/Formats/Tiff/ImageExtensionsTest.cs
  23. 72
      tests/ImageSharp.Tests/Formats/WebP/ImageExtensionsTests.cs
  24. 12
      tests/ImageSharp.Tests/Image/ImageTests.DetectFormat.cs
  25. 26
      tests/ImageSharp.Tests/Image/ImageTests.Identify.cs
  26. 38
      tests/ImageSharp.Tests/Image/ImageTests.Load_FileSystemPath_PassLocalConfiguration.cs
  27. 13
      tests/ImageSharp.Tests/Image/ImageTests.Load_FileSystemPath_UseDefaultConfiguration.cs
  28. 36
      tests/ImageSharp.Tests/Image/ImageTests.Load_FromBytes_PassLocalConfiguration.cs
  29. 13
      tests/ImageSharp.Tests/Image/ImageTests.Load_FromBytes_UseGlobalConfiguration.cs
  30. 54
      tests/ImageSharp.Tests/Image/ImageTests.Load_FromStream_PassLocalConfiguration.cs
  31. 4
      tests/ImageSharp.Tests/Image/ImageTests.Load_FromStream_ThrowsRightException.cs
  32. 29
      tests/ImageSharp.Tests/Image/ImageTests.Load_FromStream_UseDefaultConfiguration.cs
  33. 34
      tests/ImageSharp.Tests/Image/ImageTests.Save.cs
  34. 88
      tests/ImageSharp.Tests/Image/ImageTests.SaveAsync.cs
  35. 72
      tests/ImageSharp.Tests/Image/ImageTests.cs
  36. 2
      tests/ImageSharp.Tests/Image/LargeImageIntegrationTests.cs
  37. 412
      tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs
  38. 4
      tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs

18
src/ImageSharp/Advanced/AdvancedImageExtensions.cs

@ -19,9 +19,9 @@ public static class AdvancedImageExtensions
/// </summary> /// </summary>
/// <param name="source">The source image.</param> /// <param name="source">The source image.</param>
/// <param name="filePath">The target file path to save the image to.</param> /// <param name="filePath">The target file path to save the image to.</param>
/// <exception cref="ArgumentNullException">The file path is null.</exception>
/// <exception cref="NotSupportedException">No encoder available for provided path.</exception>
/// <returns>The matching <see cref="IImageEncoder"/>.</returns> /// <returns>The matching <see cref="IImageEncoder"/>.</returns>
/// <exception cref="ArgumentNullException">The file path is null.</exception>
/// <exception cref="UnknownImageFormatException">No encoder available for provided path.</exception>
public static IImageEncoder DetectEncoder(this Image source, string filePath) public static IImageEncoder DetectEncoder(this Image source, string filePath)
{ {
Guard.NotNull(filePath, nameof(filePath)); Guard.NotNull(filePath, nameof(filePath));
@ -30,27 +30,27 @@ public static class AdvancedImageExtensions
if (!source.GetConfiguration().ImageFormatsManager.TryFindFormatByFileExtension(ext, out IImageFormat? format)) if (!source.GetConfiguration().ImageFormatsManager.TryFindFormatByFileExtension(ext, out IImageFormat? format))
{ {
StringBuilder sb = new(); StringBuilder sb = new();
sb.AppendLine(CultureInfo.InvariantCulture, $"No encoder was found for extension '{ext}'. Registered encoders include:"); sb = sb.AppendLine(CultureInfo.InvariantCulture, $"No encoder was found for extension '{ext}'. Registered encoders include:");
foreach (IImageFormat fmt in source.GetConfiguration().ImageFormats) foreach (IImageFormat fmt in source.GetConfiguration().ImageFormats)
{ {
sb.AppendFormat(CultureInfo.InvariantCulture, " - {0} : {1}{2}", fmt.Name, string.Join(", ", fmt.FileExtensions), Environment.NewLine); sb = sb.AppendFormat(CultureInfo.InvariantCulture, " - {0} : {1}{2}", fmt.Name, string.Join(", ", fmt.FileExtensions), Environment.NewLine);
} }
throw new NotSupportedException(sb.ToString()); throw new UnknownImageFormatException(sb.ToString());
} }
IImageEncoder? encoder = source.GetConfiguration().ImageFormatsManager.FindEncoder(format); IImageEncoder? encoder = source.GetConfiguration().ImageFormatsManager.GetEncoder(format);
if (encoder is null) if (encoder is null)
{ {
StringBuilder sb = new(); StringBuilder sb = new();
sb.AppendLine(CultureInfo.InvariantCulture, $"No encoder was found for extension '{ext}' using image format '{format.Name}'. Registered encoders include:"); sb = sb.AppendLine(CultureInfo.InvariantCulture, $"No encoder was found for extension '{ext}' using image format '{format.Name}'. Registered encoders include:");
foreach (KeyValuePair<IImageFormat, IImageEncoder> enc in source.GetConfiguration().ImageFormatsManager.ImageEncoders) foreach (KeyValuePair<IImageFormat, IImageEncoder> enc in source.GetConfiguration().ImageFormatsManager.ImageEncoders)
{ {
sb.AppendFormat(CultureInfo.InvariantCulture, " - {0} : {1}{2}", enc.Key, enc.Value.GetType().Name, Environment.NewLine); sb = sb.AppendFormat(CultureInfo.InvariantCulture, " - {0} : {1}{2}", enc.Key, enc.Value.GetType().Name, Environment.NewLine);
} }
throw new NotSupportedException(sb.ToString()); throw new UnknownImageFormatException(sb.ToString());
} }
return encoder; return encoder;

17
src/ImageSharp/Formats/ImageDecoder.cs

@ -1,6 +1,5 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
#nullable disable
using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
@ -150,7 +149,7 @@ public abstract class ImageDecoder : IImageDecoder
{ {
ResizeOptions resizeOptions = new() ResizeOptions resizeOptions = new()
{ {
Size = options.TargetSize.Value, Size = options.TargetSize!.Value,
Sampler = options.Sampler, Sampler = options.Sampler,
Mode = ResizeMode.Max Mode = ResizeMode.Max
}; };
@ -290,8 +289,18 @@ public abstract class ImageDecoder : IImageDecoder
} }
internal void SetDecoderFormat(Configuration configuration, Image image) internal void SetDecoderFormat(Configuration configuration, Image image)
=> image.Metadata.DecodedImageFormat = configuration.ImageFormatsManager.FindFormatByDecoder(this); {
if (configuration.ImageFormatsManager.TryFindFormatByDecoder(this, out IImageFormat? format))
{
image.Metadata.DecodedImageFormat = format;
}
}
internal void SetDecoderFormat(Configuration configuration, ImageInfo info) internal void SetDecoderFormat(Configuration configuration, ImageInfo info)
=> info.Metadata.DecodedImageFormat = configuration.ImageFormatsManager.FindFormatByDecoder(this); {
if (configuration.ImageFormatsManager.TryFindFormatByDecoder(this, out IImageFormat? format))
{
info.Metadata.DecodedImageFormat = format;
}
}
} }

64
src/ImageSharp/Formats/ImageExtensions.Save.cs

@ -58,7 +58,7 @@ public static partial class ImageExtensions
public static void SaveAsBmp(this Image source, string path, BmpEncoder encoder) => public static void SaveAsBmp(this Image source, string path, BmpEncoder encoder) =>
source.Save( source.Save(
path, path,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(BmpFormat.Instance)); encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(BmpFormat.Instance));
/// <summary> /// <summary>
/// Saves the image to the given stream with the Bmp format. /// Saves the image to the given stream with the Bmp format.
@ -72,7 +72,7 @@ public static partial class ImageExtensions
public static Task SaveAsBmpAsync(this Image source, string path, BmpEncoder encoder, CancellationToken cancellationToken = default) public static Task SaveAsBmpAsync(this Image source, string path, BmpEncoder encoder, CancellationToken cancellationToken = default)
=> source.SaveAsync( => source.SaveAsync(
path, path,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(BmpFormat.Instance), encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(BmpFormat.Instance),
cancellationToken); cancellationToken);
/// <summary> /// <summary>
@ -105,7 +105,7 @@ public static partial class ImageExtensions
public static void SaveAsBmp(this Image source, Stream stream, BmpEncoder encoder) public static void SaveAsBmp(this Image source, Stream stream, BmpEncoder encoder)
=> source.Save( => source.Save(
stream, stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(BmpFormat.Instance)); encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(BmpFormat.Instance));
/// <summary> /// <summary>
/// Saves the image to the given stream with the Bmp format. /// Saves the image to the given stream with the Bmp format.
@ -119,7 +119,7 @@ public static partial class ImageExtensions
public static Task SaveAsBmpAsync(this Image source, Stream stream, BmpEncoder encoder, CancellationToken cancellationToken = default) public static Task SaveAsBmpAsync(this Image source, Stream stream, BmpEncoder encoder, CancellationToken cancellationToken = default)
=> source.SaveAsync( => source.SaveAsync(
stream, stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(BmpFormat.Instance), encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(BmpFormat.Instance),
cancellationToken); cancellationToken);
/// <summary> /// <summary>
@ -160,7 +160,7 @@ public static partial class ImageExtensions
public static void SaveAsGif(this Image source, string path, GifEncoder encoder) => public static void SaveAsGif(this Image source, string path, GifEncoder encoder) =>
source.Save( source.Save(
path, path,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(GifFormat.Instance)); encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(GifFormat.Instance));
/// <summary> /// <summary>
/// Saves the image to the given stream with the Gif format. /// Saves the image to the given stream with the Gif format.
@ -174,7 +174,7 @@ public static partial class ImageExtensions
public static Task SaveAsGifAsync(this Image source, string path, GifEncoder encoder, CancellationToken cancellationToken = default) public static Task SaveAsGifAsync(this Image source, string path, GifEncoder encoder, CancellationToken cancellationToken = default)
=> source.SaveAsync( => source.SaveAsync(
path, path,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(GifFormat.Instance), encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(GifFormat.Instance),
cancellationToken); cancellationToken);
/// <summary> /// <summary>
@ -207,7 +207,7 @@ public static partial class ImageExtensions
public static void SaveAsGif(this Image source, Stream stream, GifEncoder encoder) public static void SaveAsGif(this Image source, Stream stream, GifEncoder encoder)
=> source.Save( => source.Save(
stream, stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(GifFormat.Instance)); encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(GifFormat.Instance));
/// <summary> /// <summary>
/// Saves the image to the given stream with the Gif format. /// Saves the image to the given stream with the Gif format.
@ -221,7 +221,7 @@ public static partial class ImageExtensions
public static Task SaveAsGifAsync(this Image source, Stream stream, GifEncoder encoder, CancellationToken cancellationToken = default) public static Task SaveAsGifAsync(this Image source, Stream stream, GifEncoder encoder, CancellationToken cancellationToken = default)
=> source.SaveAsync( => source.SaveAsync(
stream, stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(GifFormat.Instance), encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(GifFormat.Instance),
cancellationToken); cancellationToken);
/// <summary> /// <summary>
@ -262,7 +262,7 @@ public static partial class ImageExtensions
public static void SaveAsJpeg(this Image source, string path, JpegEncoder encoder) => public static void SaveAsJpeg(this Image source, string path, JpegEncoder encoder) =>
source.Save( source.Save(
path, path,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(JpegFormat.Instance)); encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(JpegFormat.Instance));
/// <summary> /// <summary>
/// Saves the image to the given stream with the Jpeg format. /// Saves the image to the given stream with the Jpeg format.
@ -276,7 +276,7 @@ public static partial class ImageExtensions
public static Task SaveAsJpegAsync(this Image source, string path, JpegEncoder encoder, CancellationToken cancellationToken = default) public static Task SaveAsJpegAsync(this Image source, string path, JpegEncoder encoder, CancellationToken cancellationToken = default)
=> source.SaveAsync( => source.SaveAsync(
path, path,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(JpegFormat.Instance), encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(JpegFormat.Instance),
cancellationToken); cancellationToken);
/// <summary> /// <summary>
@ -309,7 +309,7 @@ public static partial class ImageExtensions
public static void SaveAsJpeg(this Image source, Stream stream, JpegEncoder encoder) public static void SaveAsJpeg(this Image source, Stream stream, JpegEncoder encoder)
=> source.Save( => source.Save(
stream, stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(JpegFormat.Instance)); encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(JpegFormat.Instance));
/// <summary> /// <summary>
/// Saves the image to the given stream with the Jpeg format. /// Saves the image to the given stream with the Jpeg format.
@ -323,7 +323,7 @@ public static partial class ImageExtensions
public static Task SaveAsJpegAsync(this Image source, Stream stream, JpegEncoder encoder, CancellationToken cancellationToken = default) public static Task SaveAsJpegAsync(this Image source, Stream stream, JpegEncoder encoder, CancellationToken cancellationToken = default)
=> source.SaveAsync( => source.SaveAsync(
stream, stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(JpegFormat.Instance), encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(JpegFormat.Instance),
cancellationToken); cancellationToken);
/// <summary> /// <summary>
@ -364,7 +364,7 @@ public static partial class ImageExtensions
public static void SaveAsPbm(this Image source, string path, PbmEncoder encoder) => public static void SaveAsPbm(this Image source, string path, PbmEncoder encoder) =>
source.Save( source.Save(
path, path,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(PbmFormat.Instance)); encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(PbmFormat.Instance));
/// <summary> /// <summary>
/// Saves the image to the given stream with the Pbm format. /// Saves the image to the given stream with the Pbm format.
@ -378,7 +378,7 @@ public static partial class ImageExtensions
public static Task SaveAsPbmAsync(this Image source, string path, PbmEncoder encoder, CancellationToken cancellationToken = default) public static Task SaveAsPbmAsync(this Image source, string path, PbmEncoder encoder, CancellationToken cancellationToken = default)
=> source.SaveAsync( => source.SaveAsync(
path, path,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(PbmFormat.Instance), encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(PbmFormat.Instance),
cancellationToken); cancellationToken);
/// <summary> /// <summary>
@ -411,7 +411,7 @@ public static partial class ImageExtensions
public static void SaveAsPbm(this Image source, Stream stream, PbmEncoder encoder) public static void SaveAsPbm(this Image source, Stream stream, PbmEncoder encoder)
=> source.Save( => source.Save(
stream, stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(PbmFormat.Instance)); encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(PbmFormat.Instance));
/// <summary> /// <summary>
/// Saves the image to the given stream with the Pbm format. /// Saves the image to the given stream with the Pbm format.
@ -425,7 +425,7 @@ public static partial class ImageExtensions
public static Task SaveAsPbmAsync(this Image source, Stream stream, PbmEncoder encoder, CancellationToken cancellationToken = default) public static Task SaveAsPbmAsync(this Image source, Stream stream, PbmEncoder encoder, CancellationToken cancellationToken = default)
=> source.SaveAsync( => source.SaveAsync(
stream, stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(PbmFormat.Instance), encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(PbmFormat.Instance),
cancellationToken); cancellationToken);
/// <summary> /// <summary>
@ -466,7 +466,7 @@ public static partial class ImageExtensions
public static void SaveAsPng(this Image source, string path, PngEncoder encoder) => public static void SaveAsPng(this Image source, string path, PngEncoder encoder) =>
source.Save( source.Save(
path, path,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(PngFormat.Instance)); encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(PngFormat.Instance));
/// <summary> /// <summary>
/// Saves the image to the given stream with the Png format. /// Saves the image to the given stream with the Png format.
@ -480,7 +480,7 @@ public static partial class ImageExtensions
public static Task SaveAsPngAsync(this Image source, string path, PngEncoder encoder, CancellationToken cancellationToken = default) public static Task SaveAsPngAsync(this Image source, string path, PngEncoder encoder, CancellationToken cancellationToken = default)
=> source.SaveAsync( => source.SaveAsync(
path, path,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(PngFormat.Instance), encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(PngFormat.Instance),
cancellationToken); cancellationToken);
/// <summary> /// <summary>
@ -513,7 +513,7 @@ public static partial class ImageExtensions
public static void SaveAsPng(this Image source, Stream stream, PngEncoder encoder) public static void SaveAsPng(this Image source, Stream stream, PngEncoder encoder)
=> source.Save( => source.Save(
stream, stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(PngFormat.Instance)); encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(PngFormat.Instance));
/// <summary> /// <summary>
/// Saves the image to the given stream with the Png format. /// Saves the image to the given stream with the Png format.
@ -527,7 +527,7 @@ public static partial class ImageExtensions
public static Task SaveAsPngAsync(this Image source, Stream stream, PngEncoder encoder, CancellationToken cancellationToken = default) public static Task SaveAsPngAsync(this Image source, Stream stream, PngEncoder encoder, CancellationToken cancellationToken = default)
=> source.SaveAsync( => source.SaveAsync(
stream, stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(PngFormat.Instance), encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(PngFormat.Instance),
cancellationToken); cancellationToken);
/// <summary> /// <summary>
@ -568,7 +568,7 @@ public static partial class ImageExtensions
public static void SaveAsTga(this Image source, string path, TgaEncoder encoder) => public static void SaveAsTga(this Image source, string path, TgaEncoder encoder) =>
source.Save( source.Save(
path, path,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(TgaFormat.Instance)); encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(TgaFormat.Instance));
/// <summary> /// <summary>
/// Saves the image to the given stream with the Tga format. /// Saves the image to the given stream with the Tga format.
@ -582,7 +582,7 @@ public static partial class ImageExtensions
public static Task SaveAsTgaAsync(this Image source, string path, TgaEncoder encoder, CancellationToken cancellationToken = default) public static Task SaveAsTgaAsync(this Image source, string path, TgaEncoder encoder, CancellationToken cancellationToken = default)
=> source.SaveAsync( => source.SaveAsync(
path, path,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(TgaFormat.Instance), encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(TgaFormat.Instance),
cancellationToken); cancellationToken);
/// <summary> /// <summary>
@ -615,7 +615,7 @@ public static partial class ImageExtensions
public static void SaveAsTga(this Image source, Stream stream, TgaEncoder encoder) public static void SaveAsTga(this Image source, Stream stream, TgaEncoder encoder)
=> source.Save( => source.Save(
stream, stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(TgaFormat.Instance)); encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(TgaFormat.Instance));
/// <summary> /// <summary>
/// Saves the image to the given stream with the Tga format. /// Saves the image to the given stream with the Tga format.
@ -629,7 +629,7 @@ public static partial class ImageExtensions
public static Task SaveAsTgaAsync(this Image source, Stream stream, TgaEncoder encoder, CancellationToken cancellationToken = default) public static Task SaveAsTgaAsync(this Image source, Stream stream, TgaEncoder encoder, CancellationToken cancellationToken = default)
=> source.SaveAsync( => source.SaveAsync(
stream, stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(TgaFormat.Instance), encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(TgaFormat.Instance),
cancellationToken); cancellationToken);
/// <summary> /// <summary>
@ -670,7 +670,7 @@ public static partial class ImageExtensions
public static void SaveAsWebp(this Image source, string path, WebpEncoder encoder) => public static void SaveAsWebp(this Image source, string path, WebpEncoder encoder) =>
source.Save( source.Save(
path, path,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(WebpFormat.Instance)); encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(WebpFormat.Instance));
/// <summary> /// <summary>
/// Saves the image to the given stream with the Webp format. /// Saves the image to the given stream with the Webp format.
@ -684,7 +684,7 @@ public static partial class ImageExtensions
public static Task SaveAsWebpAsync(this Image source, string path, WebpEncoder encoder, CancellationToken cancellationToken = default) public static Task SaveAsWebpAsync(this Image source, string path, WebpEncoder encoder, CancellationToken cancellationToken = default)
=> source.SaveAsync( => source.SaveAsync(
path, path,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(WebpFormat.Instance), encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(WebpFormat.Instance),
cancellationToken); cancellationToken);
/// <summary> /// <summary>
@ -717,7 +717,7 @@ public static partial class ImageExtensions
public static void SaveAsWebp(this Image source, Stream stream, WebpEncoder encoder) public static void SaveAsWebp(this Image source, Stream stream, WebpEncoder encoder)
=> source.Save( => source.Save(
stream, stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(WebpFormat.Instance)); encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(WebpFormat.Instance));
/// <summary> /// <summary>
/// Saves the image to the given stream with the Webp format. /// Saves the image to the given stream with the Webp format.
@ -731,7 +731,7 @@ public static partial class ImageExtensions
public static Task SaveAsWebpAsync(this Image source, Stream stream, WebpEncoder encoder, CancellationToken cancellationToken = default) public static Task SaveAsWebpAsync(this Image source, Stream stream, WebpEncoder encoder, CancellationToken cancellationToken = default)
=> source.SaveAsync( => source.SaveAsync(
stream, stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(WebpFormat.Instance), encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(WebpFormat.Instance),
cancellationToken); cancellationToken);
/// <summary> /// <summary>
@ -772,7 +772,7 @@ public static partial class ImageExtensions
public static void SaveAsTiff(this Image source, string path, TiffEncoder encoder) => public static void SaveAsTiff(this Image source, string path, TiffEncoder encoder) =>
source.Save( source.Save(
path, path,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(TiffFormat.Instance)); encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(TiffFormat.Instance));
/// <summary> /// <summary>
/// Saves the image to the given stream with the Tiff format. /// Saves the image to the given stream with the Tiff format.
@ -786,7 +786,7 @@ public static partial class ImageExtensions
public static Task SaveAsTiffAsync(this Image source, string path, TiffEncoder encoder, CancellationToken cancellationToken = default) public static Task SaveAsTiffAsync(this Image source, string path, TiffEncoder encoder, CancellationToken cancellationToken = default)
=> source.SaveAsync( => source.SaveAsync(
path, path,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(TiffFormat.Instance), encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(TiffFormat.Instance),
cancellationToken); cancellationToken);
/// <summary> /// <summary>
@ -819,7 +819,7 @@ public static partial class ImageExtensions
public static void SaveAsTiff(this Image source, Stream stream, TiffEncoder encoder) public static void SaveAsTiff(this Image source, Stream stream, TiffEncoder encoder)
=> source.Save( => source.Save(
stream, stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(TiffFormat.Instance)); encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(TiffFormat.Instance));
/// <summary> /// <summary>
/// Saves the image to the given stream with the Tiff format. /// Saves the image to the given stream with the Tiff format.
@ -833,7 +833,7 @@ public static partial class ImageExtensions
public static Task SaveAsTiffAsync(this Image source, Stream stream, TiffEncoder encoder, CancellationToken cancellationToken = default) public static Task SaveAsTiffAsync(this Image source, Stream stream, TiffEncoder encoder, CancellationToken cancellationToken = default)
=> source.SaveAsync( => source.SaveAsync(
stream, stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(TiffFormat.Instance), encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(TiffFormat.Instance),
cancellationToken); cancellationToken);
} }

51
src/ImageSharp/Formats/ImageFormatManager.cs

@ -3,6 +3,8 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Text;
namespace SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.Formats;
@ -129,8 +131,11 @@ public class ImageFormatManager
return format is not null; return format is not null;
} }
internal IImageFormat? FindFormatByDecoder(IImageDecoder decoder) internal bool TryFindFormatByDecoder(IImageDecoder decoder, [NotNullWhen(true)] out IImageFormat? format)
=> this.mimeTypeDecoders.FirstOrDefault(x => x.Value.GetType() == decoder.GetType()).Key; {
format = this.mimeTypeDecoders.FirstOrDefault(x => x.Value.GetType() == decoder.GetType()).Key;
return format is not null;
}
/// <summary> /// <summary>
/// Sets a specific image encoder as the encoder for a specific image format. /// Sets a specific image encoder as the encoder for a specific image format.
@ -178,32 +183,54 @@ public class ImageFormatManager
/// For the specified mime type find the decoder. /// For the specified mime type find the decoder.
/// </summary> /// </summary>
/// <param name="format">The format to discover</param> /// <param name="format">The format to discover</param>
/// <returns>The <see cref="IImageDecoder"/> if found otherwise null</returns> /// <returns>The <see cref="IImageDecoder"/>.</returns>
public IImageDecoder? FindDecoder(IImageFormat format) /// <exception cref="UnknownImageFormatException">The format is not registered.</exception>
public IImageDecoder GetDecoder(IImageFormat format)
{ {
Guard.NotNull(format, nameof(format)); Guard.NotNull(format, nameof(format));
return this.mimeTypeDecoders.TryGetValue(format, out IImageDecoder? decoder) if (!this.mimeTypeDecoders.TryGetValue(format, out IImageDecoder? decoder))
? decoder {
: null; ThrowInvalidDecoder(this);
}
return decoder;
} }
/// <summary> /// <summary>
/// For the specified mime type find the encoder. /// For the specified mime type find the encoder.
/// </summary> /// </summary>
/// <param name="format">The format to discover</param> /// <param name="format">The format to discover</param>
/// <returns>The <see cref="IImageEncoder"/> if found otherwise null</returns> /// <returns>The <see cref="IImageEncoder"/>.</returns>
public IImageEncoder? FindEncoder(IImageFormat format) /// <exception cref="UnknownImageFormatException">The format is not registered.</exception>
public IImageEncoder GetEncoder(IImageFormat format)
{ {
Guard.NotNull(format, nameof(format)); Guard.NotNull(format, nameof(format));
return this.mimeTypeEncoders.TryGetValue(format, out IImageEncoder? encoder) if (!this.mimeTypeEncoders.TryGetValue(format, out IImageEncoder? encoder))
? encoder {
: null; ThrowInvalidDecoder(this);
}
return encoder;
} }
/// <summary> /// <summary>
/// Sets the max header size. /// Sets the max header size.
/// </summary> /// </summary>
private void SetMaxHeaderSize() => this.MaxHeaderSize = this.imageFormatDetectors.Max(x => x.HeaderSize); private void SetMaxHeaderSize() => this.MaxHeaderSize = this.imageFormatDetectors.Max(x => x.HeaderSize);
[DoesNotReturn]
internal static void ThrowInvalidDecoder(ImageFormatManager manager)
{
StringBuilder sb = new();
sb = sb.AppendLine("Image cannot be loaded. Available decoders:");
foreach (KeyValuePair<IImageFormat, IImageDecoder> val in manager.ImageDecoders)
{
sb = sb.AppendFormat(CultureInfo.InvariantCulture, " - {0} : {1}{2}", val.Key.Name, val.Value.GetType().Name, Environment.NewLine);
}
throw new UnknownImageFormatException(sb.ToString());
}
} }

91
src/ImageSharp/Image.Decode.cs

@ -44,14 +44,15 @@ public abstract partial class Image
/// <param name="configuration">The general configuration.</param> /// <param name="configuration">The general configuration.</param>
/// <param name="stream">The image stream to read the header from.</param> /// <param name="stream">The image stream to read the header from.</param>
/// <returns>The mime type or null if none found.</returns> /// <returns>The mime type or null if none found.</returns>
private static IImageFormat? InternalDetectFormat(Configuration configuration, Stream stream) /// <exception cref="UnknownImageFormatException">The input format is not recognized.</exception>
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 // 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. // to ensure that only formats that headers fit within the given buffer length are tested.
int headerSize = (int)Math.Min(configuration.MaxHeaderSize, stream.Length); int headerSize = (int)Math.Min(configuration.MaxHeaderSize, stream.Length);
if (headerSize <= 0) if (headerSize <= 0)
{ {
return null; ImageFormatManager.ThrowInvalidDecoder(configuration.ImageFormatsManager);
} }
// Header sizes are so small, that headersBuffer will be always stackalloc-ed in practice, // Header sizes are so small, that headersBuffer will be always stackalloc-ed in practice,
@ -85,7 +86,12 @@ public abstract partial class Image
} }
} }
return format; if (format is null)
{
ImageFormatManager.ThrowInvalidDecoder(configuration.ImageFormatsManager);
}
return format!;
} }
/// <summary> /// <summary>
@ -93,13 +99,11 @@ public abstract partial class Image
/// </summary> /// </summary>
/// <param name="options">The general decoder options.</param> /// <param name="options">The general decoder options.</param>
/// <param name="stream">The image stream to read the header from.</param> /// <param name="stream">The image stream to read the header from.</param>
/// <returns>The <see cref="IImageDecoder"/> or <see langword="null"/>.</returns> /// <returns>The <see cref="IImageDecoder"/>.</returns>
private static IImageDecoder? DiscoverDecoder(DecoderOptions options, Stream stream) private static IImageDecoder DiscoverDecoder(DecoderOptions options, Stream stream)
{ {
IImageFormat? format = InternalDetectFormat(options.Configuration, stream); IImageFormat format = InternalDetectFormat(options.Configuration, stream);
return format is not null return options.Configuration.ImageFormatsManager.GetDecoder(format);
? options.Configuration.ImageFormatsManager.FindDecoder(format)
: null;
} }
/// <summary> /// <summary>
@ -111,56 +115,36 @@ public abstract partial class Image
/// <returns> /// <returns>
/// A new <see cref="Image{TPixel}"/>. /// A new <see cref="Image{TPixel}"/>.
/// </returns> /// </returns>
private static Image<TPixel>? Decode<TPixel>(DecoderOptions options, Stream stream) private static Image<TPixel> Decode<TPixel>(DecoderOptions options, Stream stream)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
IImageDecoder? decoder = DiscoverDecoder(options, stream); IImageDecoder decoder = DiscoverDecoder(options, stream);
if (decoder is null)
{
return null;
}
return decoder.Decode<TPixel>(options, stream); return decoder.Decode<TPixel>(options, stream);
} }
private static async Task<Image<TPixel>?> DecodeAsync<TPixel>( private static Task<Image<TPixel>> DecodeAsync<TPixel>(
DecoderOptions options, DecoderOptions options,
Stream stream, Stream stream,
CancellationToken cancellationToken) CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
IImageDecoder? decoder = DiscoverDecoder(options, stream); IImageDecoder decoder = DiscoverDecoder(options, stream);
if (decoder is null) return decoder.DecodeAsync<TPixel>(options, stream, cancellationToken);
{
return null;
}
return await decoder.DecodeAsync<TPixel>(options, stream, cancellationToken).ConfigureAwait(false);
} }
private static Image? Decode(DecoderOptions options, Stream stream) private static Image Decode(DecoderOptions options, Stream stream)
{ {
IImageDecoder? decoder = DiscoverDecoder(options, stream); IImageDecoder decoder = DiscoverDecoder(options, stream);
if (decoder is null)
{
return null;
}
return decoder.Decode(options, stream); return decoder.Decode(options, stream);
} }
private static async Task<Image?> DecodeAsync( private static Task<Image> DecodeAsync(
DecoderOptions options, DecoderOptions options,
Stream stream, Stream stream,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
IImageDecoder? decoder = DiscoverDecoder(options, stream); IImageDecoder decoder = DiscoverDecoder(options, stream);
if (decoder is null) return decoder.DecodeAsync(options, stream, cancellationToken);
{
return null;
}
return await decoder.DecodeAsync(options, stream, cancellationToken).ConfigureAwait(false);
} }
/// <summary> /// <summary>
@ -168,17 +152,10 @@ public abstract partial class Image
/// </summary> /// </summary>
/// <param name="options">The general decoder options.</param> /// <param name="options">The general decoder options.</param>
/// <param name="stream">The stream.</param> /// <param name="stream">The stream.</param>
/// <returns> /// <returns>The <see cref="ImageInfo"/>.</returns>
/// The <see cref="ImageInfo"/> or null if a suitable info detector is not found. private static ImageInfo InternalIdentify(DecoderOptions options, Stream stream)
/// </returns>
private static ImageInfo? InternalIdentify(DecoderOptions options, Stream stream)
{ {
IImageDecoder? decoder = DiscoverDecoder(options, stream); IImageDecoder decoder = DiscoverDecoder(options, stream);
if (decoder is null)
{
return null;
}
return decoder.Identify(options, stream); return decoder.Identify(options, stream);
} }
@ -188,21 +165,13 @@ public abstract partial class Image
/// <param name="options">The general decoder options.</param> /// <param name="options">The general decoder options.</param>
/// <param name="stream">The stream.</param> /// <param name="stream">The stream.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns> /// <returns>The <see cref="ImageInfo"/>.</returns>
/// The <see cref="ImageInfo"/> or null if a suitable info detector is not found. private static Task<ImageInfo> InternalIdentifyAsync(
/// </returns>
private static async Task<ImageInfo?> InternalIdentifyAsync(
DecoderOptions options, DecoderOptions options,
Stream stream, Stream stream,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
IImageDecoder? decoder = DiscoverDecoder(options, stream); IImageDecoder decoder = DiscoverDecoder(options, stream);
return decoder.IdentifyAsync(options, stream, cancellationToken);
if (decoder is null)
{
return null;
}
return await decoder.IdentifyAsync(options, stream, cancellationToken).ConfigureAwait(false);
} }
} }

166
src/ImageSharp/Image.FromBytes.cs

@ -15,21 +15,21 @@ public abstract partial class Image
/// <summary> /// <summary>
/// By reading the header on the provided byte span this calculates the images format. /// By reading the header on the provided byte span this calculates the images format.
/// </summary> /// </summary>
/// <param name="data">The byte span containing encoded image data to read the header from.</param> /// <param name="buffer">The byte span containing encoded image data to read the header from.</param>
/// <param name="format">The format or null if none found.</param> /// <param name="format">The format or null if none found.</param>
/// <returns>returns true when format was detected otherwise false.</returns> /// <returns>returns true when format was detected otherwise false.</returns>
public static bool TryDetectFormat(ReadOnlySpan<byte> data, [NotNullWhen(true)] out IImageFormat? format) public static bool TryDetectFormat(ReadOnlySpan<byte> buffer, [NotNullWhen(true)] out IImageFormat? format)
=> TryDetectFormat(DecoderOptions.Default, data, out format); => TryDetectFormat(DecoderOptions.Default, buffer, out format);
/// <summary> /// <summary>
/// By reading the header on the provided byte span this calculates the images format. /// By reading the header on the provided byte span this calculates the images format.
/// </summary> /// </summary>
/// <param name="options">The general decoder options.</param> /// <param name="options">The general decoder options.</param>
/// <param name="data">The byte span containing encoded image data to read the header from.</param> /// <param name="buffer">The byte span containing encoded image data to read the header from.</param>
/// <param name="format">The mime type or null if none found.</param> /// <param name="format">The mime type or null if none found.</param>
/// <exception cref="ArgumentNullException">The options are null.</exception> /// <exception cref="ArgumentNullException">The options are null.</exception>
/// <returns>returns true when format was detected otherwise false.</returns> /// <returns>returns true when format was detected otherwise false.</returns>
public static bool TryDetectFormat(DecoderOptions options, ReadOnlySpan<byte> data, [NotNullWhen(true)] out IImageFormat? format) public static bool TryDetectFormat(DecoderOptions options, ReadOnlySpan<byte> buffer, [NotNullWhen(true)] out IImageFormat? format)
{ {
Guard.NotNull(options, nameof(options.Configuration)); Guard.NotNull(options, nameof(options.Configuration));
@ -43,7 +43,7 @@ public abstract partial class Image
foreach (IImageFormatDetector detector in configuration.ImageFormatsManager.FormatDetectors) foreach (IImageFormatDetector detector in configuration.ImageFormatsManager.FormatDetectors)
{ {
if (detector.TryDetectFormat(data, out format)) if (detector.TryDetectFormat(buffer, out format))
{ {
return true; return true;
} }
@ -57,7 +57,7 @@ public abstract partial class Image
/// Reads the raw image information from the specified stream without fully decoding it. /// Reads the raw image information from the specified stream without fully decoding it.
/// A return value indicates whether the operation succeeded. /// A return value indicates whether the operation succeeded.
/// </summary> /// </summary>
/// <param name="data">The byte array containing encoded image data to read the header from.</param> /// <param name="buffer">The byte array containing encoded image data to read the header from.</param>
/// <param name="info"> /// <param name="info">
/// When this method returns, contains the raw image information; /// When this method returns, contains the raw image information;
/// otherwise, the default value for the type of the <paramref name="info"/> parameter. /// otherwise, the default value for the type of the <paramref name="info"/> parameter.
@ -66,15 +66,15 @@ public abstract partial class Image
/// <returns><see langword="true"/> if the information can be read; otherwise, <see langword="false"/></returns> /// <returns><see langword="true"/> if the information can be read; otherwise, <see langword="false"/></returns>
/// <exception cref="ArgumentNullException">The data is null.</exception> /// <exception cref="ArgumentNullException">The data is null.</exception>
/// <exception cref="NotSupportedException">The data is not readable.</exception> /// <exception cref="NotSupportedException">The data is not readable.</exception>
public static bool TryIdentify(ReadOnlySpan<byte> data, [NotNullWhen(true)] out ImageInfo? info) public static bool TryIdentify(ReadOnlySpan<byte> buffer, [NotNullWhen(true)] out ImageInfo? info)
=> TryIdentify(DecoderOptions.Default, data, out info); => TryIdentify(DecoderOptions.Default, buffer, out info);
/// <summary> /// <summary>
/// Reads the raw image information from the specified span of bytes without fully decoding it. /// Reads the raw image information from the specified span of bytes without fully decoding it.
/// A return value indicates whether the operation succeeded. /// A return value indicates whether the operation succeeded.
/// </summary> /// </summary>
/// <param name="options">The general decoder options.</param> /// <param name="options">The general decoder options.</param>
/// <param name="data">The byte span containing encoded image data to read the header from.</param> /// <param name="buffer">The byte span containing encoded image data to read the header from.</param>
/// <param name="info"> /// <param name="info">
/// When this method returns, contains the raw image information; /// When this method returns, contains the raw image information;
/// otherwise, the default value for the type of the <paramref name="info"/> parameter. /// otherwise, the default value for the type of the <paramref name="info"/> parameter.
@ -84,141 +84,79 @@ public abstract partial class Image
/// <exception cref="ArgumentNullException">The configuration is null.</exception> /// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The data is null.</exception> /// <exception cref="ArgumentNullException">The data is null.</exception>
/// <exception cref="NotSupportedException">The data is not readable.</exception> /// <exception cref="NotSupportedException">The data is not readable.</exception>
public static unsafe bool TryIdentify(DecoderOptions options, ReadOnlySpan<byte> data, [NotNullWhen(true)] out ImageInfo? info) public static unsafe bool TryIdentify(DecoderOptions options, ReadOnlySpan<byte> buffer, [NotNullWhen(true)] out ImageInfo? info)
{ {
fixed (byte* ptr = data) fixed (byte* ptr = buffer)
{ {
using UnmanagedMemoryStream stream = new(ptr, data.Length); using UnmanagedMemoryStream stream = new(ptr, buffer.Length);
return TryIdentify(options, stream, out info); return TryIdentify(options, stream, out info);
} }
} }
/// <summary> /// <summary>
/// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte span. /// Creates a new instance of the <see cref="Image"/> class from the given byte span.
/// The pixel format is automatically determined by the decoder.
/// </summary> /// </summary>
/// <param name="data">The byte span containing encoded image data.</param> /// <param name="buffer">The byte span containing encoded image data.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <returns><see cref="Image"/>.</returns>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception> /// <exception cref="NotSupportedException">The image format is not supported.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception> /// <exception cref="InvalidImageContentException">The encoded image contains invalid content.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception> /// <exception cref="UnknownImageFormatException">The encoded image format is unknown.</exception>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns> /// <returns>The <see cref="Image"/>.</returns>
public static Image<TPixel> Load<TPixel>(ReadOnlySpan<byte> data) public static Image Load(ReadOnlySpan<byte> buffer)
where TPixel : unmanaged, IPixel<TPixel> => Load(DecoderOptions.Default, buffer);
=> Load<TPixel>(DecoderOptions.Default, data);
/// <summary>
/// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte span.
/// </summary>
/// <param name="data">The byte span containing image data.</param>
/// <param name="format">The mime type of the decoded image.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(ReadOnlySpan<byte> data, out IImageFormat format)
where TPixel : unmanaged, IPixel<TPixel>
=> Load<TPixel>(DecoderOptions.Default, data, out format);
/// <summary> /// <summary>
/// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte span. /// Creates a new instance of the <see cref="Image"/> class from the given byte span.
/// The pixel format is automatically determined by the decoder.
/// </summary> /// </summary>
/// <param name="options">The general decoder options.</param> /// <param name="options">The general decoder options.</param>
/// <param name="data">The byte span containing encoded image data.</param> /// <param name="buffer">The byte span containing encoded image data.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <returns><see cref="Image"/>.</returns>
/// <exception cref="ArgumentNullException">The options are null.</exception> /// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception> /// <exception cref="NotSupportedException">The image format is not supported.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception> /// <exception cref="InvalidImageContentException">The encoded image contains invalid content.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception> /// <exception cref="UnknownImageFormatException">The encoded image format is unknown.</exception>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns> public static unsafe Image Load(DecoderOptions options, ReadOnlySpan<byte> buffer)
public static unsafe Image<TPixel> Load<TPixel>(DecoderOptions options, ReadOnlySpan<byte> data)
where TPixel : unmanaged, IPixel<TPixel>
{ {
fixed (byte* ptr = data) fixed (byte* ptr = buffer)
{ {
using UnmanagedMemoryStream stream = new(ptr, data.Length); using UnmanagedMemoryStream stream = new(ptr, buffer.Length);
return Load<TPixel>(options, stream); return Load(options, stream);
} }
} }
/// <summary> /// <summary>
/// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte span. /// Creates a new instance of the <see cref="Image{TPixel}"/> class from the given byte span.
/// </summary> /// </summary>
/// <param name="options">The general decoder options.</param>
/// <param name="data">The byte span containing image data.</param>
/// <param name="format">The <see cref="IImageFormat"/> of the decoded image.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <exception cref="ArgumentNullException">The options are null.</exception> /// <param name="data">The byte span containing encoded image data.</param>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception> /// <returns><see cref="Image{TPixel}"/>.</returns>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception> /// <exception cref="NotSupportedException">The image format is not supported.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception> /// <exception cref="InvalidImageContentException">The encoded image contains invalid content.</exception>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns> /// <exception cref="UnknownImageFormatException">The encoded image format is unknown.</exception>
public static unsafe Image<TPixel> Load<TPixel>( public static Image<TPixel> Load<TPixel>(ReadOnlySpan<byte> data)
DecoderOptions options,
ReadOnlySpan<byte> data,
out IImageFormat format)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ => Load<TPixel>(DecoderOptions.Default, data);
fixed (byte* ptr = data)
{
using UnmanagedMemoryStream stream = new(ptr, data.Length);
return Load<TPixel>(options, stream, out format);
}
}
/// <summary>
/// Load a new instance of <see cref="Image"/> from the given encoded byte span.
/// </summary>
/// <param name="data">The byte span containing image data.</param>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(ReadOnlySpan<byte> data)
=> Load(DecoderOptions.Default, data);
/// <summary>
/// Load a new instance of <see cref="Image"/> from the given encoded byte array.
/// </summary>
/// <param name="data">The byte span containing image data.</param>
/// <param name="format">The detected format.</param>
/// <exception cref="ArgumentNullException">The decoder is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(ReadOnlySpan<byte> data, out IImageFormat format)
=> Load(DecoderOptions.Default, data, out format);
/// <summary>
/// Decodes a new instance of <see cref="Image"/> from the given encoded byte span.
/// </summary>
/// <param name="options">The general decoder options.</param>
/// <param name="data">The byte span containing image data.</param>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(DecoderOptions options, ReadOnlySpan<byte> data)
=> Load(options, data, out _);
/// <summary> /// <summary>
/// Load a new instance of <see cref="Image"/> from the given encoded byte span. /// Creates a new instance of the <see cref="Image{TPixel}"/> class from the given byte span.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="options">The general decoder options.</param> /// <param name="options">The general decoder options.</param>
/// <param name="data">The byte span containing image data.</param> /// <param name="data">The byte span containing encoded image data.</param>
/// <param name="format">The <see cref="IImageFormat"/> of the decoded image.</param>> /// <returns><see cref="Image{TPixel}"/>.</returns>
/// <exception cref="ArgumentNullException">The options are null.</exception> /// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception> /// <exception cref="NotSupportedException">The image format is not supported.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception> /// <exception cref="InvalidImageContentException">The encoded image contains invalid content.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception> /// <exception cref="UnknownImageFormatException">The encoded image format is unknown.</exception>
/// <returns>The <see cref="Image"/>.</returns> public static unsafe Image<TPixel> Load<TPixel>(DecoderOptions options, ReadOnlySpan<byte> data)
public static unsafe Image Load( where TPixel : unmanaged, IPixel<TPixel>
DecoderOptions options,
ReadOnlySpan<byte> data,
out IImageFormat format)
{ {
fixed (byte* ptr = data) fixed (byte* ptr = data)
{ {
using UnmanagedMemoryStream stream = new(ptr, data.Length); using UnmanagedMemoryStream stream = new(ptr, data.Length);
return Load(options, stream, out format); return Load<TPixel>(options, stream);
} }
} }
} }

255
src/ImageSharp/Image.FromFile.cs

@ -16,22 +16,22 @@ public abstract partial class Image
/// Detects the encoded image format type from the specified file. /// Detects the encoded image format type from the specified file.
/// A return value indicates whether the operation succeeded. /// A return value indicates whether the operation succeeded.
/// </summary> /// </summary>
/// <param name="filePath">The image file to open and to read the header from.</param> /// <param name="path">The image file to open and to read the header from.</param>
/// <param name="format"> /// <param name="format">
/// When this method returns, contains the format that matches the given file; /// When this method returns, contains the format that matches the given file;
/// otherwise, the default value for the type of the <paramref name="format"/> parameter. /// otherwise, the default value for the type of the <paramref name="format"/> parameter.
/// This parameter is passed uninitialized. /// This parameter is passed uninitialized.
/// </param> /// </param>
/// <returns><see langword="true"/> if a match is found; otherwise, <see langword="false"/></returns> /// <returns><see langword="true"/> if a match is found; otherwise, <see langword="false"/></returns>
public static bool TryDetectFormat(string filePath, [NotNullWhen(true)] out IImageFormat? format) public static bool TryDetectFormat(string path, [NotNullWhen(true)] out IImageFormat? format)
=> TryDetectFormat(DecoderOptions.Default, filePath, out format); => TryDetectFormat(DecoderOptions.Default, path, out format);
/// <summary> /// <summary>
/// Detects the encoded image format type from the specified file. /// Detects the encoded image format type from the specified file.
/// A return value indicates whether the operation succeeded. /// A return value indicates whether the operation succeeded.
/// </summary> /// </summary>
/// <param name="options">The general decoder options.</param> /// <param name="options">The general decoder options.</param>
/// <param name="filePath">The image file to open and to read the header from.</param> /// <param name="path">The image file to open and to read the header from.</param>
/// <param name="format"> /// <param name="format">
/// When this method returns, contains the format that matches the given file; /// When this method returns, contains the format that matches the given file;
/// otherwise, the default value for the type of the <paramref name="format"/> parameter. /// otherwise, the default value for the type of the <paramref name="format"/> parameter.
@ -39,11 +39,11 @@ public abstract partial class Image
/// </param> /// </param>
/// <returns><see langword="true"/> if a match is found; otherwise, <see langword="false"/></returns> /// <returns><see langword="true"/> if a match is found; otherwise, <see langword="false"/></returns>
/// <exception cref="ArgumentNullException">The options are null.</exception> /// <exception cref="ArgumentNullException">The options are null.</exception>
public static bool TryDetectFormat(DecoderOptions options, string filePath, [NotNullWhen(true)] out IImageFormat? format) public static bool TryDetectFormat(DecoderOptions options, string path, [NotNullWhen(true)] out IImageFormat? format)
{ {
Guard.NotNull(options, nameof(options)); Guard.NotNull(options, nameof(options));
using Stream file = options.Configuration.FileSystem.OpenRead(filePath); using Stream file = options.Configuration.FileSystem.OpenRead(path);
return TryDetectFormat(options, file, out format); return TryDetectFormat(options, file, out format);
} }
@ -51,31 +51,31 @@ public abstract partial class Image
/// Detects the encoded image format type from the specified file. /// Detects the encoded image format type from the specified file.
/// A return value indicates whether the operation succeeded. /// A return value indicates whether the operation succeeded.
/// </summary> /// </summary>
/// <param name="filePath">The image file to open and to read the header from.</param> /// <param name="path">The image file to open and to read the header from.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>A <see cref="Task{Attempt}"/> representing the asynchronous operation.</returns> /// <returns>A <see cref="Task{Attempt}"/> representing the asynchronous operation.</returns>
public static Task<Attempt<IImageFormat>> TryDetectFormatAsync( public static Task<Attempt<IImageFormat>> TryDetectFormatAsync(
string filePath, string path,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
=> TryDetectFormatAsync(DecoderOptions.Default, filePath, cancellationToken); => TryDetectFormatAsync(DecoderOptions.Default, path, cancellationToken);
/// <summary> /// <summary>
/// Detects the encoded image format type from the specified file. /// Detects the encoded image format type from the specified file.
/// A return value indicates whether the operation succeeded. /// A return value indicates whether the operation succeeded.
/// </summary> /// </summary>
/// <param name="options">The general decoder options.</param> /// <param name="options">The general decoder options.</param>
/// <param name="filePath">The image file to open and to read the header from.</param> /// <param name="path">The image file to open and to read the header from.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The options are null.</exception> /// <exception cref="ArgumentNullException">The options are null.</exception>
/// <returns>A <see cref="Task{Attempt}"/> representing the asynchronous operation.</returns> /// <returns>A <see cref="Task{Attempt}"/> representing the asynchronous operation.</returns>
public static async Task<Attempt<IImageFormat>> TryDetectFormatAsync( public static async Task<Attempt<IImageFormat>> TryDetectFormatAsync(
DecoderOptions options, DecoderOptions options,
string filePath, string path,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
Guard.NotNull(options, nameof(options)); Guard.NotNull(options, nameof(options));
using Stream stream = options.Configuration.FileSystem.OpenRead(filePath); using Stream stream = options.Configuration.FileSystem.OpenRead(path);
return await TryDetectFormatAsync(options, stream, cancellationToken).ConfigureAwait(false); return await TryDetectFormatAsync(options, stream, cancellationToken).ConfigureAwait(false);
} }
@ -83,22 +83,22 @@ public abstract partial class Image
/// Reads the raw image information from the specified file path 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. /// A return value indicates whether the operation succeeded.
/// </summary> /// </summary>
/// <param name="filePath">The image file to open and to read the header from.</param> /// <param name="path">The image file to open and to read the header from.</param>
/// <param name="info"> /// <param name="info">
/// When this method returns, contains the raw image information; /// When this method returns, contains the raw image information;
/// otherwise, the default value for the type of the <paramref name="info"/> parameter. /// otherwise, the default value for the type of the <paramref name="info"/> parameter.
/// This parameter is passed uninitialized. /// This parameter is passed uninitialized.
/// </param> /// </param>
/// <returns><see langword="true"/> if the information can be read; otherwise, <see langword="false"/></returns> /// <returns><see langword="true"/> if the information can be read; otherwise, <see langword="false"/></returns>
public static bool TryIdentify(string filePath, [NotNullWhen(true)] out ImageInfo? info) public static bool TryIdentify(string path, [NotNullWhen(true)] out ImageInfo? info)
=> TryIdentify(DecoderOptions.Default, filePath, out info); => TryIdentify(DecoderOptions.Default, path, out info);
/// <summary> /// <summary>
/// Reads the raw image information from the specified file path 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. /// A return value indicates whether the operation succeeded.
/// </summary> /// </summary>
/// <param name="options">The general decoder options.</param> /// <param name="options">The general decoder options.</param>
/// <param name="filePath">The image file to open and to read the header from.</param> /// <param name="path">The image file to open and to read the header from.</param>
/// <param name="info"> /// <param name="info">
/// When this method returns, contains the raw image information; /// When this method returns, contains the raw image information;
/// otherwise, the default value for the type of the <paramref name="info"/> parameter. /// otherwise, the default value for the type of the <paramref name="info"/> parameter.
@ -106,11 +106,11 @@ public abstract partial class Image
/// </param> /// </param>
/// <returns><see langword="true"/> if the information can be read; otherwise, <see langword="false"/></returns> /// <returns><see langword="true"/> if the information can be read; otherwise, <see langword="false"/></returns>
/// <exception cref="ArgumentNullException">The options are null.</exception> /// <exception cref="ArgumentNullException">The options are null.</exception>
public static bool TryIdentify(DecoderOptions options, string filePath, [NotNullWhen(true)] out ImageInfo? info) public static bool TryIdentify(DecoderOptions options, string path, [NotNullWhen(true)] out ImageInfo? info)
{ {
Guard.NotNull(options, nameof(options)); Guard.NotNull(options, nameof(options));
using Stream stream = options.Configuration.FileSystem.OpenRead(filePath); using Stream stream = options.Configuration.FileSystem.OpenRead(path);
return TryIdentify(options, stream, out info); return TryIdentify(options, stream, out info);
} }
@ -118,197 +118,134 @@ public abstract partial class Image
/// Reads the raw image information from the specified stream without fully decoding it. /// Reads the raw image information from the specified stream without fully decoding it.
/// A return value indicates whether the operation succeeded. /// A return value indicates whether the operation succeeded.
/// </summary> /// </summary>
/// <param name="filePath">The image file to open and to read the header from.</param> /// <param name="path">The image file to open and to read the header from.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception> /// <exception cref="ArgumentNullException">The options are null.</exception>
/// <returns> /// <returns>
/// The <see cref="Task{Attempt}"/> representing the asynchronous operation. /// The <see cref="Task{Attempt}"/> representing the asynchronous operation.
/// </returns> /// </returns>
public static Task<Attempt<ImageInfo>> TryIdentifyAsync( public static Task<Attempt<ImageInfo>> TryIdentifyAsync(
string filePath, string path,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
=> TryIdentifyAsync(DecoderOptions.Default, filePath, cancellationToken); => TryIdentifyAsync(DecoderOptions.Default, path, cancellationToken);
/// <summary> /// <summary>
/// Reads the raw image information from the specified stream without fully decoding it. /// Reads the raw image information from the specified stream without fully decoding it.
/// A return value indicates whether the operation succeeded. /// A return value indicates whether the operation succeeded.
/// </summary> /// </summary>
/// <param name="options">The general decoder options.</param> /// <param name="options">The general decoder options.</param>
/// <param name="filePath">The image file to open and to read the header from.</param> /// <param name="path">The image file to open and to read the header from.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception> /// <exception cref="ArgumentNullException">The options are null.</exception>
/// <returns> /// <returns>
/// The <see cref="Task{Attempt}"/> representing the asynchronous operation. /// The <see cref="Task{Attempt}"/> representing the asynchronous operation.
/// </returns> /// </returns>
public static async Task<Attempt<ImageInfo>> TryIdentifyAsync( public static async Task<Attempt<ImageInfo>> TryIdentifyAsync(
DecoderOptions options, DecoderOptions options,
string filePath, string path,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
Guard.NotNull(options, nameof(options)); Guard.NotNull(options, nameof(options));
using Stream stream = options.Configuration.FileSystem.OpenRead(filePath); using Stream stream = options.Configuration.FileSystem.OpenRead(path);
return await TryIdentifyAsync(options, stream, cancellationToken).ConfigureAwait(false); return await TryIdentifyAsync(options, stream, cancellationToken).ConfigureAwait(false);
} }
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image"/> class from the given file. /// Creates a new instance of the <see cref="Image"/> class from the given file path.
/// The pixel format is automatically determined by the decoder.
/// </summary> /// </summary>
/// <param name="path">The file path to the image.</param> /// <param name="path">The file path to the image.</param>
/// <exception cref="NotSupportedException"> /// <returns><see cref="Image"/>.</returns>
/// Thrown if the stream is not readable nor seekable. /// <exception cref="ArgumentNullException">The path is null.</exception>
/// </exception> /// <exception cref="NotSupportedException">The file stream is not readable or the image format is not supported.</exception>
/// <returns>The <see cref="Image"/>.</returns> /// <exception cref="InvalidImageContentException">The encoded image contains invalid content.</exception>
/// <exception cref="UnknownImageFormatException">The encoded image format is unknown.</exception>
public static Image Load(string path) public static Image Load(string path)
=> Load(DecoderOptions.Default, path); => Load(DecoderOptions.Default, path);
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image"/> class from the given file. /// Creates a new instance of the <see cref="Image"/> class from the given file path.
/// </summary> /// The pixel format is automatically determined by the decoder.
/// <param name="path">The file path to the image.</param>
/// <param name="format">The mime type of the decoded image.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image Load(string path, out IImageFormat format)
=> Load(DecoderOptions.Default, path, out format);
/// <summary>
/// Create a new instance of the <see cref="Image"/> class from the given file.
/// </summary> /// </summary>
/// <param name="options">The general decoder options.</param> /// <param name="options">The general decoder options.</param>
/// <param name="path">The file path to the image.</param> /// <param name="path">The file path to the image.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception> /// <returns><see cref="Image"/>.</returns>
/// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="ArgumentNullException">The path is null.</exception> /// <exception cref="ArgumentNullException">The path is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception> /// <exception cref="NotSupportedException">The file stream is not readable or the image format is not supported.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception> /// <exception cref="InvalidImageContentException">The encoded image contains invalid content.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception> /// <exception cref="UnknownImageFormatException">The encoded image format is unknown.</exception>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(DecoderOptions options, string path) public static Image Load(DecoderOptions options, string path)
=> Load(options, path, out _);
/// <summary>
/// Create a new instance of the <see cref="Image"/> class from the given file.
/// </summary>
/// <param name="options">The general decoder options.</param>
/// <param name="path">The file path to the image.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The path is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>A <see cref="Task{Image}"/> representing the asynchronous operation.</returns>
public static async Task<Image> LoadAsync(
DecoderOptions options,
string path,
CancellationToken cancellationToken = default)
{ {
Guard.NotNull(options, nameof(options));
Guard.NotNull(path, nameof(path));
using Stream stream = options.Configuration.FileSystem.OpenRead(path); using Stream stream = options.Configuration.FileSystem.OpenRead(path);
(Image img, _) = await LoadWithFormatAsync(options, stream, cancellationToken) return Load(options, stream);
.ConfigureAwait(false);
return img;
} }
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image"/> class from the given file. /// Creates a new instance of the <see cref="Image"/> class from the given file path.
/// The pixel format is automatically determined by the decoder.
/// </summary> /// </summary>
/// <param name="path">The file path to the image.</param> /// <param name="path">The file path to the image.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The path is null.</exception>
/// <exception cref="ArgumentNullException">The decoder is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>A <see cref="Task{Image}"/> representing the asynchronous operation.</returns> /// <returns>A <see cref="Task{Image}"/> representing the asynchronous operation.</returns>
/// <exception cref="ArgumentNullException">The path is null.</exception>
/// <exception cref="NotSupportedException">The file stream is not readable or the image format is not supported.</exception>
/// <exception cref="InvalidImageContentException">The encoded image contains invalid content.</exception>
/// <exception cref="UnknownImageFormatException">The encoded image format is unknown.</exception>
public static Task<Image> LoadAsync(string path, CancellationToken cancellationToken = default) public static Task<Image> LoadAsync(string path, CancellationToken cancellationToken = default)
=> LoadAsync(DecoderOptions.Default, path, cancellationToken); => LoadAsync(DecoderOptions.Default, path, cancellationToken);
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image"/> class from the given file. /// Creates a new instance of the <see cref="Image"/> class from the given file path.
/// </summary> /// The pixel format is automatically determined by the decoder.
/// <param name="path">The file path to the image.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The path is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A <see cref="Task{Image}"/> representing the asynchronous operation.</returns>
public static Task<Image<TPixel>> LoadAsync<TPixel>(string path, CancellationToken cancellationToken = default)
where TPixel : unmanaged, IPixel<TPixel>
=> LoadAsync<TPixel>(DecoderOptions.Default, path, cancellationToken);
/// <summary>
/// Create a new instance of the <see cref="Image"/> class from the given file.
/// </summary> /// </summary>
/// <param name="options">The general decoder options.</param> /// <param name="options">The general decoder options.</param>
/// <param name="path">The file path to the image.</param> /// <param name="path">The file path to the image.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The path is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A <see cref="Task{Image}"/> representing the asynchronous operation.</returns> /// <returns>A <see cref="Task{Image}"/> representing the asynchronous operation.</returns>
public static async Task<Image<TPixel>> LoadAsync<TPixel>( /// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="ArgumentNullException">The path is null.</exception>
/// <exception cref="NotSupportedException">The file stream is not readable or the image format is not supported.</exception>
/// <exception cref="InvalidImageContentException">The encoded image contains invalid content.</exception>
/// <exception cref="UnknownImageFormatException">The encoded image format is unknown.</exception>
public static async Task<Image> LoadAsync(
DecoderOptions options, DecoderOptions options,
string path, string path,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
where TPixel : unmanaged, IPixel<TPixel>
{ {
Guard.NotNull(options, nameof(options));
using Stream stream = options.Configuration.FileSystem.OpenRead(path); using Stream stream = options.Configuration.FileSystem.OpenRead(path);
(Image<TPixel> img, _) = return await LoadAsync(options, stream, cancellationToken).ConfigureAwait(false);
await LoadWithFormatAsync<TPixel>(options, stream, cancellationToken).ConfigureAwait(false);
return img;
} }
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given file. /// Creates a new instance of the <see cref="Image{TPixel}"/> class from the given file path.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="path">The file path to the image.</param> /// <param name="path">The file path to the image.</param>
/// <returns><see cref="Image{TPixel}"/>.</returns>
/// <exception cref="ArgumentNullException">The path is null.</exception> /// <exception cref="ArgumentNullException">The path is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception> /// <exception cref="NotSupportedException">The file stream is not readable or the image format is not supported.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception> /// <exception cref="InvalidImageContentException">The encoded image contains invalid content.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception> /// <exception cref="UnknownImageFormatException">The encoded image format is unknown.</exception>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(string path) public static Image<TPixel> Load<TPixel>(string path)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
=> Load<TPixel>(DecoderOptions.Default, path); => Load<TPixel>(DecoderOptions.Default, path);
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given file. /// Creates a new instance of the <see cref="Image{TPixel}"/> class from the given file path.
/// </summary> /// </summary>
/// <param name="path">The file path to the image.</param>
/// <param name="format">The mime type of the decoded image.</param>
/// <exception cref="ArgumentNullException">The path is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(string path, out IImageFormat format)
where TPixel : unmanaged, IPixel<TPixel>
=> Load<TPixel>(DecoderOptions.Default, path, out format);
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given file.
/// </summary>
/// <param name="options">The general decoder options.</param> /// <param name="options">The general decoder options.</param>
/// <param name="path">The file path to the image.</param> /// <param name="path">The file path to the image.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception> /// <returns><see cref="Image{TPixel}"/>.</returns>
/// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="ArgumentNullException">The path is null.</exception> /// <exception cref="ArgumentNullException">The path is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception> /// <exception cref="NotSupportedException">The file stream is not readable or the image format is not supported.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception> /// <exception cref="InvalidImageContentException">The encoded image contains invalid content.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception> /// <exception cref="UnknownImageFormatException">The encoded image format is unknown.</exception>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(DecoderOptions options, string path) public static Image<TPixel> Load<TPixel>(DecoderOptions options, string path)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
@ -320,47 +257,43 @@ public abstract partial class Image
} }
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given file. /// Creates a new instance of the <see cref="Image{TPixel}"/> class from the given file path.
/// </summary> /// </summary>
/// <param name="options">The general decoder options.</param> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="path">The file path to the image.</param> /// <param name="path">The file path to the image.</param>
/// <param name="format">The mime type of the decoded image.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception> /// <returns>A <see cref="Task{Image}"/> representing the asynchronous operation.</returns>
/// <exception cref="ArgumentNullException">The path is null.</exception> /// <exception cref="ArgumentNullException">The path is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception> /// <exception cref="NotSupportedException">The file stream is not readable or the image format is not supported.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception> /// <exception cref="InvalidImageContentException">The encoded image contains invalid content.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception> /// <exception cref="UnknownImageFormatException">The encoded image format is unknown.</exception>
/// <typeparam name="TPixel">The pixel format.</typeparam> public static Task<Image<TPixel>> LoadAsync<TPixel>(string path, CancellationToken cancellationToken = default)
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(DecoderOptions options, string path, out IImageFormat format)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ => LoadAsync<TPixel>(DecoderOptions.Default, path, cancellationToken);
Guard.NotNull(options, nameof(options));
Guard.NotNull(path, nameof(path));
using Stream stream = options.Configuration.FileSystem.OpenRead(path);
return Load<TPixel>(options, stream, out format);
}
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image"/> class from the given file. /// Creates a new instance of the <see cref="Image{TPixel}"/> class from the given file path.
/// The pixel type is selected by the decoder.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="options">The general decoder options.</param> /// <param name="options">The general decoder options.</param>
/// <param name="path">The file path to the image.</param> /// <param name="path">The file path to the image.</param>
/// <param name="format">The mime type of the decoded image.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception> /// <returns>A <see cref="Task{Image}"/> representing the asynchronous operation.</returns>
/// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="ArgumentNullException">The path is null.</exception> /// <exception cref="ArgumentNullException">The path is null.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception> /// <exception cref="NotSupportedException">The file stream is not readable or the image format is not supported.</exception>
/// <exception cref="NotSupportedException">Image format is not supported.</exception> /// <exception cref="InvalidImageContentException">The encoded image contains invalid content.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception> /// <exception cref="UnknownImageFormatException">The encoded image format is unknown.</exception>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns> public static async Task<Image<TPixel>> LoadAsync<TPixel>(
public static Image Load(DecoderOptions options, string path, out IImageFormat format) DecoderOptions options,
string path,
CancellationToken cancellationToken = default)
where TPixel : unmanaged, IPixel<TPixel>
{ {
Guard.NotNull(options, nameof(options)); Guard.NotNull(options, nameof(options));
Guard.NotNull(path, nameof(path)); Guard.NotNull(path, nameof(path));
using Stream stream = options.Configuration.FileSystem.OpenRead(path); using Stream stream = options.Configuration.FileSystem.OpenRead(path);
return Load(options, stream, out format); return await LoadAsync<TPixel>(options, stream, cancellationToken).ConfigureAwait(false);
} }
} }

291
src/ImageSharp/Image.FromStream.cs

@ -2,8 +2,6 @@
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Text;
using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
@ -136,7 +134,6 @@ public abstract partial class Image
/// </summary> /// </summary>
/// <param name="stream">The image stream to read the information from.</param> /// <param name="stream">The image stream to read the information from.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="ArgumentNullException">The stream is null.</exception> /// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable.</exception> /// <exception cref="NotSupportedException">The stream is not readable.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception> /// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
@ -177,296 +174,130 @@ public abstract partial class Image
} }
/// <summary> /// <summary>
/// Decode a new instance of the <see cref="Image"/> class from the given stream. /// Creates a new instance of the <see cref="Image"/> class from the given stream.
/// The pixel format is selected by the decoder. /// The pixel format is automatically determined by the decoder.
/// </summary>
/// <param name="stream">The stream containing image information.</param>
/// <param name="format">The format type of the decoded image.</param>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(Stream stream, out IImageFormat format)
=> Load(DecoderOptions.Default, stream, out format);
/// <summary>
/// Decode a new instance of the <see cref="Image"/> class from the given stream.
/// The pixel format is selected by the decoder.
/// </summary> /// </summary>
/// <param name="stream">The stream containing image information.</param> /// <param name="stream">The stream containing image information.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <returns><see cref="Image"/>.</returns>
/// <exception cref="ArgumentNullException">The stream is null.</exception> /// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception> /// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception> /// <exception cref="InvalidImageContentException">The encoded image contains invalid content.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception> /// <exception cref="UnknownImageFormatException">The encoded image format is unknown.</exception>
/// <returns>A <see cref="Task{ValueTuple}"/> representing the asynchronous operation.</returns> public static Image Load(Stream stream)
public static Task<(Image Image, IImageFormat Format)> LoadWithFormatAsync(Stream stream, CancellationToken cancellationToken = default) => Load(DecoderOptions.Default, stream);
=> LoadWithFormatAsync(DecoderOptions.Default, stream, cancellationToken);
/// <summary> /// <summary>
/// Decode a new instance of the <see cref="Image"/> class from the given stream. /// Creates a new instance of the <see cref="Image"/> class from the given stream.
/// The pixel format is selected by the decoder. /// The pixel format is automatically determined by the decoder.
/// </summary> /// </summary>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The stream containing image information.</param> /// <param name="stream">The stream containing image information.</param>
/// <returns><see cref="Image"/>.</returns>
/// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="ArgumentNullException">The stream is null.</exception> /// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception> /// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception> /// <exception cref="InvalidImageContentException">The encoded image contains invalid content.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception> /// <exception cref="UnknownImageFormatException">The encoded image format is unknown.</exception>
/// <returns>The <see cref="Image"/>.</returns> public static Image Load(DecoderOptions options, Stream stream)
public static Image Load(Stream stream) => Load(DecoderOptions.Default, stream); => WithSeekableStream(options, stream, s => Decode(options, s));
/// <summary> /// <summary>
/// Decode a new instance of the <see cref="Image"/> class from the given stream. /// Creates a new instance of the <see cref="Image"/> class from the given stream.
/// The pixel format is selected by the decoder. /// The pixel format is automatically determined by the decoder.
/// </summary> /// </summary>
/// <param name="stream">The stream containing image information.</param> /// <param name="stream">The stream containing image information.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>A <see cref="Task{Image}"/> representing the asynchronous operation.</returns>
/// <exception cref="ArgumentNullException">The stream is null.</exception> /// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception> /// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception> /// <exception cref="InvalidImageContentException">The encoded image contains invalid content.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception> /// <exception cref="UnknownImageFormatException">The encoded image format is unknown.</exception>
/// <returns>A <see cref="Task{Image}"/> representing the asynchronous operation.</returns>
public static Task<Image> LoadAsync(Stream stream, CancellationToken cancellationToken = default) public static Task<Image> LoadAsync(Stream stream, CancellationToken cancellationToken = default)
=> LoadAsync(DecoderOptions.Default, stream, cancellationToken); => LoadAsync(DecoderOptions.Default, stream, cancellationToken);
/// <summary> /// <summary>
/// Decode a new instance of the <see cref="Image"/> class from the given stream. /// Creates a new instance of the <see cref="Image"/> class from the given stream.
/// </summary> /// The pixel format is automatically determined by the decoder.
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The stream containing image information.</param>
/// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>A new <see cref="Image"/>.</returns>
public static Image Load(DecoderOptions options, Stream stream)
=> Load(options, stream, out _);
/// <summary>
/// Decode a new instance of the <see cref="Image"/> class from the given stream.
/// </summary> /// </summary>
/// <param name="options">The general decoder options.</param> /// <param name="options">The general decoder options.</param>
/// <param name="stream">The stream containing image information.</param> /// <param name="stream">The stream containing image information.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>A <see cref="Task{Image}"/> representing the asynchronous operation.</returns>
/// <exception cref="ArgumentNullException">The options are null.</exception> /// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="ArgumentNullException">The stream is null.</exception> /// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception> /// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception> /// <exception cref="InvalidImageContentException">The encoded image contains invalid content.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception> /// <exception cref="UnknownImageFormatException">The encoded image format is unknown.</exception>
/// <returns>A <see cref="Task{Image}"/> representing the asynchronous operation.</returns> public static Task<Image> LoadAsync(
public static async Task<Image> LoadAsync(DecoderOptions options, Stream stream, CancellationToken cancellationToken = default) DecoderOptions options,
=> (await LoadWithFormatAsync(options, stream, cancellationToken).ConfigureAwait(false)).Image; Stream stream,
CancellationToken cancellationToken = default)
=> WithSeekableStreamAsync(options, stream, (s, ct) => DecodeAsync(options, s, ct), cancellationToken);
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream. /// Creates a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="stream">The stream containing image information.</param> /// <param name="stream">The stream containing image information.</param>
/// <returns><see cref="Image{TPixel}"/>.</returns>
/// <exception cref="ArgumentNullException">The stream is null.</exception> /// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception> /// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception> /// <exception cref="InvalidImageContentException">The encoded image contains invalid content.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception> /// <exception cref="UnknownImageFormatException">The encoded image format is unknown.</exception>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(Stream stream) public static Image<TPixel> Load<TPixel>(Stream stream)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
=> Load<TPixel>(DecoderOptions.Default, stream); => Load<TPixel>(DecoderOptions.Default, stream);
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream. /// Creates a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
/// </summary>
/// <param name="stream">The stream containing image information.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A <see cref="Task{Image}"/> representing the asynchronous operation.</returns>
public static Task<Image<TPixel>> LoadAsync<TPixel>(Stream stream, CancellationToken cancellationToken = default)
where TPixel : unmanaged, IPixel<TPixel>
=> LoadAsync<TPixel>(DecoderOptions.Default, stream, cancellationToken);
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
/// </summary> /// </summary>
/// <param name="stream">The stream containing image information.</param>
/// <param name="format">The format type of the decoded image.</param>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(Stream stream, out IImageFormat format)
where TPixel : unmanaged, IPixel<TPixel>
=> Load<TPixel>(DecoderOptions.Default, stream, out format);
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
/// </summary>
/// <param name="stream">The stream containing image information.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A <see cref="Task{ValueTuple}"/> representing the asynchronous operation.</returns>
public static Task<(Image<TPixel> Image, IImageFormat Format)> LoadWithFormatAsync<TPixel>(Stream stream, CancellationToken cancellationToken = default)
where TPixel : unmanaged, IPixel<TPixel>
=> LoadWithFormatAsync<TPixel>(DecoderOptions.Default, stream, cancellationToken);
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
/// </summary>
/// <param name="options">The general decoder options.</param> /// <param name="options">The general decoder options.</param>
/// <param name="stream">The stream containing image information.</param> /// <param name="stream">The stream containing image information.</param>
/// <returns><see cref="Image{TPixel}"/>.</returns>
/// <exception cref="ArgumentNullException">The options are null.</exception> /// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="ArgumentNullException">The stream is null.</exception> /// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception> /// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception> /// <exception cref="InvalidImageContentException">The encoded image contains invalid content.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception> /// <exception cref="UnknownImageFormatException">The encoded image format is unknown.</exception>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(DecoderOptions options, Stream stream) public static Image<TPixel> Load<TPixel>(DecoderOptions options, Stream stream)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
=> Load<TPixel>(options, stream, out IImageFormat _); => WithSeekableStream(options, stream, s => Decode<TPixel>(options, s));
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream. /// Creates a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
/// </summary> /// </summary>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The stream containing image information.</param>
/// <param name="format">The format type of the decoded image.</param>
/// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static Image<TPixel> Load<TPixel>(DecoderOptions options, Stream stream, out IImageFormat format)
where TPixel : unmanaged, IPixel<TPixel>
{
Image<TPixel>? image = WithSeekableStream(options, stream, s => Decode<TPixel>(options, s));
if (image is null)
{
ThrowNotLoaded(options);
}
format = image.Metadata.DecodedImageFormat!;
return image;
}
/// <summary>
/// Create a new instance of the <see cref="Image"/> class from the given stream.
/// </summary>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The stream containing image information.</param> /// <param name="stream">The stream containing image information.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The options are null.</exception> /// <returns>A <see cref="Task{Image}"/> representing the asynchronous operation.</returns>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>A <see cref="Task{ValueTuple}"/> representing the asynchronous operation.</returns>
public static async Task<(Image Image, IImageFormat Format)> LoadWithFormatAsync(
DecoderOptions options,
Stream stream,
CancellationToken cancellationToken = default)
{
Image? image = await WithSeekableStreamAsync(options, stream, (s, ct) => DecodeAsync(options, s, ct), cancellationToken)
.ConfigureAwait(false);
if (image is null)
{
ThrowNotLoaded(options);
}
return new(image, image.Metadata.DecodedImageFormat!);
}
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
/// </summary>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The stream containing image information.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="ArgumentNullException">The stream is null.</exception> /// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception> /// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception> /// <exception cref="InvalidImageContentException">The encoded image contains invalid content.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception> /// <exception cref="UnknownImageFormatException">The encoded image format is unknown.</exception>
/// <typeparam name="TPixel">The pixel format.</typeparam> public static Task<Image<TPixel>> LoadAsync<TPixel>(Stream stream, CancellationToken cancellationToken = default)
/// <returns>A <see cref="Task{ValueTuple}"/> representing the asynchronous operation.</returns>
public static async Task<(Image<TPixel> Image, IImageFormat Format)> LoadWithFormatAsync<TPixel>(
DecoderOptions options,
Stream stream,
CancellationToken cancellationToken = default)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ => LoadAsync<TPixel>(DecoderOptions.Default, stream, cancellationToken);
Image<TPixel>? image = await WithSeekableStreamAsync(options, stream, (s, ct) => DecodeAsync<TPixel>(options, s, ct), cancellationToken)
.ConfigureAwait(false);
if (image is null)
{
ThrowNotLoaded(options);
}
return new(image, image.Metadata.DecodedImageFormat!);
}
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream. /// Creates a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="options">The general decoder options.</param> /// <param name="options">The general decoder options.</param>
/// <param name="stream">The stream containing image information.</param> /// <param name="stream">The stream containing image information.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>A <see cref="Task{Image}"/> representing the asynchronous operation.</returns>
/// <exception cref="ArgumentNullException">The options are null.</exception> /// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="ArgumentNullException">The stream is null.</exception> /// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception> /// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception> /// <exception cref="InvalidImageContentException">The encoded image contains invalid content.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception> /// <exception cref="UnknownImageFormatException">The encoded image format is unknown.</exception>
/// <typeparam name="TPixel">The pixel format.</typeparam> public static Task<Image<TPixel>> LoadAsync<TPixel>(
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static async Task<Image<TPixel>> LoadAsync<TPixel>(
DecoderOptions options, DecoderOptions options,
Stream stream, Stream stream,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ => WithSeekableStreamAsync(options, stream, (s, ct) => DecodeAsync<TPixel>(options, s, ct), cancellationToken);
(Image<TPixel> img, _) = await LoadWithFormatAsync<TPixel>(options, stream, cancellationToken)
.ConfigureAwait(false);
return img;
}
/// <summary>
/// Decode a new instance of the <see cref="Image"/> class from the given stream.
/// The pixel format is selected by the decoder.
/// </summary>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The stream containing image information.</param>
/// <param name="format">The format type of the decoded image.</param>
/// <exception cref="ArgumentNullException">The options are null.</exception>
/// <exception cref="ArgumentNullException">The stream is null.</exception>
/// <exception cref="NotSupportedException">The stream is not readable or the image format is not supported.</exception>
/// <exception cref="UnknownImageFormatException">Image format not recognised.</exception>
/// <exception cref="InvalidImageContentException">Image contains invalid content.</exception>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image Load(DecoderOptions options, Stream stream, out IImageFormat format)
{
Image? image = WithSeekableStream(options, stream, s => Decode(options, s));
if (image is null)
{
ThrowNotLoaded(options);
}
format = image.Metadata.DecodedImageFormat!;
return image;
}
/// <summary> /// <summary>
/// Performs the given action against the stream ensuring that it is seekable. /// Performs the given action against the stream ensuring that it is seekable.
@ -549,18 +380,4 @@ public abstract partial class Image
return await action(memoryStream, cancellationToken).ConfigureAwait(false); return await action(memoryStream, cancellationToken).ConfigureAwait(false);
} }
[DoesNotReturn]
private static void ThrowNotLoaded(DecoderOptions options)
{
StringBuilder sb = new();
sb.AppendLine("Image cannot be loaded. Available decoders:");
foreach (KeyValuePair<IImageFormat, IImageDecoder> val in options.Configuration.ImageFormatsManager.ImageDecoders)
{
sb.AppendFormat(CultureInfo.InvariantCulture, " - {0} : {1}{2}", val.Key.Name, val.Value.GetType().Name, Environment.NewLine);
}
throw new UnknownImageFormatException(sb.ToString());
}
} }

2
src/ImageSharp/Image.LoadPixelData.cs

@ -72,7 +72,7 @@ public abstract partial class Image
int count = width * height; int count = width * height;
Guard.MustBeGreaterThanOrEqualTo(data.Length, count, nameof(data)); Guard.MustBeGreaterThanOrEqualTo(data.Length, count, nameof(data));
var image = new Image<TPixel>(configuration, width, height); Image<TPixel> image = new(configuration, width, height);
data = data[..count]; data = data[..count];
data.CopyTo(image.Frames.RootFrame.PixelBuffer.FastMemoryGroup); data.CopyTo(image.Frames.RootFrame.PixelBuffer.FastMemoryGroup);

4
src/ImageSharp/ImageExtensions.cs

@ -95,7 +95,7 @@ public static partial class ImageExtensions
throw new NotSupportedException("Cannot write to the stream."); throw new NotSupportedException("Cannot write to the stream.");
} }
IImageEncoder encoder = source.GetConfiguration().ImageFormatsManager.FindEncoder(format); IImageEncoder encoder = source.GetConfiguration().ImageFormatsManager.GetEncoder(format);
if (encoder is null) if (encoder is null)
{ {
@ -139,7 +139,7 @@ public static partial class ImageExtensions
throw new NotSupportedException("Cannot write to the stream."); throw new NotSupportedException("Cannot write to the stream.");
} }
IImageEncoder encoder = source.GetConfiguration().ImageFormatsManager.FindEncoder(format); IImageEncoder encoder = source.GetConfiguration().ImageFormatsManager.GetEncoder(format);
if (encoder is null) if (encoder is null)
{ {

72
tests/ImageSharp.Tests/Formats/Bmp/ImageExtensionsTest.cs

@ -15,15 +15,13 @@ public class ImageExtensionsTest
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest));
string file = Path.Combine(dir, "SaveAsBmp_Path.bmp"); string file = Path.Combine(dir, "SaveAsBmp_Path.bmp");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
image.SaveAsBmp(file); image.SaveAsBmp(file);
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is BmpFormat);
Assert.Equal("image/bmp", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
@ -32,15 +30,13 @@ public class ImageExtensionsTest
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest));
string file = Path.Combine(dir, "SaveAsBmpAsync_Path.bmp"); string file = Path.Combine(dir, "SaveAsBmpAsync_Path.bmp");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
await image.SaveAsBmpAsync(file); await image.SaveAsBmpAsync(file);
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is BmpFormat);
Assert.Equal("image/bmp", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
@ -49,15 +45,13 @@ public class ImageExtensionsTest
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions));
string file = Path.Combine(dir, "SaveAsBmp_Path_Encoder.bmp"); string file = Path.Combine(dir, "SaveAsBmp_Path_Encoder.bmp");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
image.SaveAsBmp(file, new BmpEncoder()); image.SaveAsBmp(file, new BmpEncoder());
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is BmpFormat);
Assert.Equal("image/bmp", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
@ -66,86 +60,76 @@ public class ImageExtensionsTest
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions));
string file = Path.Combine(dir, "SaveAsBmpAsync_Path_Encoder.bmp"); string file = Path.Combine(dir, "SaveAsBmpAsync_Path_Encoder.bmp");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
await image.SaveAsBmpAsync(file, new BmpEncoder()); await image.SaveAsBmpAsync(file, new BmpEncoder());
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is BmpFormat);
Assert.Equal("image/bmp", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public void SaveAsBmp_Stream() public void SaveAsBmp_Stream()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
image.SaveAsBmp(memoryStream); image.SaveAsBmp(memoryStream);
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is BmpFormat);
Assert.Equal("image/bmp", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public async Task SaveAsBmpAsync_StreamAsync() public async Task SaveAsBmpAsync_StreamAsync()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
await image.SaveAsBmpAsync(memoryStream); await image.SaveAsBmpAsync(memoryStream);
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is BmpFormat);
Assert.Equal("image/bmp", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public void SaveAsBmp_Stream_Encoder() public void SaveAsBmp_Stream_Encoder()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
image.SaveAsBmp(memoryStream, new BmpEncoder()); image.SaveAsBmp(memoryStream, new BmpEncoder());
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is BmpFormat);
Assert.Equal("image/bmp", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public async Task SaveAsBmpAsync_Stream_Encoder() public async Task SaveAsBmpAsync_Stream_Encoder()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
await image.SaveAsBmpAsync(memoryStream, new BmpEncoder()); await image.SaveAsBmpAsync(memoryStream, new BmpEncoder());
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is BmpFormat);
Assert.Equal("image/bmp", mime.DefaultMimeType);
}
} }
} }

9
tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs

@ -207,10 +207,10 @@ public class GeneralFormatTests
foreach (TestFile file in Files) foreach (TestFile file in Files)
{ {
byte[] serialized; byte[] serialized;
using (Image image = Image.Load(file.Bytes, out IImageFormat mimeType)) using (Image image = Image.Load(file.Bytes))
using (MemoryStream memoryStream = new()) using (MemoryStream memoryStream = new())
{ {
image.Save(memoryStream, mimeType); image.Save(memoryStream, image.Metadata.DecodedImageFormat);
memoryStream.Flush(); memoryStream.Flush();
serialized = memoryStream.ToArray(); serialized = memoryStream.ToArray();
} }
@ -264,14 +264,13 @@ public class GeneralFormatTests
} }
[Fact] [Fact]
public void IdentifyReturnsNullWithInvalidStream() public void Identify_UnknownImageFormatException_WithInvalidStream()
{ {
byte[] invalid = new byte[10]; byte[] invalid = new byte[10];
using MemoryStream memoryStream = new(invalid); using MemoryStream memoryStream = new(invalid);
Image.TryIdentify(memoryStream, out ImageInfo imageInfo);
Assert.Null(imageInfo); Assert.Throws<UnknownImageFormatException>(() => Image.TryIdentify(invalid, out ImageInfo imageInfo));
} }
private static IImageFormat GetFormat(string format) private static IImageFormat GetFormat(string format)

72
tests/ImageSharp.Tests/Formats/Gif/ImageExtensionsTest.cs

@ -15,15 +15,13 @@ public class ImageExtensionsTest
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest));
string file = Path.Combine(dir, "SaveAsGif_Path.gif"); string file = Path.Combine(dir, "SaveAsGif_Path.gif");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
image.SaveAsGif(file); image.SaveAsGif(file);
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is GifFormat);
Assert.Equal("image/gif", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
@ -32,15 +30,13 @@ public class ImageExtensionsTest
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest));
string file = Path.Combine(dir, "SaveAsGifAsync_Path.gif"); string file = Path.Combine(dir, "SaveAsGifAsync_Path.gif");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
await image.SaveAsGifAsync(file); await image.SaveAsGifAsync(file);
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is GifFormat);
Assert.Equal("image/gif", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
@ -49,15 +45,13 @@ public class ImageExtensionsTest
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions));
string file = Path.Combine(dir, "SaveAsGif_Path_Encoder.gif"); string file = Path.Combine(dir, "SaveAsGif_Path_Encoder.gif");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
image.SaveAsGif(file, new GifEncoder()); image.SaveAsGif(file, new GifEncoder());
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is GifFormat);
Assert.Equal("image/gif", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
@ -66,86 +60,76 @@ public class ImageExtensionsTest
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions));
string file = Path.Combine(dir, "SaveAsGifAsync_Path_Encoder.gif"); string file = Path.Combine(dir, "SaveAsGifAsync_Path_Encoder.gif");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
await image.SaveAsGifAsync(file, new GifEncoder()); await image.SaveAsGifAsync(file, new GifEncoder());
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is GifFormat);
Assert.Equal("image/gif", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public void SaveAsGif_Stream() public void SaveAsGif_Stream()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
image.SaveAsGif(memoryStream); image.SaveAsGif(memoryStream);
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is GifFormat);
Assert.Equal("image/gif", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public async Task SaveAsGifAsync_StreamAsync() public async Task SaveAsGifAsync_StreamAsync()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
await image.SaveAsGifAsync(memoryStream); await image.SaveAsGifAsync(memoryStream);
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is GifFormat);
Assert.Equal("image/gif", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public void SaveAsGif_Stream_Encoder() public void SaveAsGif_Stream_Encoder()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
image.SaveAsGif(memoryStream, new GifEncoder()); image.SaveAsGif(memoryStream, new GifEncoder());
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is GifFormat);
Assert.Equal("image/gif", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public async Task SaveAsGifAsync_Stream_Encoder() public async Task SaveAsGifAsync_Stream_Encoder()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
await image.SaveAsGifAsync(memoryStream, new GifEncoder()); await image.SaveAsGifAsync(memoryStream, new GifEncoder());
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is GifFormat);
Assert.Equal("image/gif", mime.DefaultMimeType);
}
} }
} }

8
tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs

@ -74,12 +74,12 @@ public class ImageFormatManagerTests
{ {
IImageEncoder encoder1 = new Mock<IImageEncoder>().Object; IImageEncoder encoder1 = new Mock<IImageEncoder>().Object;
this.FormatsManagerEmpty.SetEncoder(TestFormat.GlobalTestFormat, encoder1); this.FormatsManagerEmpty.SetEncoder(TestFormat.GlobalTestFormat, encoder1);
IImageEncoder found = this.FormatsManagerEmpty.FindEncoder(TestFormat.GlobalTestFormat); IImageEncoder found = this.FormatsManagerEmpty.GetEncoder(TestFormat.GlobalTestFormat);
Assert.Equal(encoder1, found); Assert.Equal(encoder1, found);
IImageEncoder encoder2 = new Mock<IImageEncoder>().Object; IImageEncoder encoder2 = new Mock<IImageEncoder>().Object;
this.FormatsManagerEmpty.SetEncoder(TestFormat.GlobalTestFormat, encoder2); this.FormatsManagerEmpty.SetEncoder(TestFormat.GlobalTestFormat, encoder2);
IImageEncoder found2 = this.FormatsManagerEmpty.FindEncoder(TestFormat.GlobalTestFormat); IImageEncoder found2 = this.FormatsManagerEmpty.GetEncoder(TestFormat.GlobalTestFormat);
Assert.Equal(encoder2, found2); Assert.Equal(encoder2, found2);
Assert.NotEqual(found, found2); Assert.NotEqual(found, found2);
} }
@ -89,12 +89,12 @@ public class ImageFormatManagerTests
{ {
IImageDecoder decoder1 = new Mock<IImageDecoder>().Object; IImageDecoder decoder1 = new Mock<IImageDecoder>().Object;
this.FormatsManagerEmpty.SetDecoder(TestFormat.GlobalTestFormat, decoder1); this.FormatsManagerEmpty.SetDecoder(TestFormat.GlobalTestFormat, decoder1);
IImageDecoder found = this.FormatsManagerEmpty.FindDecoder(TestFormat.GlobalTestFormat); IImageDecoder found = this.FormatsManagerEmpty.GetDecoder(TestFormat.GlobalTestFormat);
Assert.Equal(decoder1, found); Assert.Equal(decoder1, found);
IImageDecoder decoder2 = new Mock<IImageDecoder>().Object; IImageDecoder decoder2 = new Mock<IImageDecoder>().Object;
this.FormatsManagerEmpty.SetDecoder(TestFormat.GlobalTestFormat, decoder2); this.FormatsManagerEmpty.SetDecoder(TestFormat.GlobalTestFormat, decoder2);
IImageDecoder found2 = this.FormatsManagerEmpty.FindDecoder(TestFormat.GlobalTestFormat); IImageDecoder found2 = this.FormatsManagerEmpty.GetDecoder(TestFormat.GlobalTestFormat);
Assert.Equal(decoder2, found2); Assert.Equal(decoder2, found2);
Assert.NotEqual(found, found2); Assert.NotEqual(found, found2);
} }

72
tests/ImageSharp.Tests/Formats/Jpg/ImageExtensionsTest.cs

@ -16,15 +16,13 @@ public class ImageExtensionsTest
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest));
string file = Path.Combine(dir, "SaveAsJpeg_Path.jpg"); string file = Path.Combine(dir, "SaveAsJpeg_Path.jpg");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
image.SaveAsJpeg(file); image.SaveAsJpeg(file);
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is JpegFormat);
Assert.Equal("image/jpeg", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
@ -33,15 +31,13 @@ public class ImageExtensionsTest
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest));
string file = Path.Combine(dir, "SaveAsJpegAsync_Path.jpg"); string file = Path.Combine(dir, "SaveAsJpegAsync_Path.jpg");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
await image.SaveAsJpegAsync(file); await image.SaveAsJpegAsync(file);
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is JpegFormat);
Assert.Equal("image/jpeg", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
@ -50,15 +46,13 @@ public class ImageExtensionsTest
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions));
string file = Path.Combine(dir, "SaveAsJpeg_Path_Encoder.jpg"); string file = Path.Combine(dir, "SaveAsJpeg_Path_Encoder.jpg");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
image.SaveAsJpeg(file, new JpegEncoder()); image.SaveAsJpeg(file, new JpegEncoder());
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is JpegFormat);
Assert.Equal("image/jpeg", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
@ -67,86 +61,76 @@ public class ImageExtensionsTest
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions));
string file = Path.Combine(dir, "SaveAsJpegAsync_Path_Encoder.jpg"); string file = Path.Combine(dir, "SaveAsJpegAsync_Path_Encoder.jpg");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
await image.SaveAsJpegAsync(file, new JpegEncoder()); await image.SaveAsJpegAsync(file, new JpegEncoder());
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is JpegFormat);
Assert.Equal("image/jpeg", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public void SaveAsJpeg_Stream() public void SaveAsJpeg_Stream()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
image.SaveAsJpeg(memoryStream); image.SaveAsJpeg(memoryStream);
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is JpegFormat);
Assert.Equal("image/jpeg", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public async Task SaveAsJpegAsync_StreamAsync() public async Task SaveAsJpegAsync_StreamAsync()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
await image.SaveAsJpegAsync(memoryStream); await image.SaveAsJpegAsync(memoryStream);
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is JpegFormat);
Assert.Equal("image/jpeg", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public void SaveAsJpeg_Stream_Encoder() public void SaveAsJpeg_Stream_Encoder()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
image.SaveAsJpeg(memoryStream, new JpegEncoder()); image.SaveAsJpeg(memoryStream, new JpegEncoder());
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is JpegFormat);
Assert.Equal("image/jpeg", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public async Task SaveAsJpegAsync_Stream_Encoder() public async Task SaveAsJpegAsync_Stream_Encoder()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
await image.SaveAsJpegAsync(memoryStream, new JpegEncoder()); await image.SaveAsJpegAsync(memoryStream, new JpegEncoder());
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is JpegFormat);
Assert.Equal("image/jpeg", mime.DefaultMimeType);
}
} }
} }

42
tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs

@ -75,8 +75,8 @@ public partial class JpegDecoderTests
[MemberData(nameof(RatioFiles))] [MemberData(nameof(RatioFiles))]
public void Decode_VerifyRatio(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit) public void Decode_VerifyRatio(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit)
{ {
var testFile = TestFile.Create(imagePath); TestFile testFile = TestFile.Create(imagePath);
using var stream = new MemoryStream(testFile.Bytes, false); using MemoryStream stream = new(testFile.Bytes, false);
using Image image = JpegDecoder.Instance.Decode(DecoderOptions.Default, stream); using Image image = JpegDecoder.Instance.Decode(DecoderOptions.Default, stream);
ImageMetadata meta = image.Metadata; ImageMetadata meta = image.Metadata;
Assert.Equal(xResolution, meta.HorizontalResolution); Assert.Equal(xResolution, meta.HorizontalResolution);
@ -88,8 +88,8 @@ public partial class JpegDecoderTests
[MemberData(nameof(RatioFiles))] [MemberData(nameof(RatioFiles))]
public void Identify_VerifyRatio(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit) public void Identify_VerifyRatio(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit)
{ {
var testFile = TestFile.Create(imagePath); TestFile testFile = TestFile.Create(imagePath);
using var stream = new MemoryStream(testFile.Bytes, false); using MemoryStream stream = new(testFile.Bytes, false);
ImageInfo image = JpegDecoder.Instance.Identify(DecoderOptions.Default, stream); ImageInfo image = JpegDecoder.Instance.Identify(DecoderOptions.Default, stream);
ImageMetadata meta = image.Metadata; ImageMetadata meta = image.Metadata;
Assert.Equal(xResolution, meta.HorizontalResolution); Assert.Equal(xResolution, meta.HorizontalResolution);
@ -101,8 +101,8 @@ public partial class JpegDecoderTests
[MemberData(nameof(RatioFiles))] [MemberData(nameof(RatioFiles))]
public async Task Identify_VerifyRatioAsync(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit) public async Task Identify_VerifyRatioAsync(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit)
{ {
var testFile = TestFile.Create(imagePath); TestFile testFile = TestFile.Create(imagePath);
using var stream = new MemoryStream(testFile.Bytes, false); using MemoryStream stream = new(testFile.Bytes, false);
ImageInfo image = await JpegDecoder.Instance.IdentifyAsync(DecoderOptions.Default, stream); ImageInfo image = await JpegDecoder.Instance.IdentifyAsync(DecoderOptions.Default, stream);
ImageMetadata meta = image.Metadata; ImageMetadata meta = image.Metadata;
Assert.Equal(xResolution, meta.HorizontalResolution); Assert.Equal(xResolution, meta.HorizontalResolution);
@ -114,8 +114,8 @@ public partial class JpegDecoderTests
[MemberData(nameof(QualityFiles))] [MemberData(nameof(QualityFiles))]
public void Identify_VerifyQuality(string imagePath, int quality) public void Identify_VerifyQuality(string imagePath, int quality)
{ {
var testFile = TestFile.Create(imagePath); TestFile testFile = TestFile.Create(imagePath);
using var stream = new MemoryStream(testFile.Bytes, false); using MemoryStream stream = new(testFile.Bytes, false);
ImageInfo image = JpegDecoder.Instance.Identify(DecoderOptions.Default, stream); ImageInfo image = JpegDecoder.Instance.Identify(DecoderOptions.Default, stream);
JpegMetadata meta = image.Metadata.GetJpegMetadata(); JpegMetadata meta = image.Metadata.GetJpegMetadata();
Assert.Equal(quality, meta.Quality); Assert.Equal(quality, meta.Quality);
@ -125,8 +125,8 @@ public partial class JpegDecoderTests
[MemberData(nameof(QualityFiles))] [MemberData(nameof(QualityFiles))]
public void Decode_VerifyQuality(string imagePath, int quality) public void Decode_VerifyQuality(string imagePath, int quality)
{ {
var testFile = TestFile.Create(imagePath); TestFile testFile = TestFile.Create(imagePath);
using var stream = new MemoryStream(testFile.Bytes, false); using MemoryStream stream = new(testFile.Bytes, false);
using Image image = JpegDecoder.Instance.Decode(DecoderOptions.Default, stream); using Image image = JpegDecoder.Instance.Decode(DecoderOptions.Default, stream);
JpegMetadata meta = image.Metadata.GetJpegMetadata(); JpegMetadata meta = image.Metadata.GetJpegMetadata();
Assert.Equal(quality, meta.Quality); Assert.Equal(quality, meta.Quality);
@ -136,8 +136,8 @@ public partial class JpegDecoderTests
[MemberData(nameof(QualityFiles))] [MemberData(nameof(QualityFiles))]
public async Task Decode_VerifyQualityAsync(string imagePath, int quality) public async Task Decode_VerifyQualityAsync(string imagePath, int quality)
{ {
var testFile = TestFile.Create(imagePath); TestFile testFile = TestFile.Create(imagePath);
using var stream = new MemoryStream(testFile.Bytes, false); using MemoryStream stream = new(testFile.Bytes, false);
using Image image = await JpegDecoder.Instance.DecodeAsync(DecoderOptions.Default, stream); using Image image = await JpegDecoder.Instance.DecodeAsync(DecoderOptions.Default, stream);
JpegMetadata meta = image.Metadata.GetJpegMetadata(); JpegMetadata meta = image.Metadata.GetJpegMetadata();
Assert.Equal(quality, meta.Quality); Assert.Equal(quality, meta.Quality);
@ -153,8 +153,8 @@ public partial class JpegDecoderTests
[InlineData(TestImages.Jpeg.Baseline.Jpeg411, JpegEncodingColor.YCbCrRatio411)] [InlineData(TestImages.Jpeg.Baseline.Jpeg411, JpegEncodingColor.YCbCrRatio411)]
public void Identify_DetectsCorrectColorType(string imagePath, JpegEncodingColor expectedColorType) public void Identify_DetectsCorrectColorType(string imagePath, JpegEncodingColor expectedColorType)
{ {
var testFile = TestFile.Create(imagePath); TestFile testFile = TestFile.Create(imagePath);
using var stream = new MemoryStream(testFile.Bytes, false); using MemoryStream stream = new(testFile.Bytes, false);
ImageInfo image = JpegDecoder.Instance.Identify(DecoderOptions.Default, stream); ImageInfo image = JpegDecoder.Instance.Identify(DecoderOptions.Default, stream);
JpegMetadata meta = image.Metadata.GetJpegMetadata(); JpegMetadata meta = image.Metadata.GetJpegMetadata();
Assert.Equal(expectedColorType, meta.ColorType); Assert.Equal(expectedColorType, meta.ColorType);
@ -176,8 +176,8 @@ public partial class JpegDecoderTests
private static void TestImageInfo(string imagePath, IImageDecoder decoder, bool useIdentify, Action<IImageInfo> test) private static void TestImageInfo(string imagePath, IImageDecoder decoder, bool useIdentify, Action<IImageInfo> test)
{ {
var testFile = TestFile.Create(imagePath); TestFile testFile = TestFile.Create(imagePath);
using var stream = new MemoryStream(testFile.Bytes, false); using MemoryStream stream = new(testFile.Bytes, false);
if (useIdentify) if (useIdentify)
{ {
ImageInfo imageInfo = decoder.Identify(DecoderOptions.Default, stream); ImageInfo imageInfo = decoder.Identify(DecoderOptions.Default, stream);
@ -318,10 +318,10 @@ public partial class JpegDecoderTests
[Fact] [Fact]
public void EncodedStringTags_WriteAndRead() public void EncodedStringTags_WriteAndRead()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = Image.Load(TestFile.GetInputFileFullPath(TestImages.Jpeg.Baseline.Calliphora))) using (Image image = Image.Load(TestFile.GetInputFileFullPath(TestImages.Jpeg.Baseline.Calliphora)))
{ {
var exif = new ExifProfile(); ExifProfile exif = new();
exif.SetValue(ExifTag.GPSDateStamp, "2022-01-06"); exif.SetValue(ExifTag.GPSDateStamp, "2022-01-06");
@ -343,7 +343,7 @@ public partial class JpegDecoderTests
} }
memoryStream.Seek(0, SeekOrigin.Begin); memoryStream.Seek(0, SeekOrigin.Begin);
using (var image = Image.Load(memoryStream)) using (Image image = Image.Load(memoryStream))
{ {
ExifProfile exif = image.Metadata.ExifProfile; ExifProfile exif = image.Metadata.ExifProfile;
VerifyEncodedStrings(exif); VerifyEncodedStrings(exif);
@ -353,7 +353,7 @@ public partial class JpegDecoderTests
[Fact] [Fact]
public void EncodedStringTags_Read() public void EncodedStringTags_Read()
{ {
using var image = Image.Load(TestFile.GetInputFileFullPath(TestImages.Jpeg.Baseline.Calliphora_EncodedStrings)); using Image image = Image.Load(TestFile.GetInputFileFullPath(TestImages.Jpeg.Baseline.Calliphora_EncodedStrings));
ExifProfile exif = image.Metadata.ExifProfile; ExifProfile exif = image.Metadata.ExifProfile;
VerifyEncodedStrings(exif); VerifyEncodedStrings(exif);
} }

10
tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs

@ -35,7 +35,7 @@ public partial class JpegDecoderTests
if (!CustomToleranceValues.TryGetValue(file, out float tolerance)) if (!CustomToleranceValues.TryGetValue(file, out float tolerance))
{ {
bool baseline = file.IndexOf("baseline", StringComparison.OrdinalIgnoreCase) >= 0; bool baseline = file.Contains("baseline", StringComparison.OrdinalIgnoreCase);
tolerance = baseline ? BaselineTolerance : ProgressiveTolerance; tolerance = baseline ? BaselineTolerance : ProgressiveTolerance;
} }
@ -68,9 +68,9 @@ public partial class JpegDecoderTests
{ {
JpegDecoderOptions options = new(); JpegDecoderOptions options = new();
byte[] bytes = TestFile.Create(TestImages.Jpeg.Progressive.Progress).Bytes; byte[] bytes = TestFile.Create(TestImages.Jpeg.Progressive.Progress).Bytes;
using var ms = new MemoryStream(bytes); using MemoryStream ms = new(bytes);
using var bufferedStream = new BufferedReadStream(Configuration.Default, ms); using BufferedReadStream bufferedStream = new(Configuration.Default, ms);
using var decoder = new JpegDecoderCore(options); using JpegDecoderCore decoder = new(options);
using Image<Rgba32> image = decoder.Decode<Rgba32>(bufferedStream, cancellationToken: default); using Image<Rgba32> image = decoder.Decode<Rgba32>(bufferedStream, cancellationToken: default);
// I don't know why these numbers are different. All I know is that the decoder works // I don't know why these numbers are different. All I know is that the decoder works
@ -85,7 +85,7 @@ public partial class JpegDecoderTests
public void Decode_NonGeneric_CreatesRgb24Image() public void Decode_NonGeneric_CreatesRgb24Image()
{ {
string file = Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, TestImages.Jpeg.Baseline.Jpeg420Small); string file = Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, TestImages.Jpeg.Baseline.Jpeg420Small);
using var image = Image.Load(file); using Image image = Image.Load(file);
Assert.IsType<Image<Rgb24>>(image); Assert.IsType<Image<Rgb24>>(image);
} }

72
tests/ImageSharp.Tests/Formats/Pbm/ImageExtensionsTest.cs

@ -15,15 +15,13 @@ public class ImageExtensionsTest
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest));
string file = Path.Combine(dir, "SaveAsPbm_Path.pbm"); string file = Path.Combine(dir, "SaveAsPbm_Path.pbm");
using (var image = new Image<L8>(10, 10)) using (Image<L8> image = new(10, 10))
{ {
image.SaveAsPbm(file); image.SaveAsPbm(file);
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is PbmFormat);
Assert.Equal("image/x-portable-pixmap", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
@ -32,15 +30,13 @@ public class ImageExtensionsTest
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest));
string file = Path.Combine(dir, "SaveAsPbmAsync_Path.pbm"); string file = Path.Combine(dir, "SaveAsPbmAsync_Path.pbm");
using (var image = new Image<L8>(10, 10)) using (Image<L8> image = new(10, 10))
{ {
await image.SaveAsPbmAsync(file); await image.SaveAsPbmAsync(file);
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is PbmFormat);
Assert.Equal("image/x-portable-pixmap", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
@ -49,15 +45,13 @@ public class ImageExtensionsTest
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions));
string file = Path.Combine(dir, "SaveAsPbm_Path_Encoder.pbm"); string file = Path.Combine(dir, "SaveAsPbm_Path_Encoder.pbm");
using (var image = new Image<L8>(10, 10)) using (Image<L8> image = new(10, 10))
{ {
image.SaveAsPbm(file, new PbmEncoder()); image.SaveAsPbm(file, new PbmEncoder());
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is PbmFormat);
Assert.Equal("image/x-portable-pixmap", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
@ -66,86 +60,76 @@ public class ImageExtensionsTest
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions));
string file = Path.Combine(dir, "SaveAsPbmAsync_Path_Encoder.pbm"); string file = Path.Combine(dir, "SaveAsPbmAsync_Path_Encoder.pbm");
using (var image = new Image<L8>(10, 10)) using (Image<L8> image = new(10, 10))
{ {
await image.SaveAsPbmAsync(file, new PbmEncoder()); await image.SaveAsPbmAsync(file, new PbmEncoder());
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is PbmFormat);
Assert.Equal("image/x-portable-pixmap", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public void SaveAsPbm_Stream() public void SaveAsPbm_Stream()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<L8>(10, 10)) using (Image<L8> image = new(10, 10))
{ {
image.SaveAsPbm(memoryStream); image.SaveAsPbm(memoryStream);
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is PbmFormat);
Assert.Equal("image/x-portable-pixmap", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public async Task SaveAsPbmAsync_StreamAsync() public async Task SaveAsPbmAsync_StreamAsync()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<L8>(10, 10)) using (Image<L8> image = new(10, 10))
{ {
await image.SaveAsPbmAsync(memoryStream); await image.SaveAsPbmAsync(memoryStream);
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is PbmFormat);
Assert.Equal("image/x-portable-pixmap", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public void SaveAsPbm_Stream_Encoder() public void SaveAsPbm_Stream_Encoder()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<L8>(10, 10)) using (Image<L8> image = new(10, 10))
{ {
image.SaveAsPbm(memoryStream, new PbmEncoder()); image.SaveAsPbm(memoryStream, new PbmEncoder());
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is PbmFormat);
Assert.Equal("image/x-portable-pixmap", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public async Task SaveAsPbmAsync_Stream_Encoder() public async Task SaveAsPbmAsync_Stream_Encoder()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<L8>(10, 10)) using (Image<L8> image = new(10, 10))
{ {
await image.SaveAsPbmAsync(memoryStream, new PbmEncoder()); await image.SaveAsPbmAsync(memoryStream, new PbmEncoder());
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is PbmFormat);
Assert.Equal("image/x-portable-pixmap", mime.DefaultMimeType);
}
} }
} }

72
tests/ImageSharp.Tests/Formats/Png/ImageExtensionsTest.cs

@ -16,15 +16,13 @@ public class ImageExtensionsTest
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest));
string file = Path.Combine(dir, "SaveAsPng_Path.png"); string file = Path.Combine(dir, "SaveAsPng_Path.png");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
image.SaveAsPng(file); image.SaveAsPng(file);
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is PngFormat);
Assert.Equal("image/png", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
@ -33,15 +31,13 @@ public class ImageExtensionsTest
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest));
string file = Path.Combine(dir, "SaveAsPngAsync_Path.png"); string file = Path.Combine(dir, "SaveAsPngAsync_Path.png");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
await image.SaveAsPngAsync(file); await image.SaveAsPngAsync(file);
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is PngFormat);
Assert.Equal("image/png", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
@ -50,15 +46,13 @@ public class ImageExtensionsTest
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions));
string file = Path.Combine(dir, "SaveAsPng_Path_Encoder.png"); string file = Path.Combine(dir, "SaveAsPng_Path_Encoder.png");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
image.SaveAsPng(file, new PngEncoder()); image.SaveAsPng(file, new PngEncoder());
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is PngFormat);
Assert.Equal("image/png", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
@ -67,86 +61,76 @@ public class ImageExtensionsTest
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions));
string file = Path.Combine(dir, "SaveAsPngAsync_Path_Encoder.png"); string file = Path.Combine(dir, "SaveAsPngAsync_Path_Encoder.png");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
await image.SaveAsPngAsync(file, new PngEncoder()); await image.SaveAsPngAsync(file, new PngEncoder());
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is PngFormat);
Assert.Equal("image/png", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public void SaveAsPng_Stream() public void SaveAsPng_Stream()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
image.SaveAsPng(memoryStream); image.SaveAsPng(memoryStream);
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is PngFormat);
Assert.Equal("image/png", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public async Task SaveAsPngAsync_StreamAsync() public async Task SaveAsPngAsync_StreamAsync()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
await image.SaveAsPngAsync(memoryStream); await image.SaveAsPngAsync(memoryStream);
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is PngFormat);
Assert.Equal("image/png", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public void SaveAsPng_Stream_Encoder() public void SaveAsPng_Stream_Encoder()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
image.SaveAsPng(memoryStream, new PngEncoder()); image.SaveAsPng(memoryStream, new PngEncoder());
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is PngFormat);
Assert.Equal("image/png", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public async Task SaveAsPngAsync_Stream_Encoder() public async Task SaveAsPngAsync_Stream_Encoder()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
await image.SaveAsPngAsync(memoryStream, new PngEncoder()); await image.SaveAsPngAsync(memoryStream, new PngEncoder());
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is PngFormat);
Assert.Equal("image/png", mime.DefaultMimeType);
}
} }
} }

72
tests/ImageSharp.Tests/Formats/Tga/ImageExtensionsTest.cs

@ -15,15 +15,13 @@ public class ImageExtensionsTest
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest));
string file = Path.Combine(dir, "SaveAsTga_Path.tga"); string file = Path.Combine(dir, "SaveAsTga_Path.tga");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
image.SaveAsTga(file); image.SaveAsTga(file);
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is TgaFormat);
Assert.Equal("image/tga", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
@ -32,15 +30,13 @@ public class ImageExtensionsTest
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest));
string file = Path.Combine(dir, "SaveAsTgaAsync_Path.tga"); string file = Path.Combine(dir, "SaveAsTgaAsync_Path.tga");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
await image.SaveAsTgaAsync(file); await image.SaveAsTgaAsync(file);
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is TgaFormat);
Assert.Equal("image/tga", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
@ -49,15 +45,13 @@ public class ImageExtensionsTest
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions));
string file = Path.Combine(dir, "SaveAsTga_Path_Encoder.tga"); string file = Path.Combine(dir, "SaveAsTga_Path_Encoder.tga");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
image.SaveAsTga(file, new TgaEncoder()); image.SaveAsTga(file, new TgaEncoder());
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is TgaFormat);
Assert.Equal("image/tga", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
@ -66,86 +60,76 @@ public class ImageExtensionsTest
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions));
string file = Path.Combine(dir, "SaveAsTgaAsync_Path_Encoder.tga"); string file = Path.Combine(dir, "SaveAsTgaAsync_Path_Encoder.tga");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
await image.SaveAsTgaAsync(file, new TgaEncoder()); await image.SaveAsTgaAsync(file, new TgaEncoder());
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is TgaFormat);
Assert.Equal("image/tga", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public void SaveAsTga_Stream() public void SaveAsTga_Stream()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
image.SaveAsTga(memoryStream); image.SaveAsTga(memoryStream);
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is TgaFormat);
Assert.Equal("image/tga", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public async Task SaveAsTgaAsync_StreamAsync() public async Task SaveAsTgaAsync_StreamAsync()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
await image.SaveAsTgaAsync(memoryStream); await image.SaveAsTgaAsync(memoryStream);
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is TgaFormat);
Assert.Equal("image/tga", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public void SaveAsTga_Stream_Encoder() public void SaveAsTga_Stream_Encoder()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
image.SaveAsTga(memoryStream, new TgaEncoder()); image.SaveAsTga(memoryStream, new TgaEncoder());
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is TgaFormat);
Assert.Equal("image/tga", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public async Task SaveAsTgaAsync_Stream_Encoder() public async Task SaveAsTgaAsync_Stream_Encoder()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
await image.SaveAsTgaAsync(memoryStream, new TgaEncoder()); await image.SaveAsTgaAsync(memoryStream, new TgaEncoder());
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is TgaFormat);
Assert.Equal("image/tga", mime.DefaultMimeType);
}
} }
} }

2
tests/ImageSharp.Tests/Formats/Tga/TgaFileHeaderTests.cs

@ -26,7 +26,7 @@ public class TgaFileHeaderTests
Assert.Throws<UnknownImageFormatException>(() => Assert.Throws<UnknownImageFormatException>(() =>
{ {
using (Image.Load(DecoderOptions.Default, stream, out IImageFormat _)) using (Image.Load(DecoderOptions.Default, stream))
{ {
} }
}); });

72
tests/ImageSharp.Tests/Formats/Tiff/ImageExtensionsTest.cs

@ -16,15 +16,13 @@ public class ImageExtensionsTest
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest));
string file = Path.Combine(dir, "SaveAsTiff_Path.tiff"); string file = Path.Combine(dir, "SaveAsTiff_Path.tiff");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
image.SaveAsTiff(file); image.SaveAsTiff(file);
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is TiffFormat);
Assert.Equal("image/tiff", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
@ -33,15 +31,13 @@ public class ImageExtensionsTest
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest));
string file = Path.Combine(dir, "SaveAsTiffAsync_Path.tiff"); string file = Path.Combine(dir, "SaveAsTiffAsync_Path.tiff");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
await image.SaveAsTiffAsync(file); await image.SaveAsTiffAsync(file);
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is TiffFormat);
Assert.Equal("image/tiff", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
@ -50,15 +46,13 @@ public class ImageExtensionsTest
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions));
string file = Path.Combine(dir, "SaveAsTiff_Path_Encoder.tiff"); string file = Path.Combine(dir, "SaveAsTiff_Path_Encoder.tiff");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
image.SaveAsTiff(file, new TiffEncoder()); image.SaveAsTiff(file, new TiffEncoder());
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is TiffFormat);
Assert.Equal("image/tiff", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
@ -67,86 +61,76 @@ public class ImageExtensionsTest
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions));
string file = Path.Combine(dir, "SaveAsTiffAsync_Path_Encoder.tiff"); string file = Path.Combine(dir, "SaveAsTiffAsync_Path_Encoder.tiff");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
await image.SaveAsTiffAsync(file, new TiffEncoder()); await image.SaveAsTiffAsync(file, new TiffEncoder());
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is TiffFormat);
Assert.Equal("image/tiff", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public void SaveAsTiff_Stream() public void SaveAsTiff_Stream()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
image.SaveAsTiff(memoryStream); image.SaveAsTiff(memoryStream);
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is TiffFormat);
Assert.Equal("image/tiff", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public async Task SaveAsTiffAsync_StreamAsync() public async Task SaveAsTiffAsync_StreamAsync()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
await image.SaveAsTiffAsync(memoryStream); await image.SaveAsTiffAsync(memoryStream);
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is TiffFormat);
Assert.Equal("image/tiff", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public void SaveAsTiff_Stream_Encoder() public void SaveAsTiff_Stream_Encoder()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
image.SaveAsTiff(memoryStream, new TiffEncoder()); image.SaveAsTiff(memoryStream, new TiffEncoder());
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is TiffFormat);
Assert.Equal("image/tiff", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public async Task SaveAsTiffAsync_Stream_Encoder() public async Task SaveAsTiffAsync_Stream_Encoder()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
await image.SaveAsTiffAsync(memoryStream, new TiffEncoder()); await image.SaveAsTiffAsync(memoryStream, new TiffEncoder());
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is TiffFormat);
Assert.Equal("image/tiff", mime.DefaultMimeType);
}
} }
} }

72
tests/ImageSharp.Tests/Formats/WebP/ImageExtensionsTests.cs

@ -16,15 +16,13 @@ public class ImageExtensionsTests
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTests)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTests));
string file = Path.Combine(dir, "SaveAsWebp_Path.webp"); string file = Path.Combine(dir, "SaveAsWebp_Path.webp");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
image.SaveAsWebp(file); image.SaveAsWebp(file);
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is WebpFormat);
Assert.Equal("image/webp", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
@ -33,15 +31,13 @@ public class ImageExtensionsTests
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTests)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTests));
string file = Path.Combine(dir, "SaveAsWebpAsync_Path.webp"); string file = Path.Combine(dir, "SaveAsWebpAsync_Path.webp");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
await image.SaveAsWebpAsync(file); await image.SaveAsWebpAsync(file);
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is WebpFormat);
Assert.Equal("image/webp", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
@ -50,15 +46,13 @@ public class ImageExtensionsTests
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions));
string file = Path.Combine(dir, "SaveAsWebp_Path_Encoder.webp"); string file = Path.Combine(dir, "SaveAsWebp_Path_Encoder.webp");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
image.SaveAsWebp(file, new WebpEncoder()); image.SaveAsWebp(file, new WebpEncoder());
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is WebpFormat);
Assert.Equal("image/webp", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
@ -67,86 +61,76 @@ public class ImageExtensionsTests
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions));
string file = Path.Combine(dir, "SaveAsWebpAsync_Path_Encoder.webp"); string file = Path.Combine(dir, "SaveAsWebpAsync_Path_Encoder.webp");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
await image.SaveAsWebpAsync(file, new WebpEncoder()); await image.SaveAsWebpAsync(file, new WebpEncoder());
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is WebpFormat);
Assert.Equal("image/webp", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public void SaveAsWebp_Stream() public void SaveAsWebp_Stream()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
image.SaveAsWebp(memoryStream); image.SaveAsWebp(memoryStream);
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is WebpFormat);
Assert.Equal("image/webp", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public async Task SaveAsWebpAsync_StreamAsync() public async Task SaveAsWebpAsync_StreamAsync()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
await image.SaveAsWebpAsync(memoryStream); await image.SaveAsWebpAsync(memoryStream);
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is WebpFormat);
Assert.Equal("image/webp", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public void SaveAsWebp_Stream_Encoder() public void SaveAsWebp_Stream_Encoder()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
image.SaveAsWebp(memoryStream, new WebpEncoder()); image.SaveAsWebp(memoryStream, new WebpEncoder());
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is WebpFormat);
Assert.Equal("image/webp", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public async Task SaveAsWebpAsync_Stream_Encoder() public async Task SaveAsWebpAsync_Stream_Encoder()
{ {
using var memoryStream = new MemoryStream(); using MemoryStream memoryStream = new();
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
await image.SaveAsWebpAsync(memoryStream, new WebpEncoder()); await image.SaveAsWebpAsync(memoryStream, new WebpEncoder());
} }
memoryStream.Position = 0; memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime)) Image.TryDetectFormat(memoryStream, out IImageFormat format);
{ Assert.True(format is WebpFormat);
Assert.Equal("image/webp", mime.DefaultMimeType);
}
} }
} }

12
tests/ImageSharp.Tests/Image/ImageTests.DetectFormat.cs

@ -125,17 +125,14 @@ public partial class ImageTests
} }
[Fact] [Fact]
public void WhenNoMatchingFormatFound_ReturnsNull() public void WhenNoMatchingFormatFound_Throws_UnknownImageFormatException()
{ {
DecoderOptions options = new() DecoderOptions options = new()
{ {
Configuration = new() Configuration = new()
}; };
bool result = Image.TryDetectFormat(options, this.DataStream, out IImageFormat type); Assert.Throws<UnknownImageFormatException>(() => Image.TryDetectFormat(options, this.DataStream, out IImageFormat type));
Assert.False(result);
Assert.Null(type);
} }
[Fact] [Fact]
@ -159,15 +156,14 @@ public partial class ImageTests
} }
[Fact] [Fact]
public async Task WhenNoMatchingFormatFoundAsync_ReturnsNull() public Task WhenNoMatchingFormatFoundAsync_Throws_UnknownImageFormatException()
{ {
DecoderOptions options = new() DecoderOptions options = new()
{ {
Configuration = new() Configuration = new()
}; };
Attempt<IImageFormat> attempt = await Image.TryDetectFormatAsync(options, new AsyncStreamWrapper(this.DataStream, () => false)); return Assert.ThrowsAsync<UnknownImageFormatException>(async () => await Image.TryDetectFormatAsync(options, new AsyncStreamWrapper(this.DataStream, () => false)));
Assert.Null(attempt.Value);
} }
} }
} }

26
tests/ImageSharp.Tests/Image/ImageTests.Identify.cs

@ -21,8 +21,6 @@ public partial class ImageTests
private static byte[] ActualImageBytes => TestFile.Create(TestImages.Bmp.F).Bytes; private static byte[] ActualImageBytes => TestFile.Create(TestImages.Bmp.F).Bytes;
private IImageFormat LocalImageFormat => this.localImageFormatMock.Object;
private static IImageFormat ExpectedGlobalFormat private static IImageFormat ExpectedGlobalFormat
{ {
get get
@ -131,16 +129,15 @@ public partial class ImageTests
} }
[Fact] [Fact]
public void WhenNoMatchingFormatFound_ReturnsNull() public void WhenNoMatchingFormatFound_Throws_UnknownImageFormatException()
{ {
DecoderOptions options = new() { Configuration = new() }; DecoderOptions options = new() { Configuration = new() };
Assert.False(Image.TryIdentify(options, this.DataStream, out ImageInfo info)); Assert.Throws<UnknownImageFormatException>(() => Image.TryIdentify(options, this.DataStream, out ImageInfo info));
Assert.Null(info);
} }
[Fact] [Fact]
public void FromStream_ZeroLength_ReturnsNull() public void FromStream_ZeroLength_Throws_UnknownImageFormatException()
{ {
// https://github.com/SixLabors/ImageSharp/issues/1903 // https://github.com/SixLabors/ImageSharp/issues/1903
using ZipArchive zipFile = new(new MemoryStream( using ZipArchive zipFile = new(new MemoryStream(
@ -159,8 +156,7 @@ public partial class ImageTests
})); }));
using Stream stream = zipFile.Entries[0].Open(); using Stream stream = zipFile.Entries[0].Open();
Assert.False(Image.TryIdentify(stream, out ImageInfo info)); Assert.Throws<UnknownImageFormatException>(() => Image.TryIdentify(stream, out ImageInfo info));
Assert.Null(info);
} }
[Fact] [Fact]
@ -215,7 +211,7 @@ public partial class ImageTests
} }
[Fact] [Fact]
public async Task FromStreamAsync_ZeroLength_ReturnsNull() public async Task FromStreamAsync_ZeroLength_Throws_UnknownImageFormatException()
{ {
// https://github.com/SixLabors/ImageSharp/issues/1903 // https://github.com/SixLabors/ImageSharp/issues/1903
using ZipArchive zipFile = new(new MemoryStream( using ZipArchive zipFile = new(new MemoryStream(
@ -234,10 +230,7 @@ public partial class ImageTests
})); }));
using Stream stream = zipFile.Entries[0].Open(); using Stream stream = zipFile.Entries[0].Open();
Attempt<ImageInfo> attempt = await Image.TryIdentifyAsync(stream); await Assert.ThrowsAsync<UnknownImageFormatException>(async () => await Image.TryIdentifyAsync(stream));
Assert.False(attempt.Success);
Assert.Null(attempt.Value);
} }
[Fact] [Fact]
@ -293,15 +286,12 @@ public partial class ImageTests
} }
[Fact] [Fact]
public async Task WhenNoMatchingFormatFoundAsync_ReturnsNull() public Task WhenNoMatchingFormatFoundAsync_Throws_UnknownImageFormatException()
{ {
DecoderOptions options = new() { Configuration = new() }; DecoderOptions options = new() { Configuration = new() };
AsyncStreamWrapper asyncStream = new(this.DataStream, () => false); AsyncStreamWrapper asyncStream = new(this.DataStream, () => false);
Attempt<ImageInfo> attempt = await Image.TryIdentifyAsync(options, asyncStream); return Assert.ThrowsAsync<UnknownImageFormatException>(async () => await Image.TryIdentifyAsync(options, asyncStream));
Assert.False(attempt.Success);
Assert.Null(attempt.Value);
} }
} }
} }

38
tests/ImageSharp.Tests/Image/ImageTests.Load_FileSystemPath_PassLocalConfiguration.cs

@ -18,10 +18,11 @@ public partial class ImageTests
Configuration = this.TopLevelConfiguration Configuration = this.TopLevelConfiguration
}; };
var img = Image.Load<Rgb24>(options, this.MockFilePath); using (Image<Rgb24> img = Image.Load<Rgb24>(options, this.MockFilePath))
{
Assert.NotNull(img); Assert.NotNull(img);
Assert.Equal(this.TestFormat.Sample<Rgb24>(), img); Assert.Equal(this.TestFormat.Sample<Rgb24>(), img);
}
this.TestFormat.VerifySpecificDecodeCall<Rgb24>(this.Marker, this.TopLevelConfiguration); this.TestFormat.VerifySpecificDecodeCall<Rgb24>(this.Marker, this.TopLevelConfiguration);
} }
@ -34,10 +35,11 @@ public partial class ImageTests
Configuration = this.TopLevelConfiguration Configuration = this.TopLevelConfiguration
}; };
var img = Image.Load(options, this.MockFilePath); using (Image img = Image.Load(options, this.MockFilePath))
{
Assert.NotNull(img); Assert.NotNull(img);
Assert.Equal(this.TestFormat.SampleAgnostic(), img); Assert.Equal(this.TestFormat.SampleAgnostic(), img);
}
this.TestFormat.VerifyAgnosticDecodeCall(this.Marker, this.TopLevelConfiguration); this.TestFormat.VerifyAgnosticDecodeCall(this.Marker, this.TopLevelConfiguration);
} }
@ -50,10 +52,11 @@ public partial class ImageTests
Configuration = this.TopLevelConfiguration Configuration = this.TopLevelConfiguration
}; };
var img = Image.Load<Rgba32>(options, this.MockFilePath, out IImageFormat format); using (Image<Rgba32> img = Image.Load<Rgba32>(options, this.MockFilePath))
{
Assert.NotNull(img); Assert.NotNull(img);
Assert.Equal(this.TestFormat, format); Assert.Equal(this.TestFormat, img.Metadata.DecodedImageFormat);
}
this.TestFormat.VerifySpecificDecodeCall<Rgba32>(this.Marker, this.TopLevelConfiguration); this.TestFormat.VerifySpecificDecodeCall<Rgba32>(this.Marker, this.TopLevelConfiguration);
} }
@ -66,17 +69,18 @@ public partial class ImageTests
Configuration = this.TopLevelConfiguration Configuration = this.TopLevelConfiguration
}; };
var img = Image.Load(options, this.MockFilePath, out IImageFormat format); using (Image img = Image.Load(options, this.MockFilePath))
{
Assert.NotNull(img); Assert.NotNull(img);
Assert.Equal(this.TestFormat, format); Assert.Equal(this.TestFormat, img.Metadata.DecodedImageFormat);
}
this.TestFormat.VerifyAgnosticDecodeCall(this.Marker, this.TopLevelConfiguration); this.TestFormat.VerifyAgnosticDecodeCall(this.Marker, this.TopLevelConfiguration);
} }
[Fact] [Fact]
public void WhenFileNotFound_Throws() public void WhenFileNotFound_Throws()
=> Assert.Throws<System.IO.FileNotFoundException>( => Assert.Throws<FileNotFoundException>(
() => () =>
{ {
DecoderOptions options = new() DecoderOptions options = new()

13
tests/ImageSharp.Tests/Image/ImageTests.Load_FileSystemPath_UseDefaultConfiguration.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Bmp; using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
@ -18,14 +17,14 @@ public partial class ImageTests
[Fact] [Fact]
public void Path_Specific() public void Path_Specific()
{ {
using var img = Image.Load<Rgba32>(this.Path); using Image<Rgba32> img = Image.Load<Rgba32>(this.Path);
VerifyDecodedImage(img); VerifyDecodedImage(img);
} }
[Fact] [Fact]
public void Path_Agnostic() public void Path_Agnostic()
{ {
using var img = Image.Load(this.Path); using Image img = Image.Load(this.Path);
VerifyDecodedImage(img); VerifyDecodedImage(img);
} }
@ -53,17 +52,17 @@ public partial class ImageTests
[Fact] [Fact]
public void Path_OutFormat_Specific() public void Path_OutFormat_Specific()
{ {
using var img = Image.Load<Rgba32>(this.Path, out IImageFormat format); using Image<Rgba32> img = Image.Load<Rgba32>(this.Path);
VerifyDecodedImage(img); VerifyDecodedImage(img);
Assert.IsType<BmpFormat>(format); Assert.IsType<BmpFormat>(img.Metadata.DecodedImageFormat);
} }
[Fact] [Fact]
public void Path_OutFormat_Agnostic() public void Path_OutFormat_Agnostic()
{ {
using var img = Image.Load(this.Path, out IImageFormat format); using Image img = Image.Load(this.Path);
VerifyDecodedImage(img); VerifyDecodedImage(img);
Assert.IsType<BmpFormat>(format); Assert.IsType<BmpFormat>(img.Metadata.DecodedImageFormat);
} }
[Fact] [Fact]

36
tests/ImageSharp.Tests/Image/ImageTests.Load_FromBytes_PassLocalConfiguration.cs

@ -20,10 +20,11 @@ public partial class ImageTests
Configuration = this.TopLevelConfiguration Configuration = this.TopLevelConfiguration
}; };
var img = Image.Load<Rgb24>(options, this.ByteSpan); using (Image<Rgb24> img = Image.Load<Rgb24>(options, this.ByteSpan))
{
Assert.NotNull(img); Assert.NotNull(img);
Assert.Equal(this.TestFormat.Sample<Rgb24>(), img); Assert.Equal(this.TestFormat.Sample<Rgb24>(), img);
}
this.TestFormat.VerifySpecificDecodeCall<Rgb24>(this.Marker, this.TopLevelConfiguration); this.TestFormat.VerifySpecificDecodeCall<Rgb24>(this.Marker, this.TopLevelConfiguration);
} }
@ -36,10 +37,11 @@ public partial class ImageTests
Configuration = this.TopLevelConfiguration Configuration = this.TopLevelConfiguration
}; };
var img = Image.Load(options, this.ByteSpan); using (Image img = Image.Load(options, this.ByteSpan))
{
Assert.NotNull(img); Assert.NotNull(img);
Assert.Equal(this.TestFormat.SampleAgnostic(), img); Assert.Equal(this.TestFormat.SampleAgnostic(), img);
}
this.TestFormat.VerifyAgnosticDecodeCall(this.Marker, this.TopLevelConfiguration); this.TestFormat.VerifyAgnosticDecodeCall(this.Marker, this.TopLevelConfiguration);
} }
@ -52,10 +54,11 @@ public partial class ImageTests
Configuration = this.TopLevelConfiguration Configuration = this.TopLevelConfiguration
}; };
var img = Image.Load<Bgr24>(options, this.ByteSpan, out IImageFormat format); using (Image<Bgr24> img = Image.Load<Bgr24>(options, this.ByteSpan))
{
Assert.NotNull(img); Assert.NotNull(img);
Assert.Equal(this.TestFormat, format); Assert.Equal(this.TestFormat, img.Metadata.DecodedImageFormat);
}
this.TestFormat.VerifySpecificDecodeCall<Bgr24>(this.Marker, this.TopLevelConfiguration); this.TestFormat.VerifySpecificDecodeCall<Bgr24>(this.Marker, this.TopLevelConfiguration);
} }
@ -68,10 +71,11 @@ public partial class ImageTests
Configuration = this.TopLevelConfiguration Configuration = this.TopLevelConfiguration
}; };
var img = Image.Load(options, this.ByteSpan, out IImageFormat format); using (Image img = Image.Load(options, this.ByteSpan))
{
Assert.NotNull(img); Assert.NotNull(img);
Assert.Equal(this.TestFormat, format); Assert.Equal(this.TestFormat, img.Metadata.DecodedImageFormat);
}
this.TestFormat.VerifyAgnosticDecodeCall(this.Marker, this.TopLevelConfiguration); this.TestFormat.VerifyAgnosticDecodeCall(this.Marker, this.TopLevelConfiguration);
} }

13
tests/ImageSharp.Tests/Image/ImageTests.Load_FromBytes_UseGlobalConfiguration.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Bmp; using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
@ -20,31 +19,31 @@ public partial class ImageTests
[Fact] [Fact]
public void Bytes_Specific() public void Bytes_Specific()
{ {
using var img = Image.Load<Rgba32>(ByteSpan); using Image<Rgba32> img = Image.Load<Rgba32>(ByteSpan);
VerifyDecodedImage(img); VerifyDecodedImage(img);
} }
[Fact] [Fact]
public void Bytes_Agnostic() public void Bytes_Agnostic()
{ {
using var img = Image.Load(ByteSpan); using Image img = Image.Load(ByteSpan);
VerifyDecodedImage(img); VerifyDecodedImage(img);
} }
[Fact] [Fact]
public void Bytes_OutFormat_Specific() public void Bytes_OutFormat_Specific()
{ {
using var img = Image.Load<Rgba32>(ByteSpan, out IImageFormat format); using Image<Rgba32> img = Image.Load<Rgba32>(ByteSpan);
VerifyDecodedImage(img); VerifyDecodedImage(img);
Assert.IsType<BmpFormat>(format); Assert.IsType<BmpFormat>(img.Metadata.DecodedImageFormat);
} }
[Fact] [Fact]
public void Bytes_OutFormat_Agnostic() public void Bytes_OutFormat_Agnostic()
{ {
using var img = Image.Load(ByteSpan, out IImageFormat format); using Image img = Image.Load(ByteSpan);
VerifyDecodedImage(img); VerifyDecodedImage(img);
Assert.IsType<BmpFormat>(format); Assert.IsType<BmpFormat>(img.Metadata.DecodedImageFormat);
} }
} }
} }

54
tests/ImageSharp.Tests/Image/ImageTests.Load_FromStream_PassLocalConfiguration.cs

@ -18,10 +18,11 @@ public partial class ImageTests
Configuration = this.TopLevelConfiguration Configuration = this.TopLevelConfiguration
}; };
var img = Image.Load<Rgb24>(options, this.DataStream); using (Image<Rgb24> img = Image.Load<Rgb24>(options, this.DataStream))
{
Assert.NotNull(img); Assert.NotNull(img);
Assert.Equal(this.TestFormat.Sample<Rgb24>(), img); Assert.Equal(this.TestFormat.Sample<Rgb24>(), img);
}
this.TestFormat.VerifySpecificDecodeCall<Rgb24>(this.Marker, this.TopLevelConfiguration); this.TestFormat.VerifySpecificDecodeCall<Rgb24>(this.Marker, this.TopLevelConfiguration);
} }
@ -34,10 +35,11 @@ public partial class ImageTests
Configuration = this.TopLevelConfiguration Configuration = this.TopLevelConfiguration
}; };
var img = Image.Load(options, this.DataStream); using (Image img = Image.Load(options, this.DataStream))
{
Assert.NotNull(img); Assert.NotNull(img);
Assert.Equal(this.TestFormat.SampleAgnostic(), img); Assert.Equal(this.TestFormat.SampleAgnostic(), img);
}
this.TestFormat.VerifyAgnosticDecodeCall(this.Marker, this.TopLevelConfiguration); this.TestFormat.VerifyAgnosticDecodeCall(this.Marker, this.TopLevelConfiguration);
} }
@ -50,10 +52,11 @@ public partial class ImageTests
Configuration = this.TopLevelConfiguration Configuration = this.TopLevelConfiguration
}; };
var stream = new NonSeekableStream(this.DataStream); NonSeekableStream stream = new(this.DataStream);
var img = Image.Load<Rgba32>(options, stream); using (Image<Rgba32> img = Image.Load<Rgba32>(options, stream))
{
Assert.NotNull(img); Assert.NotNull(img);
}
this.TestFormat.VerifySpecificDecodeCall<Rgba32>(this.Marker, this.TopLevelConfiguration); this.TestFormat.VerifySpecificDecodeCall<Rgba32>(this.Marker, this.TopLevelConfiguration);
} }
@ -66,10 +69,11 @@ public partial class ImageTests
Configuration = this.TopLevelConfiguration Configuration = this.TopLevelConfiguration
}; };
var stream = new NonSeekableStream(this.DataStream); NonSeekableStream stream = new(this.DataStream);
Image<Rgba32> img = await Image.LoadAsync<Rgba32>(options, stream); using (Image<Rgba32> img = await Image.LoadAsync<Rgba32>(options, stream))
{
Assert.NotNull(img); Assert.NotNull(img);
}
this.TestFormat.VerifySpecificDecodeCall<Rgba32>(this.Marker, this.TopLevelConfiguration); this.TestFormat.VerifySpecificDecodeCall<Rgba32>(this.Marker, this.TopLevelConfiguration);
} }
@ -82,10 +86,11 @@ public partial class ImageTests
Configuration = this.TopLevelConfiguration Configuration = this.TopLevelConfiguration
}; };
var img = Image.Load<Rgba32>(options, this.DataStream, out IImageFormat format); using (Image<Rgba32> img = Image.Load<Rgba32>(options, this.DataStream))
{
Assert.NotNull(img); Assert.NotNull(img);
Assert.Equal(this.TestFormat, format); Assert.Equal(this.TestFormat, img.Metadata.DecodedImageFormat);
}
this.TestFormat.VerifySpecificDecodeCall<Rgba32>(this.Marker, this.TopLevelConfiguration); this.TestFormat.VerifySpecificDecodeCall<Rgba32>(this.Marker, this.TopLevelConfiguration);
} }
@ -98,10 +103,11 @@ public partial class ImageTests
Configuration = this.TopLevelConfiguration Configuration = this.TopLevelConfiguration
}; };
var img = Image.Load(options, this.DataStream, out IImageFormat format); using (Image img = Image.Load(options, this.DataStream))
{
Assert.NotNull(img); Assert.NotNull(img);
Assert.Equal(this.TestFormat, format); Assert.Equal(this.TestFormat, img.Metadata.DecodedImageFormat);
}
this.TestFormat.VerifyAgnosticDecodeCall(this.Marker, this.TopLevelConfiguration); this.TestFormat.VerifyAgnosticDecodeCall(this.Marker, this.TopLevelConfiguration);
} }

4
tests/ImageSharp.Tests/Image/ImageTests.Load_FromStream_ThrowsRightException.cs

@ -18,7 +18,7 @@ public partial class ImageTests
public void Image_Load_Throws_UnknownImageFormatException() public void Image_Load_Throws_UnknownImageFormatException()
=> Assert.Throws<UnknownImageFormatException>(() => => Assert.Throws<UnknownImageFormatException>(() =>
{ {
using (Image.Load(DecoderOptions.Default, this.Stream, out IImageFormat format)) using (Image.Load(DecoderOptions.Default, this.Stream))
{ {
} }
}); });
@ -27,7 +27,7 @@ public partial class ImageTests
public void Image_Load_T_Throws_UnknownImageFormatException() public void Image_Load_T_Throws_UnknownImageFormatException()
=> Assert.Throws<UnknownImageFormatException>(() => => Assert.Throws<UnknownImageFormatException>(() =>
{ {
using (Image.Load<Rgba32>(DecoderOptions.Default, this.Stream, out IImageFormat format)) using (Image.Load<Rgba32>(DecoderOptions.Default, this.Stream))
{ {
} }
}); });

29
tests/ImageSharp.Tests/Image/ImageTests.Load_FromStream_UseDefaultConfiguration.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Bmp; using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests.TestUtilities; using SixLabors.ImageSharp.Tests.TestUtilities;
@ -32,42 +31,42 @@ public partial class ImageTests
[Fact] [Fact]
public void Stream_Specific() public void Stream_Specific()
{ {
using var img = Image.Load<Rgba32>(this.Stream); using Image<Rgba32> img = Image.Load<Rgba32>(this.Stream);
VerifyDecodedImage(img); VerifyDecodedImage(img);
} }
[Fact] [Fact]
public void Stream_Agnostic() public void Stream_Agnostic()
{ {
using var img = Image.Load(this.Stream); using Image img = Image.Load(this.Stream);
VerifyDecodedImage(img); VerifyDecodedImage(img);
} }
[Fact] [Fact]
public void Stream_OutFormat_Specific() public void Stream_OutFormat_Specific()
{ {
using var img = Image.Load<Rgba32>(this.Stream, out IImageFormat format); using Image<Rgba32> img = Image.Load<Rgba32>(this.Stream);
VerifyDecodedImage(img); VerifyDecodedImage(img);
Assert.IsType<BmpFormat>(format); Assert.IsType<BmpFormat>(img.Metadata.DecodedImageFormat);
} }
[Fact] [Fact]
public void Stream_OutFormat_Agnostic() public void Stream_OutFormat_Agnostic()
{ {
using var img = Image.Load(this.Stream, out IImageFormat format); using Image img = Image.Load(this.Stream);
VerifyDecodedImage(img); VerifyDecodedImage(img);
Assert.IsType<BmpFormat>(format); Assert.IsType<BmpFormat>(img.Metadata.DecodedImageFormat);
} }
[Fact] [Fact]
public async Task Async_Stream_OutFormat_Agnostic() public async Task Async_Stream_OutFormat_Agnostic()
{ {
this.AllowSynchronousIO = false; this.AllowSynchronousIO = false;
(Image Image, IImageFormat Format) formattedImage = await Image.LoadWithFormatAsync(this.Stream); Image image = await Image.LoadAsync(this.Stream);
using (formattedImage.Image) using (image)
{ {
VerifyDecodedImage(formattedImage.Image); VerifyDecodedImage(image);
Assert.IsType<BmpFormat>(formattedImage.Format); Assert.IsType<BmpFormat>(image.Metadata.DecodedImageFormat);
} }
} }
@ -91,11 +90,11 @@ public partial class ImageTests
public async Task Async_Stream_OutFormat_Specific() public async Task Async_Stream_OutFormat_Specific()
{ {
this.AllowSynchronousIO = false; this.AllowSynchronousIO = false;
(Image<Rgba32> Image, IImageFormat Format) formattedImage = await Image.LoadWithFormatAsync<Rgba32>(this.Stream); Image<Rgba32> image = await Image.LoadAsync<Rgba32>(this.Stream);
using (formattedImage.Image) using (image)
{ {
VerifyDecodedImage(formattedImage.Image); VerifyDecodedImage(image);
Assert.IsType<BmpFormat>(formattedImage.Format); Assert.IsType<BmpFormat>(image.Metadata.DecodedImageFormat);
} }
} }

34
tests/ImageSharp.Tests/Image/ImageTests.Save.cs

@ -19,30 +19,26 @@ public partial class ImageTests
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageTests)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageTests));
string file = Path.Combine(dir, "DetectedEncoding.png"); string file = Path.Combine(dir, "DetectedEncoding.png");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
image.Save(file); image.Save(file);
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is PngFormat);
Assert.Equal("image/png", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public void WhenExtensionIsUnknown_Throws() public void WhenExtensionIsUnknown_Throws_UnknownImageFormatException()
{ {
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageTests)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageTests));
string file = Path.Combine(dir, "UnknownExtensionsEncoding_Throws.tmp"); string file = Path.Combine(dir, "UnknownExtensionsEncoding_Throws.tmp");
Assert.Throws<NotSupportedException>( Assert.Throws<UnknownImageFormatException>(
() => () =>
{ {
using (var image = new Image<Rgba32>(10, 10)) using Image<Rgba32> image = new(10, 10);
{ image.Save(file);
image.Save(file);
}
}); });
} }
@ -52,27 +48,23 @@ public partial class ImageTests
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageTests)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageTests));
string file = Path.Combine(dir, "SetEncoding.dat"); string file = Path.Combine(dir, "SetEncoding.dat");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
image.Save(file, new PngEncoder()); image.Save(file, new PngEncoder());
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is PngFormat);
Assert.Equal("image/png", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public void ThrowsWhenDisposed() public void ThrowsWhenDisposed()
{ {
using var image = new Image<Rgba32>(5, 5); using Image<Rgba32> image = new(5, 5);
image.Dispose(); image.Dispose();
IImageEncoder encoder = Mock.Of<IImageEncoder>(); IImageEncoder encoder = Mock.Of<IImageEncoder>();
using (var stream = new MemoryStream()) using MemoryStream stream = new();
{ Assert.Throws<ObjectDisposedException>(() => image.Save(stream, encoder));
Assert.Throws<ObjectDisposedException>(() => image.Save(stream, encoder));
}
} }
} }
} }

88
tests/ImageSharp.Tests/Image/ImageTests.SaveAsync.cs

@ -21,30 +21,26 @@ public partial class ImageTests
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageTests)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageTests));
string file = Path.Combine(dir, "DetectedEncodingAsync.png"); string file = Path.Combine(dir, "DetectedEncodingAsync.png");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
await image.SaveAsync(file); await image.SaveAsync(file);
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is PngFormat);
Assert.Equal("image/png", mime.DefaultMimeType);
}
} }
[Fact] [Fact]
public async Task WhenExtensionIsUnknown_Throws() public Task WhenExtensionIsUnknown_Throws_UnknownImageFormatException()
{ {
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageTests)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageTests));
string file = Path.Combine(dir, "UnknownExtensionsEncoding_Throws.tmp"); string file = Path.Combine(dir, "UnknownExtensionsEncoding_Throws.tmp");
await Assert.ThrowsAsync<NotSupportedException>( return Assert.ThrowsAsync<UnknownImageFormatException>(
async () => async () =>
{ {
using (var image = new Image<Rgba32>(10, 10)) using Image<Rgba32> image = new(10, 10);
{ await image.SaveAsync(file);
await image.SaveAsync(file);
}
}); });
} }
@ -54,15 +50,13 @@ public partial class ImageTests
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageTests)); string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageTests));
string file = Path.Combine(dir, "SetEncoding.dat"); string file = Path.Combine(dir, "SetEncoding.dat");
using (var image = new Image<Rgba32>(10, 10)) using (Image<Rgba32> image = new(10, 10))
{ {
await image.SaveAsync(file, new PngEncoder()); await image.SaveAsync(file, new PngEncoder());
} }
using (Image.Load(file, out IImageFormat mime)) Image.TryDetectFormat(file, out IImageFormat format);
{ Assert.True(format is PngFormat);
Assert.Equal("image/png", mime.DefaultMimeType);
}
} }
[Theory] [Theory]
@ -74,39 +68,29 @@ public partial class ImageTests
[InlineData("test.gif", "image/gif")] [InlineData("test.gif", "image/gif")]
public async Task SaveStreamWithMime(string filename, string mimeType) public async Task SaveStreamWithMime(string filename, string mimeType)
{ {
using (var image = new Image<Rgba32>(5, 5)) using Image<Rgba32> image = new(5, 5);
{ string ext = Path.GetExtension(filename);
string ext = Path.GetExtension(filename); image.GetConfiguration().ImageFormatsManager.TryFindFormatByFileExtension(ext, out IImageFormat format);
image.GetConfiguration().ImageFormatsManager.TryFindFormatByFileExtension(ext, out IImageFormat format); Assert.Equal(mimeType, format!.DefaultMimeType);
Assert.Equal(mimeType, format!.DefaultMimeType);
using (var stream = new MemoryStream())
{
var asyncStream = new AsyncStreamWrapper(stream, () => false);
await image.SaveAsync(asyncStream, format);
stream.Position = 0; using MemoryStream stream = new();
AsyncStreamWrapper asyncStream = new(stream, () => false);
await image.SaveAsync(asyncStream, format);
(Image Image, IImageFormat Format) imf = await Image.LoadWithFormatAsync(stream); stream.Position = 0;
Assert.Equal(format, imf.Format); Image.TryDetectFormat(stream, out IImageFormat format2);
Assert.Equal(mimeType, imf.Format.DefaultMimeType); Assert.Equal(format, format2);
imf.Image.Dispose();
}
}
} }
[Fact] [Fact]
public async Task ThrowsWhenDisposed() public async Task ThrowsWhenDisposed()
{ {
var image = new Image<Rgba32>(5, 5); Image<Rgba32> image = new(5, 5);
image.Dispose(); image.Dispose();
IImageEncoder encoder = Mock.Of<IImageEncoder>(); IImageEncoder encoder = Mock.Of<IImageEncoder>();
using (var stream = new MemoryStream()) using MemoryStream stream = new();
{ await Assert.ThrowsAsync<ObjectDisposedException>(async () => await image.SaveAsync(stream, encoder));
await Assert.ThrowsAsync<ObjectDisposedException>(async () => await image.SaveAsync(stream, encoder));
}
} }
[Theory] [Theory]
@ -118,27 +102,23 @@ public partial class ImageTests
[InlineData("test.gif")] [InlineData("test.gif")]
public async Task SaveAsync_NeverCallsSyncMethods(string filename) public async Task SaveAsync_NeverCallsSyncMethods(string filename)
{ {
using (var image = new Image<Rgba32>(5, 5)) using Image<Rgba32> image = new(5, 5);
{ IImageEncoder encoder = image.DetectEncoder(filename);
IImageEncoder encoder = image.DetectEncoder(filename); using MemoryStream stream = new();
using (var stream = new MemoryStream()) AsyncStreamWrapper asyncStream = new(stream, () => false);
{ await image.SaveAsync(asyncStream, encoder);
var asyncStream = new AsyncStreamWrapper(stream, () => false);
await image.SaveAsync(asyncStream, encoder);
}
}
} }
[Fact] [Fact]
public async Task SaveAsync_WithNonSeekableStream_IsCancellable() public async Task SaveAsync_WithNonSeekableStream_IsCancellable()
{ {
using var image = new Image<Rgba32>(4000, 4000); using Image<Rgba32> image = new(4000, 4000);
var encoder = new PngEncoder() { CompressionLevel = PngCompressionLevel.BestCompression }; PngEncoder encoder = new() { CompressionLevel = PngCompressionLevel.BestCompression };
using var stream = new MemoryStream(); using MemoryStream stream = new();
var asyncStream = new AsyncStreamWrapper(stream, () => false); AsyncStreamWrapper asyncStream = new(stream, () => false);
var cts = new CancellationTokenSource(); CancellationTokenSource cts = new();
var pausedStream = new PausedStream(asyncStream); PausedStream pausedStream = new(asyncStream);
pausedStream.OnWaiting(s => pausedStream.OnWaiting(s =>
{ {
cts.Cancel(); cts.Cancel();

72
tests/ImageSharp.Tests/Image/ImageTests.cs

@ -23,7 +23,7 @@ public partial class ImageTests
[Fact] [Fact]
public void Width_Height() public void Width_Height()
{ {
using (var image = new Image<Rgba32>(11, 23)) using (Image<Rgba32> image = new(11, 23))
{ {
Assert.Equal(11, image.Width); Assert.Equal(11, image.Width);
Assert.Equal(23, image.Height); Assert.Equal(23, image.Height);
@ -40,7 +40,7 @@ public partial class ImageTests
{ {
Configuration configuration = Configuration.Default.Clone(); Configuration configuration = Configuration.Default.Clone();
using (var image = new Image<Rgba32>(configuration, 11, 23)) using (Image<Rgba32> image = new(configuration, 11, 23))
{ {
Assert.Equal(11, image.Width); Assert.Equal(11, image.Width);
Assert.Equal(23, image.Height); Assert.Equal(23, image.Height);
@ -58,7 +58,7 @@ public partial class ImageTests
Configuration configuration = Configuration.Default.Clone(); Configuration configuration = Configuration.Default.Clone();
Rgba32 color = Color.Aquamarine; Rgba32 color = Color.Aquamarine;
using (var image = new Image<Rgba32>(configuration, 11, 23, color)) using (Image<Rgba32> image = new(configuration, 11, 23, color))
{ {
Assert.Equal(11, image.Width); Assert.Equal(11, image.Width);
Assert.Equal(23, image.Height); Assert.Equal(23, image.Height);
@ -77,9 +77,9 @@ public partial class ImageTests
byte dirtyValue = 123; byte dirtyValue = 123;
configuration.MemoryAllocator = new TestMemoryAllocator(dirtyValue); configuration.MemoryAllocator = new TestMemoryAllocator(dirtyValue);
var metadata = new ImageMetadata(); ImageMetadata metadata = new();
using (var image = Image.CreateUninitialized<L8>(configuration, 21, 22, metadata)) using (Image<L8> image = Image.CreateUninitialized<L8>(configuration, 21, 22, metadata))
{ {
Assert.Equal(21, image.Width); Assert.Equal(21, image.Width);
Assert.Equal(22, image.Height); Assert.Equal(22, image.Height);
@ -108,7 +108,7 @@ public partial class ImageTests
this.LimitBufferCapacity(100); this.LimitBufferCapacity(100);
} }
using var image = new Image<Rgba32>(this.configuration, 10, 10); using Image<Rgba32> image = new(this.configuration, 10, 10);
Rgba32 val = image[3, 4]; Rgba32 val = image[3, 4];
Assert.Equal(default(Rgba32), val); Assert.Equal(default(Rgba32), val);
image[3, 4] = Color.Red; image[3, 4] = Color.Red;
@ -116,7 +116,7 @@ public partial class ImageTests
Assert.Equal(Color.Red.ToRgba32(), val); Assert.Equal(Color.Red.ToRgba32(), val);
} }
public static TheoryData<bool, int> OutOfRangeData = new TheoryData<bool, int>() public static TheoryData<bool, int> OutOfRangeData = new()
{ {
{ false, -1 }, { false, -1 },
{ false, 10 }, { false, 10 },
@ -133,7 +133,7 @@ public partial class ImageTests
this.LimitBufferCapacity(100); this.LimitBufferCapacity(100);
} }
using var image = new Image<Rgba32>(this.configuration, 10, 10); using Image<Rgba32> image = new(this.configuration, 10, 10);
ArgumentOutOfRangeException ex = Assert.Throws<ArgumentOutOfRangeException>(() => _ = image[x, 3]); ArgumentOutOfRangeException ex = Assert.Throws<ArgumentOutOfRangeException>(() => _ = image[x, 3]);
Assert.Equal("x", ex.ParamName); Assert.Equal("x", ex.ParamName);
} }
@ -147,7 +147,7 @@ public partial class ImageTests
this.LimitBufferCapacity(100); this.LimitBufferCapacity(100);
} }
using var image = new Image<Rgba32>(this.configuration, 10, 10); using Image<Rgba32> image = new(this.configuration, 10, 10);
ArgumentOutOfRangeException ex = Assert.Throws<ArgumentOutOfRangeException>(() => image[x, 3] = default); ArgumentOutOfRangeException ex = Assert.Throws<ArgumentOutOfRangeException>(() => image[x, 3] = default);
Assert.Equal("x", ex.ParamName); Assert.Equal("x", ex.ParamName);
} }
@ -161,7 +161,7 @@ public partial class ImageTests
this.LimitBufferCapacity(100); this.LimitBufferCapacity(100);
} }
using var image = new Image<Rgba32>(this.configuration, 10, 10); using Image<Rgba32> image = new(this.configuration, 10, 10);
ArgumentOutOfRangeException ex = Assert.Throws<ArgumentOutOfRangeException>(() => image[3, y] = default); ArgumentOutOfRangeException ex = Assert.Throws<ArgumentOutOfRangeException>(() => image[3, y] = default);
Assert.Equal("y", ex.ParamName); Assert.Equal("y", ex.ParamName);
} }
@ -178,7 +178,7 @@ public partial class ImageTests
this.LimitBufferCapacity(20); this.LimitBufferCapacity(20);
} }
using var image = new Image<La16>(this.configuration, 10, 10); using Image<La16> image = new(this.configuration, 10, 10);
if (disco) if (disco)
{ {
Assert.True(image.GetPixelMemoryGroup().Count > 1); Assert.True(image.GetPixelMemoryGroup().Count > 1);
@ -204,7 +204,7 @@ public partial class ImageTests
[InlineData(true)] [InlineData(true)]
public void CopyPixelDataTo_DestinationTooShort_Throws(bool byteSpan) public void CopyPixelDataTo_DestinationTooShort_Throws(bool byteSpan)
{ {
using var image = new Image<La16>(this.configuration, 10, 10); using Image<La16> image = new(this.configuration, 10, 10);
Assert.ThrowsAny<ArgumentOutOfRangeException>(() => Assert.ThrowsAny<ArgumentOutOfRangeException>(() =>
{ {
@ -243,7 +243,7 @@ public partial class ImageTests
[Fact] [Fact]
public void NullReference_Throws() public void NullReference_Throws()
{ {
using var img = new Image<Rgb24>(1, 1); using Image<Rgb24> img = new(1, 1);
Assert.Throws<ArgumentNullException>(() => img.ProcessPixelRows(null)); Assert.Throws<ArgumentNullException>(() => img.ProcessPixelRows(null));
@ -262,7 +262,7 @@ public partial class ImageTests
public void MultipleDisposeCalls() public void MultipleDisposeCalls()
{ {
var image = new Image<Rgba32>(this.configuration, 10, 10); Image<Rgba32> image = new(this.configuration, 10, 10);
image.Dispose(); image.Dispose();
image.Dispose(); image.Dispose();
} }
@ -270,24 +270,24 @@ public partial class ImageTests
[Fact] [Fact]
public void NonPrivateProperties_ObjectDisposedException() public void NonPrivateProperties_ObjectDisposedException()
{ {
var image = new Image<Rgba32>(this.configuration, 10, 10); Image<Rgba32> image = new(this.configuration, 10, 10);
var genericImage = (Image)image; Image genericImage = (Image)image;
image.Dispose(); image.Dispose();
// Image<TPixel> // Image<TPixel>
Assert.Throws<ObjectDisposedException>(() => { var prop = image.Frames; }); Assert.Throws<ObjectDisposedException>(() => { ImageFrameCollection<Rgba32> prop = image.Frames; });
// Image // Image
Assert.Throws<ObjectDisposedException>(() => { var prop = genericImage.Frames; }); Assert.Throws<ObjectDisposedException>(() => { ImageFrameCollection prop = genericImage.Frames; });
} }
[Fact] [Fact]
public void Save_ObjectDisposedException() public void Save_ObjectDisposedException()
{ {
using var stream = new MemoryStream(); using MemoryStream stream = new();
var image = new Image<Rgba32>(this.configuration, 10, 10); Image<Rgba32> image = new(this.configuration, 10, 10);
var encoder = new JpegEncoder(); JpegEncoder encoder = new();
image.Dispose(); image.Dispose();
@ -307,18 +307,18 @@ public partial class ImageTests
[Fact] [Fact]
public void NonPrivateMethods_ObjectDisposedException() public void NonPrivateMethods_ObjectDisposedException()
{ {
var image = new Image<Rgba32>(this.configuration, 10, 10); Image<Rgba32> image = new(this.configuration, 10, 10);
var genericImage = (Image)image; Image genericImage = (Image)image;
image.Dispose(); image.Dispose();
// Image<TPixel> // Image<TPixel>
Assert.Throws<ObjectDisposedException>(() => { var res = image.Clone(this.configuration); }); Assert.Throws<ObjectDisposedException>(() => { Image<Rgba32> res = image.Clone(this.configuration); });
Assert.Throws<ObjectDisposedException>(() => { var res = image.CloneAs<Rgba32>(this.configuration); }); Assert.Throws<ObjectDisposedException>(() => { Image<Rgba32> res = image.CloneAs<Rgba32>(this.configuration); });
Assert.Throws<ObjectDisposedException>(() => { var res = image.DangerousTryGetSinglePixelMemory(out Memory<Rgba32> _); }); Assert.Throws<ObjectDisposedException>(() => { bool res = image.DangerousTryGetSinglePixelMemory(out Memory<Rgba32> _); });
// Image // Image
Assert.Throws<ObjectDisposedException>(() => { var res = genericImage.CloneAs<Rgba32>(this.configuration); }); Assert.Throws<ObjectDisposedException>(() => { Image<Rgba32> res = genericImage.CloneAs<Rgba32>(this.configuration); });
} }
} }
@ -327,29 +327,29 @@ public partial class ImageTests
[Fact] [Fact]
public void KnownExtension_ReturnsEncoder() public void KnownExtension_ReturnsEncoder()
{ {
using var image = new Image<L8>(1, 1); using Image<L8> image = new(1, 1);
IImageEncoder encoder = image.DetectEncoder("dummy.png"); IImageEncoder encoder = image.DetectEncoder("dummy.png");
Assert.NotNull(encoder); Assert.NotNull(encoder);
Assert.IsType<PngEncoder>(encoder); Assert.IsType<PngEncoder>(encoder);
} }
[Fact] [Fact]
public void UnknownExtension_ThrowsNotSupportedException() public void UnknownExtension_ThrowsUnknownImageFormatException()
{ {
using var image = new Image<L8>(1, 1); using Image<L8> image = new(1, 1);
Assert.Throws<NotSupportedException>(() => image.DetectEncoder("dummy.yolo")); Assert.Throws<UnknownImageFormatException>(() => image.DetectEncoder("dummy.yolo"));
} }
[Fact] [Fact]
public void NoDetectorRegisteredForKnownExtension_ThrowsNotSupportedException() public void NoDetectorRegisteredForKnownExtension_ThrowsUnknownImageFormatException()
{ {
var configuration = new Configuration(); Configuration configuration = new();
var format = new TestFormat(); TestFormat format = new();
configuration.ImageFormatsManager.AddImageFormat(format); configuration.ImageFormatsManager.AddImageFormat(format);
configuration.ImageFormatsManager.AddImageFormatDetector(new MockImageFormatDetector(format)); configuration.ImageFormatsManager.AddImageFormatDetector(new MockImageFormatDetector(format));
using var image = new Image<L8>(configuration, 1, 1); using Image<L8> image = new(configuration, 1, 1);
Assert.Throws<NotSupportedException>(() => image.DetectEncoder($"dummy.{format.Extension}")); Assert.Throws<UnknownImageFormatException>(() => image.DetectEncoder($"dummy.{format.Extension}"));
} }
} }
} }

2
tests/ImageSharp.Tests/Image/LargeImageIntegrationTests.cs

@ -56,7 +56,7 @@ public class LargeImageIntegrationTests
Configuration configuration = Configuration.Default.Clone(); Configuration configuration = Configuration.Default.Clone();
configuration.PreferContiguousImageBuffers = true; configuration.PreferContiguousImageBuffers = true;
configuration.ImageFormatsManager.TryFindFormatByFileExtension(formatInner, out IImageFormat format); configuration.ImageFormatsManager.TryFindFormatByFileExtension(formatInner, out IImageFormat format);
IImageEncoder encoder = configuration.ImageFormatsManager.FindEncoder(format!); IImageEncoder encoder = configuration.ImageFormatsManager.GetEncoder(format!);
string dir = TestEnvironment.CreateOutputDirectory(".Temp"); string dir = TestEnvironment.CreateOutputDirectory(".Temp");
string path = Path.Combine(dir, $"{Guid.NewGuid()}.{formatInner}"); string path = Path.Combine(dir, $"{Guid.NewGuid()}.{formatInner}");
using (Image<Rgba32> temp = new(2048, 2048)) using (Image<Rgba32> temp = new(2048, 2048))

412
tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs

@ -38,15 +38,13 @@ public class ResizeTests
{ {
string filePath = TestFile.GetInputFileFullPath(TestImages.Jpeg.Baseline.Calliphora); string filePath = TestFile.GetInputFileFullPath(TestImages.Jpeg.Baseline.Calliphora);
using (var image = Image.Load(filePath)) using Image image = Image.Load(filePath);
{ image.Mutate(x => x.Resize(image.Size() / 2));
image.Mutate(x => x.Resize(image.Size() / 2)); string path = Path.Combine(
string path = System.IO.Path.Combine( TestEnvironment.CreateOutputDirectory(nameof(ResizeTests)),
TestEnvironment.CreateOutputDirectory(nameof(ResizeTests)), nameof(this.Resize_PixelAgnostic) + ".png");
nameof(this.Resize_PixelAgnostic) + ".png");
image.Save(path); image.Save(path);
}
} }
[Theory(Skip = "Debug only, enable manually")] [Theory(Skip = "Debug only, enable manually")]
@ -63,11 +61,9 @@ public class ResizeTests
provider.Configuration.WorkingBufferSizeHintInBytes = workingBufferSizeHintInKilobytes * 1024; provider.Configuration.WorkingBufferSizeHintInBytes = workingBufferSizeHintInKilobytes * 1024;
using (Image<TPixel> image = provider.GetImage()) using Image<TPixel> image = provider.GetImage();
{ image.Mutate(x => x.Resize(destSize, destSize));
image.Mutate(x => x.Resize(destSize, destSize)); image.DebugSave(provider, appendPixelTypeToFileName: false);
image.DebugSave(provider, appendPixelTypeToFileName: false);
}
} }
[Theory] [Theory]
@ -81,14 +77,12 @@ public class ResizeTests
// [WithBasicTestPatternImages(15, 12, PixelTypes.Rgba32, 2, 3, 1, 2)] means: // [WithBasicTestPatternImages(15, 12, PixelTypes.Rgba32, 2, 3, 1, 2)] means:
// resizing: (15, 12) -> (10, 6) // resizing: (15, 12) -> (10, 6)
// kernel dimensions: (3, 4) // kernel dimensions: (3, 4)
using (Image<TPixel> image = provider.GetImage()) using Image<TPixel> image = provider.GetImage();
{ Size destSize = new Size(image.Width * wN / wD, image.Height * hN / hD);
var destSize = new Size(image.Width * wN / wD, image.Height * hN / hD); image.Mutate(x => x.Resize(destSize, KnownResamplers.Bicubic, false));
image.Mutate(x => x.Resize(destSize, KnownResamplers.Bicubic, false)); FormattableString outputInfo = $"({wN}÷{wD},{hN}÷{hD})";
FormattableString outputInfo = $"({wN}÷{wD},{hN}÷{hD})"; image.DebugSave(provider, outputInfo, appendPixelTypeToFileName: false);
image.DebugSave(provider, outputInfo, appendPixelTypeToFileName: false); image.CompareToReferenceOutput(provider, outputInfo, appendPixelTypeToFileName: false);
image.CompareToReferenceOutput(provider, outputInfo, appendPixelTypeToFileName: false);
}
} }
private static readonly int SizeOfVector4 = Unsafe.SizeOf<Vector4>(); private static readonly int SizeOfVector4 = Unsafe.SizeOf<Vector4>();
@ -106,48 +100,44 @@ public class ResizeTests
int workingBufferLimitInRows) int workingBufferLimitInRows)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Image<TPixel> image0 = provider.GetImage()) using Image<TPixel> image0 = provider.GetImage();
{ Size destSize = image0.Size() / 4;
Size destSize = image0.Size() / 4;
Configuration configuration = Configuration.CreateDefaultInstance();
var configuration = Configuration.CreateDefaultInstance();
int workingBufferSizeHintInBytes = workingBufferLimitInRows * destSize.Width * SizeOfVector4;
int workingBufferSizeHintInBytes = workingBufferLimitInRows * destSize.Width * SizeOfVector4; TestMemoryAllocator allocator = new TestMemoryAllocator();
var allocator = new TestMemoryAllocator(); allocator.EnableNonThreadSafeLogging();
allocator.EnableNonThreadSafeLogging(); configuration.MemoryAllocator = allocator;
configuration.MemoryAllocator = allocator; configuration.WorkingBufferSizeHintInBytes = workingBufferSizeHintInBytes;
configuration.WorkingBufferSizeHintInBytes = workingBufferSizeHintInBytes;
ResizeKernelMap verticalKernelMap = ResizeKernelMap.Calculate<BicubicResampler>(
var verticalKernelMap = ResizeKernelMap.Calculate<BicubicResampler>( default,
default, destSize.Height,
destSize.Height, image0.Height,
image0.Height, Configuration.Default.MemoryAllocator);
Configuration.Default.MemoryAllocator); int minimumWorkerAllocationInBytes = verticalKernelMap.MaxDiameter * 2 * destSize.Width * SizeOfVector4;
int minimumWorkerAllocationInBytes = verticalKernelMap.MaxDiameter * 2 * destSize.Width * SizeOfVector4; verticalKernelMap.Dispose();
verticalKernelMap.Dispose();
using Image<TPixel> image = image0.Clone(configuration);
using (Image<TPixel> image = image0.Clone(configuration)) image.Mutate(x => x.Resize(destSize, KnownResamplers.Bicubic, false));
{
image.Mutate(x => x.Resize(destSize, KnownResamplers.Bicubic, false)); image.DebugSave(
provider,
image.DebugSave( testOutputDetails: workingBufferLimitInRows,
provider, appendPixelTypeToFileName: false);
testOutputDetails: workingBufferLimitInRows, image.CompareToReferenceOutput(
appendPixelTypeToFileName: false); ImageComparer.TolerantPercentage(0.004f),
image.CompareToReferenceOutput( provider,
ImageComparer.TolerantPercentage(0.004f), testOutputDetails: workingBufferLimitInRows,
provider, appendPixelTypeToFileName: false);
testOutputDetails: workingBufferLimitInRows,
appendPixelTypeToFileName: false);
Assert.NotEmpty(allocator.AllocationLog); Assert.NotEmpty(allocator.AllocationLog);
int maxAllocationSize = allocator.AllocationLog.Where( int maxAllocationSize = allocator.AllocationLog.Where(
e => e.ElementType == typeof(Vector4)).Max(e => e.LengthInBytes); e => e.ElementType == typeof(Vector4)).Max(e => e.LengthInBytes);
Assert.True(maxAllocationSize <= Math.Max(workingBufferSizeHintInBytes, minimumWorkerAllocationInBytes)); Assert.True(maxAllocationSize <= Math.Max(workingBufferSizeHintInBytes, minimumWorkerAllocationInBytes));
}
}
} }
[Theory] [Theory]
@ -188,13 +178,11 @@ public class ResizeTests
public void Resize_Compand<TPixel>(TestImageProvider<TPixel> provider) public void Resize_Compand<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Image<TPixel> image = provider.GetImage()) using Image<TPixel> image = provider.GetImage();
{ image.Mutate(x => x.Resize(image.Size() / 2, true));
image.Mutate(x => x.Resize(image.Size() / 2, true));
image.DebugSave(provider); image.DebugSave(provider);
image.CompareToReferenceOutput(ValidatorComparer, provider); image.CompareToReferenceOutput(ValidatorComparer, provider);
}
} }
[Theory] [Theory]
@ -223,7 +211,7 @@ public class ResizeTests
provider.RunValidatingProcessorTest( provider.RunValidatingProcessorTest(
x => x =>
{ {
var resizeOptions = new ResizeOptions() ResizeOptions resizeOptions = new ResizeOptions()
{ {
Size = x.GetCurrentSize() / 2, Size = x.GetCurrentSize() / 2,
Mode = ResizeMode.Crop, Mode = ResizeMode.Crop,
@ -243,13 +231,11 @@ public class ResizeTests
public void Resize_IsAppliedToAllFrames<TPixel>(TestImageProvider<TPixel> provider) public void Resize_IsAppliedToAllFrames<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Image<TPixel> image = provider.GetImage()) using Image<TPixel> image = provider.GetImage();
{ image.Mutate(x => x.Resize(image.Width / 2, image.Height / 2, KnownResamplers.Bicubic));
image.Mutate(x => x.Resize(image.Width / 2, image.Height / 2, KnownResamplers.Bicubic));
// Comparer fights decoder with gif-s. Could not use CompareToReferenceOutput here :( // Comparer fights decoder with gif-s. Could not use CompareToReferenceOutput here :(
image.DebugSave(provider, extension: "gif"); image.DebugSave(provider, extension: "gif");
}
} }
[Theory] [Theory]
@ -265,17 +251,13 @@ public class ResizeTests
public void Resize_ThrowsForWrappedMemoryImage<TPixel>(TestImageProvider<TPixel> provider) public void Resize_ThrowsForWrappedMemoryImage<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Image<TPixel> image0 = provider.GetImage()) using Image<TPixel> image0 = provider.GetImage();
{ Assert.True(image0.DangerousTryGetSinglePixelMemory(out Memory<TPixel> imageMem));
Assert.True(image0.DangerousTryGetSinglePixelMemory(out Memory<TPixel> imageMem)); TestMemoryManager<TPixel> mmg = TestMemoryManager<TPixel>.CreateAsCopyOf(imageMem.Span);
var mmg = TestMemoryManager<TPixel>.CreateAsCopyOf(imageMem.Span);
using (var image1 = Image.WrapMemory(mmg.Memory, image0.Width, image0.Height)) using Image<TPixel> image1 = Image.WrapMemory(mmg.Memory, image0.Width, image0.Height);
{ Assert.ThrowsAny<Exception>(
Assert.ThrowsAny<Exception>( () => { image1.Mutate(x => x.Resize(image0.Width / 2, image0.Height / 2, true)); });
() => { image1.Mutate(x => x.Resize(image0.Width / 2, image0.Height / 2, true)); });
}
}
} }
[Theory] [Theory]
@ -341,7 +323,7 @@ public class ResizeTests
&& TestEnvironment.NetCoreVersion == null && TestEnvironment.NetCoreVersion == null
&& sampler is NearestNeighborResampler; && sampler is NearestNeighborResampler;
var comparer = ImageComparer.TolerantPercentage(allowHigherInaccuracy ? 0.3f : 0.017f); ImageComparer comparer = ImageComparer.TolerantPercentage(allowHigherInaccuracy ? 0.3f : 0.017f);
// Let's make the working buffer size non-default: // Let's make the working buffer size non-default:
provider.Configuration.WorkingBufferSizeHintInBytes = 16 * 1024 * SizeOfVector4; provider.Configuration.WorkingBufferSizeHintInBytes = 16 * 1024 * SizeOfVector4;
@ -382,27 +364,25 @@ public class ResizeTests
public void ResizeFromSourceRectangle<TPixel>(TestImageProvider<TPixel> provider) public void ResizeFromSourceRectangle<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Image<TPixel> image = provider.GetImage()) using Image<TPixel> image = provider.GetImage();
{ Rectangle sourceRectangle = new Rectangle(
var sourceRectangle = new Rectangle( image.Width / 8,
image.Width / 8, image.Height / 8,
image.Height / 8, image.Width / 4,
image.Width / 4, image.Height / 4);
image.Height / 4); Rectangle destRectangle = new Rectangle(image.Width / 4, image.Height / 4, image.Width / 2, image.Height / 2);
var destRectangle = new Rectangle(image.Width / 4, image.Height / 4, image.Width / 2, image.Height / 2);
image.Mutate(
image.Mutate( x => x.Resize(
x => x.Resize( image.Width,
image.Width, image.Height,
image.Height, KnownResamplers.Bicubic,
KnownResamplers.Bicubic, sourceRectangle,
sourceRectangle, destRectangle,
destRectangle, false));
false));
image.DebugSave(provider);
image.DebugSave(provider); image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false);
image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false);
}
} }
[Theory] [Theory]
@ -410,13 +390,11 @@ public class ResizeTests
public void ResizeHeightAndKeepAspect<TPixel>(TestImageProvider<TPixel> provider) public void ResizeHeightAndKeepAspect<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Image<TPixel> image = provider.GetImage()) using Image<TPixel> image = provider.GetImage();
{ image.Mutate(x => x.Resize(0, image.Height / 3, false));
image.Mutate(x => x.Resize(0, image.Height / 3, false));
image.DebugSave(provider); image.DebugSave(provider);
image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false); image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false);
}
} }
[Theory] [Theory]
@ -424,12 +402,10 @@ public class ResizeTests
public void ResizeHeightCannotKeepAspectKeepsOnePixel<TPixel>(TestImageProvider<TPixel> provider) public void ResizeHeightCannotKeepAspectKeepsOnePixel<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Image<TPixel> image = provider.GetImage()) using Image<TPixel> image = provider.GetImage();
{ image.Mutate(x => x.Resize(0, 5));
image.Mutate(x => x.Resize(0, 5)); Assert.Equal(1, image.Width);
Assert.Equal(1, image.Width); Assert.Equal(5, image.Height);
Assert.Equal(5, image.Height);
}
} }
[Theory] [Theory]
@ -437,13 +413,11 @@ public class ResizeTests
public void ResizeWidthAndKeepAspect<TPixel>(TestImageProvider<TPixel> provider) public void ResizeWidthAndKeepAspect<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Image<TPixel> image = provider.GetImage()) using Image<TPixel> image = provider.GetImage();
{ image.Mutate(x => x.Resize(image.Width / 3, 0, false));
image.Mutate(x => x.Resize(image.Width / 3, 0, false));
image.DebugSave(provider); image.DebugSave(provider);
image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false); image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false);
}
} }
[Theory] [Theory]
@ -451,12 +425,10 @@ public class ResizeTests
public void ResizeWidthCannotKeepAspectKeepsOnePixel<TPixel>(TestImageProvider<TPixel> provider) public void ResizeWidthCannotKeepAspectKeepsOnePixel<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Image<TPixel> image = provider.GetImage()) using Image<TPixel> image = provider.GetImage();
{ image.Mutate(x => x.Resize(5, 0));
image.Mutate(x => x.Resize(5, 0)); Assert.Equal(5, image.Width);
Assert.Equal(5, image.Width); Assert.Equal(1, image.Height);
Assert.Equal(1, image.Height);
}
} }
[Theory] [Theory]
@ -464,20 +436,18 @@ public class ResizeTests
public void ResizeWithBoxPadMode<TPixel>(TestImageProvider<TPixel> provider) public void ResizeWithBoxPadMode<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Image<TPixel> image = provider.GetImage()) using Image<TPixel> image = provider.GetImage();
ResizeOptions options = new ResizeOptions
{ {
var options = new ResizeOptions Size = new Size(image.Width + 200, image.Height + 200),
{ Mode = ResizeMode.BoxPad,
Size = new Size(image.Width + 200, image.Height + 200), PadColor = Color.HotPink
Mode = ResizeMode.BoxPad, };
PadColor = Color.HotPink
};
image.Mutate(x => x.Resize(options)); image.Mutate(x => x.Resize(options));
image.DebugSave(provider); image.DebugSave(provider);
image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false); image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false);
}
} }
[Theory] [Theory]
@ -485,15 +455,13 @@ public class ResizeTests
public void ResizeWithCropHeightMode<TPixel>(TestImageProvider<TPixel> provider) public void ResizeWithCropHeightMode<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Image<TPixel> image = provider.GetImage()) using Image<TPixel> image = provider.GetImage();
{ ResizeOptions options = new ResizeOptions { Size = new Size(image.Width, image.Height / 2) };
var options = new ResizeOptions { Size = new Size(image.Width, image.Height / 2) };
image.Mutate(x => x.Resize(options)); image.Mutate(x => x.Resize(options));
image.DebugSave(provider); image.DebugSave(provider);
image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false); image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false);
}
} }
[Theory] [Theory]
@ -501,15 +469,13 @@ public class ResizeTests
public void ResizeWithCropWidthMode<TPixel>(TestImageProvider<TPixel> provider) public void ResizeWithCropWidthMode<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Image<TPixel> image = provider.GetImage()) using Image<TPixel> image = provider.GetImage();
{ ResizeOptions options = new ResizeOptions { Size = new Size(image.Width / 2, image.Height) };
var options = new ResizeOptions { Size = new Size(image.Width / 2, image.Height) };
image.Mutate(x => x.Resize(options)); image.Mutate(x => x.Resize(options));
image.DebugSave(provider); image.DebugSave(provider);
image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false); image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false);
}
} }
[Theory] [Theory]
@ -517,19 +483,17 @@ public class ResizeTests
public void CanResizeLargeImageWithCropMode<TPixel>(TestImageProvider<TPixel> provider) public void CanResizeLargeImageWithCropMode<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Image<TPixel> image = provider.GetImage()) using Image<TPixel> image = provider.GetImage();
ResizeOptions options = new ResizeOptions
{ {
var options = new ResizeOptions Size = new Size(480, 600),
{ Mode = ResizeMode.Crop
Size = new Size(480, 600), };
Mode = ResizeMode.Crop
};
image.Mutate(x => x.Resize(options)); image.Mutate(x => x.Resize(options));
image.DebugSave(provider); image.DebugSave(provider);
image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false); image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false);
}
} }
[Theory] [Theory]
@ -537,15 +501,13 @@ public class ResizeTests
public void ResizeWithMaxMode<TPixel>(TestImageProvider<TPixel> provider) public void ResizeWithMaxMode<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Image<TPixel> image = provider.GetImage()) using Image<TPixel> image = provider.GetImage();
{ ResizeOptions options = new ResizeOptions { Size = new Size(300, 300), Mode = ResizeMode.Max };
var options = new ResizeOptions { Size = new Size(300, 300), Mode = ResizeMode.Max };
image.Mutate(x => x.Resize(options)); image.Mutate(x => x.Resize(options));
image.DebugSave(provider); image.DebugSave(provider);
image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false); image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false);
}
} }
[Theory] [Theory]
@ -553,19 +515,17 @@ public class ResizeTests
public void ResizeWithMinMode<TPixel>(TestImageProvider<TPixel> provider) public void ResizeWithMinMode<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Image<TPixel> image = provider.GetImage()) using Image<TPixel> image = provider.GetImage();
ResizeOptions options = new ResizeOptions
{ {
var options = new ResizeOptions Size = new Size((int)Math.Round(image.Width * .75F), (int)Math.Round(image.Height * .95F)),
{ Mode = ResizeMode.Min
Size = new Size((int)Math.Round(image.Width * .75F), (int)Math.Round(image.Height * .95F)), };
Mode = ResizeMode.Min
};
image.Mutate(x => x.Resize(options)); image.Mutate(x => x.Resize(options));
image.DebugSave(provider); image.DebugSave(provider);
image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false); image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false);
}
} }
[Theory] [Theory]
@ -573,20 +533,18 @@ public class ResizeTests
public void ResizeWithPadMode<TPixel>(TestImageProvider<TPixel> provider) public void ResizeWithPadMode<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Image<TPixel> image = provider.GetImage()) using Image<TPixel> image = provider.GetImage();
ResizeOptions options = new ResizeOptions
{ {
var options = new ResizeOptions Size = new Size(image.Width + 200, image.Height),
{ Mode = ResizeMode.Pad,
Size = new Size(image.Width + 200, image.Height), PadColor = Color.Lavender
Mode = ResizeMode.Pad, };
PadColor = Color.Lavender
};
image.Mutate(x => x.Resize(options)); image.Mutate(x => x.Resize(options));
image.DebugSave(provider); image.DebugSave(provider);
image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false); image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false);
}
} }
[Theory] [Theory]
@ -594,19 +552,17 @@ public class ResizeTests
public void ResizeWithStretchMode<TPixel>(TestImageProvider<TPixel> provider) public void ResizeWithStretchMode<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Image<TPixel> image = provider.GetImage()) using Image<TPixel> image = provider.GetImage();
ResizeOptions options = new ResizeOptions
{ {
var options = new ResizeOptions Size = new Size(image.Width / 2, image.Height),
{ Mode = ResizeMode.Stretch
Size = new Size(image.Width / 2, image.Height), };
Mode = ResizeMode.Stretch
};
image.Mutate(x => x.Resize(options)); image.Mutate(x => x.Resize(options));
image.DebugSave(provider); image.DebugSave(provider);
image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false); image.CompareToReferenceOutput(ValidatorComparer, provider, appendPixelTypeToFileName: false);
}
} }
[Theory] [Theory]
@ -622,27 +578,23 @@ public class ResizeTests
return; return;
} }
using (Image<TPixel> image = provider.GetImage()) using Image<TPixel> image = provider.GetImage();
{ // Don't bother saving, we're testing the EXIF metadata updates.
// Don't bother saving, we're testing the EXIF metadata updates. image.Mutate(x => x.Resize(image.Width / 2, image.Height / 2));
image.Mutate(x => x.Resize(image.Width / 2, image.Height / 2));
}
} }
[Fact] [Fact]
public void Issue1195() public void Issue1195()
{ {
using (var image = new Image<Rgba32>(2, 300)) using Image<Rgba32> image = new Image<Rgba32>(2, 300);
{ Size size = new Size(50, 50);
var size = new Size(50, 50); image.Mutate(x => x
image.Mutate(x => x .Resize(
.Resize( new ResizeOptions
new ResizeOptions {
{ Size = size,
Size = size, Mode = ResizeMode.Max
Mode = ResizeMode.Max }));
}));
}
} }
[Theory] [Theory]
@ -653,20 +605,18 @@ public class ResizeTests
[InlineData(3, 7)] [InlineData(3, 7)]
public void Issue1342(int width, int height) public void Issue1342(int width, int height)
{ {
using (var image = new Image<Rgba32>(1, 1)) using Image<Rgba32> image = new Image<Rgba32>(1, 1);
{ Size size = new Size(width, height);
var size = new Size(width, height); image.Mutate(x => x
image.Mutate(x => x .Resize(
.Resize( new ResizeOptions
new ResizeOptions {
{ Size = size,
Size = size, Sampler = KnownResamplers.NearestNeighbor
Sampler = KnownResamplers.NearestNeighbor }));
}));
Assert.Equal(width, image.Width); Assert.Equal(width, image.Width);
Assert.Equal(height, image.Height); Assert.Equal(height, image.Height);
}
} }
[Theory] [Theory]

4
tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs

@ -24,13 +24,13 @@ public static partial class TestEnvironment
internal static IImageDecoder GetReferenceDecoder(string filePath) internal static IImageDecoder GetReferenceDecoder(string filePath)
{ {
IImageFormat format = GetImageFormat(filePath); IImageFormat format = GetImageFormat(filePath);
return Configuration.ImageFormatsManager.FindDecoder(format); return Configuration.ImageFormatsManager.GetDecoder(format);
} }
internal static IImageEncoder GetReferenceEncoder(string filePath) internal static IImageEncoder GetReferenceEncoder(string filePath)
{ {
IImageFormat format = GetImageFormat(filePath); IImageFormat format = GetImageFormat(filePath);
return Configuration.ImageFormatsManager.FindEncoder(format); return Configuration.ImageFormatsManager.GetEncoder(format);
} }
internal static IImageFormat GetImageFormat(string filePath) internal static IImageFormat GetImageFormat(string filePath)

Loading…
Cancel
Save