mirror of https://github.com/SixLabors/ImageSharp
46 changed files with 1293 additions and 689 deletions
@ -0,0 +1,67 @@ |
|||
// <copyright file="Image.Decode.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Buffers; |
|||
using System.Diagnostics; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using Formats; |
|||
|
|||
/// <summary>
|
|||
/// Represents an image. Each pixel is a made up four 8-bit components red, green, blue, and alpha
|
|||
/// packed into a single unsigned integer value.
|
|||
/// </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> |
|||
{ |
|||
img = null; |
|||
int maxHeaderSize = config.MaxHeaderSize; |
|||
if (maxHeaderSize <= 0) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
IImageFormat format; |
|||
byte[] header = ArrayPool<byte>.Shared.Rent(maxHeaderSize); |
|||
try |
|||
{ |
|||
long startPosition = stream.Position; |
|||
stream.Read(header, 0, maxHeaderSize); |
|||
stream.Position = startPosition; |
|||
format = config.ImageFormats.FirstOrDefault(x => x.IsSupportedFileFormat(header)); |
|||
} |
|||
finally |
|||
{ |
|||
ArrayPool<byte>.Shared.Return(header); |
|||
} |
|||
|
|||
if (format == null) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
img = format.Decoder.Decode<TColor>(stream, options); |
|||
img.CurrentImageFormat = format; |
|||
return true; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,148 @@ |
|||
// <copyright file="Image.FromStream.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Buffers; |
|||
using System.Diagnostics; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using Formats; |
|||
|
|||
/// <summary>
|
|||
/// Represents an image. Each pixel is a made up four 8-bit components red, green, blue, and alpha
|
|||
/// packed into a single unsigned integer value.
|
|||
/// </summary>
|
|||
public sealed partial class Image |
|||
{ |
|||
/// <summary>
|
|||
/// Loads the image from the given stream.
|
|||
/// </summary>
|
|||
/// <param name="stream">The stream containing image information.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image Load(byte[] stream) |
|||
{ |
|||
return Load(stream, null, null); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given stream.
|
|||
/// </summary>
|
|||
/// <param name="stream">The stream containing image information.</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[] stream, IDecoderOptions options) |
|||
{ |
|||
return Load(stream, options, null); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given stream.
|
|||
/// </summary>
|
|||
/// <param name="stream">The stream containing image information.</param>
|
|||
/// <param name="config">The config 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[] stream, Configuration config) |
|||
{ |
|||
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="options">The options for the decoder.</param>
|
|||
/// <param name="config">The configuration options.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image Load(byte[] stream, IDecoderOptions options, Configuration config) |
|||
{ |
|||
using (MemoryStream ms = new MemoryStream(stream)) |
|||
{ |
|||
return Load(ms, options, 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>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image<TColor> Load<TColor>(byte[] stream) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
return Load<TColor>(stream, null, 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="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[] stream, IDecoderOptions options) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
return Load<TColor>(stream, options, 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="config">The config 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[] stream, Configuration config) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
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="options">The options for the decoder.</param>
|
|||
/// <param name="config">The configuration options.</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[] stream, IDecoderOptions options, Configuration config) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
using (MemoryStream ms = new MemoryStream(stream)) |
|||
{ |
|||
return Load<TColor>(ms, options, config); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,148 @@ |
|||
// <copyright file="Image.FromStream.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Buffers; |
|||
using System.Diagnostics; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using Formats; |
|||
|
|||
#if !NETSTANDARD1_1
|
|||
/// <summary>
|
|||
/// Represents an image. Each pixel is a made up four 8-bit components red, green, blue, and alpha
|
|||
/// packed into a single unsigned integer value.
|
|||
/// </summary>
|
|||
public sealed partial class Image |
|||
{ |
|||
/// <summary>
|
|||
/// Loads the image from the given stream.
|
|||
/// </summary>
|
|||
/// <param name="stream">The stream containing image information.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image Load(string stream) |
|||
{ |
|||
return Load(stream, null, null); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given stream.
|
|||
/// </summary>
|
|||
/// <param name="stream">The stream containing image information.</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 stream, IDecoderOptions options) |
|||
{ |
|||
return Load(stream, options, null); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given stream.
|
|||
/// </summary>
|
|||
/// <param name="stream">The stream containing image information.</param>
|
|||
/// <param name="config">The config 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 stream, Configuration config) |
|||
{ |
|||
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="options">The options for the decoder.</param>
|
|||
/// <param name="config">The configuration options.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image Load(string stream, IDecoderOptions options, Configuration config) |
|||
{ |
|||
return new Image(Image.Load<Color>(stream, options, 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>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image<TColor> Load<TColor>(string stream) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
return Load<TColor>(stream, null, 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="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 stream, IDecoderOptions options) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
return Load<TColor>(stream, options, 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="config">The config 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 stream, Configuration config) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
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="options">The options for the decoder.</param>
|
|||
/// <param name="config">The configuration options.</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 stream, IDecoderOptions options, Configuration config) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
config = config ?? Configuration.Default; |
|||
using (Stream s = config.FileSystem.OpenRead(stream)) |
|||
{ |
|||
return Load<TColor>(s, options, config); |
|||
} |
|||
} |
|||
} |
|||
#endif
|
|||
} |
|||
@ -0,0 +1,184 @@ |
|||
// <copyright file="Image.FromStream.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Buffers; |
|||
using System.Diagnostics; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using Formats; |
|||
|
|||
/// <summary>
|
|||
/// Represents an image. Each pixel is a made up four 8-bit components red, green, blue, and alpha
|
|||
/// packed into a single unsigned integer value.
|
|||
/// </summary>
|
|||
public sealed partial class Image |
|||
{ |
|||
/// <summary>
|
|||
/// Loads the image from the given stream.
|
|||
/// </summary>
|
|||
/// <param name="stream">The stream containing image information.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image Load(Stream stream) |
|||
{ |
|||
return Load(stream, null, null); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given stream.
|
|||
/// </summary>
|
|||
/// <param name="stream">The stream containing image information.</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, IDecoderOptions options) |
|||
{ |
|||
return Load(stream, options, null); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given stream.
|
|||
/// </summary>
|
|||
/// <param name="stream">The stream containing image information.</param>
|
|||
/// <param name="config">The config 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, Configuration config) |
|||
{ |
|||
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="options">The options for the decoder.</param>
|
|||
/// <param name="config">The configuration options.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image Load(Stream stream, IDecoderOptions options, Configuration config) |
|||
{ |
|||
return new Image(Load<Color>(stream, options, 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>
|
|||
/// <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) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
return Load<TColor>(stream, null, 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="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, IDecoderOptions options) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
return Load<TColor>(stream, options, 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="config">The config 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, Configuration config) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
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="options">The options for the decoder.</param>
|
|||
/// <param name="config">The configuration options.</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, IDecoderOptions options, Configuration config) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
config = config ?? Configuration.Default; |
|||
|
|||
if (!config.ImageFormats.Any()) |
|||
{ |
|||
throw new InvalidOperationException("No image formats have been configured."); |
|||
} |
|||
|
|||
if (!stream.CanRead) |
|||
{ |
|||
throw new NotSupportedException("Cannot read from the stream."); |
|||
} |
|||
|
|||
if (stream.CanSeek) |
|||
{ |
|||
if (Decode(stream, options, config, out Image<TColor> img)) |
|||
{ |
|||
return img; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
// We want to be able to load images from things like HttpContext.Request.Body
|
|||
using (MemoryStream ms = new MemoryStream()) |
|||
{ |
|||
stream.CopyTo(ms); |
|||
ms.Position = 0; |
|||
|
|||
if (Decode(ms, options, config, out Image<TColor> img)) |
|||
{ |
|||
return img; |
|||
} |
|||
} |
|||
} |
|||
|
|||
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()); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,341 @@ |
|||
// <copyright file="PixelAccessorTests.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.IO; |
|||
using System.Linq; |
|||
using ImageSharp.Formats; |
|||
using ImageSharp.IO; |
|||
using Moq; |
|||
using Xunit; |
|||
|
|||
/// <summary>
|
|||
/// Tests the <see cref="Image"/> class.
|
|||
/// </summary>
|
|||
public class ImageLoadTests : IDisposable |
|||
{ |
|||
private readonly Mock<IFileSystem> fileSystem; |
|||
private readonly IDecoderOptions decoderOptions; |
|||
private Image<Color> returnImage; |
|||
private Mock<IImageDecoder> localDecoder; |
|||
private Mock<IImageFormat> localFormat; |
|||
private readonly string FilePath; |
|||
|
|||
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 ImageLoadTests() |
|||
{ |
|||
this.returnImage = new Image<Color>(1, 1); |
|||
|
|||
this.localDecoder = new Mock<IImageDecoder>(); |
|||
this.localFormat = new Mock<IImageFormat>(); |
|||
this.localFormat.Setup(x => x.Decoder).Returns(this.localDecoder.Object); |
|||
this.localFormat.Setup(x => x.Encoder).Returns(new Mock<IImageEncoder>().Object); |
|||
this.localFormat.Setup(x => x.MimeType).Returns("img/test"); |
|||
this.localFormat.Setup(x => x.Extension).Returns("png"); |
|||
this.localFormat.Setup(x => x.HeaderSize).Returns(1); |
|||
this.localFormat.Setup(x => x.IsSupportedFileFormat(It.IsAny<byte[]>())).Returns(true); |
|||
this.localFormat.Setup(x => x.SupportedExtensions).Returns(new string[] { "png", "jpg" }); |
|||
this.localDecoder.Setup(x => x.Decode<Color>(It.IsAny<Stream>(), It.IsAny<IDecoderOptions>())) |
|||
.Callback<Stream, IDecoderOptions>((s, o) => { |
|||
using (var ms = new MemoryStream()) |
|||
{ |
|||
s.CopyTo(ms); |
|||
this.DecodedData = ms.ToArray(); |
|||
} |
|||
}) |
|||
.Returns(this.returnImage); |
|||
|
|||
this.fileSystem = new Mock<IFileSystem>(); |
|||
|
|||
this.LocalConfiguration = new Configuration(this.localFormat.Object) |
|||
{ |
|||
FileSystem = this.fileSystem.Object |
|||
}; |
|||
TestFormat.RegisterGloablTestFormat(); |
|||
this.Marker = Guid.NewGuid().ToByteArray(); |
|||
this.DataStream = TestFormat.GlobalTestFormat.CreateStream(this.Marker); |
|||
this.decoderOptions = new Mock<IDecoderOptions>().Object; |
|||
|
|||
this.FilePath = Guid.NewGuid().ToString(); |
|||
this.fileSystem.Setup(x => x.OpenRead(this.FilePath)).Returns(this.DataStream); |
|||
} |
|||
|
|||
[Fact] |
|||
public void LoadFromStream() |
|||
{ |
|||
Image img = Image.Load(this.DataStream); |
|||
|
|||
Assert.NotNull(img); |
|||
Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); |
|||
|
|||
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null); |
|||
} |
|||
|
|||
[Fact] |
|||
public void LoadFromStreamWithType() |
|||
{ |
|||
Image<Color> img = Image.Load<Color>(this.DataStream); |
|||
|
|||
Assert.NotNull(img); |
|||
Assert.Equal(TestFormat.GlobalTestFormat.Sample<Color>(), img); |
|||
Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); |
|||
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null); |
|||
} |
|||
|
|||
[Fact] |
|||
public void LoadFromStreamWithOptions() |
|||
{ |
|||
Image img = Image.Load(this.DataStream, this.decoderOptions); |
|||
|
|||
Assert.NotNull(img); |
|||
Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); |
|||
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions); |
|||
} |
|||
|
|||
[Fact] |
|||
public void LoadFromStreamWithTypeAndOptions() |
|||
{ |
|||
Image<Color> img = Image.Load<Color>(this.DataStream, this.decoderOptions); |
|||
|
|||
Assert.NotNull(img); |
|||
Assert.Equal(TestFormat.GlobalTestFormat.Sample<Color>(), img); |
|||
Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); |
|||
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions); |
|||
} |
|||
|
|||
[Fact] |
|||
public void LoadFromStreamWithConfig() |
|||
{ |
|||
Stream stream = new MemoryStream(); |
|||
Image img = Image.Load(stream, this.LocalConfiguration); |
|||
|
|||
Assert.NotNull(img); |
|||
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); |
|||
this.localDecoder.Verify(x => x.Decode<Color>(stream, null)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void LoadFromStreamWithTypeAndConfig() |
|||
{ |
|||
Stream stream = new MemoryStream(); |
|||
Image<Color> img = Image.Load<Color>(stream, this.LocalConfiguration); |
|||
|
|||
Assert.NotNull(img); |
|||
Assert.Equal(this.returnImage, img); |
|||
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); |
|||
this.localDecoder.Verify(x => x.Decode<Color>(stream, null)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void LoadFromStreamWithConfigAndOptions() |
|||
{ |
|||
Stream stream = new MemoryStream(); |
|||
Image img = Image.Load(stream, this.decoderOptions, this.LocalConfiguration); |
|||
|
|||
Assert.NotNull(img); |
|||
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); |
|||
this.localDecoder.Verify(x => x.Decode<Color>(stream, this.decoderOptions)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void LoadFromStreamWithTypeAndConfigAndOptions() |
|||
{ |
|||
Stream stream = new MemoryStream(); |
|||
Image<Color> img = Image.Load<Color>(stream, this.decoderOptions, this.LocalConfiguration); |
|||
|
|||
Assert.NotNull(img); |
|||
Assert.Equal(this.returnImage, img); |
|||
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); |
|||
this.localDecoder.Verify(x => x.Decode<Color>(stream, this.decoderOptions)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void LoadFromBytes() |
|||
{ |
|||
Image img = Image.Load(this.DataStream.ToArray()); |
|||
|
|||
Assert.NotNull(img); |
|||
Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); |
|||
|
|||
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null); |
|||
} |
|||
|
|||
[Fact] |
|||
public void LoadFromBytesWithType() |
|||
{ |
|||
Image<Color> img = Image.Load<Color>(this.DataStream.ToArray()); |
|||
|
|||
Assert.NotNull(img); |
|||
Assert.Equal(TestFormat.GlobalTestFormat.Sample<Color>(), img); |
|||
Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); |
|||
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null); |
|||
} |
|||
|
|||
[Fact] |
|||
public void LoadFromBytesWithOptions() |
|||
{ |
|||
Image img = Image.Load(this.DataStream.ToArray(), this.decoderOptions); |
|||
|
|||
Assert.NotNull(img); |
|||
Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); |
|||
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions); |
|||
} |
|||
|
|||
[Fact] |
|||
public void LoadFromBytesWithTypeAndOptions() |
|||
{ |
|||
Image<Color> img = Image.Load<Color>(this.DataStream.ToArray(), this.decoderOptions); |
|||
|
|||
Assert.NotNull(img); |
|||
Assert.Equal(TestFormat.GlobalTestFormat.Sample<Color>(), img); |
|||
Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); |
|||
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions); |
|||
} |
|||
|
|||
[Fact] |
|||
public void LoadFromBytesWithConfig() |
|||
{ |
|||
Image img = Image.Load(this.DataStream.ToArray(), this.LocalConfiguration); |
|||
|
|||
Assert.NotNull(img); |
|||
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); |
|||
this.localDecoder.Verify(x => x.Decode<Color>(It.IsAny<Stream>(), null)); |
|||
Assert.Equal(this.DataStream.ToArray(), this.DecodedData); |
|||
} |
|||
|
|||
[Fact] |
|||
public void LoadFromBytesWithTypeAndConfig() |
|||
{ |
|||
Image<Color> img = Image.Load<Color>(this.DataStream.ToArray(), this.LocalConfiguration); |
|||
|
|||
Assert.NotNull(img); |
|||
Assert.Equal(this.returnImage, img); |
|||
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); |
|||
|
|||
this.localDecoder.Verify(x => x.Decode<Color>(It.IsAny<Stream>(), null)); |
|||
Assert.Equal(this.DataStream.ToArray(), this.DecodedData); |
|||
} |
|||
|
|||
[Fact] |
|||
public void LoadFromBytesWithConfigAndOptions() |
|||
{ |
|||
Image img = Image.Load(this.DataStream.ToArray(), this.decoderOptions, this.LocalConfiguration); |
|||
|
|||
Assert.NotNull(img); |
|||
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); |
|||
this.localDecoder.Verify(x => x.Decode<Color>(It.IsAny<Stream>(), this.decoderOptions)); |
|||
Assert.Equal(this.DataStream.ToArray(), this.DecodedData); |
|||
} |
|||
|
|||
[Fact] |
|||
public void LoadFromBytesWithTypeAndConfigAndOptions() |
|||
{ |
|||
Image<Color> img = Image.Load<Color>(this.DataStream.ToArray(), this.decoderOptions, this.LocalConfiguration); |
|||
|
|||
Assert.NotNull(img); |
|||
Assert.Equal(this.returnImage, img); |
|||
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); |
|||
this.localDecoder.Verify(x => x.Decode<Color>(It.IsAny<Stream>(), this.decoderOptions)); |
|||
Assert.Equal(this.DataStream.ToArray(), this.DecodedData); |
|||
} |
|||
|
|||
[Fact] |
|||
public void LoadFromFile() |
|||
{ |
|||
Image img = Image.Load(this.DataStream); |
|||
|
|||
Assert.NotNull(img); |
|||
Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); |
|||
|
|||
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null); |
|||
} |
|||
|
|||
[Fact] |
|||
public void LoadFromFileWithType() |
|||
{ |
|||
Image<Color> img = Image.Load<Color>(this.DataStream); |
|||
|
|||
Assert.NotNull(img); |
|||
Assert.Equal(TestFormat.GlobalTestFormat.Sample<Color>(), img); |
|||
Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); |
|||
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null); |
|||
} |
|||
|
|||
[Fact] |
|||
public void LoadFromFileWithOptions() |
|||
{ |
|||
Image img = Image.Load(this.DataStream, this.decoderOptions); |
|||
|
|||
Assert.NotNull(img); |
|||
Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); |
|||
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions); |
|||
} |
|||
|
|||
[Fact] |
|||
public void LoadFromFileWithTypeAndOptions() |
|||
{ |
|||
Image<Color> img = Image.Load<Color>(this.DataStream, this.decoderOptions); |
|||
|
|||
Assert.NotNull(img); |
|||
Assert.Equal(TestFormat.GlobalTestFormat.Sample<Color>(), img); |
|||
Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); |
|||
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions); |
|||
} |
|||
|
|||
[Fact] |
|||
public void LoadFromFileWithConfig() |
|||
{ |
|||
Image img = Image.Load(this.FilePath, this.LocalConfiguration); |
|||
|
|||
Assert.NotNull(img); |
|||
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); |
|||
this.localDecoder.Verify(x => x.Decode<Color>(this.DataStream, null)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void LoadFromFileWithTypeAndConfig() |
|||
{ |
|||
Image<Color> img = Image.Load<Color>(this.FilePath, this.LocalConfiguration); |
|||
|
|||
Assert.NotNull(img); |
|||
Assert.Equal(this.returnImage, img); |
|||
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); |
|||
this.localDecoder.Verify(x => x.Decode<Color>(this.DataStream, null)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void LoadFromFileWithConfigAndOptions() |
|||
{ |
|||
Image img = Image.Load(this.FilePath, this.decoderOptions, this.LocalConfiguration); |
|||
|
|||
Assert.NotNull(img); |
|||
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); |
|||
this.localDecoder.Verify(x => x.Decode<Color>(this.DataStream, this.decoderOptions)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void LoadFromFileWithTypeAndConfigAndOptions() |
|||
{ |
|||
Image<Color> img = Image.Load<Color>(FilePath, this.decoderOptions, this.LocalConfiguration); |
|||
|
|||
Assert.NotNull(img); |
|||
Assert.Equal(this.returnImage, img); |
|||
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); |
|||
this.localDecoder.Verify(x => x.Decode<Color>(this.DataStream, this.decoderOptions)); |
|||
} |
|||
|
|||
public void Dispose() |
|||
{ |
|||
// clean up the global object;
|
|||
this.returnImage?.Dispose(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,174 @@ |
|||
// <copyright file="TestImage.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 TestFormat : ImageSharp.Formats.IImageFormat |
|||
{ |
|||
public static TestFormat GlobalTestFormat { get; } = new TestFormat(); |
|||
|
|||
public static void RegisterGloablTestFormat() |
|||
{ |
|||
Configuration.Default.AddImageFormat(GlobalTestFormat); |
|||
} |
|||
|
|||
public TestFormat() |
|||
{ |
|||
this.Encoder = new TestEncoder(this); ; |
|||
this.Decoder = new TestDecoder(this); ; |
|||
} |
|||
|
|||
public List<DecodeOperation> DecodeCalls { get; } = new List<DecodeOperation>(); |
|||
|
|||
public IImageEncoder Encoder { get; } |
|||
|
|||
public IImageDecoder Decoder { get; } |
|||
|
|||
private byte[] header = Guid.NewGuid().ToByteArray(); |
|||
|
|||
public MemoryStream CreateStream(byte[] marker = null) |
|||
{ |
|||
MemoryStream ms = new MemoryStream(); |
|||
byte[] data = this.header; |
|||
ms.Write(data, 0, data.Length); |
|||
if (marker != null) |
|||
{ |
|||
ms.Write(marker, 0, marker.Length); |
|||
} |
|||
ms.Position = 0; |
|||
return ms; |
|||
} |
|||
|
|||
Dictionary<Type, object> _sampleImages = new Dictionary<Type, object>(); |
|||
|
|||
public void VerifyDecodeCall(byte[] marker, IDecoderOptions options) |
|||
{ |
|||
DecodeOperation[] discovered = this.DecodeCalls.Where(x => x.IsMatch(marker, options)).ToArray(); |
|||
|
|||
Assert.True(discovered.Any(), "No calls to decode on this formate with the proveded options happend"); |
|||
|
|||
foreach (DecodeOperation d in discovered) { |
|||
this.DecodeCalls.Remove(d); |
|||
} |
|||
} |
|||
|
|||
public Image<TColor> Sample<TColor>() |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
lock (this._sampleImages) |
|||
{ |
|||
if (!this._sampleImages.ContainsKey(typeof(TColor))) |
|||
{ |
|||
this._sampleImages.Add(typeof(TColor), new Image<TColor>(1, 1)); |
|||
} |
|||
|
|||
return (Image<TColor>)this._sampleImages[typeof(TColor)]; |
|||
} |
|||
} |
|||
|
|||
public string MimeType => "img/test"; |
|||
|
|||
public string Extension => "test_ext"; |
|||
|
|||
public IEnumerable<string> SupportedExtensions => new[] { "test_ext" }; |
|||
|
|||
public int HeaderSize => this.header.Length; |
|||
|
|||
public bool IsSupportedFileFormat(byte[] header) |
|||
{ |
|||
if (header.Length < this.header.Length) |
|||
{ |
|||
return false; |
|||
} |
|||
for (int i = 0; i < this.header.Length; i++) |
|||
{ |
|||
if (header[i] != this.header[i]) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
public struct DecodeOperation |
|||
{ |
|||
public byte[] marker; |
|||
public IDecoderOptions options; |
|||
|
|||
public bool IsMatch(byte[] testMarker, IDecoderOptions testOptions) |
|||
{ |
|||
if(this.options != testOptions) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (testMarker.Length != this.marker.Length) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
for (int i = 0; i < this.marker.Length; i++) |
|||
{ |
|||
if (testMarker[i] != this.marker[i]) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
public class TestDecoder : ImageSharp.Formats.IImageDecoder |
|||
{ |
|||
private TestFormat testFormat; |
|||
|
|||
public TestDecoder(TestFormat testFormat) |
|||
{ |
|||
this.testFormat = testFormat; |
|||
} |
|||
|
|||
public Image<TColor> Decode<TColor>(Stream stream, IDecoderOptions options) where TColor : struct, IPixel<TColor> |
|||
{ |
|||
var ms = new MemoryStream(); |
|||
stream.CopyTo(ms); |
|||
var marker = ms.ToArray().Skip(this.testFormat.header.Length).ToArray(); |
|||
this.testFormat.DecodeCalls.Add(new DecodeOperation |
|||
{ |
|||
marker = marker, |
|||
options = options |
|||
}); |
|||
|
|||
// TODO record this happend so we an verify it.
|
|||
return this.testFormat.Sample<TColor>(); |
|||
} |
|||
} |
|||
|
|||
public class TestEncoder : ImageSharp.Formats.IImageEncoder |
|||
{ |
|||
private TestFormat testFormat; |
|||
|
|||
public TestEncoder(TestFormat testFormat) |
|||
{ |
|||
this.testFormat = testFormat; |
|||
} |
|||
|
|||
public void Encode<TColor>(Image<TColor> image, Stream stream, IEncoderOptions options) where TColor : struct, IPixel<TColor> |
|||
{ |
|||
// TODO record this happend so we an verify it.
|
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue