Browse Source

Add IImageDecoder overloads

Adds overloads the the Image.Load(..) methods that take an IImageDecoder.
pull/143/head
Scott Williams 9 years ago
parent
commit
1343c78411
  1. 40
      src/ImageSharp/Image.Decode.cs
  2. 72
      src/ImageSharp/Image.FromBytes.cs
  3. 70
      src/ImageSharp/Image.FromFile.cs
  4. 108
      src/ImageSharp/Image.FromStream.cs
  5. 133
      tests/ImageSharp.Tests/Image/ImageLoadTests.cs
  6. 72
      tests/ImageSharp.Tests/TestFileSystem.cs

40
src/ImageSharp/Image.Decode.cs

@ -19,25 +19,12 @@ namespace ImageSharp
/// </summary>
public sealed partial class Image
{
/// <summary>
/// Decodes the image stream to the current image.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="stream">The stream.</param>
/// <param name="options">The options for the decoder.</param>
/// <param name="config">the configuration.</param>
/// <param name="img">The decoded image</param>
/// <returns>
/// [true] if can successfull decode the image otherwise [false].
/// </returns>
private static bool Decode<TColor>(Stream stream, IDecoderOptions options, Configuration config, out Image<TColor> img)
where TColor : struct, IPixel<TColor>
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<byte>.Shared.Return(header);
}
return format;
}
/// <summary>
/// Decodes the image stream to the current image.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="stream">The stream.</param>
/// <param name="options">The options for the decoder.</param>
/// <param name="config">the configuration.</param>
/// <returns>
/// The decoded image
/// </returns>
private static Image<TColor> Decode<TColor>(Stream stream, IDecoderOptions options, Configuration config)
where TColor : struct, IPixel<TColor>
{
IImageFormat format = DiscoverFormat(stream, options, config);
if (format == null)
{
return false;
return null;
}
img = format.Decoder.Decode<TColor>(stream, options);
Image<TColor> img = format.Decoder.Decode<TColor>(stream, options);
img.CurrentImageFormat = format;
return true;
return img;
}
}
}

72
src/ImageSharp/Image.FromBytes.cs

@ -29,7 +29,7 @@ namespace ImageSharp
/// <returns>The image</returns>
public static Image Load(byte[] data)
{
return Load(data, null, null);
return Load(data, null, (Configuration)null);
}
/// <summary>
@ -60,6 +60,20 @@ namespace ImageSharp
return Load(data, null, config);
}
/// <summary>
/// Loads the image from the given byte array.
/// </summary>
/// <param name="data">The byte array containing image data.</param>
/// <param name="decoder">The decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(byte[] data, IImageDecoder decoder)
{
return Load(data, decoder, null);
}
/// <summary>
/// Loads the image from the given byte array.
/// </summary>
@ -78,6 +92,24 @@ namespace ImageSharp
}
}
/// <summary>
/// Loads the image from the given byte array.
/// </summary>
/// <param name="data">The byte array containing image data.</param>
/// <param name="decoder">The decoder.</param>
/// <param name="options">The options for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(byte[] data, IImageDecoder decoder, IDecoderOptions options)
{
using (MemoryStream ms = new MemoryStream(data))
{
return Load(ms, decoder, options);
}
}
/// <summary>
/// Loads the image from the given byte array.
/// </summary>
@ -90,7 +122,7 @@ namespace ImageSharp
public static Image<TColor> Load<TColor>(byte[] data)
where TColor : struct, IPixel<TColor>
{
return Load<TColor>(data, null, null);
return Load<TColor>(data, null, (Configuration)null);
}
/// <summary>
@ -125,6 +157,22 @@ namespace ImageSharp
return Load<TColor>(data, null, config);
}
/// <summary>
/// Loads the image from the given byte array.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="data">The byte array containing image data.</param>
/// <param name="decoder">The decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image<TColor> Load<TColor>(byte[] data, IImageDecoder decoder)
where TColor : struct, IPixel<TColor>
{
return Load<TColor>(data, decoder, null);
}
/// <summary>
/// Loads the image from the given byte array.
/// </summary>
@ -144,5 +192,25 @@ namespace ImageSharp
return Load<TColor>(ms, options, config);
}
}
/// <summary>
/// Loads the image from the given byte array.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="data">The byte array containing image data.</param>
/// <param name="decoder">The decoder.</param>
/// <param name="options">The options for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image<TColor> Load<TColor>(byte[] data, IImageDecoder decoder, IDecoderOptions options)
where TColor : struct, IPixel<TColor>
{
using (MemoryStream ms = new MemoryStream(data))
{
return Load<TColor>(ms, decoder, options);
}
}
}
}

70
src/ImageSharp/Image.FromFile.cs

@ -30,7 +30,7 @@ namespace ImageSharp
/// <returns>The image</returns>
public static Image Load(string path)
{
return Load(path, null, null);
return Load(path, null, (Configuration)null);
}
/// <summary>
@ -61,6 +61,35 @@ namespace ImageSharp
return Load(path, null, config);
}
/// <summary>
/// Loads the image from the given file.
/// </summary>
/// <param name="path">The file path to the image.</param>
/// <param name="decoder">The decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(string path, IImageDecoder decoder)
{
return Load(path, decoder, null);
}
/// <summary>
/// Loads the image from the given file.
/// </summary>
/// <param name="path">The file path to the image.</param>
/// <param name="decoder">The decoder.</param>
/// <param name="options">The options for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(string path, IImageDecoder decoder, IDecoderOptions options)
{
return new Image(Load<Color>(path, decoder, options));
}
/// <summary>
/// Loads the image from the given file.
/// </summary>
@ -88,7 +117,7 @@ namespace ImageSharp
public static Image<TColor> Load<TColor>(string path)
where TColor : struct, IPixel<TColor>
{
return Load<TColor>(path, null, null);
return Load<TColor>(path, null, (Configuration)null);
}
/// <summary>
@ -123,6 +152,22 @@ namespace ImageSharp
return Load<TColor>(path, null, config);
}
/// <summary>
/// Loads the image from the given file.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="path">The file path to the image.</param>
/// <param name="decoder">The decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image<TColor> Load<TColor>(string path, IImageDecoder decoder)
where TColor : struct, IPixel<TColor>
{
return Load<TColor>(path, decoder, null);
}
/// <summary>
/// Loads the image from the given file.
/// </summary>
@ -143,6 +188,27 @@ namespace ImageSharp
return Load<TColor>(s, options, config);
}
}
/// <summary>
/// Loads the image from the given file.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="path">The file path to the image.</param>
/// <param name="decoder">The decoder.</param>
/// <param name="options">The options for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image<TColor> Load<TColor>(string path, IImageDecoder decoder, IDecoderOptions options)
where TColor : struct, IPixel<TColor>
{
Configuration config = Configuration.Default;
using (Stream s = config.FileSystem.OpenRead(path))
{
return Load<TColor>(s, decoder, options);
}
}
}
#endif
}

108
src/ImageSharp/Image.FromStream.cs

@ -29,7 +29,7 @@ namespace ImageSharp
/// <returns>The image</returns>
public static Image Load(Stream stream)
{
return Load(stream, null, null);
return Load(stream, null, (Configuration)null);
}
/// <summary>
@ -60,6 +60,20 @@ namespace ImageSharp
return Load(stream, null, config);
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <param name="stream">The stream containing image information.</param>
/// <param name="decoder">The decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(Stream stream, IImageDecoder decoder)
{
return Load(stream, decoder, null);
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
@ -75,6 +89,21 @@ namespace ImageSharp
return new Image(Load<Color>(stream, options, config));
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <param name="stream">The stream containing image information.</param>
/// <param name="decoder">The decoder.</param>
/// <param name="options">The options for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(Stream stream, IImageDecoder decoder, IDecoderOptions options)
{
return new Image(Load<Color>(stream, decoder, options));
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
@ -87,7 +116,7 @@ namespace ImageSharp
public static Image<TColor> Load<TColor>(Stream stream)
where TColor : struct, IPixel<TColor>
{
return Load<TColor>(stream, null, null);
return Load<TColor>(stream, null, (Configuration)null);
}
/// <summary>
@ -122,6 +151,39 @@ namespace ImageSharp
return Load<TColor>(stream, null, config);
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="stream">The stream containing image information.</param>
/// <param name="decoder">The decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image<TColor> Load<TColor>(Stream stream, IImageDecoder decoder)
where TColor : struct, IPixel<TColor>
{
return Load<TColor>(stream, decoder, null);
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="stream">The stream containing image information.</param>
/// <param name="decoder">The decoder.</param>
/// <param name="options">The options for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image<TColor> Load<TColor>(Stream stream, IImageDecoder decoder, IDecoderOptions options)
where TColor : struct, IPixel<TColor>
{
return WithSeekableStream(stream, s => decoder.Decode<TColor>(s, options));
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
@ -138,11 +200,29 @@ namespace ImageSharp
{
config = config ?? Configuration.Default;
if (!config.ImageFormats.Any())
Image<TColor> img = WithSeekableStream(stream, s =>
{
return Decode<TColor>(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<T>(Stream stream, Func<Stream, T> 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<TColor> 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<TColor> 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());
}
}
}

133
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<Color>(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<Color>(stream, null));
}
[Fact]
public void LoadFromStreamWithTypeAndDecoder()
{
Stream stream = new MemoryStream();
Image<Color> img = Image.Load<Color>(stream, this.localDecoder.Object);
Assert.NotNull(img);
Assert.Equal(this.returnImage, img);
this.localDecoder.Verify(x => x.Decode<Color>(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<Color>(stream, this.decoderOptions));
}
[Fact]
public void LoadFromStreamWithTypeAndDecoderAndOptions()
{
Stream stream = new MemoryStream();
Image<Color> img = Image.Load<Color>(stream, this.localDecoder.Object, this.decoderOptions);
Assert.NotNull(img);
Assert.Equal(this.returnImage, img);
this.localDecoder.Verify(x => x.Decode<Color>(stream, this.decoderOptions));
}
[Fact]
public void LoadFromBytes()
{
@ -246,7 +293,50 @@ namespace ImageSharp.Tests
this.localDecoder.Verify(x => x.Decode<Color>(It.IsAny<Stream>(), 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<Color>(It.IsAny<Stream>(), null));
Assert.Equal(this.DataStream.ToArray(), this.DecodedData);
}
[Fact]
public void LoadFromBytesWithTypeAndDecoder()
{
Image<Color> img = Image.Load<Color>(this.DataStream.ToArray(), this.localDecoder.Object);
Assert.NotNull(img);
Assert.Equal(this.returnImage, img);
this.localDecoder.Verify(x => x.Decode<Color>(It.IsAny<Stream>(), 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<Color>(It.IsAny<Stream>(), this.decoderOptions));
Assert.Equal(this.DataStream.ToArray(), this.DecodedData);
}
[Fact]
public void LoadFromBytesWithTypeAndDecoderAndOptions()
{
Image<Color> img = Image.Load<Color>(this.DataStream.ToArray(), this.localDecoder.Object, this.decoderOptions);
Assert.NotNull(img);
Assert.Equal(this.returnImage, img);
this.localDecoder.Verify(x => x.Decode<Color>(It.IsAny<Stream>(), 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<Color> img = Image.Load<Color>(FilePath, this.decoderOptions, this.LocalConfiguration);
Image<Color> img = Image.Load<Color>(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<Color>(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<Color>(this.DataStream, null));
}
[Fact]
public void LoadFromFileWithTypeAndDecoder()
{
Image<Color> img = Image.Load<Color>(this.FilePath, this.localDecoder.Object);
Assert.NotNull(img);
Assert.Equal(this.returnImage, img);
this.localDecoder.Verify(x => x.Decode<Color>(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<Color>(this.DataStream, this.decoderOptions));
}
[Fact]
public void LoadFromFileWithTypeAndDecoderAndOptions()
{
Image<Color> img = Image.Load<Color>(this.FilePath, this.localDecoder.Object, this.decoderOptions);
Assert.NotNull(img);
Assert.Equal(this.returnImage, img);
this.localDecoder.Verify(x => x.Decode<Color>(this.DataStream, this.decoderOptions));
}
public void Dispose()
{
// clean up the global object;

72
tests/ImageSharp.Tests/TestFileSystem.cs

@ -0,0 +1,72 @@
// <copyright file="TestFileSystem.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
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;
/// <summary>
/// A test image file.
/// </summary>
public class TestFileSystem : ImageSharp.IO.IFileSystem
{
public static TestFileSystem Global { get; } = new TestFileSystem();
public static void RegisterGloablTestFormat()
{
Configuration.Default.FileSystem = Global;
}
Dictionary<string, Stream> fileSystem = new Dictionary<string, Stream>(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);
}
}
}
Loading…
Cancel
Save