diff --git a/src/ImageSharp/Image.FromBytes.cs b/src/ImageSharp/Image.FromBytes.cs index 44c53d776..98a39193d 100644 --- a/src/ImageSharp/Image.FromBytes.cs +++ b/src/ImageSharp/Image.FromBytes.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.IO; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; @@ -15,7 +16,7 @@ namespace SixLabors.ImageSharp /// /// By reading the header on the provided byte array this calculates the images format. /// - /// The byte array containing image data to read the header from. + /// The byte array containing encoded image data to read the header from. /// The format or null if none found. public static IImageFormat DetectFormat(byte[] data) { @@ -26,7 +27,7 @@ namespace SixLabors.ImageSharp /// By reading the header on the provided byte array this calculates the images format. /// /// The configuration. - /// The byte array containing image data to read the header from. + /// The byte array containing encoded image data to read the header from. /// The mime type or null if none found. public static IImageFormat DetectFormat(Configuration config, byte[] data) { @@ -37,30 +38,30 @@ namespace SixLabors.ImageSharp } /// - /// Create a new instance of the class from the given byte array. + /// Load a new instance of from the given encoded byte array. /// /// The byte array containing image data. /// A new . public static Image Load(byte[] data) => Load(Configuration.Default, data); /// - /// Create a new instance of the class from the given byte array. + /// Load a new instance of from the given encoded byte array. /// - /// The byte array containing image data. + /// The byte array containing encoded image data. /// The mime type of the decoded image. /// A new . public static Image Load(byte[] data, out IImageFormat format) => Load(Configuration.Default, data, out format); /// - /// Create a new instance of the class from the given byte array. + /// Load a new instance of from the given encoded byte array. /// /// The config for the decoder. - /// The byte array containing image data. + /// The byte array containing encoded image data. /// A new . public static Image Load(Configuration config, byte[] data) => Load(config, data); /// - /// Create a new instance of the class from the given byte array. + /// Load a new instance of from the given encoded byte array. /// /// The config for the decoder. /// The byte array containing image data. @@ -69,15 +70,15 @@ namespace SixLabors.ImageSharp public static Image Load(Configuration config, byte[] data, out IImageFormat format) => Load(config, data, out format); /// - /// Create a new instance of the class from the given byte array. + /// Load a new instance of from the given encoded byte array. /// - /// The byte array containing image data. + /// The byte array containing encoded image data. /// The decoder. /// A new . public static Image Load(byte[] data, IImageDecoder decoder) => Load(data, decoder); /// - /// Create a new instance of the class from the given byte array. + /// Load a new instance of from the given encoded byte array. /// /// The config for the decoder. /// The byte array containing image data. @@ -86,9 +87,9 @@ namespace SixLabors.ImageSharp public static Image Load(Configuration config, byte[] data, IImageDecoder decoder) => Load(config, data, decoder); /// - /// Create a new instance of the class from the given byte array. + /// Load a new instance of from the given encoded byte array. /// - /// The byte array containing image data. + /// The byte array containing encoded image data. /// The pixel format. /// A new . public static Image Load(byte[] data) @@ -96,7 +97,7 @@ namespace SixLabors.ImageSharp => Load(Configuration.Default, data); /// - /// Create a new instance of the class from the given byte array. + /// Load a new instance of from the given encoded byte array. /// /// The byte array containing image data. /// The mime type of the decoded image. @@ -107,10 +108,10 @@ namespace SixLabors.ImageSharp => Load(Configuration.Default, data, out format); /// - /// Create a new instance of the class from the given byte array. + /// Load a new instance of from the given encoded byte array. /// /// The configuration options. - /// The byte array containing image data. + /// The byte array containing encoded image data. /// The pixel format. /// A new . public static Image Load(Configuration config, byte[] data) @@ -123,11 +124,11 @@ namespace SixLabors.ImageSharp } /// - /// Create a new instance of the class from the given byte array. + /// Load a new instance of from the given encoded byte array. /// /// The configuration options. - /// The byte array containing image data. - /// The mime type of the decoded image. + /// The byte array containing encoded image data. + /// The of the decoded image. /// The pixel format. /// A new . public static Image Load(Configuration config, byte[] data, out IImageFormat format) @@ -140,9 +141,9 @@ namespace SixLabors.ImageSharp } /// - /// Create a new instance of the class from the given byte array. + /// Load a new instance of from the given encoded byte array. /// - /// The byte array containing image data. + /// The byte array containing encoded image data. /// The decoder. /// The pixel format. /// A new . @@ -156,10 +157,10 @@ namespace SixLabors.ImageSharp } /// - /// Create a new instance of the class from the given byte array. + /// Load a new instance of from the given encoded byte array. /// /// The Configuration. - /// The byte array containing image data. + /// The byte array containing encoded image data. /// The decoder. /// The pixel format. /// A new . @@ -171,5 +172,125 @@ namespace SixLabors.ImageSharp return Load(config, memoryStream, decoder); } } + +#if !NETSTANDARD1_1 + + /// + /// By reading the header on the provided byte array this calculates the images format. + /// + /// The byte array containing encoded image data to read the header from. + /// The format or null if none found. + public static IImageFormat DetectFormat(ReadOnlySpan data) + { + return DetectFormat(Configuration.Default, data); + } + + /// + /// By reading the header on the provided byte array this calculates the images format. + /// + /// The configuration. + /// The byte array containing encoded image data to read the header from. + /// The mime type or null if none found. + public static unsafe IImageFormat DetectFormat(Configuration config, ReadOnlySpan data) + { + fixed (byte* ptr = &data.GetPinnableReference()) + { + using (var stream = new UnmanagedMemoryStream(ptr, data.Length)) + { + return DetectFormat(config, stream); + } + } + } + + /// + /// Load a new instance of from the given encoded byte span. + /// + /// The byte span containing image data. + /// A new . + public static Image Load(ReadOnlySpan data) => Load(Configuration.Default, data); + + /// + /// Load a new instance of from the given encoded byte span. + /// + /// The config for the decoder. + /// The byte span containing encoded image data. + /// A new . + public static Image Load(Configuration config, ReadOnlySpan data) => Load(config, data); + + /// + /// Load a new instance of from the given encoded byte span. + /// + /// The byte span containing encoded image data. + /// The pixel format. + /// A new . + public static Image Load(ReadOnlySpan data) + where TPixel : struct, IPixel + => Load(Configuration.Default, data); + + /// + /// Load a new instance of from the given encoded byte span. + /// + /// The configuration options. + /// The byte span containing encoded image data. + /// The pixel format. + /// A new . + public static unsafe Image Load(Configuration config, ReadOnlySpan data) + where TPixel : struct, IPixel + { + fixed (byte* ptr = &data.GetPinnableReference()) + { + using (var stream = new UnmanagedMemoryStream(ptr, data.Length)) + { + return Load(config, stream); + } + } + } + + /// + /// Load a new instance of from the given encoded byte span. + /// + /// The Configuration. + /// The byte span containing image data. + /// The decoder. + /// The pixel format. + /// A new . + public static unsafe Image Load( + Configuration config, + ReadOnlySpan data, + IImageDecoder decoder) + where TPixel : struct, IPixel + { + fixed (byte* ptr = &data.GetPinnableReference()) + { + using (var stream = new UnmanagedMemoryStream(ptr, data.Length)) + { + return Load(config, stream, decoder); + } + } + } + + /// + /// Load a new instance of from the given encoded byte span. + /// + /// The configuration options. + /// The byte span containing image data. + /// The of the decoded image. + /// The pixel format. + /// A new . + public static unsafe Image Load( + Configuration config, + ReadOnlySpan data, + out IImageFormat format) + where TPixel : struct, IPixel + { + fixed (byte* ptr = &data.GetPinnableReference()) + { + using (var stream = new UnmanagedMemoryStream(ptr, data.Length)) + { + return Load(config, stream, out format); + } + } + } +#endif } } \ No newline at end of file diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index b1934faa6..777c5016c 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -44,6 +44,9 @@ + + + diff --git a/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs b/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs index a6f6600f0..f10a4ce84 100644 --- a/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs +++ b/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs @@ -20,12 +20,12 @@ namespace SixLabors.ImageSharp.Tests { public class ImageFormatManagerTests { - public ImageFormatManager FormatsManagerEmpty { get; private set; } - public ImageFormatManager DefaultFormatsManager { get; private set; } + public ImageFormatManager FormatsManagerEmpty { get; } + public ImageFormatManager DefaultFormatsManager { get; } public ImageFormatManagerTests() { - this.DefaultFormatsManager = Configuration.Default.ImageFormatsManager; + this.DefaultFormatsManager = Configuration.CreateDefaultInstance().ImageFormatsManager; this.FormatsManagerEmpty = new ImageFormatManager(); } diff --git a/tests/ImageSharp.Tests/Image/ImageDiscoverMimeType.cs b/tests/ImageSharp.Tests/Image/ImageDiscoverMimeType.cs deleted file mode 100644 index 1a2275062..000000000 --- a/tests/ImageSharp.Tests/Image/ImageDiscoverMimeType.cs +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.IO; -using SixLabors.ImageSharp.Formats; -using SixLabors.ImageSharp.IO; -using Moq; -using Xunit; - -namespace SixLabors.ImageSharp.Tests -{ - /// - /// Tests the class. - /// - public class DiscoverImageFormatTests - { - private readonly Mock fileSystem; - private readonly string FilePath; - private readonly IImageFormatDetector localMimeTypeDetector; - private readonly Mock localImageFormatMock; - - public IImageFormat localImageFormat => this.localImageFormatMock.Object; - public Configuration LocalConfiguration { get; private set; } - public byte[] Marker { get; private set; } - public MemoryStream DataStream { get; private set; } - public byte[] DecodedData { get; private set; } - private const string localMimeType = "image/local"; - - public DiscoverImageFormatTests() - { - this.localImageFormatMock = new Mock(); - - this.localMimeTypeDetector = new MockImageFormatDetector(this.localImageFormatMock.Object); - - this.fileSystem = new Mock(); - - this.LocalConfiguration = new Configuration - { - FileSystem = this.fileSystem.Object - }; - - this.LocalConfiguration.ImageFormatsManager.AddImageFormatDetector(this.localMimeTypeDetector); - - TestFormat.RegisterGlobalTestFormat(); - this.Marker = Guid.NewGuid().ToByteArray(); - this.DataStream = TestFormat.GlobalTestFormat.CreateStream(this.Marker); - - this.FilePath = Guid.NewGuid().ToString(); - this.fileSystem.Setup(x => x.OpenRead(this.FilePath)).Returns(this.DataStream); - - TestFileSystem.RegisterGlobalTestFormat(); - TestFileSystem.Global.AddFile(this.FilePath, this.DataStream); - } - - [Fact] - public void DiscoverImageFormatByteArray() - { - IImageFormat type = Image.DetectFormat(this.DataStream.ToArray()); - Assert.Equal(TestFormat.GlobalTestFormat, type); - } - - [Fact] - public void DiscoverImageFormatByteArray_WithConfig() - { - IImageFormat type = Image.DetectFormat(this.LocalConfiguration, this.DataStream.ToArray()); - Assert.Equal(this.localImageFormat, type); - } - - [Fact] - public void DiscoverImageFormatFile() - { - IImageFormat type = Image.DetectFormat(this.FilePath); - Assert.Equal(TestFormat.GlobalTestFormat, type); - } - - [Fact] - public void DiscoverImageFormatFilePath_WithConfig() - { - IImageFormat type = Image.DetectFormat(this.LocalConfiguration, this.FilePath); - Assert.Equal(this.localImageFormat, type); - } - - [Fact] - public void DiscoverImageFormatStream() - { - IImageFormat type = Image.DetectFormat(this.DataStream); - Assert.Equal(TestFormat.GlobalTestFormat, type); - } - - [Fact] - public void DiscoverImageFormatFileStream_WithConfig() - { - IImageFormat type = Image.DetectFormat(this.LocalConfiguration, this.DataStream); - Assert.Equal(this.localImageFormat, type); - } - - [Fact] - public void DiscoverImageFormatNoDetectorsRegisterdShouldReturnNull() - { - IImageFormat type = Image.DetectFormat(new Configuration(), this.DataStream); - Assert.Null(type); - } - } -} diff --git a/tests/ImageSharp.Tests/Image/ImageTests.DetectFormat.cs b/tests/ImageSharp.Tests/Image/ImageTests.DetectFormat.cs new file mode 100644 index 000000000..9d709d488 --- /dev/null +++ b/tests/ImageSharp.Tests/Image/ImageTests.DetectFormat.cs @@ -0,0 +1,99 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.IO; +using SixLabors.ImageSharp.Formats; +using SixLabors.ImageSharp.IO; +using Moq; +using Xunit; +// ReSharper disable InconsistentNaming + +namespace SixLabors.ImageSharp.Tests +{ + public partial class ImageTests + { + /// + /// Tests the class. + /// + public class DetectFormat : ImageLoadTestBase + { + private static readonly string ActualImagePath = TestFile.GetInputFileFullPath(TestImages.Bmp.F); + + private byte[] ActualImageBytes => TestFile.Create(TestImages.Bmp.F).Bytes; + + private ReadOnlySpan ActualImageSpan => this.ActualImageBytes.AsSpan(); + + private byte[] ByteArray => this.DataStream.ToArray(); + + private ReadOnlySpan ByteSpan => this.ByteArray.AsSpan(); + + private IImageFormat LocalImageFormat => this.localImageFormatMock.Object; + + private static readonly IImageFormat ExpectedGlobalFormat = + Configuration.Default.ImageFormatsManager.FindFormatByFileExtension("bmp"); + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void FromBytes_GlobalConfiguration(bool useSpan) + { + IImageFormat type = useSpan + ? Image.DetectFormat(this.ActualImageSpan) + : Image.DetectFormat(this.ActualImageBytes); + + Assert.Equal(ExpectedGlobalFormat, type); + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void FromBytes_CustomConfiguration(bool useSpan) + { + IImageFormat type = useSpan + ? Image.DetectFormat(this.LocalConfiguration, this.ByteArray.AsSpan()) + : Image.DetectFormat(this.LocalConfiguration, this.ByteArray); + + Assert.Equal(this.LocalImageFormat, type); + } + + [Fact] + public void FromFileSystemPath_GlobalConfiguration() + { + IImageFormat type = Image.DetectFormat(ActualImagePath); + Assert.Equal(ExpectedGlobalFormat, type); + } + + [Fact] + public void FromFileSystemPath_CustomConfiguration() + { + IImageFormat type = Image.DetectFormat(this.LocalConfiguration, this.MockFilePath); + Assert.Equal(this.LocalImageFormat, type); + } + + [Fact] + public void FromStream_GlobalConfiguration() + { + using (var stream = new MemoryStream(this.ActualImageBytes)) + { + IImageFormat type = Image.DetectFormat(stream); + Assert.Equal(ExpectedGlobalFormat, type); + } + } + + [Fact] + public void FromStream_CustomConfiguration() + { + IImageFormat type = Image.DetectFormat(this.LocalConfiguration, this.DataStream); + Assert.Equal(this.LocalImageFormat, type); + } + + [Fact] + public void WhenNoMatchingFormatFound_ReturnsNull() + { + IImageFormat type = Image.DetectFormat(new Configuration(), this.DataStream); + Assert.Null(type); + } + } + } +} diff --git a/tests/ImageSharp.Tests/Image/ImageTests.ImageLoadTestBase.cs b/tests/ImageSharp.Tests/Image/ImageTests.ImageLoadTestBase.cs new file mode 100644 index 000000000..aabc3f50e --- /dev/null +++ b/tests/ImageSharp.Tests/Image/ImageTests.ImageLoadTestBase.cs @@ -0,0 +1,92 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.IO; + +using Moq; + +using SixLabors.ImageSharp.Formats; +using SixLabors.ImageSharp.IO; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Tests +{ + public partial class ImageTests + { + public abstract class ImageLoadTestBase : IDisposable + { + protected Image returnImage; + + protected Mock localDecoder; + + protected IImageFormatDetector localMimeTypeDetector; + + protected Mock localImageFormatMock; + + protected readonly string MockFilePath = Guid.NewGuid().ToString(); + + internal readonly Mock localFileSystemMock = new Mock(); + + protected readonly TestFileSystem topLevelFileSystem = new TestFileSystem(); + + public Configuration LocalConfiguration { get; } + + public TestFormat TestFormat { get; } = new TestFormat(); + + /// + /// Gets the top-level configuration in the context of this test case. + /// It has registered. + /// + public Configuration TopLevelConfiguration { get; } + + public byte[] Marker { get; } + + public MemoryStream DataStream { get; } + + public byte[] DecodedData { get; private set; } + + protected ImageLoadTestBase() + { + this.returnImage = new Image(1, 1); + + this.localImageFormatMock = new Mock(); + + this.localDecoder = new Mock(); + this.localMimeTypeDetector = new MockImageFormatDetector(this.localImageFormatMock.Object); + this.localDecoder.Setup(x => x.Decode(It.IsAny(), It.IsAny())) + .Callback((c, s) => + { + using (var ms = new MemoryStream()) + { + s.CopyTo(ms); + this.DecodedData = ms.ToArray(); + } + }) + .Returns(this.returnImage); + + this.LocalConfiguration = new Configuration + { + }; + this.LocalConfiguration.ImageFormatsManager.AddImageFormatDetector(this.localMimeTypeDetector); + this.LocalConfiguration.ImageFormatsManager.SetDecoder(this.localImageFormatMock.Object, this.localDecoder.Object); + + this.TopLevelConfiguration = new Configuration(this.TestFormat); + + this.Marker = Guid.NewGuid().ToByteArray(); + this.DataStream = this.TestFormat.CreateStream(this.Marker); + + this.localFileSystemMock.Setup(x => x.OpenRead(this.MockFilePath)).Returns(this.DataStream); + this.topLevelFileSystem.AddFile(this.MockFilePath, this.DataStream); + this.LocalConfiguration.FileSystem = this.localFileSystemMock.Object; + this.TopLevelConfiguration.FileSystem = this.topLevelFileSystem; + } + + public void Dispose() + { + // clean up the global object; + this.returnImage?.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Image/ImageTests.LoadPixelData.cs b/tests/ImageSharp.Tests/Image/ImageTests.LoadPixelData.cs new file mode 100644 index 000000000..7a5fa8729 --- /dev/null +++ b/tests/ImageSharp.Tests/Image/ImageTests.LoadPixelData.cs @@ -0,0 +1,60 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; + +namespace SixLabors.ImageSharp.Tests +{ + public partial class ImageTests + { + public class LoadPixelData + { + [Theory] + [InlineData(false)] + [InlineData(true)] + public void FromPixels(bool useSpan) + { + Rgba32[] data = { Rgba32.Black, Rgba32.White, Rgba32.White, Rgba32.Black, }; + + using (Image img = useSpan + ? Image.LoadPixelData(data.AsSpan(), 2, 2) + : Image.LoadPixelData(data, 2, 2)) + { + Assert.NotNull(img); + Assert.Equal(Rgba32.Black, img[0, 0]); + Assert.Equal(Rgba32.White, img[0, 1]); + + Assert.Equal(Rgba32.White, img[1, 0]); + Assert.Equal(Rgba32.Black, img[1, 1]); + } + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void FromBytes(bool useSpan) + { + byte[] data = + { + 0, 0, 0, 255, // 0,0 + 255, 255, 255, 255, // 0,1 + 255, 255, 255, 255, // 1,0 + 0, 0, 0, 255, // 1,1 + }; + using (Image img = useSpan + ? Image.LoadPixelData(data.AsSpan(), 2, 2) + : Image.LoadPixelData(data, 2, 2)) + { + Assert.NotNull(img); + Assert.Equal(Rgba32.Black, img[0, 0]); + Assert.Equal(Rgba32.White, img[0, 1]); + + Assert.Equal(Rgba32.White, img[1, 0]); + Assert.Equal(Rgba32.Black, img[1, 1]); + } + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Image/ImageTests.Load_BasicCases.cs b/tests/ImageSharp.Tests/Image/ImageTests.Load_BasicCases.cs deleted file mode 100644 index e442b5654..000000000 --- a/tests/ImageSharp.Tests/Image/ImageTests.Load_BasicCases.cs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using SixLabors.ImageSharp.PixelFormats; -using Xunit; -// ReSharper disable InconsistentNaming - -namespace SixLabors.ImageSharp.Tests -{ - public partial class ImageTests - { - public class Load_BasicCases - { - [Fact] - public void ByteArray() - { - Assert.Throws(() => - { - Image.Load((byte[])null); - }); - - var file = TestFile.Create(TestImages.Bmp.Car); - using (var image = Image.Load(file.Bytes)) - { - Assert.Equal(600, image.Width); - Assert.Equal(450, image.Height); - } - } - - [Fact] - public void FileSystemPath() - { - var file = TestFile.Create(TestImages.Bmp.Car); - using (var image = Image.Load(file.FullPath)) - { - Assert.Equal(600, image.Width); - Assert.Equal(450, image.Height); - } - } - - [Fact] - public void FileSystemPath_FileNotFound() - { - System.IO.FileNotFoundException ex = Assert.Throws( - () => - { - Image.Load(Guid.NewGuid().ToString()); - }); - } - - [Fact] - public void FileSystemPath_NullPath() - { - ArgumentNullException ex = Assert.Throws( - () => - { - Image.Load((string)null); - }); - } - } - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Image/ImageTests.Load_ComplexCases.cs b/tests/ImageSharp.Tests/Image/ImageTests.Load_ComplexCases.cs deleted file mode 100644 index 957e5c40a..000000000 --- a/tests/ImageSharp.Tests/Image/ImageTests.Load_ComplexCases.cs +++ /dev/null @@ -1,338 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.IO; - -using Moq; - -using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Formats; -using SixLabors.ImageSharp.IO; -using SixLabors.ImageSharp.PixelFormats; - -using Xunit; -// ReSharper disable InconsistentNaming - -namespace SixLabors.ImageSharp.Tests -{ - public partial class ImageTests - { - /// - /// Tests the class. - /// - public class Load_ComplexCases : IDisposable - { - private readonly Mock fileSystem; - private readonly Image returnImage; - private readonly Mock localDecoder; - private readonly string FilePath; - private readonly IImageFormatDetector localMimeTypeDetector; - private readonly Mock localImageFormatMock; - - public Configuration LocalConfiguration { get; private set; } - public byte[] Marker { get; private set; } - public MemoryStream DataStream { get; private set; } - public byte[] DecodedData { get; private set; } - - public Load_ComplexCases() - { - this.returnImage = new Image(1, 1); - - this.localImageFormatMock = new Mock(); - - this.localDecoder = new Mock(); - this.localMimeTypeDetector = new MockImageFormatDetector(this.localImageFormatMock.Object); - this.localDecoder.Setup(x => x.Decode(It.IsAny(), It.IsAny())) - - .Callback((c, s) => - { - using (var ms = new MemoryStream()) - { - s.CopyTo(ms); - this.DecodedData = ms.ToArray(); - } - }) - .Returns(this.returnImage); - - this.fileSystem = new Mock(); - - this.LocalConfiguration = new Configuration - { - FileSystem = this.fileSystem.Object - }; - this.LocalConfiguration.ImageFormatsManager.AddImageFormatDetector(this.localMimeTypeDetector); - this.LocalConfiguration.ImageFormatsManager.SetDecoder(this.localImageFormatMock.Object, this.localDecoder.Object); - - TestFormat.RegisterGlobalTestFormat(); - this.Marker = Guid.NewGuid().ToByteArray(); - this.DataStream = TestFormat.GlobalTestFormat.CreateStream(this.Marker); - - this.FilePath = Guid.NewGuid().ToString(); - this.fileSystem.Setup(x => x.OpenRead(this.FilePath)).Returns(this.DataStream); - - TestFileSystem.RegisterGlobalTestFormat(); - TestFileSystem.Global.AddFile(this.FilePath, this.DataStream); - } - - [Fact] - public void LoadFromStream() - { - var img = Image.Load(this.DataStream); - - Assert.NotNull(img); - - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default); - } - - [Fact] - public void LoadFromNoneSeekableStream() - { - var stream = new NoneSeekableStream(this.DataStream); - var img = Image.Load(stream); - - Assert.NotNull(img); - - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default); - } - - [Fact] - public void LoadFromStreamWithType() - { - var img = Image.Load(this.DataStream); - - Assert.NotNull(img); - Assert.Equal(TestFormat.GlobalTestFormat.Sample(), img); - - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default); - } - - - [Fact] - public void LoadFromStreamWithConfig() - { - Stream stream = new MemoryStream(); - var img = Image.Load(this.LocalConfiguration, stream); - - Assert.NotNull(img); - - this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, stream)); - } - - [Fact] - public void LoadFromStreamWithTypeAndConfig() - { - Stream stream = new MemoryStream(); - var img = Image.Load(this.LocalConfiguration, stream); - - Assert.NotNull(img); - Assert.Equal(this.returnImage, img); - - this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, stream)); - } - - - [Fact] - public void LoadFromStreamWithDecoder() - { - Stream stream = new MemoryStream(); - var img = Image.Load(stream, this.localDecoder.Object); - - Assert.NotNull(img); - this.localDecoder.Verify(x => x.Decode(Configuration.Default, stream)); - } - - [Fact] - public void LoadFromStreamWithTypeAndDecoder() - { - Stream stream = new MemoryStream(); - var img = Image.Load(stream, this.localDecoder.Object); - - Assert.NotNull(img); - Assert.Equal(this.returnImage, img); - this.localDecoder.Verify(x => x.Decode(Configuration.Default, stream)); - } - - [Fact] - public void LoadFromBytes() - { - var img = Image.Load(this.DataStream.ToArray()); - - Assert.NotNull(img); - - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default); - } - - [Fact] - public void LoadFromBytesWithType() - { - var img = Image.Load(this.DataStream.ToArray()); - - Assert.NotNull(img); - Assert.Equal(TestFormat.GlobalTestFormat.Sample(), img); - - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default); - - } - - [Fact] - public void LoadFromBytesWithConfig() - { - var img = Image.Load(this.LocalConfiguration, this.DataStream.ToArray()); - - Assert.NotNull(img); - - this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, It.IsAny())); - - Assert.Equal(this.DataStream.ToArray(), this.DecodedData); - } - - [Fact] - public void LoadFromBytesWithTypeAndConfig() - { - var img = Image.Load(this.LocalConfiguration, this.DataStream.ToArray()); - - Assert.NotNull(img); - Assert.Equal(this.returnImage, img); - - this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, It.IsAny())); - - Assert.Equal(this.DataStream.ToArray(), this.DecodedData); - } - - [Fact] - public void LoadFromBytesWithDecoder() - { - var img = Image.Load(this.DataStream.ToArray(), this.localDecoder.Object); - - Assert.NotNull(img); - this.localDecoder.Verify(x => x.Decode(Configuration.Default, It.IsAny())); - Assert.Equal(this.DataStream.ToArray(), this.DecodedData); - } - - [Fact] - public void LoadFromBytesWithTypeAndDecoder() - { - var img = Image.Load(this.DataStream.ToArray(), this.localDecoder.Object); - - Assert.NotNull(img); - Assert.Equal(this.returnImage, img); - this.localDecoder.Verify(x => x.Decode(Configuration.Default, It.IsAny())); - Assert.Equal(this.DataStream.ToArray(), this.DecodedData); - } - - [Fact] - public void LoadFromFile() - { - var img = Image.Load(this.DataStream); - - Assert.NotNull(img); - - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default); - } - - [Fact] - public void LoadFromFileWithType() - { - var img = Image.Load(this.DataStream); - - Assert.NotNull(img); - Assert.Equal(TestFormat.GlobalTestFormat.Sample(), img); - - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default); - } - - [Fact] - public void LoadFromFileWithConfig() - { - var img = Image.Load(this.LocalConfiguration, this.FilePath); - - Assert.NotNull(img); - - this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, this.DataStream)); - } - - [Fact] - public void LoadFromFileWithTypeAndConfig() - { - var img = Image.Load(this.LocalConfiguration, this.FilePath); - - Assert.NotNull(img); - Assert.Equal(this.returnImage, img); - - this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, this.DataStream)); - } - - [Fact] - public void LoadFromFileWithDecoder() - { - var img = Image.Load(this.FilePath, this.localDecoder.Object); - - Assert.NotNull(img); - this.localDecoder.Verify(x => x.Decode(Configuration.Default, this.DataStream)); - } - - [Fact] - public void LoadFromFileWithTypeAndDecoder() - { - var img = Image.Load(this.FilePath, this.localDecoder.Object); - - Assert.NotNull(img); - Assert.Equal(this.returnImage, img); - this.localDecoder.Verify(x => x.Decode(Configuration.Default, this.DataStream)); - } - - [Fact] - public void LoadFromPixelData_Pixels() - { - var img = Image.LoadPixelData(new Rgba32[] { - Rgba32.Black, Rgba32.White, - Rgba32.White, Rgba32.Black, - }, 2, 2); - - Assert.NotNull(img); - Assert.Equal(Rgba32.Black, img[0, 0]); - Assert.Equal(Rgba32.White, img[0, 1]); - - Assert.Equal(Rgba32.White, img[1, 0]); - Assert.Equal(Rgba32.Black, img[1, 1]); - } - - [Fact] - public void LoadFromPixelData_Bytes() - { - var img = Image.LoadPixelData(new byte[] { - 0,0,0,255, // 0,0 - 255,255,255,255, // 0,1 - 255,255,255,255, // 1,0 - 0,0,0,255, // 1,1 - }, 2, 2); - - Assert.NotNull(img); - Assert.Equal(Rgba32.Black, img[0, 0]); - Assert.Equal(Rgba32.White, img[0, 1]); - - Assert.Equal(Rgba32.White, img[1, 0]); - Assert.Equal(Rgba32.Black, img[1, 1]); - } - - - [Fact] - public void LoadsImageWithoutThrowingCrcException() - { - var image1Provider = TestImageProvider.File(TestImages.Png.VersioningImage1); - - using (Image img = image1Provider.GetImage()) - { - Assert.Equal(166036, img.Frames.RootFrame.GetPixelSpan().Length); - } - } - - public void Dispose() - { - // clean up the global object; - this.returnImage?.Dispose(); - } - } - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Image/ImageTests.Load_FileSystemPath.cs b/tests/ImageSharp.Tests/Image/ImageTests.Load_FileSystemPath.cs new file mode 100644 index 000000000..1a21d3d10 --- /dev/null +++ b/tests/ImageSharp.Tests/Image/ImageTests.Load_FileSystemPath.cs @@ -0,0 +1,83 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; +// ReSharper disable InconsistentNaming + +namespace SixLabors.ImageSharp.Tests +{ + using Moq; + + using SixLabors.ImageSharp.IO; + + public partial class ImageTests + { + public class Load_FileSystemPath : ImageLoadTestBase + { + [Fact] + public void BasicCase() + { + var img = Image.Load(this.TopLevelConfiguration, this.MockFilePath); + + Assert.NotNull(img); + + this.TestFormat.VerifyDecodeCall(this.Marker, this.TopLevelConfiguration); + } + + [Fact] + public void UseLocalConfiguration() + { + var img = Image.Load(this.LocalConfiguration, this.MockFilePath); + + Assert.NotNull(img); + + this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, this.DataStream)); + } + + [Fact] + public void UseCustomDecoder() + { + var img = Image.Load(this.TopLevelConfiguration, this.MockFilePath, this.localDecoder.Object); + + Assert.NotNull(img); + this.localDecoder.Verify(x => x.Decode(this.TopLevelConfiguration, this.DataStream)); + } + + + [Fact] + public void UseGlobalConfigration() + { + var file = TestFile.Create(TestImages.Bmp.Car); + using (var image = Image.Load(file.FullPath)) + { + Assert.Equal(600, image.Width); + Assert.Equal(450, image.Height); + } + } + + [Fact] + public void WhenFileNotFound_Throws() + { + System.IO.FileNotFoundException ex = Assert.Throws( + () => + { + Image.Load(Guid.NewGuid().ToString()); + }); + } + + [Fact] + public void WhenPathIsNull_Throws() + { + ArgumentNullException ex = Assert.Throws( + () => + { + Image.Load((string)null); + }); + } + } + + + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Image/ImageTests.Load_FromBytes.cs b/tests/ImageSharp.Tests/Image/ImageTests.Load_FromBytes.cs new file mode 100644 index 000000000..eed1a2825 --- /dev/null +++ b/tests/ImageSharp.Tests/Image/ImageTests.Load_FromBytes.cs @@ -0,0 +1,120 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.IO; + +using Moq; + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; + +using Xunit; + +// ReSharper disable InconsistentNaming +namespace SixLabors.ImageSharp.Tests +{ + public partial class ImageTests + { + public class Load_FromBytes : ImageLoadTestBase + { + private byte[] ByteArray => this.DataStream.ToArray(); + + private ReadOnlySpan ByteSpan => this.ByteArray.AsSpan(); + + private byte[] ActualImageBytes => TestFile.Create(TestImages.Bmp.F).Bytes; + + private ReadOnlySpan ActualImageSpan => this.ActualImageBytes.AsSpan(); + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void BasicCase(bool useSpan) + { + Image img = useSpan + ? Image.Load(this.TopLevelConfiguration, this.ByteSpan) + : Image.Load(this.TopLevelConfiguration, this.ByteArray); + + Assert.NotNull(img); + Assert.Equal(this.TestFormat.Sample(), img); + + this.TestFormat.VerifyDecodeCall(this.Marker, this.TopLevelConfiguration); + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void NonDefaultPixelType(bool useSpan) + { + Image img = useSpan + ? Image.Load(this.TopLevelConfiguration, this.ByteSpan) + : Image.Load(this.TopLevelConfiguration, this.ByteArray); + + Assert.NotNull(img); + Assert.Equal(this.TestFormat.Sample(), img); + + this.TestFormat.VerifyDecodeCall(this.Marker, this.TopLevelConfiguration); + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void UseLocalConfiguration(bool useSpan) + { + Image img = useSpan + ? Image.Load(this.LocalConfiguration, this.ByteSpan) + : Image.Load(this.LocalConfiguration, this.ByteArray); + + Assert.NotNull(img); + + this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, It.IsAny())); + + Assert.Equal(this.DataStream.ToArray(), this.DecodedData); + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void UseCustomDecoder(bool useSpan) + { + Image img = useSpan + ? Image.Load( + this.TopLevelConfiguration, + this.ByteSpan, + this.localDecoder.Object) + : Image.Load( + this.TopLevelConfiguration, + this.ByteArray, + this.localDecoder.Object); + Assert.NotNull(img); + this.localDecoder.Verify(x => x.Decode(this.TopLevelConfiguration, It.IsAny())); + Assert.Equal(this.DataStream.ToArray(), this.DecodedData); + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void UseGlobalConfiguration(bool useSpan) + { + using (Image img = + useSpan ? Image.Load(this.ActualImageSpan) : Image.Load(this.ActualImageBytes)) + { + Assert.Equal(new Size(108, 202), img.Size()); + } + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void UseGlobalConfiguration_NonDefaultPixelType(bool useSpan) + { + using (Image img = useSpan + ? Image.Load(this.ActualImageSpan) + : Image.Load(this.ActualImageBytes)) + { + Assert.Equal(new Size(108, 202), img.Size()); + } + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Image/ImageTests.Load_FromStream.cs b/tests/ImageSharp.Tests/Image/ImageTests.Load_FromStream.cs new file mode 100644 index 000000000..6b6acb1b8 --- /dev/null +++ b/tests/ImageSharp.Tests/Image/ImageTests.Load_FromStream.cs @@ -0,0 +1,102 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.IO; + +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +// ReSharper disable InconsistentNaming + +namespace SixLabors.ImageSharp.Tests +{ + using SixLabors.Primitives; + + public partial class ImageTests + { + /// + /// Tests the class. + /// + public class Load_FromStream : ImageLoadTestBase + { + [Fact] + public void BasicCase() + { + var img = Image.Load(this.TopLevelConfiguration, this.DataStream); + + Assert.NotNull(img); + Assert.Equal(this.TestFormat.Sample(), img); + + this.TestFormat.VerifyDecodeCall(this.Marker, this.TopLevelConfiguration); + } + + [Fact] + public void UseGlobalConfiguration() + { + byte[] data = TestFile.Create(TestImages.Bmp.F).Bytes; + + using (var stream = new MemoryStream(data)) + using (var img = Image.Load(stream)) + { + Assert.Equal(new Size(108, 202), img.Size()); + } + } + + [Fact] + public void NonDefaultPixelTypeImage() + { + var img = Image.Load(this.TopLevelConfiguration, this.DataStream); + + Assert.NotNull(img); + Assert.Equal(this.TestFormat.Sample(), img); + + this.TestFormat.VerifyDecodeCall(this.Marker, this.TopLevelConfiguration); + } + + [Fact] + public void NonSeekableStream() + { + var stream = new NoneSeekableStream(this.DataStream); + var img = Image.Load(this.TopLevelConfiguration, stream); + + Assert.NotNull(img); + + this.TestFormat.VerifyDecodeCall(this.Marker, this.TopLevelConfiguration); + } + + [Fact] + public void UseLocalConfiguration() + { + Stream stream = new MemoryStream(); + var img = Image.Load(this.LocalConfiguration, stream); + + Assert.NotNull(img); + + this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, stream)); + } + + [Fact] + public void UseCustomDecoder() + { + Stream stream = new MemoryStream(); + var img = Image.Load(this.TopLevelConfiguration, stream, this.localDecoder.Object); + + Assert.NotNull(img); + this.localDecoder.Verify(x => x.Decode(this.TopLevelConfiguration, stream)); + } + + // TODO: This should be a png decoder test! + [Fact] + public void LoadsImageWithoutThrowingCrcException() + { + var image1Provider = TestImageProvider.File(TestImages.Png.VersioningImage1); + + using (Image img = image1Provider.GetImage()) + { + Assert.Equal(166036, img.Frames.RootFrame.GetPixelSpan().Length); + } + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestFormat.cs b/tests/ImageSharp.Tests/TestFormat.cs index 70e6c498a..64357a17e 100644 --- a/tests/ImageSharp.Tests/TestFormat.cs +++ b/tests/ImageSharp.Tests/TestFormat.cs @@ -18,13 +18,10 @@ namespace SixLabors.ImageSharp.Tests /// public class TestFormat : IConfigurationModule, IImageFormat { + // We should not change Configuration.Default in individual tests! + // Create new configuration instances with new Configuration(TestFormat.GlobalTestFormat) instead! public static TestFormat GlobalTestFormat { get; } = new TestFormat(); - public static void RegisterGlobalTestFormat() - { - Configuration.Default.Configure(GlobalTestFormat); - } - public TestFormat() { this.Encoder = new TestEncoder(this); @@ -155,12 +152,12 @@ namespace SixLabors.ImageSharp.Tests private TestFormat testFormat; - public int HeaderSize => testFormat.HeaderSize; + public int HeaderSize => this.testFormat.HeaderSize; public IImageFormat DetectFormat(ReadOnlySpan header) { - if (testFormat.IsSupportedFileFormat(header)) - return testFormat; + if (this.testFormat.IsSupportedFileFormat(header)) + return this.testFormat; return null; }