diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs
index 5734d70fb..43613867e 100644
--- a/src/ImageSharp/Configuration.cs
+++ b/src/ImageSharp/Configuration.cs
@@ -6,6 +6,7 @@
namespace ImageSharp
{
using System;
+ using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
@@ -17,7 +18,7 @@ namespace ImageSharp
///
/// Provides initialization code which allows extending the library.
///
- public class Configuration
+ public class Configuration : IImageFormatHost
{
///
/// A lazily initialized configuration default instance.
@@ -30,14 +31,24 @@ namespace ImageSharp
private readonly object syncRoot = new object();
///
- /// The list of supported .
+ /// The list of supported keyed to mimestypes.
///
- private readonly List encoders = new List();
+ private readonly ConcurrentDictionary mimeTypeEncoders = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase);
///
- /// The list of supported .
+ /// The list of supported keyed to fiel extensions.
///
- private readonly List decoders = new List();
+ private readonly ConcurrentDictionary extensionsEncoders = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase);
+
+ ///
+ /// The list of supported keyed to mimestypes.
+ ///
+ private readonly ConcurrentDictionary mimeTypeDecoders = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase);
+
+ ///
+ /// The list of supported s.
+ ///
+ private readonly List mimeTypeDetectors = new List();
///
/// Initializes a new instance of the class.
@@ -46,30 +57,55 @@ namespace ImageSharp
{
}
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// A collection of providers to configure
+ public Configuration(params IImageFormatProvider[] providers)
+ {
+ if (providers != null)
+ {
+ foreach (IImageFormatProvider p in providers)
+ {
+ p.Configure(this);
+ }
+ }
+ }
+
///
/// Gets the default instance.
///
public static Configuration Default { get; } = Lazy.Value;
///
- /// Gets the collection of supported
+ /// Gets the global parallel options for processing tasks in parallel.
///
- public IReadOnlyCollection ImageEncoders => new ReadOnlyCollection(this.encoders);
+ public ParallelOptions ParallelOptions { get; } = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount };
///
- /// Gets the collection of supported
+ /// Gets the maximum header size of all formats.
///
- public IReadOnlyCollection ImageDecoders => new ReadOnlyCollection(this.decoders);
+ internal int MaxHeaderSize { get; private set; }
///
- /// Gets the global parallel options for processing tasks in parallel.
+ /// Gets the currently registerd s.
///
- public ParallelOptions ParallelOptions { get; } = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount };
+ internal IEnumerable MimeTypeDetectors => this.mimeTypeDetectors;
///
- /// Gets the maximum header size of all formats.
+ /// Gets the typeof of all the current image decoders
///
- internal int MaxHeaderSize { get; private set; }
+ internal IEnumerable AllMimeImageDecoders => this.mimeTypeDecoders.Select(x => x.Value.GetType()).Distinct().ToList();
+
+ ///
+ /// Gets the typeof of all the current image decoders
+ ///
+ internal IEnumerable AllMimeImageEncoders => this.mimeTypeEncoders.Select(x => x.Value.GetType()).Distinct().ToList();
+
+ ///
+ /// Gets the typeof of all the current image decoders
+ ///
+ internal IEnumerable AllExtImageEncoders => this.mimeTypeEncoders.Select(x => x.Value.GetType()).Distinct().ToList();
#if !NETSTANDARD1_1
///
@@ -79,36 +115,102 @@ namespace ImageSharp
#endif
///
- /// Adds a new to the collection of supported image formats.
+ /// Registers a new format provider.
///
- /// The new format to add.
- public void AddImageFormat(IImageDecoder decoder)
+ /// The format providers to call configure on.
+ public void AddImageFormat(IImageFormatProvider formatProvider)
+ {
+ Guard.NotNull(formatProvider, nameof(formatProvider));
+ formatProvider.Configure(this);
+ }
+
+ ///
+ public void SetMimeTypeEncoder(string mimeType, IImageEncoder encoder)
{
+ Guard.NotNullOrEmpty(mimeType, nameof(mimeType));
+ Guard.NotNull(encoder, nameof(encoder));
+ this.mimeTypeEncoders.AddOrUpdate(mimeType?.Trim(), encoder, (s, e) => encoder);
+ }
+
+ ///
+ public void SetFileExtensionEncoder(string extension, IImageEncoder encoder)
+ {
+ Guard.NotNullOrEmpty(extension, nameof(extension));
+ Guard.NotNull(encoder, nameof(encoder));
+ this.extensionsEncoders.AddOrUpdate(extension?.Trim(), encoder, (s, e) => encoder);
+ }
+
+ ///
+ public void SetMimeTypeDecoder(string mimeType, IImageDecoder decoder)
+ {
+ Guard.NotNullOrEmpty(mimeType, nameof(mimeType));
Guard.NotNull(decoder, nameof(decoder));
- Guard.NotNullOrEmpty(decoder.FileExtensions, nameof(decoder.FileExtensions));
- Guard.NotNullOrEmpty(decoder.MimeTypes, nameof(decoder.MimeTypes));
+ this.mimeTypeDecoders.AddOrUpdate(mimeType, decoder, (s, e) => decoder);
+ }
+
+ ///
+ /// Removes all the registerd detectors
+ ///
+ public void ClearMimeTypeDetector()
+ {
+ this.mimeTypeDetectors.Clear();
+ }
+
+ ///
+ public void AddMimeTypeDetector(IMimeTypeDetector detector)
+ {
+ Guard.NotNull(detector, nameof(detector));
+ this.mimeTypeDetectors.Add(detector);
+ this.SetMaxHeaderSize();
+ }
- lock (this.syncRoot)
+ ///
+ /// For the specified mimetype find the decoder.
+ ///
+ /// the mimetype to discover
+ /// the IImageDecoder if found othersize null
+ public IImageDecoder FindMimeTypeDecoder(string mimeType)
+ {
+ Guard.NotNullOrEmpty(mimeType, nameof(mimeType));
+ if (this.mimeTypeDecoders.TryGetValue(mimeType, out IImageDecoder dec))
{
- this.decoders.Add(decoder);
+ return dec;
+ }
+
+ return null;
+ }
- this.SetMaxHeaderSize();
+ ///
+ /// For the specified mimetype find the encoder.
+ ///
+ /// the mimetype to discover
+ /// the IImageEncoder if found othersize null
+ public IImageEncoder FindMimeTypeEncoder(string mimeType)
+ {
+ Guard.NotNullOrEmpty(mimeType, nameof(mimeType));
+ if (this.mimeTypeEncoders.TryGetValue(mimeType, out IImageEncoder dec))
+ {
+ return dec;
}
+
+ return null;
}
///
- /// Adds a new to the collection of supported image formats.
+ /// For the specified mimetype find the encoder.
///
- /// The new format to add.
- public void AddImageFormat(IImageEncoder encoder)
+ /// the extensions to discover
+ /// the IImageEncoder if found othersize null
+ public IImageEncoder FindFileExtensionsEncoder(string extensions)
{
- Guard.NotNull(encoder, nameof(encoder));
- Guard.NotNullOrEmpty(encoder.FileExtensions, nameof(encoder.FileExtensions));
- Guard.NotNullOrEmpty(encoder.MimeTypes, nameof(encoder.MimeTypes));
- lock (this.syncRoot)
+ extensions = extensions?.TrimStart('.');
+ Guard.NotNullOrEmpty(extensions, nameof(extensions));
+ if (this.extensionsEncoders.TryGetValue(extensions, out IImageEncoder dec))
{
- this.encoders.Add(encoder);
+ return dec;
}
+
+ return null;
}
///
@@ -117,19 +219,11 @@ namespace ImageSharp
/// The default configuration of
internal static Configuration CreateDefaultInstance()
{
- Configuration config = new Configuration();
-
- // lets try auto loading the known image formats
- config.AddImageFormat(new Formats.PngEncoder());
- config.AddImageFormat(new Formats.JpegEncoder());
- config.AddImageFormat(new Formats.GifEncoder());
- config.AddImageFormat(new Formats.BmpEncoder());
-
- config.AddImageFormat(new Formats.PngDecoder());
- config.AddImageFormat(new Formats.JpegDecoder());
- config.AddImageFormat(new Formats.GifDecoder());
- config.AddImageFormat(new Formats.BmpDecoder());
- return config;
+ return new Configuration(
+ new PngImageFormatProvider(),
+ new JpegImageFormatProvider(),
+ new GifImageFormatProvider(),
+ new BmpImageFormatProvider());
}
///
@@ -137,7 +231,7 @@ namespace ImageSharp
///
private void SetMaxHeaderSize()
{
- this.MaxHeaderSize = this.decoders.Max(x => x.HeaderSize);
+ this.MaxHeaderSize = this.mimeTypeDetectors.Max(x => x.HeaderSize);
}
}
}
diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs
index 9ff331490..e1dc489f4 100644
--- a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs
@@ -28,23 +28,6 @@ namespace ImageSharp.Formats
///
public class BmpDecoder : IImageDecoder
{
- ///
- public IEnumerable MimeTypes => BmpConstants.MimeTypes;
-
- ///
- public IEnumerable FileExtensions => BmpConstants.FileExtensions;
-
- ///
- public int HeaderSize => 2;
-
- ///
- public bool IsSupportedFileFormat(Span header)
- {
- return header.Length >= this.HeaderSize &&
- header[0] == 0x42 && // B
- header[1] == 0x4D; // M
- }
-
///
public Image Decode(Configuration configuration, Stream stream)
diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoder.cs b/src/ImageSharp/Formats/Bmp/BmpEncoder.cs
index 25db0eda0..f47bedb81 100644
--- a/src/ImageSharp/Formats/Bmp/BmpEncoder.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpEncoder.cs
@@ -22,12 +22,6 @@ namespace ImageSharp.Formats
///
public BmpBitsPerPixel BitsPerPixel { get; set; } = BmpBitsPerPixel.Pixel24;
- ///
- public IEnumerable MimeTypes => BmpConstants.MimeTypes;
-
- ///
- public IEnumerable FileExtensions => BmpConstants.FileExtensions;
-
///
public void Encode(Image image, Stream stream)
where TPixel : struct, IPixel
diff --git a/src/ImageSharp/Formats/Bmp/BmpImageFormatProvider.cs b/src/ImageSharp/Formats/Bmp/BmpImageFormatProvider.cs
new file mode 100644
index 000000000..145e1fdb6
--- /dev/null
+++ b/src/ImageSharp/Formats/Bmp/BmpImageFormatProvider.cs
@@ -0,0 +1,42 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Formats
+{
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Text;
+ using ImageSharp.PixelFormats;
+
+ ///
+ /// Detects gif file headers
+ ///
+ public class BmpImageFormatProvider : IImageFormatProvider
+ {
+ ///
+ public void Configure(IImageFormatHost host)
+ {
+ var encoder = new BmpEncoder();
+ foreach (string mimeType in BmpConstants.MimeTypes)
+ {
+ host.SetMimeTypeEncoder(mimeType, encoder);
+ }
+
+ foreach (string mimeType in BmpConstants.FileExtensions)
+ {
+ host.SetFileExtensionEncoder(mimeType, encoder);
+ }
+
+ var decoder = new BmpDecoder();
+ foreach (string mimeType in BmpConstants.MimeTypes)
+ {
+ host.SetMimeTypeDecoder(mimeType, decoder);
+ }
+
+ host.AddMimeTypeDetector(new BmpMimeTypeDetector());
+ }
+ }
+}
diff --git a/src/ImageSharp/Formats/Bmp/BmpMimeTypeDetector.cs b/src/ImageSharp/Formats/Bmp/BmpMimeTypeDetector.cs
new file mode 100644
index 000000000..c13181d6a
--- /dev/null
+++ b/src/ImageSharp/Formats/Bmp/BmpMimeTypeDetector.cs
@@ -0,0 +1,40 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Formats
+{
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Text;
+ using ImageSharp.PixelFormats;
+
+ ///
+ /// Detects bmp file headers
+ ///
+ internal class BmpMimeTypeDetector : IMimeTypeDetector
+ {
+ ///
+ public int HeaderSize => 2;
+
+ ///
+ public string DetectMimeType(Span header)
+ {
+ if (this.IsSupportedFileFormat(header))
+ {
+ return "image/bmp";
+ }
+
+ return null;
+ }
+
+ private bool IsSupportedFileFormat(Span header)
+ {
+ return header.Length >= this.HeaderSize &&
+ header[0] == 0x42 && // B
+ header[1] == 0x4D; // M
+ }
+ }
+}
diff --git a/src/ImageSharp/Formats/Gif/GifDecoder.cs b/src/ImageSharp/Formats/Gif/GifDecoder.cs
index 506b37dc8..c922767b8 100644
--- a/src/ImageSharp/Formats/Gif/GifDecoder.cs
+++ b/src/ImageSharp/Formats/Gif/GifDecoder.cs
@@ -16,12 +16,6 @@ namespace ImageSharp.Formats
///
public class GifDecoder : IImageDecoder
{
- ///
- public IEnumerable MimeTypes => GifConstants.MimeTypes;
-
- ///
- public IEnumerable FileExtensions => GifConstants.FileExtensions;
-
///
/// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded.
///
@@ -32,21 +26,6 @@ namespace ImageSharp.Formats
///
public Encoding TextEncoding { get; set; } = GifConstants.DefaultEncoding;
- ///
- public int HeaderSize => 6;
-
- ///
- public bool IsSupportedFileFormat(Span header)
- {
- return header.Length >= this.HeaderSize &&
- header[0] == 0x47 && // G
- header[1] == 0x49 && // I
- header[2] == 0x46 && // F
- header[3] == 0x38 && // 8
- (header[4] == 0x39 || header[4] == 0x37) && // 9 or 7
- header[5] == 0x61; // a
- }
-
///
public Image Decode(Configuration configuration, Stream stream)
where TPixel : struct, IPixel
diff --git a/src/ImageSharp/Formats/Gif/GifEncoder.cs b/src/ImageSharp/Formats/Gif/GifEncoder.cs
index f7dba9266..3ded88429 100644
--- a/src/ImageSharp/Formats/Gif/GifEncoder.cs
+++ b/src/ImageSharp/Formats/Gif/GifEncoder.cs
@@ -17,12 +17,6 @@ namespace ImageSharp.Formats
///
public class GifEncoder : IImageEncoder
{
- ///
- public IEnumerable MimeTypes => GifConstants.MimeTypes;
-
- ///
- public IEnumerable FileExtensions => GifConstants.FileExtensions;
-
///
/// Gets or sets a value indicating whether the metadata should be ignored when the image is being encoded.
///
diff --git a/src/ImageSharp/Formats/Gif/GifImageFormatProvider.cs b/src/ImageSharp/Formats/Gif/GifImageFormatProvider.cs
new file mode 100644
index 000000000..7e521353f
--- /dev/null
+++ b/src/ImageSharp/Formats/Gif/GifImageFormatProvider.cs
@@ -0,0 +1,42 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Formats
+{
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Text;
+ using ImageSharp.PixelFormats;
+
+ ///
+ /// Detects gif file headers
+ ///
+ public class GifImageFormatProvider : IImageFormatProvider
+ {
+ ///
+ public void Configure(IImageFormatHost host)
+ {
+ var encoder = new GifEncoder();
+ foreach (string mimeType in GifConstants.MimeTypes)
+ {
+ host.SetMimeTypeEncoder(mimeType, encoder);
+ }
+
+ foreach (string mimeType in GifConstants.FileExtensions)
+ {
+ host.SetFileExtensionEncoder(mimeType, encoder);
+ }
+
+ var decoder = new GifDecoder();
+ foreach (string mimeType in GifConstants.MimeTypes)
+ {
+ host.SetMimeTypeDecoder(mimeType, decoder);
+ }
+
+ host.AddMimeTypeDetector(new GifMimeTypeDetector());
+ }
+ }
+}
diff --git a/src/ImageSharp/Formats/Gif/GifMimeTypeDetector.cs b/src/ImageSharp/Formats/Gif/GifMimeTypeDetector.cs
new file mode 100644
index 000000000..f4ad8fa8e
--- /dev/null
+++ b/src/ImageSharp/Formats/Gif/GifMimeTypeDetector.cs
@@ -0,0 +1,44 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Formats
+{
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Text;
+ using ImageSharp.PixelFormats;
+
+ ///
+ /// Detects gif file headers
+ ///
+ public class GifMimeTypeDetector : IMimeTypeDetector
+ {
+ ///
+ public int HeaderSize => 6;
+
+ ///
+ public string DetectMimeType(Span header)
+ {
+ if (this.IsSupportedFileFormat(header))
+ {
+ return "image/gif";
+ }
+
+ return null;
+ }
+
+ private bool IsSupportedFileFormat(Span header)
+ {
+ return header.Length >= this.HeaderSize &&
+ header[0] == 0x47 && // G
+ header[1] == 0x49 && // I
+ header[2] == 0x46 && // F
+ header[3] == 0x38 && // 8
+ (header[4] == 0x39 || header[4] == 0x37) && // 9 or 7
+ header[5] == 0x61; // a
+ }
+ }
+}
diff --git a/src/ImageSharp/Formats/IImageDecoder.cs b/src/ImageSharp/Formats/IImageDecoder.cs
index ff655d718..66eabb1b8 100644
--- a/src/ImageSharp/Formats/IImageDecoder.cs
+++ b/src/ImageSharp/Formats/IImageDecoder.cs
@@ -16,32 +16,6 @@ namespace ImageSharp.Formats
///
public interface IImageDecoder
{
- ///
- /// Gets the collection of mime types that this decoder supports decoding on.
- ///
- IEnumerable MimeTypes { get; }
-
- ///
- /// Gets the collection of file extensionsthis decoder supports decoding.
- ///
- IEnumerable FileExtensions { get; }
-
- ///
- /// Gets the size of the header for this image type.
- ///
- /// The size of the header.
- int HeaderSize { get; }
-
- ///
- /// Returns a value indicating whether the supports the specified
- /// file header.
- ///
- /// The containing the file header.
- ///
- /// True if the decoder supports the file header; otherwise, false.
- ///
- bool IsSupportedFileFormat(Span header);
-
///
/// Decodes the image from the specified stream to the .
///
diff --git a/src/ImageSharp/Formats/IImageEncoder.cs b/src/ImageSharp/Formats/IImageEncoder.cs
index 465f8eec5..4ad41ebc2 100644
--- a/src/ImageSharp/Formats/IImageEncoder.cs
+++ b/src/ImageSharp/Formats/IImageEncoder.cs
@@ -16,16 +16,6 @@ namespace ImageSharp.Formats
///
public interface IImageEncoder
{
- ///
- /// Gets the collection of mime types that this decoder supports encoding for.
- ///
- IEnumerable MimeTypes { get; }
-
- ///
- /// Gets the collection of file extensionsthis decoder supports encoding for.
- ///
- IEnumerable FileExtensions { get; }
-
///
/// Encodes the image to the specified stream from the .
///
diff --git a/src/ImageSharp/Formats/IImageFormatProvider.cs b/src/ImageSharp/Formats/IImageFormatProvider.cs
new file mode 100644
index 000000000..c7d354ec6
--- /dev/null
+++ b/src/ImageSharp/Formats/IImageFormatProvider.cs
@@ -0,0 +1,56 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Formats
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Text;
+
+ ///
+ /// Represents an abstract class that can register image encoders, decoders and mime type detectors
+ ///
+ public interface IImageFormatProvider
+ {
+ ///
+ /// Called when loaded so the provider and register its encoders, decodes and mime type detectors into an IImageFormatHost.
+ ///
+ /// The host that will retain the encoders, decodes and mime type detectors.
+ void Configure(IImageFormatHost host);
+ }
+
+ ///
+ /// Represents an abstract class that can have encoders decoders and mimetype detecotrs loaded into.
+ ///
+ public interface IImageFormatHost
+ {
+ ///
+ /// Sets a specific image encoder as the encoder for a specific mimetype
+ ///
+ /// the target mimetype
+ /// the encoder to use
+ void SetMimeTypeEncoder(string mimeType, IImageEncoder encoder); // could/should this be an Action???
+
+ ///
+ /// Sets a specific image encoder as the encoder for a specific mimetype
+ ///
+ /// the target mimetype
+ /// the encoder to use
+ void SetFileExtensionEncoder(string extension, IImageEncoder encoder);
+
+ ///
+ /// Sets a specific image decoder as the decoder for a specific mimetype
+ ///
+ /// the target mimetype
+ /// the decoder to use
+ void SetMimeTypeDecoder(string mimeType, IImageDecoder decoder);
+
+ ///
+ /// Adds a new detector for detecting in mime types
+ ///
+ /// The detector
+ void AddMimeTypeDetector(IMimeTypeDetector detector);
+ }
+}
diff --git a/src/ImageSharp/Formats/IMimeTypeDetector.cs b/src/ImageSharp/Formats/IMimeTypeDetector.cs
new file mode 100644
index 000000000..f55be7151
--- /dev/null
+++ b/src/ImageSharp/Formats/IMimeTypeDetector.cs
@@ -0,0 +1,30 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Formats
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Text;
+
+ ///
+ /// Used for detecting mime types from a file header
+ ///
+ public interface IMimeTypeDetector
+ {
+ ///
+ /// Gets the size of the header for this image type.
+ ///
+ /// The size of the header.
+ int HeaderSize { get; }
+
+ ///
+ /// Detect mimetype
+ ///
+ /// The containing the file header.
+ /// returns the mime type of detected othersie returns null
+ string DetectMimeType(Span header);
+ }
+}
diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs
index 09575a12e..b809908e9 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs
@@ -21,22 +21,6 @@ namespace ImageSharp.Formats
///
public bool IgnoreMetadata { get; set; }
- ///
- public IEnumerable MimeTypes => JpegConstants.MimeTypes;
-
- ///
- public IEnumerable FileExtensions => JpegConstants.FileExtensions;
-
- ///
- public int HeaderSize => 11;
-
- ///
- public bool IsSupportedFileFormat(Span header)
- {
- return header.Length >= this.HeaderSize &&
- (IsJfif(header) || IsExif(header) || IsJpeg(header));
- }
-
///
public Image Decode(Configuration configuration, Stream stream)
where TPixel : struct, IPixel
@@ -49,54 +33,5 @@ namespace ImageSharp.Formats
return decoder.Decode(stream);
}
}
-
- ///
- /// Returns a value indicating whether the given bytes identify Jfif data.
- ///
- /// The bytes representing the file header.
- /// The
- private static bool IsJfif(Span header)
- {
- bool isJfif =
- header[6] == 0x4A && // J
- header[7] == 0x46 && // F
- header[8] == 0x49 && // I
- header[9] == 0x46 && // F
- header[10] == 0x00;
-
- return isJfif;
- }
-
- ///
- /// Returns a value indicating whether the given bytes identify EXIF data.
- ///
- /// The bytes representing the file header.
- /// The
- private static bool IsExif(Span header)
- {
- bool isExif =
- header[6] == 0x45 && // E
- header[7] == 0x78 && // X
- header[8] == 0x69 && // I
- header[9] == 0x66 && // F
- header[10] == 0x00;
-
- return isExif;
- }
-
- ///
- /// Returns a value indicating whether the given bytes identify Jpeg data.
- /// This is a last chance resort for jpegs that contain ICC information.
- ///
- /// The bytes representing the file header.
- /// The
- private static bool IsJpeg(Span header)
- {
- bool isJpg =
- header[0] == 0xFF && // 255
- header[1] == 0xD8; // 216
-
- return isJpg;
- }
}
}
diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs
index f76df0585..d0be9eaf8 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs
@@ -34,12 +34,6 @@ namespace ImageSharp.Formats
/// The subsample ratio of the jpg image.
public JpegSubsample? Subsample { get; set; }
- ///
- public IEnumerable MimeTypes => JpegConstants.MimeTypes;
-
- ///
- public IEnumerable FileExtensions => JpegConstants.FileExtensions;
-
///
/// Encodes the image to the specified stream from the .
///
diff --git a/src/ImageSharp/Formats/Jpeg/JpegImageFormatProvider.cs b/src/ImageSharp/Formats/Jpeg/JpegImageFormatProvider.cs
new file mode 100644
index 000000000..6cd49e20e
--- /dev/null
+++ b/src/ImageSharp/Formats/Jpeg/JpegImageFormatProvider.cs
@@ -0,0 +1,42 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Formats
+{
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Text;
+ using ImageSharp.PixelFormats;
+
+ ///
+ /// Detects png file headers
+ ///
+ public class JpegImageFormatProvider : IImageFormatProvider
+ {
+ ///
+ public void Configure(IImageFormatHost host)
+ {
+ var pngEncoder = new JpegEncoder();
+ foreach (string mimeType in JpegConstants.MimeTypes)
+ {
+ host.SetMimeTypeEncoder(mimeType, pngEncoder);
+ }
+
+ foreach (string mimeType in JpegConstants.FileExtensions)
+ {
+ host.SetFileExtensionEncoder(mimeType, pngEncoder);
+ }
+
+ var pngDecoder = new JpegDecoder();
+ foreach (string mimeType in JpegConstants.MimeTypes)
+ {
+ host.SetMimeTypeDecoder(mimeType, pngDecoder);
+ }
+
+ host.AddMimeTypeDetector(new JpegMimeTypeDetector());
+ }
+ }
+}
diff --git a/src/ImageSharp/Formats/Jpeg/JpegMimeTypeDetector.cs b/src/ImageSharp/Formats/Jpeg/JpegMimeTypeDetector.cs
new file mode 100644
index 000000000..f84a91f70
--- /dev/null
+++ b/src/ImageSharp/Formats/Jpeg/JpegMimeTypeDetector.cs
@@ -0,0 +1,88 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Formats
+{
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Text;
+ using ImageSharp.PixelFormats;
+
+ ///
+ /// Detects Jpeg file headers
+ ///
+ public class JpegMimeTypeDetector : IMimeTypeDetector
+ {
+ ///
+ public int HeaderSize => 11;
+
+ ///
+ public string DetectMimeType(Span header)
+ {
+ if (this.IsSupportedFileFormat(header))
+ {
+ return "image/jpeg";
+ }
+
+ return null;
+ }
+
+ private bool IsSupportedFileFormat(Span header)
+ {
+ return header.Length >= this.HeaderSize &&
+ (this.IsJfif(header) || this.IsExif(header) || this.IsJpeg(header));
+ }
+
+ ///
+ /// Returns a value indicating whether the given bytes identify Jfif data.
+ ///
+ /// The bytes representing the file header.
+ /// The
+ private bool IsJfif(Span header)
+ {
+ bool isJfif =
+ header[6] == 0x4A && // J
+ header[7] == 0x46 && // F
+ header[8] == 0x49 && // I
+ header[9] == 0x46 && // F
+ header[10] == 0x00;
+
+ return isJfif;
+ }
+
+ ///
+ /// Returns a value indicating whether the given bytes identify EXIF data.
+ ///
+ /// The bytes representing the file header.
+ /// The
+ private bool IsExif(Span header)
+ {
+ bool isExif =
+ header[6] == 0x45 && // E
+ header[7] == 0x78 && // X
+ header[8] == 0x69 && // I
+ header[9] == 0x66 && // F
+ header[10] == 0x00;
+
+ return isExif;
+ }
+
+ ///
+ /// Returns a value indicating whether the given bytes identify Jpeg data.
+ /// This is a last chance resort for jpegs that contain ICC information.
+ ///
+ /// The bytes representing the file header.
+ /// The
+ private bool IsJpeg(Span header)
+ {
+ bool isJpg =
+ header[0] == 0xFF && // 255
+ header[1] == 0xD8; // 216
+
+ return isJpg;
+ }
+ }
+}
diff --git a/src/ImageSharp/Formats/Png/PngDecoder.cs b/src/ImageSharp/Formats/Png/PngDecoder.cs
index da00ff906..c9fab8e3f 100644
--- a/src/ImageSharp/Formats/Png/PngDecoder.cs
+++ b/src/ImageSharp/Formats/Png/PngDecoder.cs
@@ -38,34 +38,11 @@ namespace ImageSharp.Formats
///
public bool IgnoreMetadata { get; set; }
- ///
- public IEnumerable MimeTypes => PngConstants.MimeTypes;
-
- ///
- public IEnumerable FileExtensions => PngConstants.FileExtensions;
-
- ///
- public int HeaderSize => 8;
-
///
/// Gets or sets the encoding that should be used when reading text chunks.
///
public Encoding TextEncoding { get; set; } = PngConstants.DefaultEncoding;
- ///
- public bool IsSupportedFileFormat(Span header)
- {
- return header.Length >= this.HeaderSize &&
- header[0] == 0x89 &&
- header[1] == 0x50 && // P
- header[2] == 0x4E && // N
- header[3] == 0x47 && // G
- header[4] == 0x0D && // CR
- header[5] == 0x0A && // LF
- header[6] == 0x1A && // EOF
- header[7] == 0x0A; // LF
- }
-
///
/// Decodes the image from the specified stream to the .
///
diff --git a/src/ImageSharp/Formats/Png/PngEncoder.cs b/src/ImageSharp/Formats/Png/PngEncoder.cs
index 023e465e9..d15161ded 100644
--- a/src/ImageSharp/Formats/Png/PngEncoder.cs
+++ b/src/ImageSharp/Formats/Png/PngEncoder.cs
@@ -16,12 +16,6 @@ namespace ImageSharp.Formats
///
public class PngEncoder : IImageEncoder
{
- ///
- public IEnumerable MimeTypes => PngConstants.MimeTypes;
-
- ///
- public IEnumerable FileExtensions => PngConstants.FileExtensions;
-
///
/// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded.
///
diff --git a/src/ImageSharp/Formats/Png/PngImageFormatProvider.cs b/src/ImageSharp/Formats/Png/PngImageFormatProvider.cs
new file mode 100644
index 000000000..5708cc812
--- /dev/null
+++ b/src/ImageSharp/Formats/Png/PngImageFormatProvider.cs
@@ -0,0 +1,42 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Formats
+{
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Text;
+ using ImageSharp.PixelFormats;
+
+ ///
+ /// Detects png file headers
+ ///
+ public class PngImageFormatProvider : IImageFormatProvider
+ {
+ ///
+ public void Configure(IImageFormatHost host)
+ {
+ var pngEncoder = new PngEncoder();
+ foreach (string mimeType in PngConstants.MimeTypes)
+ {
+ host.SetMimeTypeEncoder(mimeType, pngEncoder);
+ }
+
+ foreach (string mimeType in PngConstants.FileExtensions)
+ {
+ host.SetFileExtensionEncoder(mimeType, pngEncoder);
+ }
+
+ var pngDecoder = new PngDecoder();
+ foreach (string mimeType in PngConstants.MimeTypes)
+ {
+ host.SetMimeTypeDecoder(mimeType, pngDecoder);
+ }
+
+ host.AddMimeTypeDetector(new PngMimeTypeDetector());
+ }
+ }
+}
diff --git a/src/ImageSharp/Formats/Png/PngMimeTypeDetector.cs b/src/ImageSharp/Formats/Png/PngMimeTypeDetector.cs
new file mode 100644
index 000000000..6b5d43fbd
--- /dev/null
+++ b/src/ImageSharp/Formats/Png/PngMimeTypeDetector.cs
@@ -0,0 +1,46 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Formats
+{
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Text;
+ using ImageSharp.PixelFormats;
+
+ ///
+ /// Detects png file headers
+ ///
+ public class PngMimeTypeDetector : IMimeTypeDetector
+ {
+ ///
+ public int HeaderSize => 8;
+
+ ///
+ public string DetectMimeType(Span header)
+ {
+ if (this.IsSupportedFileFormat(header))
+ {
+ return "image/png";
+ }
+
+ return null;
+ }
+
+ private bool IsSupportedFileFormat(Span header)
+ {
+ return header.Length >= this.HeaderSize &&
+ header[0] == 0x89 &&
+ header[1] == 0x50 && // P
+ header[2] == 0x4E && // N
+ header[3] == 0x47 && // G
+ header[4] == 0x0D && // CR
+ header[5] == 0x0A && // LF
+ header[6] == 0x1A && // EOF
+ header[7] == 0x0A; // LF
+ }
+ }
+}
diff --git a/src/ImageSharp/Image/Image.Decode.cs b/src/ImageSharp/Image/Image.Decode.cs
index 2730da8f2..96d5df45f 100644
--- a/src/ImageSharp/Image/Image.Decode.cs
+++ b/src/ImageSharp/Image/Image.Decode.cs
@@ -22,8 +22,8 @@ namespace ImageSharp
///
/// The image stream to read the header from.
/// The configuration.
- /// The image format or null if none found.
- private static IImageDecoder DiscoverDecoder(Stream stream, Configuration config)
+ /// The mimetype or null if none found.
+ private static string InternalDiscoverMimeType(Stream stream, Configuration config)
{
// This is probably a candidate for making into a public API in the future!
int maxHeaderSize = config.MaxHeaderSize;
@@ -32,19 +32,31 @@ namespace ImageSharp
return null;
}
- IImageDecoder format;
byte[] header = ArrayPool.Shared.Rent(maxHeaderSize);
try
{
long startPosition = stream.Position;
stream.Read(header, 0, maxHeaderSize);
stream.Position = startPosition;
- format = config.ImageDecoders.LastOrDefault(x => x.IsSupportedFileFormat(header)); // we should use last in case user has registerd a new one with their own settings
+ return config.MimeTypeDetectors.Select(x => x.DetectMimeType(header)).LastOrDefault(x => x != null);
}
finally
{
ArrayPool.Shared.Return(header);
}
+ }
+
+ ///
+ /// By reading the header on the provided stream this calculates the images format.
+ ///
+ /// The image stream to read the header from.
+ /// The configuration.
+ /// The mimeType.
+ /// The image format or null if none found.
+ private static IImageDecoder DiscoverDecoder(Stream stream, Configuration config, out string mimeType)
+ {
+
+ format = config.FindMimeTypeDecoder(mimeType);
return format;
}
@@ -59,18 +71,18 @@ namespace ImageSharp
///
/// A new .
///
- private static (Image img, IImageDecoder decoder) Decode(Stream stream, Configuration config)
+ private static (Image img, string mimeType) Decode(Stream stream, Configuration config)
#pragma warning restore SA1008 // Opening parenthesis must be spaced correctly
where TPixel : struct, IPixel
{
- IImageDecoder decoder = DiscoverDecoder(stream, config);
+ IImageDecoder decoder = DiscoverDecoder(stream, config, out string mimeType);
if (decoder == null)
{
return (null, null);
}
Image img = decoder.Decode(config, stream);
- return (img, decoder);
+ return (img, mimeType);
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Image/Image.FromBytes.cs b/src/ImageSharp/Image/Image.FromBytes.cs
index 8cc0e8f37..948fadf0c 100644
--- a/src/ImageSharp/Image/Image.FromBytes.cs
+++ b/src/ImageSharp/Image/Image.FromBytes.cs
@@ -15,6 +15,30 @@ namespace ImageSharp
///
public static partial class Image
{
+ ///
+ /// By reading the header on the provided byte array this calculates the images mimetype.
+ ///
+ /// The byte array containing image data to read the header from.
+ /// The mimetype or null if none found.
+ public static string DiscoverMimeType(byte[] data)
+ {
+ return DiscoverMimeType(null, data);
+ }
+
+ ///
+ /// By reading the header on the provided byte array this calculates the images mimetype.
+ ///
+ /// The configuration.
+ /// The byte array containing image data to read the header from.
+ /// The mimetype or null if none found.
+ public static string DiscoverMimeType(Configuration config, byte[] data)
+ {
+ using (Stream stream = new MemoryStream(data))
+ {
+ return DiscoverMimeType(config, stream);
+ }
+ }
+
///
/// Create a new instance of the class from the given byte array.
///
diff --git a/src/ImageSharp/Image/Image.FromFile.cs b/src/ImageSharp/Image/Image.FromFile.cs
index 991294921..96d509752 100644
--- a/src/ImageSharp/Image/Image.FromFile.cs
+++ b/src/ImageSharp/Image/Image.FromFile.cs
@@ -16,6 +16,31 @@ namespace ImageSharp
///
public static partial class Image
{
+ ///
+ /// By reading the header on the provided file this calculates the images mimetype.
+ ///
+ /// The image file to open and to read the header from.
+ /// The mimetype or null if none found.
+ public static string DiscoverMimeType(string filePath)
+ {
+ return DiscoverMimeType(null, filePath);
+ }
+
+ ///
+ /// By reading the header on the provided file this calculates the images mimetype.
+ ///
+ /// The configuration.
+ /// The image file to open and to read the header from.
+ /// The mimetype or null if none found.
+ public static string DiscoverMimeType(Configuration config, string filePath)
+ {
+ config = config ?? Configuration.Default;
+ using (Stream file = config.FileSystem.OpenRead(filePath))
+ {
+ return DiscoverMimeType(config, file);
+ }
+ }
+
///
/// Create a new instance of the class from the given file.
///
diff --git a/src/ImageSharp/Image/Image.FromStream.cs b/src/ImageSharp/Image/Image.FromStream.cs
index 79c66af90..1aa93525c 100644
--- a/src/ImageSharp/Image/Image.FromStream.cs
+++ b/src/ImageSharp/Image/Image.FromStream.cs
@@ -18,6 +18,27 @@ namespace ImageSharp
///
public static partial class Image
{
+ ///
+ /// By reading the header on the provided stream this calculates the images mimetype.
+ ///
+ /// The image stream to read the header from.
+ /// The mimetype or null if none found.
+ public static string DiscoverMimeType(Stream stream)
+ {
+ return DiscoverMimeType(null, stream);
+ }
+
+ ///
+ /// By reading the header on the provided stream this calculates the images mimetype.
+ ///
+ /// The configuration.
+ /// The image stream to read the header from.
+ /// The mimetype or null if none found.
+ public static string DiscoverMimeType(Configuration config, Stream stream)
+ {
+ return WithSeekableStream(stream, s => InternalDiscoverMimeType(s, config ?? Configuration.Default));
+ }
+
///
/// Create a new instance of the class from the given stream.
///
@@ -169,21 +190,21 @@ namespace ImageSharp
{
config = config ?? Configuration.Default;
mimeType = null;
- (Image img, IImageDecoder decoder) data = WithSeekableStream(stream, s => Decode(s, config));
+ (Image img, string mimeType) data = WithSeekableStream(stream, s => Decode(s, config));
- mimeType = data.decoder?.MimeTypes.FirstOrDefault();
+ mimeType = data.mimeType;
if (data.img != null)
{
return data.img;
}
- StringBuilder stringBuilder = new StringBuilder();
+ var stringBuilder = new StringBuilder();
stringBuilder.AppendLine("Image cannot be loaded. Available decoders:");
- foreach (IImageDecoder format in config.ImageDecoders)
+ foreach (Type format in config.AllMimeImageDecoders)
{
- stringBuilder.AppendLine("-" + format);
+ stringBuilder.AppendLine(" - " + format.Name);
}
throw new NotSupportedException(stringBuilder.ToString());
@@ -202,7 +223,7 @@ namespace ImageSharp
}
// We want to be able to load images from things like HttpContext.Request.Body
- using (MemoryStream ms = new MemoryStream())
+ using (var ms = new MemoryStream())
{
stream.CopyTo(ms);
ms.Position = 0;
diff --git a/src/ImageSharp/Image/Image{TPixel}.cs b/src/ImageSharp/Image/Image{TPixel}.cs
index 27f3801c4..af9cc3914 100644
--- a/src/ImageSharp/Image/Image{TPixel}.cs
+++ b/src/ImageSharp/Image/Image{TPixel}.cs
@@ -158,16 +158,16 @@ namespace ImageSharp
public Image Save(Stream stream, string mimeType)
{
Guard.NotNullOrEmpty(mimeType, nameof(mimeType));
- IImageEncoder encoder = this.Configuration.ImageEncoders?.LastOrDefault(x => x?.MimeTypes?.Contains(mimeType, StringComparer.OrdinalIgnoreCase) == true);
+ IImageEncoder encoder = this.Configuration.FindMimeTypeEncoder(mimeType);
if (encoder == null)
{
- StringBuilder stringBuilder = new StringBuilder();
+ var stringBuilder = new StringBuilder();
stringBuilder.AppendLine("Can't find encoder for provided mime type. Available encoded:");
- foreach (IImageEncoder format in this.Configuration.ImageEncoders)
+ foreach (Type format in this.Configuration.AllMimeImageEncoders)
{
- stringBuilder.AppendLine("-" + format);
+ stringBuilder.AppendLine(" - " + format);
}
throw new NotSupportedException(stringBuilder.ToString());
@@ -207,15 +207,15 @@ namespace ImageSharp
Guard.NotNullOrEmpty(filePath, nameof(filePath));
string ext = Path.GetExtension(filePath).Trim('.');
- IImageEncoder encoder = this.Configuration.ImageEncoders?.LastOrDefault(x => x?.FileExtensions?.Contains(ext, StringComparer.OrdinalIgnoreCase) == true);
+ IImageEncoder encoder = this.Configuration.FindFileExtensionsEncoder(ext);
if (encoder == null)
{
- StringBuilder stringBuilder = new StringBuilder();
+ var stringBuilder = new StringBuilder();
stringBuilder.AppendLine($"Can't find encoder for file extention '{ext}'. Available encoded:");
- foreach (IImageEncoder format in this.Configuration.ImageEncoders)
+ foreach (Type format in this.Configuration.AllExtImageEncoders)
{
- stringBuilder.AppendLine("-" + format);
+ stringBuilder.AppendLine(" - " + format);
}
throw new NotSupportedException(stringBuilder.ToString());
@@ -255,7 +255,7 @@ namespace ImageSharp
/// The
public string ToBase64String(string mimeType)
{
- using (MemoryStream stream = new MemoryStream())
+ using (var stream = new MemoryStream())
{
this.Save(stream, mimeType);
stream.Flush();
@@ -274,7 +274,7 @@ namespace ImageSharp
{
scaleFunc = PackedPixelConverterHelper.ComputeScaleFunction(scaleFunc);
- Image target = new Image(this.Configuration, this.Width, this.Height);
+ var target = new Image(this.Configuration, this.Width, this.Height);
target.CopyProperties(this);
using (PixelAccessor pixels = this.Lock())
@@ -288,7 +288,7 @@ namespace ImageSharp
{
for (int x = 0; x < target.Width; x++)
{
- TPixel2 color = default(TPixel2);
+ var color = default(TPixel2);
color.PackFromVector4(scaleFunc(pixels[x, y].ToVector4()));
targetPixels[x, y] = color;
}
diff --git a/tests/ImageSharp.Tests/ConfigurationTests.cs b/tests/ImageSharp.Tests/ConfigurationTests.cs
index e2d50649a..e8927c75c 100644
--- a/tests/ImageSharp.Tests/ConfigurationTests.cs
+++ b/tests/ImageSharp.Tests/ConfigurationTests.cs
@@ -13,7 +13,7 @@ namespace ImageSharp.Tests
using ImageSharp.Formats;
using ImageSharp.IO;
using ImageSharp.PixelFormats;
-
+ using Moq;
using Xunit;
///
@@ -21,23 +21,27 @@ namespace ImageSharp.Tests
///
public class ConfigurationTests
{
+ public Configuration ConfigurationEmpty { get; private set; }
+ public Configuration DefaultConfiguration { get; private set; }
+
+ public ConfigurationTests()
+ {
+ this.DefaultConfiguration = Configuration.CreateDefaultInstance();
+ this.ConfigurationEmpty = Configuration.CreateDefaultInstance();
+ }
+
[Fact]
public void DefaultsToLocalFileSystem()
{
- var configuration = Configuration.CreateDefaultInstance();
-
- ImageSharp.IO.IFileSystem fs = configuration.FileSystem;
-
- Assert.IsType(fs);
+ Assert.IsType(DefaultConfiguration.FileSystem);
+ Assert.IsType(ConfigurationEmpty.FileSystem);
}
[Fact]
public void IfAutoloadWellknwonFormatesIsTrueAllFormateAreLoaded()
{
- var configuration = Configuration.CreateDefaultInstance();
-
- Assert.Equal(4, configuration.ImageDecoders.Count);
- Assert.Equal(4, configuration.ImageDecoders.Count);
+ Assert.Equal(4, DefaultConfiguration.AllMimeImageDecoders.Count());
+ Assert.Equal(4, DefaultConfiguration.AllMimeImageDecoders.Count());
}
///
@@ -68,58 +72,129 @@ namespace ImageSharp.Tests
Assert.True(Configuration.Default.ParallelOptions.MaxDegreeOfParallelism == Environment.ProcessorCount);
}
- ///
- /// Test that the default configuration parallel options is not null.
- ///
[Fact]
- public void TestDefultConfigurationImageFormatsIsNotNull()
+ public void AddMimeTypeDetectorNullthrows()
{
- Assert.True(Configuration.Default.ImageDecoders != null);
- Assert.True(Configuration.Default.ImageEncoders != null);
+ Assert.Throws(() =>
+ {
+ DefaultConfiguration.AddMimeTypeDetector(null);
+ });
}
- ///
- /// Tests the method throws an exception
- /// when the format is null.
- ///
[Fact]
- public void TestAddImageFormatThrowsWithNullFormat()
+ public void RegisterNullMimeTypeEncoder()
{
Assert.Throws(() =>
{
- Configuration.Default.AddImageFormat((IImageEncoder)null);
+ DefaultConfiguration.SetMimeTypeEncoder(null, new Mock().Object);
});
Assert.Throws(() =>
{
- Configuration.Default.AddImageFormat((IImageDecoder)null);
+ DefaultConfiguration.SetMimeTypeEncoder("sdsdsd", null);
+ });
+ Assert.Throws(() =>
+ {
+ DefaultConfiguration.SetMimeTypeEncoder(null, null);
+ });
+ }
+
+ [Fact]
+ public void RegisterNullFileExtEncoder()
+ {
+ Assert.Throws(() =>
+ {
+ DefaultConfiguration.SetFileExtensionEncoder(null, new Mock().Object);
+ });
+ Assert.Throws(() =>
+ {
+ DefaultConfiguration.SetFileExtensionEncoder("sdsdsd", null);
+ });
+ Assert.Throws(() =>
+ {
+ DefaultConfiguration.SetFileExtensionEncoder(null, null);
});
}
- ///
- /// Test that the default image constructors use default configuration.
- ///
[Fact]
- public void TestImageUsesDefaultConfiguration()
+ public void RegisterNullMimeTypeDecoder()
{
- Configuration.Default.AddImageFormat(new PngDecoder());
+ Assert.Throws(() =>
+ {
+ DefaultConfiguration.SetMimeTypeDecoder(null, new Mock().Object);
+ });
+ Assert.Throws(() =>
+ {
+ DefaultConfiguration.SetMimeTypeDecoder("sdsdsd", null);
+ });
+ Assert.Throws(() =>
+ {
+ DefaultConfiguration.SetMimeTypeDecoder(null, null);
+ });
+ }
- var image = new Image(1, 1);
- Assert.Equal(image.Configuration.ParallelOptions, Configuration.Default.ParallelOptions);
- Assert.Equal(image.Configuration.ImageDecoders, Configuration.Default.ImageDecoders);
+ [Fact]
+ public void RegisterMimeTypeEncoderReplacesLast()
+ {
+ var encoder1 = new Mock().Object;
+ ConfigurationEmpty.SetMimeTypeEncoder("test", encoder1);
+ var found = ConfigurationEmpty.FindMimeTypeEncoder("TEST");
+ Assert.Equal(encoder1, found);
+
+ var encoder2 = new Mock().Object;
+ ConfigurationEmpty.SetMimeTypeEncoder("TEST", encoder2);
+ var found2 = ConfigurationEmpty.FindMimeTypeEncoder("test");
+ Assert.Equal(encoder2, found2);
+ Assert.NotEqual(found, found2);
+ }
+
+ [Fact]
+ public void RegisterFileExtEnecoderReplacesLast()
+ {
+ var encoder1 = new Mock().Object;
+ ConfigurationEmpty.SetFileExtensionEncoder("TEST", encoder1);
+ var found = ConfigurationEmpty.FindFileExtensionsEncoder("test");
+ Assert.Equal(encoder1, found);
+
+ var encoder2 = new Mock().Object;
+ ConfigurationEmpty.SetFileExtensionEncoder("test", encoder2);
+ var found2 = ConfigurationEmpty.FindFileExtensionsEncoder("TEST");
+ Assert.Equal(encoder2, found2);
+ Assert.NotEqual(found, found2);
+ }
+
+ [Fact]
+ public void RegisterMimeTypeDecoderReplacesLast()
+ {
+ var decoder1 = new Mock().Object;
+ ConfigurationEmpty.SetMimeTypeDecoder("test", decoder1);
+ var found = ConfigurationEmpty.FindMimeTypeDecoder("TEST");
+ Assert.Equal(decoder1, found);
+
+ var decoder2 = new Mock().Object;
+ ConfigurationEmpty.SetMimeTypeDecoder("TEST", decoder2);
+ var found2 = ConfigurationEmpty.FindMimeTypeDecoder("test");
+ Assert.Equal(decoder2, found2);
+ Assert.NotEqual(found, found2);
+ }
+
+
+ [Fact]
+ public void ConstructorCallConfigureOnFormatProvider()
+ {
+ var provider = new Mock();
+ var config = new Configuration(provider.Object);
+
+ provider.Verify(x => x.Configure(config));
}
- ///
- /// Test that the default image constructor copies the configuration.
- ///
[Fact]
- public void TestImageCopiesConfiguration()
+ public void AddFormatCallsConfig()
{
- Configuration.Default.AddImageFormat(new PngDecoder());
+ var provider = new Mock();
+ var config = new Configuration();
+ config.AddImageFormat(provider.Object);
- var image = new Image(1, 1);
- var image2 = new Image(image);
- Assert.Equal(image2.Configuration.ParallelOptions, image.Configuration.ParallelOptions);
- Assert.True(image2.Configuration.ImageDecoders.SequenceEqual(image.Configuration.ImageDecoders));
+ provider.Verify(x => x.Configure(config));
}
}
}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/Image/ImageLoadTests.cs b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs
index 65c2cc52c..efd7b6935 100644
--- a/tests/ImageSharp.Tests/Image/ImageLoadTests.cs
+++ b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs
@@ -23,6 +23,7 @@ namespace ImageSharp.Tests
private Image returnImage;
private Mock localDecoder;
private readonly string FilePath;
+ private readonly Mock localMimeTypeDetector;
public Configuration LocalConfiguration { get; private set; }
public byte[] Marker { get; private set; }
@@ -34,10 +35,9 @@ namespace ImageSharp.Tests
this.returnImage = new Image(1, 1);
this.localDecoder = new Mock();
- this.localDecoder.Setup(x => x.MimeTypes).Returns(new[] { "img/test" });
- this.localDecoder.Setup(x => x.FileExtensions).Returns(new[] { "png", "jpg" });
- this.localDecoder.Setup(x => x.HeaderSize).Returns(1);
- this.localDecoder.Setup(x => x.IsSupportedFileFormat(It.IsAny>())).Returns(true);
+ this.localMimeTypeDetector = new Mock();
+ this.localMimeTypeDetector.Setup(x => x.HeaderSize).Returns(1);
+ this.localMimeTypeDetector.Setup(x => x.DetectMimeType(It.IsAny>())).Returns("test");
this.localDecoder.Setup(x => x.Decode(It.IsAny(), It.IsAny()))
@@ -56,8 +56,8 @@ namespace ImageSharp.Tests
{
FileSystem = this.fileSystem.Object
};
-
- this.LocalConfiguration.AddImageFormat(this.localDecoder.Object);
+ this.LocalConfiguration.AddMimeTypeDetector(this.localMimeTypeDetector.Object);
+ this.LocalConfiguration.SetMimeTypeDecoder("test", this.localDecoder.Object);
TestFormat.RegisterGloablTestFormat();
this.Marker = Guid.NewGuid().ToByteArray();
diff --git a/tests/ImageSharp.Tests/Image/ImageSaveTests.cs b/tests/ImageSharp.Tests/Image/ImageSaveTests.cs
index 46177ba5f..e2e0b1364 100644
--- a/tests/ImageSharp.Tests/Image/ImageSaveTests.cs
+++ b/tests/ImageSharp.Tests/Image/ImageSaveTests.cs
@@ -24,24 +24,26 @@ namespace ImageSharp.Tests
private readonly Mock fileSystem;
private readonly Mock encoder;
private readonly Mock encoderNotInFormat;
+ private Mock localMimeTypeDetector;
public ImageSaveTests()
{
- this.encoder = new Mock();
- this.encoder.Setup(x => x.MimeTypes).Returns(new[] { "img/test" });
- this.encoder.Setup(x => x.FileExtensions).Returns(new string[] { "png", "jpg" });
+ this.localMimeTypeDetector = new Mock();
+ this.localMimeTypeDetector.Setup(x => x.HeaderSize).Returns(1);
+ this.localMimeTypeDetector.Setup(x => x.DetectMimeType(It.IsAny>())).Returns("img/test");
+ this.encoder = new Mock();
this.encoderNotInFormat = new Mock();
- this.encoderNotInFormat.Setup(x => x.MimeTypes).Returns(new[] { "img/test" });
- this.encoderNotInFormat.Setup(x => x.FileExtensions).Returns(new string[] { "png", "jpg" });
this.fileSystem = new Mock();
var config = new Configuration()
{
FileSystem = this.fileSystem.Object
};
- config.AddImageFormat(this.encoder.Object);
+ config.AddMimeTypeDetector(this.localMimeTypeDetector.Object);
+ config.SetMimeTypeEncoder("img/test", this.encoder.Object);
+ config.SetFileExtensionEncoder("png", this.encoder.Object);
this.Image = new Image(config, 1, 1);
}
diff --git a/tests/ImageSharp.Tests/TestFormat.cs b/tests/ImageSharp.Tests/TestFormat.cs
index 1d06f7328..701b02c09 100644
--- a/tests/ImageSharp.Tests/TestFormat.cs
+++ b/tests/ImageSharp.Tests/TestFormat.cs
@@ -19,14 +19,13 @@ namespace ImageSharp.Tests
///
/// A test image file.
///
- public class TestFormat
+ public class TestFormat : IImageFormatProvider
{
public static TestFormat GlobalTestFormat { get; } = new TestFormat();
public static void RegisterGloablTestFormat()
{
- Configuration.Default.AddImageFormat(GlobalTestFormat.Encoder);
- Configuration.Default.AddImageFormat(GlobalTestFormat.Decoder);
+ Configuration.Default.AddImageFormat(GlobalTestFormat);
}
public TestFormat()
@@ -66,7 +65,8 @@ namespace ImageSharp.Tests
Assert.True(discovered.Any(), "No calls to decode on this formate with the proveded options happend");
- foreach (DecodeOperation d in discovered) {
+ foreach (DecodeOperation d in discovered)
+ {
this.DecodeCalls.Remove(d);
}
}
@@ -80,7 +80,7 @@ namespace ImageSharp.Tests
{
this._sampleImages.Add(typeof(TPixel), new Image(1, 1));
}
-
+
return (Image)this._sampleImages[typeof(TPixel)];
}
}
@@ -108,12 +108,25 @@ namespace ImageSharp.Tests
}
return true;
}
+
+ public void Configure(IImageFormatHost host)
+ {
+ host.AddMimeTypeDetector(new TestHeader(this));
+ foreach (var ext in this.SupportedExtensions)
+ {
+ host.SetFileExtensionEncoder(ext, new TestEncoder(this));
+ }
+
+ host.SetMimeTypeEncoder(this.MimeType, new TestEncoder(this));
+ host.SetMimeTypeDecoder(this.MimeType, new TestDecoder(this));
+ }
+
public struct DecodeOperation
{
public byte[] marker;
internal Configuration config;
- public bool IsMatch(byte[] testMarker, Configuration config)
+ public bool IsMatch(byte[] testMarker, Configuration config)
{
if (this.config != config)
@@ -137,6 +150,26 @@ namespace ImageSharp.Tests
}
}
+ public class TestHeader : IMimeTypeDetector
+ {
+
+ private TestFormat testFormat;
+
+ public int HeaderSize => testFormat.HeaderSize;
+
+ public string DetectMimeType(Span header)
+ {
+ if (testFormat.IsSupportedFileFormat(header))
+ return testFormat.MimeType;
+
+ return null;
+ }
+
+ public TestHeader(TestFormat testFormat)
+ {
+ this.testFormat = testFormat;
+ }
+ }
public class TestDecoder : ImageSharp.Formats.IImageDecoder
{
private TestFormat testFormat;
diff --git a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs
index ee5246660..21b167ca2 100644
--- a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs
+++ b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs
@@ -124,7 +124,7 @@ namespace ImageSharp.Tests
private static IImageEncoder GetImageFormatByExtension(string extension)
{
extension = extension?.TrimStart('.');
- return Configuration.Default.ImageEncoders.Last(f => f.FileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase));
+ return Configuration.Default.FindFileExtensionsEncoder(extension);
}
private string GetTestOutputDir()