mirror of https://github.com/SixLabors/ImageSharp
56 changed files with 1943 additions and 698 deletions
@ -0,0 +1,66 @@ |
|||||
|
// <copyright file="Image.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.Diagnostics; |
||||
|
using System.IO; |
||||
|
|
||||
|
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>
|
||||
|
/// Create a new instance of the <see cref="Image{TColor}"/> class
|
||||
|
/// with the height and the width of the image.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TColor">The pixel format.</typeparam>
|
||||
|
/// <param name="width">The width of the image in pixels.</param>
|
||||
|
/// <param name="height">The height of the image in pixels.</param>
|
||||
|
/// <param name="metadata">The images matadata to preload.</param>
|
||||
|
/// <param name="configuration">
|
||||
|
/// The configuration providing initialization code which allows extending the library.
|
||||
|
/// </param>
|
||||
|
/// <returns>
|
||||
|
/// A new <see cref="Image{TColor}"/> unless <typeparamref name="TColor"/> is <see cref="Color"/> in which case it returns <see cref="Image" />
|
||||
|
/// </returns>
|
||||
|
internal static Image<TColor> Create<TColor>(int width, int height, ImageMetaData metadata, Configuration configuration) |
||||
|
where TColor : struct, IPixel<TColor> |
||||
|
{ |
||||
|
if (typeof(TColor) == typeof(Color)) |
||||
|
{ |
||||
|
return new Image(width, height, metadata, configuration) as Image<TColor>; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return new Image<TColor>(width, height, metadata, configuration); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Create a new instance of the <see cref="Image{TColor}"/> class
|
||||
|
/// with the height and the width of the image.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TColor">The pixel format.</typeparam>
|
||||
|
/// <param name="width">The width of the image in pixels.</param>
|
||||
|
/// <param name="height">The height of the image in pixels.</param>
|
||||
|
/// <param name="configuration">
|
||||
|
/// The configuration providing initialization code which allows extending the library.
|
||||
|
/// </param>
|
||||
|
/// <returns>
|
||||
|
/// A new <see cref="Image{TColor}"/> unless <typeparamref name="TColor"/> is <see cref="Color"/> in which case it returns <see cref="Image" />
|
||||
|
/// </returns>
|
||||
|
internal static Image<TColor> Create<TColor>(int width, int height, Configuration configuration) |
||||
|
where TColor : struct, IPixel<TColor> |
||||
|
{ |
||||
|
return Image.Create<TColor>(width, height, null, configuration); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,75 @@ |
|||||
|
// <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.Buffers; |
||||
|
using System.IO; |
||||
|
using System.Linq; |
||||
|
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>
|
||||
|
/// By reading the header on the provided stream this calculates the images format.
|
||||
|
/// </summary>
|
||||
|
/// <param name="stream">The image stream to read the header from.</param>
|
||||
|
/// <param name="config">The configuration.</param>
|
||||
|
/// <returns>The image format or null if none found.</returns>
|
||||
|
private static IImageFormat DiscoverFormat(Stream stream, Configuration config) |
||||
|
{ |
||||
|
// This is probably a candidate for making into a public API in the future!
|
||||
|
int maxHeaderSize = config.MaxHeaderSize; |
||||
|
if (maxHeaderSize <= 0) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
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); |
||||
|
} |
||||
|
|
||||
|
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, config); |
||||
|
if (format == null) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
Image<TColor> img = format.Decoder.Decode<TColor>(config, stream, options); |
||||
|
img.CurrentImageFormat = format; |
||||
|
return img; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,212 @@ |
|||||
|
// <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.IO; |
||||
|
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 byte array.
|
||||
|
/// </summary>
|
||||
|
/// <param name="data">The byte array containing image data.</param>
|
||||
|
/// <exception cref="NotSupportedException">
|
||||
|
/// Thrown if the stream is not readable nor seekable.
|
||||
|
/// </exception>
|
||||
|
/// <returns>The image</returns>
|
||||
|
public static Image Load(byte[] data) |
||||
|
{ |
||||
|
return Load(null, data, null); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Loads the image from the given byte array.
|
||||
|
/// </summary>
|
||||
|
/// <param name="data">The byte array containing image data.</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, IDecoderOptions options) |
||||
|
{ |
||||
|
return Load(null, data, options); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Loads the image from the given byte array.
|
||||
|
/// </summary>
|
||||
|
/// <param name="config">The config for the decoder.</param>
|
||||
|
/// <param name="data">The byte array containing image data.</param>
|
||||
|
/// <exception cref="NotSupportedException">
|
||||
|
/// Thrown if the stream is not readable nor seekable.
|
||||
|
/// </exception>
|
||||
|
/// <returns>The image</returns>
|
||||
|
public static Image Load(Configuration config, byte[] data) |
||||
|
{ |
||||
|
return Load(config, data, null); |
||||
|
} |
||||
|
|
||||
|
/// <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>
|
||||
|
/// <param name="config">The configuration options.</param>
|
||||
|
/// <param name="data">The byte array containing image data.</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(Configuration config, byte[] data, IDecoderOptions options) |
||||
|
{ |
||||
|
using (MemoryStream ms = new MemoryStream(data)) |
||||
|
{ |
||||
|
return Load(config, ms, options); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <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>
|
||||
|
/// <typeparam name="TColor">The pixel format.</typeparam>
|
||||
|
/// <param name="data">The byte array containing image data.</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) |
||||
|
where TColor : struct, IPixel<TColor> |
||||
|
{ |
||||
|
return Load<TColor>(null, data, null); |
||||
|
} |
||||
|
|
||||
|
/// <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="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, IDecoderOptions options) |
||||
|
where TColor : struct, IPixel<TColor> |
||||
|
{ |
||||
|
return Load<TColor>(null, data, options); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Loads the image from the given byte array.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TColor">The pixel format.</typeparam>
|
||||
|
/// <param name="config">The config for the decoder.</param>
|
||||
|
/// <param name="data">The byte array containing image data.</param>
|
||||
|
/// <exception cref="NotSupportedException">
|
||||
|
/// Thrown if the stream is not readable nor seekable.
|
||||
|
/// </exception>
|
||||
|
/// <returns>The image</returns>
|
||||
|
public static Image<TColor> Load<TColor>(Configuration config, byte[] data) |
||||
|
where TColor : struct, IPixel<TColor> |
||||
|
{ |
||||
|
return Load<TColor>(config, data, null); |
||||
|
} |
||||
|
|
||||
|
/// <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>
|
||||
|
/// <typeparam name="TColor">The pixel format.</typeparam>
|
||||
|
/// <param name="config">The configuration options.</param>
|
||||
|
/// <param name="data">The byte array containing image data.</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>(Configuration config, byte[] data, IDecoderOptions options) |
||||
|
where TColor : struct, IPixel<TColor> |
||||
|
{ |
||||
|
using (MemoryStream ms = new MemoryStream(data)) |
||||
|
{ |
||||
|
return Load<TColor>(config, ms, options); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <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); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,214 @@ |
|||||
|
// <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 |
||||
|
{ |
||||
|
#if !NETSTANDARD1_1
|
||||
|
using System; |
||||
|
using System.IO; |
||||
|
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 file.
|
||||
|
/// </summary>
|
||||
|
/// <param name="path">The file path to the image.</param>
|
||||
|
/// <exception cref="NotSupportedException">
|
||||
|
/// Thrown if the stream is not readable nor seekable.
|
||||
|
/// </exception>
|
||||
|
/// <returns>The image</returns>
|
||||
|
public static Image Load(string path) |
||||
|
{ |
||||
|
return Load(null, path, null); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Loads the image from the given file.
|
||||
|
/// </summary>
|
||||
|
/// <param name="path">The file path to the image.</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, IDecoderOptions options) |
||||
|
{ |
||||
|
return Load(null, path, options); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Loads the image from the given file.
|
||||
|
/// </summary>
|
||||
|
/// <param name="config">The config for the decoder.</param>
|
||||
|
/// <param name="path">The file path to the image.</param>
|
||||
|
/// <exception cref="NotSupportedException">
|
||||
|
/// Thrown if the stream is not readable nor seekable.
|
||||
|
/// </exception>
|
||||
|
/// <returns>The image</returns>
|
||||
|
public static Image Load(Configuration config, string path) |
||||
|
{ |
||||
|
return Load(config, path, 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>
|
||||
|
/// <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>
|
||||
|
/// <param name="config">The configuration options.</param>
|
||||
|
/// <param name="path">The file path to the image.</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(Configuration config, string path, IDecoderOptions options) |
||||
|
{ |
||||
|
config = config ?? Configuration.Default; |
||||
|
using (Stream s = config.FileSystem.OpenRead(path)) |
||||
|
{ |
||||
|
return Load(config, s, options); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <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>
|
||||
|
/// <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) |
||||
|
where TColor : struct, IPixel<TColor> |
||||
|
{ |
||||
|
return Load<TColor>(null, path, null); |
||||
|
} |
||||
|
|
||||
|
/// <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="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, IDecoderOptions options) |
||||
|
where TColor : struct, IPixel<TColor> |
||||
|
{ |
||||
|
return Load<TColor>(null, path, options); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Loads the image from the given file.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TColor">The pixel format.</typeparam>
|
||||
|
/// <param name="config">The config for the decoder.</param>
|
||||
|
/// <param name="path">The file path to the image.</param>
|
||||
|
/// <exception cref="NotSupportedException">
|
||||
|
/// Thrown if the stream is not readable nor seekable.
|
||||
|
/// </exception>
|
||||
|
/// <returns>The image</returns>
|
||||
|
public static Image<TColor> Load<TColor>(Configuration config, string path) |
||||
|
where TColor : struct, IPixel<TColor> |
||||
|
{ |
||||
|
return Load<TColor>(config, path, null); |
||||
|
} |
||||
|
|
||||
|
/// <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>
|
||||
|
/// <typeparam name="TColor">The pixel format.</typeparam>
|
||||
|
/// <param name="config">The configuration options.</param>
|
||||
|
/// <param name="path">The file path to the image.</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>(Configuration config, string path, IDecoderOptions options) |
||||
|
where TColor : struct, IPixel<TColor> |
||||
|
{ |
||||
|
config = config ?? Configuration.Default; |
||||
|
using (Stream s = config.FileSystem.OpenRead(path)) |
||||
|
{ |
||||
|
return Load<TColor>(config, s, options); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <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
|
||||
|
} |
||||
@ -0,0 +1,246 @@ |
|||||
|
// <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.IO; |
||||
|
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(null, stream, 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(null, stream, options); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Loads the image from the given stream.
|
||||
|
/// </summary>
|
||||
|
/// <param name="config">The config for the decoder.</param>
|
||||
|
/// <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(Configuration config, Stream stream) |
||||
|
{ |
||||
|
return Load(config, stream, null); |
||||
|
} |
||||
|
|
||||
|
/// <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>
|
||||
|
/// <param name="config">The configuration options.</param>
|
||||
|
/// <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(Configuration config, Stream stream, IDecoderOptions options) |
||||
|
{ |
||||
|
Image<Color> image = Load<Color>(config, stream, options); |
||||
|
|
||||
|
return image as Image ?? new Image(image); |
||||
|
} |
||||
|
|
||||
|
/// <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) |
||||
|
{ |
||||
|
Image<Color> image = new Image(Load<Color>(stream, decoder, options)); |
||||
|
|
||||
|
return image as Image ?? new Image(image); |
||||
|
} |
||||
|
|
||||
|
/// <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>(null, stream, 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>(null, stream, options); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Loads the image from the given stream.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TColor">The pixel format.</typeparam>
|
||||
|
/// <param name="config">The config for the decoder.</param>
|
||||
|
/// <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>(Configuration config, Stream stream) |
||||
|
where TColor : struct, IPixel<TColor> |
||||
|
{ |
||||
|
return Load<TColor>(config, stream, 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>
|
||||
|
/// <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>(Configuration.Default, s, options)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Loads the image from the given stream.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TColor">The pixel format.</typeparam>
|
||||
|
/// <param name="config">The configuration options.</param>
|
||||
|
/// <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>(Configuration config, Stream stream, IDecoderOptions options) |
||||
|
where TColor : struct, IPixel<TColor> |
||||
|
{ |
||||
|
config = config ?? Configuration.Default; |
||||
|
|
||||
|
Image<TColor> img = WithSeekableStream(stream, s => 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) |
||||
|
{ |
||||
|
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."); |
||||
|
} |
||||
|
|
||||
|
if (stream.CanSeek) |
||||
|
{ |
||||
|
return action(stream); |
||||
|
} |
||||
|
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; |
||||
|
|
||||
|
return action(stream); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
# ImageSharp core libraries |
||||
|
|
||||
|
## Coding conventions |
||||
|
|
||||
|
### Argument ordering |
||||
|
|
||||
|
- When passing a `Configuration` object it should be the first argument |
||||
@ -0,0 +1,520 @@ |
|||||
|
// <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(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<Configuration>(), It.IsAny<Stream>(), It.IsAny<IDecoderOptions>())) |
||||
|
|
||||
|
.Callback<Configuration, Stream, IDecoderOptions>((c, 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); |
||||
|
|
||||
|
TestFileSystem.RegisterGloablTestFormat(); |
||||
|
TestFileSystem.Global.AddFile(this.FilePath, 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, Configuration.Default); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
[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, Configuration.Default); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
[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, Configuration.Default); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
[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, Configuration.Default); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void LoadFromStreamWithConfig() |
||||
|
{ |
||||
|
Stream stream = new MemoryStream(); |
||||
|
Image img = Image.Load(this.LocalConfiguration, stream); |
||||
|
|
||||
|
Assert.NotNull(img); |
||||
|
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); |
||||
|
|
||||
|
this.localDecoder.Verify(x => x.Decode<Color>(this.LocalConfiguration, stream, null)); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void LoadFromStreamWithTypeAndConfig() |
||||
|
{ |
||||
|
Stream stream = new MemoryStream(); |
||||
|
Image<Color> img = Image.Load<Color>(this.LocalConfiguration, stream); |
||||
|
|
||||
|
Assert.NotNull(img); |
||||
|
Assert.Equal(this.returnImage, img); |
||||
|
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); |
||||
|
|
||||
|
this.localDecoder.Verify(x => x.Decode<Color>(this.LocalConfiguration, stream, null)); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void LoadFromStreamWithConfigAndOptions() |
||||
|
{ |
||||
|
Stream stream = new MemoryStream(); |
||||
|
Image img = Image.Load(this.LocalConfiguration, stream, this.decoderOptions); |
||||
|
|
||||
|
Assert.NotNull(img); |
||||
|
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); |
||||
|
|
||||
|
this.localDecoder.Verify(x => x.Decode<Color>(this.LocalConfiguration, stream, this.decoderOptions)); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void LoadFromStreamWithTypeAndConfigAndOptions() |
||||
|
{ |
||||
|
Stream stream = new MemoryStream(); |
||||
|
Image<Color> img = Image.Load<Color>(this.LocalConfiguration, stream, this.decoderOptions); |
||||
|
|
||||
|
Assert.NotNull(img); |
||||
|
Assert.Equal(this.returnImage, img); |
||||
|
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); |
||||
|
|
||||
|
this.localDecoder.Verify(x => x.Decode<Color>(this.LocalConfiguration, 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>(Configuration.Default, 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>(Configuration.Default, 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>(Configuration.Default, 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>(Configuration.Default, 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, Configuration.Default); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
[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, Configuration.Default); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
[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, Configuration.Default); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
[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, Configuration.Default); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void LoadFromBytesWithConfig() |
||||
|
{ |
||||
|
Image img = Image.Load(this.LocalConfiguration, this.DataStream.ToArray()); |
||||
|
|
||||
|
Assert.NotNull(img); |
||||
|
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); |
||||
|
|
||||
|
this.localDecoder.Verify(x => x.Decode<Color>(this.LocalConfiguration, It.IsAny<Stream>(), null)); |
||||
|
|
||||
|
Assert.Equal(this.DataStream.ToArray(), this.DecodedData); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void LoadFromBytesWithTypeAndConfig() |
||||
|
{ |
||||
|
Image<Color> img = Image.Load<Color>(this.LocalConfiguration, this.DataStream.ToArray()); |
||||
|
|
||||
|
Assert.NotNull(img); |
||||
|
Assert.Equal(this.returnImage, img); |
||||
|
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); |
||||
|
|
||||
|
|
||||
|
this.localDecoder.Verify(x => x.Decode<Color>(this.LocalConfiguration, It.IsAny<Stream>(), null)); |
||||
|
|
||||
|
Assert.Equal(this.DataStream.ToArray(), this.DecodedData); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void LoadFromBytesWithConfigAndOptions() |
||||
|
{ |
||||
|
Image img = Image.Load(this.LocalConfiguration, this.DataStream.ToArray(), this.decoderOptions); |
||||
|
|
||||
|
Assert.NotNull(img); |
||||
|
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); |
||||
|
|
||||
|
this.localDecoder.Verify(x => x.Decode<Color>(this.LocalConfiguration, It.IsAny<Stream>(), this.decoderOptions)); |
||||
|
|
||||
|
Assert.Equal(this.DataStream.ToArray(), this.DecodedData); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void LoadFromBytesWithTypeAndConfigAndOptions() |
||||
|
{ |
||||
|
Image<Color> img = Image.Load<Color>(this.LocalConfiguration, this.DataStream.ToArray(), this.decoderOptions); |
||||
|
|
||||
|
Assert.NotNull(img); |
||||
|
Assert.Equal(this.returnImage, img); |
||||
|
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); |
||||
|
|
||||
|
this.localDecoder.Verify(x => x.Decode<Color>(this.LocalConfiguration, 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>(Configuration.Default, 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>(Configuration.Default, 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>(Configuration.Default, 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>(Configuration.Default, 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, Configuration.Default); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
[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, Configuration.Default); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
[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, Configuration.Default); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
[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, Configuration.Default); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void LoadFromFileWithConfig() |
||||
|
{ |
||||
|
Image img = Image.Load(this.LocalConfiguration, this.FilePath); |
||||
|
|
||||
|
Assert.NotNull(img); |
||||
|
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); |
||||
|
|
||||
|
this.localDecoder.Verify(x => x.Decode<Color>(this.LocalConfiguration, this.DataStream, null)); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void LoadFromFileWithTypeAndConfig() |
||||
|
{ |
||||
|
Image<Color> img = Image.Load<Color>(this.LocalConfiguration, this.FilePath); |
||||
|
|
||||
|
Assert.NotNull(img); |
||||
|
Assert.Equal(this.returnImage, img); |
||||
|
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); |
||||
|
|
||||
|
this.localDecoder.Verify(x => x.Decode<Color>(this.LocalConfiguration, this.DataStream, null)); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void LoadFromFileWithConfigAndOptions() |
||||
|
{ |
||||
|
Image img = Image.Load(this.LocalConfiguration, this.FilePath, this.decoderOptions); |
||||
|
|
||||
|
Assert.NotNull(img); |
||||
|
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); |
||||
|
|
||||
|
this.localDecoder.Verify(x => x.Decode<Color>(this.LocalConfiguration, this.DataStream, this.decoderOptions)); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void LoadFromFileWithTypeAndConfigAndOptions() |
||||
|
{ |
||||
|
Image<Color> img = Image.Load<Color>(this.LocalConfiguration, this.FilePath, this.decoderOptions); |
||||
|
|
||||
|
Assert.NotNull(img); |
||||
|
Assert.Equal(this.returnImage, img); |
||||
|
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); |
||||
|
|
||||
|
this.localDecoder.Verify(x => x.Decode<Color>(this.LocalConfiguration, 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>(Configuration.Default, 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>(Configuration.Default, 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>(Configuration.Default, 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>(Configuration.Default, this.DataStream, this.decoderOptions)); |
||||
|
} |
||||
|
|
||||
|
public void Dispose() |
||||
|
{ |
||||
|
// clean up the global object;
|
||||
|
this.returnImage?.Dispose(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,71 @@ |
|||||
|
// <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) |
||||
|
{ |
||||
|
// if we have injected a fake file use it instead
|
||||
|
lock (fileSystem) |
||||
|
{ |
||||
|
if (fileSystem.ContainsKey(path)) |
||||
|
{ |
||||
|
Stream stream = fileSystem[path]; |
||||
|
stream.Position = 0; |
||||
|
return stream; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return File.Create(path); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public Stream OpenRead(string path) |
||||
|
{ |
||||
|
// if we have injected a fake file use it instead
|
||||
|
lock (fileSystem) |
||||
|
{ |
||||
|
if (fileSystem.ContainsKey(path)) |
||||
|
{ |
||||
|
Stream stream = fileSystem[path]; |
||||
|
stream.Position = 0; |
||||
|
return stream; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return File.OpenRead(path); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,185 @@ |
|||||
|
// <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, Configuration config) |
||||
|
{ |
||||
|
DecodeOperation[] discovered = this.DecodeCalls.Where(x => x.IsMatch(marker, options, config)).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; |
||||
|
internal Configuration config; |
||||
|
|
||||
|
public bool IsMatch(byte[] testMarker, IDecoderOptions testOptions, Configuration config) |
||||
|
{ |
||||
|
if (this.options != testOptions) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
if (this.config != config) |
||||
|
{ |
||||
|
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>(Configuration config, 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, |
||||
|
config = config |
||||
|
}); |
||||
|
|
||||
|
// 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