Browse Source

Merge pull request #478 from vpenades/master

Refactored Image Formats management into its own class
af/merge-core
James Jackson-South 8 years ago
committed by GitHub
parent
commit
caa816052d
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 171
      src/ImageSharp/Configuration.cs
  2. 6
      src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs
  3. 2
      src/ImageSharp/Formats/Bmp/ImageExtensions.cs
  4. 6
      src/ImageSharp/Formats/Gif/GifConfigurationModule.cs
  5. 2
      src/ImageSharp/Formats/Gif/ImageExtensions.cs
  6. 186
      src/ImageSharp/Formats/ImageFormatManager.cs
  7. 2
      src/ImageSharp/Formats/Jpeg/ImageExtensions.cs
  8. 6
      src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs
  9. 2
      src/ImageSharp/Formats/Png/ImageExtensions.cs
  10. 6
      src/ImageSharp/Formats/Png/PngConfigurationModule.cs
  11. 4
      src/ImageSharp/Image/Image.Decode.cs
  12. 2
      src/ImageSharp/Image/Image.FromStream.cs
  13. 10
      src/ImageSharp/Image/ImageExtensions.cs
  14. 85
      tests/ImageSharp.Tests/ConfigurationTests.cs
  15. 129
      tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs
  16. 2
      tests/ImageSharp.Tests/Image/ImageDiscoverMimeType.cs
  17. 4
      tests/ImageSharp.Tests/Image/ImageLoadTests.cs
  18. 4
      tests/ImageSharp.Tests/Image/ImageSaveTests.cs
  19. 6
      tests/ImageSharp.Tests/TestFormat.cs
  20. 12
      tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs
  21. 2
      tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs

171
src/ImageSharp/Configuration.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
@ -26,26 +26,6 @@ namespace SixLabors.ImageSharp
/// </summary> /// </summary>
private static readonly Lazy<Configuration> Lazy = new Lazy<Configuration>(CreateDefaultInstance); private static readonly Lazy<Configuration> Lazy = new Lazy<Configuration>(CreateDefaultInstance);
/// <summary>
/// The list of supported <see cref="IImageEncoder"/> keyed to mime types.
/// </summary>
private readonly ConcurrentDictionary<IImageFormat, IImageEncoder> mimeTypeEncoders = new ConcurrentDictionary<IImageFormat, IImageEncoder>();
/// <summary>
/// The list of supported <see cref="IImageEncoder"/> keyed to mime types.
/// </summary>
private readonly ConcurrentDictionary<IImageFormat, IImageDecoder> mimeTypeDecoders = new ConcurrentDictionary<IImageFormat, IImageDecoder>();
/// <summary>
/// The list of supported <see cref="IImageFormat"/>s.
/// </summary>
private readonly ConcurrentBag<IImageFormat> imageFormats = new ConcurrentBag<IImageFormat>();
/// <summary>
/// The list of supported <see cref="IImageFormatDetector"/>s.
/// </summary>
private ConcurrentBag<IImageFormatDetector> imageFormatDetectors = new ConcurrentBag<IImageFormatDetector>();
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Configuration" /> class. /// Initializes a new instance of the <see cref="Configuration" /> class.
/// </summary> /// </summary>
@ -76,12 +56,12 @@ namespace SixLabors.ImageSharp
/// <summary> /// <summary>
/// Gets the global parallel options for processing tasks in parallel. /// Gets the global parallel options for processing tasks in parallel.
/// </summary> /// </summary>
public ParallelOptions ParallelOptions { get; } = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }; public ParallelOptions ParallelOptions { get; private set; } = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount };
/// <summary> /// <summary>
/// Gets the currently registered <see cref="IImageFormat"/>s. /// Gets the currently registered <see cref="IImageFormat"/>s.
/// </summary> /// </summary>
public IEnumerable<IImageFormat> ImageFormats => this.imageFormats; public IEnumerable<IImageFormat> ImageFormats => this.ImageFormatsManager.ImageFormats;
/// <summary> /// <summary>
/// Gets or sets the position in a stream to use for reading when using a seekable stream as an image data source. /// Gets or sets the position in a stream to use for reading when using a seekable stream as an image data source.
@ -89,29 +69,19 @@ namespace SixLabors.ImageSharp
public ReadOrigin ReadOrigin { get; set; } = ReadOrigin.Current; public ReadOrigin ReadOrigin { get; set; } = ReadOrigin.Current;
/// <summary> /// <summary>
/// Gets or sets the <see cref="MemoryManager"/> that is currently in use. /// Gets or sets the <see cref="ImageFormatManager"/> that is currently in use.
/// </summary>
public MemoryManager MemoryManager { get; set; } = ArrayPoolMemoryManager.CreateDefault();
/// <summary>
/// Gets the maximum header size of all the formats.
/// </summary>
internal int MaxHeaderSize { get; private set; }
/// <summary>
/// Gets the currently registered <see cref="IImageFormatDetector"/>s.
/// </summary> /// </summary>
internal IEnumerable<IImageFormatDetector> FormatDetectors => this.imageFormatDetectors; public ImageFormatManager ImageFormatsManager { get; set; } = new ImageFormatManager();
/// <summary> /// <summary>
/// Gets the currently registered <see cref="IImageDecoder"/>s. /// Gets or sets the <see cref="MemoryManager"/> that is currently in use.
/// </summary> /// </summary>
internal IEnumerable<KeyValuePair<IImageFormat, IImageDecoder>> ImageDecoders => this.mimeTypeDecoders; public MemoryManager MemoryManager { get; set; } = ArrayPoolMemoryManager.CreateDefault();
/// <summary> /// <summary>
/// Gets the currently registered <see cref="IImageEncoder"/>s. /// Gets the maximum header size of all the formats.
/// </summary> /// </summary>
internal IEnumerable<KeyValuePair<IImageFormat, IImageEncoder>> ImageEncoders => this.mimeTypeEncoders; internal int MaxHeaderSize => this.ImageFormatsManager.MaxHeaderSize;
#if !NETSTANDARD1_1 #if !NETSTANDARD1_1
/// <summary> /// <summary>
@ -136,112 +106,23 @@ namespace SixLabors.ImageSharp
} }
/// <summary> /// <summary>
/// Registers a new format provider. /// Creates a shallow copy of the <see cref="Configuration"/>
/// </summary>
/// <param name="format">The format to register as a known format.</param>
public void AddImageFormat(IImageFormat format)
{
Guard.NotNull(format, nameof(format));
Guard.NotNull(format.MimeTypes, nameof(format.MimeTypes));
Guard.NotNull(format.FileExtensions, nameof(format.FileExtensions));
this.imageFormats.Add(format);
}
/// <summary>
/// For the specified file extensions type find the e <see cref="IImageFormat"/>.
/// </summary>
/// <param name="extension">The extension to discover</param>
/// <returns>The <see cref="IImageFormat"/> if found otherwise null</returns>
public IImageFormat FindFormatByFileExtension(string extension)
{
return this.imageFormats.FirstOrDefault(x => x.FileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase));
}
/// <summary>
/// For the specified mime type find the <see cref="IImageFormat"/>.
/// </summary>
/// <param name="mimeType">The mime-type to discover</param>
/// <returns>The <see cref="IImageFormat"/> if found; otherwise null</returns>
public IImageFormat FindFormatByMimeType(string mimeType)
{
return this.imageFormats.FirstOrDefault(x => x.MimeTypes.Contains(mimeType, StringComparer.OrdinalIgnoreCase));
}
/// <summary>
/// Sets a specific image encoder as the encoder for a specific image format.
/// </summary>
/// <param name="imageFormat">The image format to register the encoder for.</param>
/// <param name="encoder">The encoder to use,</param>
public void SetEncoder(IImageFormat imageFormat, IImageEncoder encoder)
{
Guard.NotNull(imageFormat, nameof(imageFormat));
Guard.NotNull(encoder, nameof(encoder));
this.AddImageFormat(imageFormat);
this.mimeTypeEncoders.AddOrUpdate(imageFormat, encoder, (s, e) => encoder);
}
/// <summary>
/// Sets a specific image decoder as the decoder for a specific image format.
/// </summary>
/// <param name="imageFormat">The image format to register the encoder for.</param>
/// <param name="decoder">The decoder to use,</param>
public void SetDecoder(IImageFormat imageFormat, IImageDecoder decoder)
{
Guard.NotNull(imageFormat, nameof(imageFormat));
Guard.NotNull(decoder, nameof(decoder));
this.AddImageFormat(imageFormat);
this.mimeTypeDecoders.AddOrUpdate(imageFormat, decoder, (s, e) => decoder);
}
/// <summary>
/// Removes all the registered image format detectors.
/// </summary>
public void ClearImageFormatDetectors()
{
this.imageFormatDetectors = new ConcurrentBag<IImageFormatDetector>();
}
/// <summary>
/// Adds a new detector for detecting mime types.
/// </summary>
/// <param name="detector">The detector to add</param>
public void AddImageFormatDetector(IImageFormatDetector detector)
{
Guard.NotNull(detector, nameof(detector));
this.imageFormatDetectors.Add(detector);
this.SetMaxHeaderSize();
}
/// <summary>
/// For the specified mime type find the decoder.
/// </summary> /// </summary>
/// <param name="format">The format to discover</param> /// <returns>A new configuration instance</returns>
/// <returns>The <see cref="IImageDecoder"/> if found otherwise null</returns> public Configuration ShallowCopy()
public IImageDecoder FindDecoder(IImageFormat format)
{ {
Guard.NotNull(format, nameof(format)); return new Configuration
if (this.mimeTypeDecoders.TryGetValue(format, out IImageDecoder decoder))
{ {
return decoder; ParallelOptions = this.ParallelOptions,
} ImageFormatsManager = this.ImageFormatsManager,
MemoryManager = this.MemoryManager,
return null; ImageOperationsProvider = this.ImageOperationsProvider,
} ReadOrigin = this.ReadOrigin,
/// <summary> #if !NETSTANDARD1_1
/// For the specified mime type find the encoder. FileSystem = this.FileSystem
/// </summary> #endif
/// <param name="format">The format to discover</param> };
/// <returns>The <see cref="IImageEncoder"/> if found otherwise null</returns>
public IImageEncoder FindEncoder(IImageFormat format)
{
Guard.NotNull(format, nameof(format));
if (this.mimeTypeEncoders.TryGetValue(format, out IImageEncoder encoder))
{
return encoder;
}
return null;
} }
/// <summary> /// <summary>
@ -260,13 +141,5 @@ namespace SixLabors.ImageSharp
new GifConfigurationModule(), new GifConfigurationModule(),
new BmpConfigurationModule()); new BmpConfigurationModule());
} }
/// <summary>
/// Sets the max header size.
/// </summary>
private void SetMaxHeaderSize()
{
this.MaxHeaderSize = this.imageFormatDetectors.Max(x => x.HeaderSize);
}
} }
} }

6
src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs

@ -11,9 +11,9 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// <inheritdoc/> /// <inheritdoc/>
public void Configure(Configuration config) public void Configure(Configuration config)
{ {
config.SetEncoder(ImageFormats.Bmp, new BmpEncoder()); config.ImageFormatsManager.SetEncoder(ImageFormats.Bmp, new BmpEncoder());
config.SetDecoder(ImageFormats.Bmp, new BmpDecoder()); config.ImageFormatsManager.SetDecoder(ImageFormats.Bmp, new BmpDecoder());
config.AddImageFormatDetector(new BmpImageFormatDetector()); config.ImageFormatsManager.AddImageFormatDetector(new BmpImageFormatDetector());
} }
} }
} }

2
src/ImageSharp/Formats/Bmp/ImageExtensions.cs

@ -36,6 +36,6 @@ namespace SixLabors.ImageSharp
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception> /// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
public static void SaveAsBmp<TPixel>(this Image<TPixel> source, Stream stream, BmpEncoder encoder) public static void SaveAsBmp<TPixel>(this Image<TPixel> source, Stream stream, BmpEncoder encoder)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> source.Save(stream, encoder ?? source.GetConfiguration().FindEncoder(ImageFormats.Bmp)); => source.Save(stream, encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(ImageFormats.Bmp));
} }
} }

6
src/ImageSharp/Formats/Gif/GifConfigurationModule.cs

@ -11,10 +11,10 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <inheritdoc/> /// <inheritdoc/>
public void Configure(Configuration config) public void Configure(Configuration config)
{ {
config.SetEncoder(ImageFormats.Gif, new GifEncoder()); config.ImageFormatsManager.SetEncoder(ImageFormats.Gif, new GifEncoder());
config.SetDecoder(ImageFormats.Gif, new GifDecoder()); config.ImageFormatsManager.SetDecoder(ImageFormats.Gif, new GifDecoder());
config.AddImageFormatDetector(new GifImageFormatDetector()); config.ImageFormatsManager.AddImageFormatDetector(new GifImageFormatDetector());
} }
} }
} }

2
src/ImageSharp/Formats/Gif/ImageExtensions.cs

@ -36,6 +36,6 @@ namespace SixLabors.ImageSharp
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception> /// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
public static void SaveAsGif<TPixel>(this Image<TPixel> source, Stream stream, GifEncoder encoder) public static void SaveAsGif<TPixel>(this Image<TPixel> source, Stream stream, GifEncoder encoder)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> source.Save(stream, encoder ?? source.GetConfiguration().FindEncoder(ImageFormats.Gif)); => source.Save(stream, encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(ImageFormats.Gif));
} }
} }

186
src/ImageSharp/Formats/ImageFormatManager.cs

@ -0,0 +1,186 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SixLabors.ImageSharp.Formats
{
/// <summary>
/// Collection of Image Formats to be used in <see cref="Configuration" /> class.
/// </summary>
public class ImageFormatManager
{
/// <summary>
/// The list of supported <see cref="IImageEncoder"/> keyed to mime types.
/// </summary>
private readonly ConcurrentDictionary<IImageFormat, IImageEncoder> mimeTypeEncoders = new ConcurrentDictionary<IImageFormat, IImageEncoder>();
/// <summary>
/// The list of supported <see cref="IImageEncoder"/> keyed to mime types.
/// </summary>
private readonly ConcurrentDictionary<IImageFormat, IImageDecoder> mimeTypeDecoders = new ConcurrentDictionary<IImageFormat, IImageDecoder>();
/// <summary>
/// The list of supported <see cref="IImageFormat"/>s.
/// </summary>
private readonly ConcurrentBag<IImageFormat> imageFormats = new ConcurrentBag<IImageFormat>();
/// <summary>
/// The list of supported <see cref="IImageFormatDetector"/>s.
/// </summary>
private ConcurrentBag<IImageFormatDetector> imageFormatDetectors = new ConcurrentBag<IImageFormatDetector>();
/// <summary>
/// Initializes a new instance of the <see cref="ImageFormatManager" /> class.
/// </summary>
public ImageFormatManager()
{
}
/// <summary>
/// Gets the maximum header size of all the formats.
/// </summary>
internal int MaxHeaderSize { get; private set; }
/// <summary>
/// Gets the currently registered <see cref="IImageFormat"/>s.
/// </summary>
public IEnumerable<IImageFormat> ImageFormats => this.imageFormats;
/// <summary>
/// Gets the currently registered <see cref="IImageFormatDetector"/>s.
/// </summary>
internal IEnumerable<IImageFormatDetector> FormatDetectors => this.imageFormatDetectors;
/// <summary>
/// Gets the currently registered <see cref="IImageDecoder"/>s.
/// </summary>
internal IEnumerable<KeyValuePair<IImageFormat, IImageDecoder>> ImageDecoders => this.mimeTypeDecoders;
/// <summary>
/// Gets the currently registered <see cref="IImageEncoder"/>s.
/// </summary>
internal IEnumerable<KeyValuePair<IImageFormat, IImageEncoder>> ImageEncoders => this.mimeTypeEncoders;
/// <summary>
/// Registers a new format provider.
/// </summary>
/// <param name="format">The format to register as a known format.</param>
public void AddImageFormat(IImageFormat format)
{
Guard.NotNull(format, nameof(format));
Guard.NotNull(format.MimeTypes, nameof(format.MimeTypes));
Guard.NotNull(format.FileExtensions, nameof(format.FileExtensions));
this.imageFormats.Add(format);
}
/// <summary>
/// For the specified file extensions type find the e <see cref="IImageFormat"/>.
/// </summary>
/// <param name="extension">The extension to discover</param>
/// <returns>The <see cref="IImageFormat"/> if found otherwise null</returns>
public IImageFormat FindFormatByFileExtension(string extension)
{
return this.imageFormats.FirstOrDefault(x => x.FileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase));
}
/// <summary>
/// For the specified mime type find the <see cref="IImageFormat"/>.
/// </summary>
/// <param name="mimeType">The mime-type to discover</param>
/// <returns>The <see cref="IImageFormat"/> if found; otherwise null</returns>
public IImageFormat FindFormatByMimeType(string mimeType)
{
return this.imageFormats.FirstOrDefault(x => x.MimeTypes.Contains(mimeType, StringComparer.OrdinalIgnoreCase));
}
/// <summary>
/// Sets a specific image encoder as the encoder for a specific image format.
/// </summary>
/// <param name="imageFormat">The image format to register the encoder for.</param>
/// <param name="encoder">The encoder to use,</param>
public void SetEncoder(IImageFormat imageFormat, IImageEncoder encoder)
{
Guard.NotNull(imageFormat, nameof(imageFormat));
Guard.NotNull(encoder, nameof(encoder));
this.AddImageFormat(imageFormat);
this.mimeTypeEncoders.AddOrUpdate(imageFormat, encoder, (s, e) => encoder);
}
/// <summary>
/// Sets a specific image decoder as the decoder for a specific image format.
/// </summary>
/// <param name="imageFormat">The image format to register the encoder for.</param>
/// <param name="decoder">The decoder to use,</param>
public void SetDecoder(IImageFormat imageFormat, IImageDecoder decoder)
{
Guard.NotNull(imageFormat, nameof(imageFormat));
Guard.NotNull(decoder, nameof(decoder));
this.AddImageFormat(imageFormat);
this.mimeTypeDecoders.AddOrUpdate(imageFormat, decoder, (s, e) => decoder);
}
/// <summary>
/// Removes all the registered image format detectors.
/// </summary>
public void ClearImageFormatDetectors()
{
this.imageFormatDetectors = new ConcurrentBag<IImageFormatDetector>();
}
/// <summary>
/// Adds a new detector for detecting mime types.
/// </summary>
/// <param name="detector">The detector to add</param>
public void AddImageFormatDetector(IImageFormatDetector detector)
{
Guard.NotNull(detector, nameof(detector));
this.imageFormatDetectors.Add(detector);
this.SetMaxHeaderSize();
}
/// <summary>
/// For the specified mime type find the decoder.
/// </summary>
/// <param name="format">The format to discover</param>
/// <returns>The <see cref="IImageDecoder"/> if found otherwise null</returns>
public IImageDecoder FindDecoder(IImageFormat format)
{
Guard.NotNull(format, nameof(format));
if (this.mimeTypeDecoders.TryGetValue(format, out IImageDecoder decoder))
{
return decoder;
}
return null;
}
/// <summary>
/// For the specified mime type find the encoder.
/// </summary>
/// <param name="format">The format to discover</param>
/// <returns>The <see cref="IImageEncoder"/> if found otherwise null</returns>
public IImageEncoder FindEncoder(IImageFormat format)
{
Guard.NotNull(format, nameof(format));
if (this.mimeTypeEncoders.TryGetValue(format, out IImageEncoder encoder))
{
return encoder;
}
return null;
}
/// <summary>
/// Sets the max header size.
/// </summary>
private void SetMaxHeaderSize()
{
this.MaxHeaderSize = this.imageFormatDetectors.Max(x => x.HeaderSize);
}
}
}

2
src/ImageSharp/Formats/Jpeg/ImageExtensions.cs

@ -36,6 +36,6 @@ namespace SixLabors.ImageSharp
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception> /// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
public static void SaveAsJpeg<TPixel>(this Image<TPixel> source, Stream stream, JpegEncoder encoder) public static void SaveAsJpeg<TPixel>(this Image<TPixel> source, Stream stream, JpegEncoder encoder)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> source.Save(stream, encoder ?? source.GetConfiguration().FindEncoder(ImageFormats.Jpeg)); => source.Save(stream, encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(ImageFormats.Jpeg));
} }
} }

6
src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs

@ -11,10 +11,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// <inheritdoc/> /// <inheritdoc/>
public void Configure(Configuration config) public void Configure(Configuration config)
{ {
config.SetEncoder(ImageFormats.Jpeg, new JpegEncoder()); config.ImageFormatsManager.SetEncoder(ImageFormats.Jpeg, new JpegEncoder());
config.SetDecoder(ImageFormats.Jpeg, new JpegDecoder()); config.ImageFormatsManager.SetDecoder(ImageFormats.Jpeg, new JpegDecoder());
config.AddImageFormatDetector(new JpegImageFormatDetector()); config.ImageFormatsManager.AddImageFormatDetector(new JpegImageFormatDetector());
} }
} }
} }

2
src/ImageSharp/Formats/Png/ImageExtensions.cs

@ -35,6 +35,6 @@ namespace SixLabors.ImageSharp
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception> /// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
public static void SaveAsPng<TPixel>(this Image<TPixel> source, Stream stream, PngEncoder encoder) public static void SaveAsPng<TPixel>(this Image<TPixel> source, Stream stream, PngEncoder encoder)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> source.Save(stream, encoder ?? source.GetConfiguration().FindEncoder(ImageFormats.Png)); => source.Save(stream, encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(ImageFormats.Png));
} }
} }

6
src/ImageSharp/Formats/Png/PngConfigurationModule.cs

@ -11,9 +11,9 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <inheritdoc/> /// <inheritdoc/>
public void Configure(Configuration config) public void Configure(Configuration config)
{ {
config.SetEncoder(ImageFormats.Png, new PngEncoder()); config.ImageFormatsManager.SetEncoder(ImageFormats.Png, new PngEncoder());
config.SetDecoder(ImageFormats.Png, new PngDecoder()); config.ImageFormatsManager.SetDecoder(ImageFormats.Png, new PngDecoder());
config.AddImageFormatDetector(new PngImageFormatDetector()); config.ImageFormatsManager.AddImageFormatDetector(new PngImageFormatDetector());
} }
} }
} }

4
src/ImageSharp/Image/Image.Decode.cs

@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp
long startPosition = stream.Position; long startPosition = stream.Position;
stream.Read(buffer.Array, 0, maxHeaderSize); stream.Read(buffer.Array, 0, maxHeaderSize);
stream.Position = startPosition; stream.Position = startPosition;
return config.FormatDetectors.Select(x => x.DetectFormat(buffer.Span)).LastOrDefault(x => x != null); return config.ImageFormatsManager.FormatDetectors.Select(x => x.DetectFormat(buffer.Span)).LastOrDefault(x => x != null);
} }
} }
@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp
format = InternalDetectFormat(stream, config); format = InternalDetectFormat(stream, config);
if (format != null) if (format != null)
{ {
return config.FindDecoder(format); return config.ImageFormatsManager.FindDecoder(format);
} }
return null; return null;

2
src/ImageSharp/Image/Image.FromStream.cs

@ -186,7 +186,7 @@ namespace SixLabors.ImageSharp
var stringBuilder = new StringBuilder(); var stringBuilder = new StringBuilder();
stringBuilder.AppendLine("Image cannot be loaded. Available decoders:"); stringBuilder.AppendLine("Image cannot be loaded. Available decoders:");
foreach (KeyValuePair<IImageFormat, IImageDecoder> val in config.ImageDecoders) foreach (KeyValuePair<IImageFormat, IImageDecoder> val in config.ImageFormatsManager.ImageDecoders)
{ {
stringBuilder.AppendLine($" - {val.Key.Name} : {val.Value.GetType().Name}"); stringBuilder.AppendLine($" - {val.Key.Name} : {val.Value.GetType().Name}");
} }

10
src/ImageSharp/Image/ImageExtensions.cs

@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp
Guard.NotNullOrEmpty(filePath, nameof(filePath)); Guard.NotNullOrEmpty(filePath, nameof(filePath));
string ext = Path.GetExtension(filePath).Trim('.'); string ext = Path.GetExtension(filePath).Trim('.');
IImageFormat format = source.GetConfiguration().FindFormatByFileExtension(ext); IImageFormat format = source.GetConfiguration().ImageFormatsManager.FindFormatByFileExtension(ext);
if (format == null) if (format == null)
{ {
var stringBuilder = new StringBuilder(); var stringBuilder = new StringBuilder();
@ -45,13 +45,13 @@ namespace SixLabors.ImageSharp
throw new NotSupportedException(stringBuilder.ToString()); throw new NotSupportedException(stringBuilder.ToString());
} }
IImageEncoder encoder = source.GetConfiguration().FindEncoder(format); IImageEncoder encoder = source.GetConfiguration().ImageFormatsManager.FindEncoder(format);
if (encoder == null) if (encoder == null)
{ {
var stringBuilder = new StringBuilder(); var stringBuilder = new StringBuilder();
stringBuilder.AppendLine($"Can't find encoder for file extention '{ext}' using image format '{format.Name}'. Registered encoders include:"); stringBuilder.AppendLine($"Can't find encoder for file extention '{ext}' using image format '{format.Name}'. Registered encoders include:");
foreach (KeyValuePair<IImageFormat, IImageEncoder> enc in source.GetConfiguration().ImageEncoders) foreach (KeyValuePair<IImageFormat, IImageEncoder> enc in source.GetConfiguration().ImageFormatsManager.ImageEncoders)
{ {
stringBuilder.AppendLine($" - {enc.Key} : {enc.Value.GetType().Name}"); stringBuilder.AppendLine($" - {enc.Key} : {enc.Value.GetType().Name}");
} }
@ -93,14 +93,14 @@ namespace SixLabors.ImageSharp
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
Guard.NotNull(format, nameof(format)); Guard.NotNull(format, nameof(format));
IImageEncoder encoder = source.GetConfiguration().FindEncoder(format); IImageEncoder encoder = source.GetConfiguration().ImageFormatsManager.FindEncoder(format);
if (encoder == null) if (encoder == null)
{ {
var stringBuilder = new StringBuilder(); var stringBuilder = new StringBuilder();
stringBuilder.AppendLine("Can't find encoder for provided mime type. Available encoded:"); stringBuilder.AppendLine("Can't find encoder for provided mime type. Available encoded:");
foreach (KeyValuePair<IImageFormat, IImageEncoder> val in source.GetConfiguration().ImageEncoders) foreach (KeyValuePair<IImageFormat, IImageEncoder> val in source.GetConfiguration().ImageFormatsManager.ImageEncoders)
{ {
stringBuilder.AppendLine($" - {val.Key.Name} : {val.Value.GetType().Name}"); stringBuilder.AppendLine($" - {val.Key.Name} : {val.Value.GetType().Name}");
} }

85
tests/ImageSharp.Tests/ConfigurationTests.cs

@ -23,7 +23,9 @@ namespace SixLabors.ImageSharp.Tests
public ConfigurationTests() public ConfigurationTests()
{ {
this.DefaultConfiguration = Configuration.CreateDefaultInstance(); // the shallow copy of configuration should behave exactly like the default configuration,
// so by using the copy, we test both the default and the copy.
this.DefaultConfiguration = Configuration.CreateDefaultInstance().ShallowCopy();
this.ConfigurationEmpty = new Configuration(); this.ConfigurationEmpty = new Configuration();
} }
@ -34,13 +36,6 @@ namespace SixLabors.ImageSharp.Tests
Assert.IsType<LocalFileSystem>(this.ConfigurationEmpty.FileSystem); Assert.IsType<LocalFileSystem>(this.ConfigurationEmpty.FileSystem);
} }
[Fact]
public void IfAutoloadWellknwonFormatesIsTrueAllFormateAreLoaded()
{
Assert.Equal(4, this.DefaultConfiguration.ImageEncoders.Count());
Assert.Equal(4, this.DefaultConfiguration.ImageDecoders.Count());
}
/// <summary> /// <summary>
/// Test that the default configuration is not null. /// Test that the default configuration is not null.
/// </summary> /// </summary>
@ -78,80 +73,6 @@ namespace SixLabors.ImageSharp.Tests
Assert.True(Configuration.Default.ParallelOptions.MaxDegreeOfParallelism == Environment.ProcessorCount); Assert.True(Configuration.Default.ParallelOptions.MaxDegreeOfParallelism == Environment.ProcessorCount);
} }
[Fact]
public void AddImageFormatDetectorNullthrows()
{
Assert.Throws<ArgumentNullException>(() =>
{
this.DefaultConfiguration.AddImageFormatDetector(null);
});
}
[Fact]
public void RegisterNullMimeTypeEncoder()
{
Assert.Throws<ArgumentNullException>(() =>
{
this.DefaultConfiguration.SetEncoder(null, new Mock<IImageEncoder>().Object);
});
Assert.Throws<ArgumentNullException>(() =>
{
this.DefaultConfiguration.SetEncoder(ImageFormats.Bmp, null);
});
Assert.Throws<ArgumentNullException>(() =>
{
this.DefaultConfiguration.SetEncoder(null, null);
});
}
[Fact]
public void RegisterNullSetDecoder()
{
Assert.Throws<ArgumentNullException>(() =>
{
this.DefaultConfiguration.SetDecoder(null, new Mock<IImageDecoder>().Object);
});
Assert.Throws<ArgumentNullException>(() =>
{
this.DefaultConfiguration.SetDecoder(ImageFormats.Bmp, null);
});
Assert.Throws<ArgumentNullException>(() =>
{
this.DefaultConfiguration.SetDecoder(null, null);
});
}
[Fact]
public void RegisterMimeTypeEncoderReplacesLast()
{
IImageEncoder encoder1 = new Mock<IImageEncoder>().Object;
this.ConfigurationEmpty.SetEncoder(TestFormat.GlobalTestFormat, encoder1);
IImageEncoder found = this.ConfigurationEmpty.FindEncoder(TestFormat.GlobalTestFormat);
Assert.Equal(encoder1, found);
IImageEncoder encoder2 = new Mock<IImageEncoder>().Object;
this.ConfigurationEmpty.SetEncoder(TestFormat.GlobalTestFormat, encoder2);
IImageEncoder found2 = this.ConfigurationEmpty.FindEncoder(TestFormat.GlobalTestFormat);
Assert.Equal(encoder2, found2);
Assert.NotEqual(found, found2);
}
[Fact]
public void RegisterMimeTypeDecoderReplacesLast()
{
IImageDecoder decoder1 = new Mock<IImageDecoder>().Object;
this.ConfigurationEmpty.SetDecoder(TestFormat.GlobalTestFormat, decoder1);
IImageDecoder found = this.ConfigurationEmpty.FindDecoder(TestFormat.GlobalTestFormat);
Assert.Equal(decoder1, found);
IImageDecoder decoder2 = new Mock<IImageDecoder>().Object;
this.ConfigurationEmpty.SetDecoder(TestFormat.GlobalTestFormat, decoder2);
IImageDecoder found2 = this.ConfigurationEmpty.FindDecoder(TestFormat.GlobalTestFormat);
Assert.Equal(decoder2, found2);
Assert.NotEqual(found, found2);
}
[Fact] [Fact]
public void ConstructorCallConfigureOnFormatProvider() public void ConstructorCallConfigureOnFormatProvider()
{ {

129
tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs

@ -0,0 +1,129 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Gif;
using Moq;
using Xunit;
namespace SixLabors.ImageSharp.Tests
{
public class ImageFormatManagerTests
{
public ImageFormatManager FormatsManagerEmpty { get; private set; }
public ImageFormatManager DefaultFormatsManager { get; private set; }
public ImageFormatManagerTests()
{
this.DefaultFormatsManager = Configuration.Default.ImageFormatsManager;
this.FormatsManagerEmpty = new ImageFormatManager();
}
[Fact]
public void IfAutoloadWellKnownFormatsIsTrueAllFormatsAreLoaded()
{
Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType<PngEncoder>().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType<BmpEncoder>().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType<JpegEncoder>().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType<GifEncoder>().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType<PngDecoder>().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType<BmpDecoder>().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType<JpegDecoder>().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType<BmpDecoder>().Count());
}
[Fact]
public void AddImageFormatDetectorNullthrows()
{
Assert.Throws<ArgumentNullException>(() =>
{
this.DefaultFormatsManager.AddImageFormatDetector(null);
});
}
[Fact]
public void RegisterNullMimeTypeEncoder()
{
Assert.Throws<ArgumentNullException>(() =>
{
this.DefaultFormatsManager.SetEncoder(null, new Mock<IImageEncoder>().Object);
});
Assert.Throws<ArgumentNullException>(() =>
{
this.DefaultFormatsManager.SetEncoder(ImageFormats.Bmp, null);
});
Assert.Throws<ArgumentNullException>(() =>
{
this.DefaultFormatsManager.SetEncoder(null, null);
});
}
[Fact]
public void RegisterNullSetDecoder()
{
Assert.Throws<ArgumentNullException>(() =>
{
this.DefaultFormatsManager.SetDecoder(null, new Mock<IImageDecoder>().Object);
});
Assert.Throws<ArgumentNullException>(() =>
{
this.DefaultFormatsManager.SetDecoder(ImageFormats.Bmp, null);
});
Assert.Throws<ArgumentNullException>(() =>
{
this.DefaultFormatsManager.SetDecoder(null, null);
});
}
[Fact]
public void RegisterMimeTypeEncoderReplacesLast()
{
IImageEncoder encoder1 = new Mock<IImageEncoder>().Object;
this.FormatsManagerEmpty.SetEncoder(TestFormat.GlobalTestFormat, encoder1);
IImageEncoder found = this.FormatsManagerEmpty.FindEncoder(TestFormat.GlobalTestFormat);
Assert.Equal(encoder1, found);
IImageEncoder encoder2 = new Mock<IImageEncoder>().Object;
this.FormatsManagerEmpty.SetEncoder(TestFormat.GlobalTestFormat, encoder2);
IImageEncoder found2 = this.FormatsManagerEmpty.FindEncoder(TestFormat.GlobalTestFormat);
Assert.Equal(encoder2, found2);
Assert.NotEqual(found, found2);
}
[Fact]
public void RegisterMimeTypeDecoderReplacesLast()
{
IImageDecoder decoder1 = new Mock<IImageDecoder>().Object;
this.FormatsManagerEmpty.SetDecoder(TestFormat.GlobalTestFormat, decoder1);
IImageDecoder found = this.FormatsManagerEmpty.FindDecoder(TestFormat.GlobalTestFormat);
Assert.Equal(decoder1, found);
IImageDecoder decoder2 = new Mock<IImageDecoder>().Object;
this.FormatsManagerEmpty.SetDecoder(TestFormat.GlobalTestFormat, decoder2);
IImageDecoder found2 = this.FormatsManagerEmpty.FindDecoder(TestFormat.GlobalTestFormat);
Assert.Equal(decoder2, found2);
Assert.NotEqual(found, found2);
}
[Fact]
public void AddFormatCallsConfig()
{
var provider = new Mock<IConfigurationModule>();
var config = new Configuration();
config.Configure(provider.Object);
provider.Verify(x => x.Configure(config));
}
}
}

2
tests/ImageSharp.Tests/Image/ImageDiscoverMimeType.cs

@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.Tests
FileSystem = this.fileSystem.Object FileSystem = this.fileSystem.Object
}; };
this.LocalConfiguration.AddImageFormatDetector(this.localMimeTypeDetector); this.LocalConfiguration.ImageFormatsManager.AddImageFormatDetector(this.localMimeTypeDetector);
TestFormat.RegisterGlobalTestFormat(); TestFormat.RegisterGlobalTestFormat();
this.Marker = Guid.NewGuid().ToByteArray(); this.Marker = Guid.NewGuid().ToByteArray();

4
tests/ImageSharp.Tests/Image/ImageLoadTests.cs

@ -54,8 +54,8 @@ namespace SixLabors.ImageSharp.Tests
{ {
FileSystem = this.fileSystem.Object FileSystem = this.fileSystem.Object
}; };
this.LocalConfiguration.AddImageFormatDetector(this.localMimeTypeDetector); this.LocalConfiguration.ImageFormatsManager.AddImageFormatDetector(this.localMimeTypeDetector);
this.LocalConfiguration.SetDecoder(this.localImageFormatMock.Object, this.localDecoder.Object); this.LocalConfiguration.ImageFormatsManager.SetDecoder(this.localImageFormatMock.Object, this.localDecoder.Object);
TestFormat.RegisterGlobalTestFormat(); TestFormat.RegisterGlobalTestFormat();
this.Marker = Guid.NewGuid().ToByteArray(); this.Marker = Guid.NewGuid().ToByteArray();

4
tests/ImageSharp.Tests/Image/ImageSaveTests.cs

@ -42,8 +42,8 @@ namespace SixLabors.ImageSharp.Tests
{ {
FileSystem = this.fileSystem.Object FileSystem = this.fileSystem.Object
}; };
config.AddImageFormatDetector(this.localMimeTypeDetector); config.ImageFormatsManager.AddImageFormatDetector(this.localMimeTypeDetector);
config.SetEncoder(this.localImageFormat.Object, this.encoder.Object); config.ImageFormatsManager.SetEncoder(this.localImageFormat.Object, this.encoder.Object);
this.Image = new Image<Rgba32>(config, 1, 1); this.Image = new Image<Rgba32>(config, 1, 1);
} }

6
tests/ImageSharp.Tests/TestFormat.cs

@ -116,9 +116,9 @@ namespace SixLabors.ImageSharp.Tests
public void Configure(Configuration host) public void Configure(Configuration host)
{ {
host.AddImageFormatDetector(new TestHeader(this)); host.ImageFormatsManager.AddImageFormatDetector(new TestHeader(this));
host.SetEncoder(this, new TestEncoder(this)); host.ImageFormatsManager.SetEncoder(this, new TestEncoder(this));
host.SetDecoder(this, new TestDecoder(this)); host.ImageFormatsManager.SetDecoder(this, new TestDecoder(this));
} }
public struct DecodeOperation public struct DecodeOperation

12
tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs

@ -21,20 +21,20 @@ namespace SixLabors.ImageSharp.Tests
internal static IImageDecoder GetReferenceDecoder(string filePath) internal static IImageDecoder GetReferenceDecoder(string filePath)
{ {
IImageFormat format = GetImageFormat(filePath); IImageFormat format = GetImageFormat(filePath);
return Configuration.FindDecoder(format); return Configuration.ImageFormatsManager.FindDecoder(format);
} }
internal static IImageEncoder GetReferenceEncoder(string filePath) internal static IImageEncoder GetReferenceEncoder(string filePath)
{ {
IImageFormat format = GetImageFormat(filePath); IImageFormat format = GetImageFormat(filePath);
return Configuration.FindEncoder(format); return Configuration.ImageFormatsManager.FindEncoder(format);
} }
internal static IImageFormat GetImageFormat(string filePath) internal static IImageFormat GetImageFormat(string filePath)
{ {
string extension = Path.GetExtension(filePath).ToLower(); string extension = Path.GetExtension(filePath).ToLower();
if (extension[0] == '.') extension = extension.Substring(1); if (extension[0] == '.') extension = extension.Substring(1);
IImageFormat format = Configuration.FindFormatByFileExtension(extension); IImageFormat format = Configuration.ImageFormatsManager.FindFormatByFileExtension(extension);
return format; return format;
} }
@ -45,9 +45,9 @@ namespace SixLabors.ImageSharp.Tests
IImageEncoder encoder, IImageEncoder encoder,
IImageFormatDetector detector) IImageFormatDetector detector)
{ {
cfg.SetDecoder(imageFormat, decoder); cfg.ImageFormatsManager.SetDecoder(imageFormat, decoder);
cfg.SetEncoder(imageFormat, encoder); cfg.ImageFormatsManager.SetEncoder(imageFormat, encoder);
cfg.AddImageFormatDetector(detector); cfg.ImageFormatsManager.AddImageFormatDetector(detector);
} }
private static Configuration CreateDefaultConfiguration() private static Configuration CreateDefaultConfiguration()

2
tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs

@ -360,7 +360,7 @@ namespace SixLabors.ImageSharp.Tests
IImageDecoder referenceDecoder = TestEnvironment.GetReferenceDecoder(path); IImageDecoder referenceDecoder = TestEnvironment.GetReferenceDecoder(path);
IImageFormat format = TestEnvironment.GetImageFormat(path); IImageFormat format = TestEnvironment.GetImageFormat(path);
IImageDecoder defaultDecoder = Configuration.Default.FindDecoder(format); IImageDecoder defaultDecoder = Configuration.Default.ImageFormatsManager.FindDecoder(format);
//if (referenceDecoder.GetType() == defaultDecoder.GetType()) //if (referenceDecoder.GetType() == defaultDecoder.GetType())
//{ //{

Loading…
Cancel
Save