diff --git a/src/ImageSharp/Image.Decode.cs b/src/ImageSharp/Image.Decode.cs
index f31f2c0a55..c95b71b1e8 100644
--- a/src/ImageSharp/Image.Decode.cs
+++ b/src/ImageSharp/Image.Decode.cs
@@ -19,25 +19,12 @@ namespace ImageSharp
///
public sealed partial class Image
{
- ///
- /// Decodes the image stream to the current image.
- ///
- /// The pixel format.
- /// The stream.
- /// The options for the decoder.
- /// the configuration.
- /// The decoded image
- ///
- /// [true] if can successfull decode the image otherwise [false].
- ///
- private static bool Decode(Stream stream, IDecoderOptions options, Configuration config, out Image img)
- where TColor : struct, IPixel
+ private static IImageFormat DiscoverFormat(Stream stream, IDecoderOptions options, Configuration config)
{
- img = null;
int maxHeaderSize = config.MaxHeaderSize;
if (maxHeaderSize <= 0)
{
- return false;
+ return null;
}
IImageFormat format;
@@ -54,14 +41,31 @@ namespace ImageSharp
ArrayPool.Shared.Return(header);
}
+ return format;
+ }
+
+ ///
+ /// Decodes the image stream to the current image.
+ ///
+ /// The pixel format.
+ /// The stream.
+ /// The options for the decoder.
+ /// the configuration.
+ ///
+ /// The decoded image
+ ///
+ private static Image Decode(Stream stream, IDecoderOptions options, Configuration config)
+ where TColor : struct, IPixel
+ {
+ IImageFormat format = DiscoverFormat(stream, options, config);
if (format == null)
{
- return false;
+ return null;
}
- img = format.Decoder.Decode(stream, options);
+ Image img = format.Decoder.Decode(stream, options);
img.CurrentImageFormat = format;
- return true;
+ return img;
}
}
}
diff --git a/src/ImageSharp/Image.FromBytes.cs b/src/ImageSharp/Image.FromBytes.cs
index 3f1a3031c0..8e0ac04a5a 100644
--- a/src/ImageSharp/Image.FromBytes.cs
+++ b/src/ImageSharp/Image.FromBytes.cs
@@ -29,7 +29,7 @@ namespace ImageSharp
/// The image
public static Image Load(byte[] data)
{
- return Load(data, null, null);
+ return Load(data, null, (Configuration)null);
}
///
@@ -60,6 +60,20 @@ namespace ImageSharp
return Load(data, null, config);
}
+ ///
+ /// Loads the image from the given byte array.
+ ///
+ /// The byte array containing image data.
+ /// The decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(byte[] data, IImageDecoder decoder)
+ {
+ return Load(data, decoder, null);
+ }
+
///
/// Loads the image from the given byte array.
///
@@ -78,6 +92,24 @@ namespace ImageSharp
}
}
+ ///
+ /// Loads the image from the given byte array.
+ ///
+ /// The byte array containing image data.
+ /// The decoder.
+ /// The options for the decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(byte[] data, IImageDecoder decoder, IDecoderOptions options)
+ {
+ using (MemoryStream ms = new MemoryStream(data))
+ {
+ return Load(ms, decoder, options);
+ }
+ }
+
///
/// Loads the image from the given byte array.
///
@@ -90,7 +122,7 @@ namespace ImageSharp
public static Image Load(byte[] data)
where TColor : struct, IPixel
{
- return Load(data, null, null);
+ return Load(data, null, (Configuration)null);
}
///
@@ -125,6 +157,22 @@ namespace ImageSharp
return Load(data, null, config);
}
+ ///
+ /// Loads the image from the given byte array.
+ ///
+ /// The pixel format.
+ /// The byte array containing image data.
+ /// The decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(byte[] data, IImageDecoder decoder)
+ where TColor : struct, IPixel
+ {
+ return Load(data, decoder, null);
+ }
+
///
/// Loads the image from the given byte array.
///
@@ -144,5 +192,25 @@ namespace ImageSharp
return Load(ms, options, config);
}
}
+
+ ///
+ /// Loads the image from the given byte array.
+ ///
+ /// The pixel format.
+ /// The byte array containing image data.
+ /// The decoder.
+ /// The options for the decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(byte[] data, IImageDecoder decoder, IDecoderOptions options)
+ where TColor : struct, IPixel
+ {
+ using (MemoryStream ms = new MemoryStream(data))
+ {
+ return Load(ms, decoder, options);
+ }
+ }
}
}
diff --git a/src/ImageSharp/Image.FromFile.cs b/src/ImageSharp/Image.FromFile.cs
index 9b8ba83ded..e9015eaa9d 100644
--- a/src/ImageSharp/Image.FromFile.cs
+++ b/src/ImageSharp/Image.FromFile.cs
@@ -30,7 +30,7 @@ namespace ImageSharp
/// The image
public static Image Load(string path)
{
- return Load(path, null, null);
+ return Load(path, null, (Configuration)null);
}
///
@@ -61,6 +61,35 @@ namespace ImageSharp
return Load(path, null, config);
}
+ ///
+ /// Loads the image from the given file.
+ ///
+ /// The file path to the image.
+ /// The decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(string path, IImageDecoder decoder)
+ {
+ return Load(path, decoder, null);
+ }
+
+ ///
+ /// Loads the image from the given file.
+ ///
+ /// The file path to the image.
+ /// The decoder.
+ /// The options for the decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(string path, IImageDecoder decoder, IDecoderOptions options)
+ {
+ return new Image(Load(path, decoder, options));
+ }
+
///
/// Loads the image from the given file.
///
@@ -88,7 +117,7 @@ namespace ImageSharp
public static Image Load(string path)
where TColor : struct, IPixel
{
- return Load(path, null, null);
+ return Load(path, null, (Configuration)null);
}
///
@@ -123,6 +152,22 @@ namespace ImageSharp
return Load(path, null, config);
}
+ ///
+ /// Loads the image from the given file.
+ ///
+ /// The pixel format.
+ /// The file path to the image.
+ /// The decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(string path, IImageDecoder decoder)
+ where TColor : struct, IPixel
+ {
+ return Load(path, decoder, null);
+ }
+
///
/// Loads the image from the given file.
///
@@ -143,6 +188,27 @@ namespace ImageSharp
return Load(s, options, config);
}
}
+
+ ///
+ /// Loads the image from the given file.
+ ///
+ /// The pixel format.
+ /// The file path to the image.
+ /// The decoder.
+ /// The options for the decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(string path, IImageDecoder decoder, IDecoderOptions options)
+ where TColor : struct, IPixel
+ {
+ Configuration config = Configuration.Default;
+ using (Stream s = config.FileSystem.OpenRead(path))
+ {
+ return Load(s, decoder, options);
+ }
+ }
}
#endif
}
diff --git a/src/ImageSharp/Image.FromStream.cs b/src/ImageSharp/Image.FromStream.cs
index 36309db5b5..b40aa62cd9 100644
--- a/src/ImageSharp/Image.FromStream.cs
+++ b/src/ImageSharp/Image.FromStream.cs
@@ -29,7 +29,7 @@ namespace ImageSharp
/// The image
public static Image Load(Stream stream)
{
- return Load(stream, null, null);
+ return Load(stream, null, (Configuration)null);
}
///
@@ -60,6 +60,20 @@ namespace ImageSharp
return Load(stream, null, config);
}
+ ///
+ /// Loads the image from the given stream.
+ ///
+ /// The stream containing image information.
+ /// The decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(Stream stream, IImageDecoder decoder)
+ {
+ return Load(stream, decoder, null);
+ }
+
///
/// Loads the image from the given stream.
///
@@ -75,6 +89,21 @@ namespace ImageSharp
return new Image(Load(stream, options, config));
}
+ ///
+ /// Loads the image from the given stream.
+ ///
+ /// The stream containing image information.
+ /// The decoder.
+ /// The options for the decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(Stream stream, IImageDecoder decoder, IDecoderOptions options)
+ {
+ return new Image(Load(stream, decoder, options));
+ }
+
///
/// Loads the image from the given stream.
///
@@ -87,7 +116,7 @@ namespace ImageSharp
public static Image Load(Stream stream)
where TColor : struct, IPixel
{
- return Load(stream, null, null);
+ return Load(stream, null, (Configuration)null);
}
///
@@ -122,6 +151,39 @@ namespace ImageSharp
return Load(stream, null, config);
}
+ ///
+ /// Loads the image from the given stream.
+ ///
+ /// The pixel format.
+ /// The stream containing image information.
+ /// The decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(Stream stream, IImageDecoder decoder)
+ where TColor : struct, IPixel
+ {
+ return Load(stream, decoder, null);
+ }
+
+ ///
+ /// Loads the image from the given stream.
+ ///
+ /// The pixel format.
+ /// The stream containing image information.
+ /// The decoder.
+ /// The options for the decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(Stream stream, IImageDecoder decoder, IDecoderOptions options)
+ where TColor : struct, IPixel
+ {
+ return WithSeekableStream(stream, s => decoder.Decode(s, options));
+ }
+
///
/// Loads the image from the given stream.
///
@@ -138,11 +200,29 @@ namespace ImageSharp
{
config = config ?? Configuration.Default;
- if (!config.ImageFormats.Any())
+ Image img = WithSeekableStream(stream, s =>
+ {
+ return Decode(stream, options, config);
+ });
+
+ if (img != null)
+ {
+ return img;
+ }
+
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.AppendLine("Image cannot be loaded. Available formats:");
+
+ foreach (IImageFormat format in config.ImageFormats)
{
- throw new InvalidOperationException("No image formats have been configured.");
+ stringBuilder.AppendLine("-" + format);
}
+ throw new NotSupportedException(stringBuilder.ToString());
+ }
+
+ private static T WithSeekableStream(Stream stream, Func action)
+ {
if (!stream.CanRead)
{
throw new NotSupportedException("Cannot read from the stream.");
@@ -150,10 +230,7 @@ namespace ImageSharp
if (stream.CanSeek)
{
- if (Decode(stream, options, config, out Image img))
- {
- return img;
- }
+ return action(stream);
}
else
{
@@ -163,22 +240,9 @@ namespace ImageSharp
stream.CopyTo(ms);
ms.Position = 0;
- if (Decode(ms, options, config, out Image img))
- {
- return img;
- }
+ return action(stream);
}
}
-
- StringBuilder stringBuilder = new StringBuilder();
- stringBuilder.AppendLine("Image cannot be loaded. Available formats:");
-
- foreach (IImageFormat format in config.ImageFormats)
- {
- stringBuilder.AppendLine("-" + format);
- }
-
- throw new NotSupportedException(stringBuilder.ToString());
}
}
}
diff --git a/tests/ImageSharp.Tests/Image/ImageLoadTests.cs b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs
index 2c97ea06fd..da3d2fb069 100644
--- a/tests/ImageSharp.Tests/Image/ImageLoadTests.cs
+++ b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs
@@ -66,6 +66,9 @@ namespace ImageSharp.Tests
this.FilePath = Guid.NewGuid().ToString();
this.fileSystem.Setup(x => x.OpenRead(this.FilePath)).Returns(this.DataStream);
+
+ TestFileSystem.RegisterGloablTestFormat();
+ TestFileSystem.Global.AddFile(this.FilePath, this.DataStream);
}
[Fact]
@@ -157,6 +160,50 @@ namespace ImageSharp.Tests
this.localDecoder.Verify(x => x.Decode(stream, this.decoderOptions));
}
+
+
+ [Fact]
+ public void LoadFromStreamWithDecoder()
+ {
+ Stream stream = new MemoryStream();
+ Image img = Image.Load(stream, this.localDecoder.Object);
+
+ Assert.NotNull(img);
+ this.localDecoder.Verify(x => x.Decode(stream, null));
+ }
+
+ [Fact]
+ public void LoadFromStreamWithTypeAndDecoder()
+ {
+ Stream stream = new MemoryStream();
+ Image img = Image.Load(stream, this.localDecoder.Object);
+
+ Assert.NotNull(img);
+ Assert.Equal(this.returnImage, img);
+ this.localDecoder.Verify(x => x.Decode(stream, null));
+ }
+
+ [Fact]
+ public void LoadFromStreamWithDecoderAndOptions()
+ {
+ Stream stream = new MemoryStream();
+ Image img = Image.Load(stream, this.localDecoder.Object, this.decoderOptions);
+
+ Assert.NotNull(img);
+ this.localDecoder.Verify(x => x.Decode(stream, this.decoderOptions));
+ }
+
+ [Fact]
+ public void LoadFromStreamWithTypeAndDecoderAndOptions()
+ {
+ Stream stream = new MemoryStream();
+ Image img = Image.Load(stream, this.localDecoder.Object, this.decoderOptions);
+
+ Assert.NotNull(img);
+ Assert.Equal(this.returnImage, img);
+ this.localDecoder.Verify(x => x.Decode(stream, this.decoderOptions));
+ }
+
[Fact]
public void LoadFromBytes()
{
@@ -246,7 +293,50 @@ namespace ImageSharp.Tests
this.localDecoder.Verify(x => x.Decode(It.IsAny(), this.decoderOptions));
Assert.Equal(this.DataStream.ToArray(), this.DecodedData);
}
-
+
+
+ [Fact]
+ public void LoadFromBytesWithDecoder()
+ {
+ Image img = Image.Load(this.DataStream.ToArray(), this.localDecoder.Object);
+
+ Assert.NotNull(img);
+ this.localDecoder.Verify(x => x.Decode(It.IsAny(), null));
+ Assert.Equal(this.DataStream.ToArray(), this.DecodedData);
+ }
+
+ [Fact]
+ public void LoadFromBytesWithTypeAndDecoder()
+ {
+ Image img = Image.Load(this.DataStream.ToArray(), this.localDecoder.Object);
+
+ Assert.NotNull(img);
+ Assert.Equal(this.returnImage, img);
+ this.localDecoder.Verify(x => x.Decode(It.IsAny(), null));
+ Assert.Equal(this.DataStream.ToArray(), this.DecodedData);
+ }
+
+ [Fact]
+ public void LoadFromBytesWithDecoderAndOptions()
+ {
+ Image img = Image.Load(this.DataStream.ToArray(), this.localDecoder.Object, this.decoderOptions);
+
+ Assert.NotNull(img);
+ this.localDecoder.Verify(x => x.Decode(It.IsAny(), this.decoderOptions));
+ Assert.Equal(this.DataStream.ToArray(), this.DecodedData);
+ }
+
+ [Fact]
+ public void LoadFromBytesWithTypeAndDecoderAndOptions()
+ {
+ Image img = Image.Load(this.DataStream.ToArray(), this.localDecoder.Object, this.decoderOptions);
+
+ Assert.NotNull(img);
+ Assert.Equal(this.returnImage, img);
+ this.localDecoder.Verify(x => x.Decode(It.IsAny(), this.decoderOptions));
+ Assert.Equal(this.DataStream.ToArray(), this.DecodedData);
+ }
+
[Fact]
public void LoadFromFile()
{
@@ -324,7 +414,7 @@ namespace ImageSharp.Tests
[Fact]
public void LoadFromFileWithTypeAndConfigAndOptions()
{
- Image img = Image.Load(FilePath, this.decoderOptions, this.LocalConfiguration);
+ Image img = Image.Load(this.FilePath, this.decoderOptions, this.LocalConfiguration);
Assert.NotNull(img);
Assert.Equal(this.returnImage, img);
@@ -332,6 +422,45 @@ namespace ImageSharp.Tests
this.localDecoder.Verify(x => x.Decode(this.DataStream, this.decoderOptions));
}
+
+ [Fact]
+ public void LoadFromFileWithDecoder()
+ {
+ Image img = Image.Load(this.FilePath, this.localDecoder.Object);
+
+ Assert.NotNull(img);
+ this.localDecoder.Verify(x => x.Decode(this.DataStream, null));
+ }
+
+ [Fact]
+ public void LoadFromFileWithTypeAndDecoder()
+ {
+ Image img = Image.Load(this.FilePath, this.localDecoder.Object);
+
+ Assert.NotNull(img);
+ Assert.Equal(this.returnImage, img);
+ this.localDecoder.Verify(x => x.Decode(this.DataStream, null));
+ }
+
+ [Fact]
+ public void LoadFromFileWithDecoderAndOptions()
+ {
+ Image img = Image.Load(this.FilePath, this.localDecoder.Object, this.decoderOptions);
+
+ Assert.NotNull(img);
+ this.localDecoder.Verify(x => x.Decode(this.DataStream, this.decoderOptions));
+ }
+
+ [Fact]
+ public void LoadFromFileWithTypeAndDecoderAndOptions()
+ {
+ Image img = Image.Load(this.FilePath, this.localDecoder.Object, this.decoderOptions);
+
+ Assert.NotNull(img);
+ Assert.Equal(this.returnImage, img);
+ this.localDecoder.Verify(x => x.Decode(this.DataStream, this.decoderOptions));
+ }
+
public void Dispose()
{
// clean up the global object;
diff --git a/tests/ImageSharp.Tests/TestFileSystem.cs b/tests/ImageSharp.Tests/TestFileSystem.cs
new file mode 100644
index 0000000000..78499ac8ee
--- /dev/null
+++ b/tests/ImageSharp.Tests/TestFileSystem.cs
@@ -0,0 +1,72 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Tests
+{
+ using System;
+ using System.Collections.Concurrent;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Linq;
+ using System.Reflection;
+ using ImageSharp.Formats;
+ using Xunit;
+
+ ///
+ /// A test image file.
+ ///
+ public class TestFileSystem : ImageSharp.IO.IFileSystem
+ {
+
+ public static TestFileSystem Global { get; } = new TestFileSystem();
+
+ public static void RegisterGloablTestFormat()
+ {
+ Configuration.Default.FileSystem = Global;
+ }
+
+ Dictionary fileSystem = new Dictionary(StringComparer.OrdinalIgnoreCase);
+
+ public void AddFile(string path, Stream data)
+ {
+ fileSystem.Add(path, data);
+ }
+
+ public Stream Create(string path)
+ {
+ MemoryStream stream = new MemoryStream();
+ lock (fileSystem)
+ {
+ if (fileSystem.ContainsKey(path))
+ {
+ fileSystem[path] = stream;
+ }
+ else
+ {
+ fileSystem.Add(path, stream);
+ }
+ }
+ return stream;
+ }
+
+
+ public Stream OpenRead(string path)
+ {
+ lock (fileSystem)
+ {
+ if (fileSystem.ContainsKey(path))
+ {
+
+ Stream stream = fileSystem[path];
+ stream.Position = 0;
+ return stream;
+ }
+ }
+
+ return File.OpenRead(path);
+ }
+ }
+}
+