Browse Source

switch from mimetype strings to IImageFormats

af/merge-core
Scott Williams 9 years ago
parent
commit
bb9280f317
  1. 2
      samples/ChangeDefaultEncoderOptions/Program.cs
  2. 183
      src/ImageSharp/Configuration.cs
  3. 27
      src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs
  4. 31
      src/ImageSharp/Formats/Bmp/BmpFormat.cs
  5. 8
      src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs
  6. 45
      src/ImageSharp/Formats/Bmp/BmpImageFormatProvider.cs
  7. 28
      src/ImageSharp/Formats/Gif/GifConfigurationModule.cs
  8. 31
      src/ImageSharp/Formats/Gif/GifFormat.cs
  9. 8
      src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs
  10. 45
      src/ImageSharp/Formats/Gif/GifImageFormatProvider.cs
  11. 39
      src/ImageSharp/Formats/IImageFormat.cs
  12. 6
      src/ImageSharp/Formats/IImageFormatDetector.cs
  13. 56
      src/ImageSharp/Formats/IImageFormatProvider.cs
  14. 28
      src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs
  15. 31
      src/ImageSharp/Formats/Jpeg/JpegFormat.cs
  16. 14
      src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs
  17. 45
      src/ImageSharp/Formats/Jpeg/JpegImageFormatProvider.cs
  18. 27
      src/ImageSharp/Formats/Png/PngConfigurationModule.cs
  19. 31
      src/ImageSharp/Formats/Png/PngFormat.cs
  20. 10
      src/ImageSharp/Formats/Png/PngImageFormatDetector.cs
  21. 45
      src/ImageSharp/Formats/Png/PngImageFormatProvider.cs
  22. 23
      src/ImageSharp/IConfigurationModule.cs
  23. 31
      src/ImageSharp/Image/Image.Decode.cs
  24. 34
      src/ImageSharp/Image/Image.FromBytes.cs
  25. 28
      src/ImageSharp/Image/Image.FromFile.cs
  26. 36
      src/ImageSharp/Image/Image.FromStream.cs
  27. 52
      src/ImageSharp/Image/Image{TPixel}.cs
  28. 39
      src/ImageSharp/ImageFormats.cs
  29. 10
      src/ImageSharp/Memory/Buffer.cs
  30. 76
      tests/ImageSharp.Tests/ConfigurationTests.cs
  31. 6
      tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs
  32. 56
      tests/ImageSharp.Tests/Image/ImageDiscoverMimeType.cs
  33. 14
      tests/ImageSharp.Tests/Image/ImageLoadTests.cs
  34. 19
      tests/ImageSharp.Tests/Image/ImageSaveTests.cs
  35. 4
      tests/ImageSharp.Tests/Image/ImageTests.cs
  36. 33
      tests/ImageSharp.Tests/TestFormat.cs
  37. 4
      tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs

2
samples/ChangeDefaultEncoderOptions/Program.cs

@ -10,7 +10,7 @@ namespace ChangeDefaultEncoderOptions
{ {
// lets switch out the default encoder for jpeg to one // lets switch out the default encoder for jpeg to one
// that saves at 90 quality and ignores the matadata // that saves at 90 quality and ignores the matadata
Configuration.Default.SetMimeTypeEncoder("image/jpeg", new ImageSharp.Formats.JpegEncoder() Configuration.Default.SetEncoder(ImageFormats.Jpeg, new ImageSharp.Formats.JpegEncoder()
{ {
Quality = 90, Quality = 90,
IgnoreMetadata = true IgnoreMetadata = true

183
src/ImageSharp/Configuration.cs

@ -18,7 +18,7 @@ namespace ImageSharp
/// <summary> /// <summary>
/// Provides initialization code which allows extending the library. /// Provides initialization code which allows extending the library.
/// </summary> /// </summary>
public class Configuration : IImageFormatHost public class Configuration
{ {
/// <summary> /// <summary>
/// A lazily initialized configuration default instance. /// A lazily initialized configuration default instance.
@ -33,22 +33,22 @@ namespace ImageSharp
/// <summary> /// <summary>
/// The list of supported <see cref="IImageEncoder"/> keyed to mime types. /// The list of supported <see cref="IImageEncoder"/> keyed to mime types.
/// </summary> /// </summary>
private readonly ConcurrentDictionary<string, IImageEncoder> mimeTypeEncoders = new ConcurrentDictionary<string, IImageEncoder>(StringComparer.OrdinalIgnoreCase); private readonly ConcurrentDictionary<IImageFormat, IImageEncoder> mimeTypeEncoders = new ConcurrentDictionary<IImageFormat, IImageEncoder>();
/// <summary> /// <summary>
/// The list of supported mime types keyed to file extensions. /// The list of supported <see cref="IImageEncoder"/> keyed to mime types.
/// </summary> /// </summary>
private readonly ConcurrentDictionary<string, string> extensionsMap = new ConcurrentDictionary<string, string>(StringComparer.OrdinalIgnoreCase); private readonly ConcurrentDictionary<IImageFormat, IImageDecoder> mimeTypeDecoders = new ConcurrentDictionary<IImageFormat, IImageDecoder>();
/// <summary> /// <summary>
/// The list of supported <see cref="IImageEncoder"/> keyed to mime types. /// The list of supported <see cref="IImageFormatDetector"/>s.
/// </summary> /// </summary>
private readonly ConcurrentDictionary<string, IImageDecoder> mimeTypeDecoders = new ConcurrentDictionary<string, IImageDecoder>(StringComparer.OrdinalIgnoreCase); private readonly List<IImageFormatDetector> imageFormatDetectors = new List<IImageFormatDetector>();
/// <summary> /// <summary>
/// The list of supported <see cref="IMimeTypeDetector"/>s. /// The list of supported <see cref="IImageFormat"/>s.
/// </summary> /// </summary>
private readonly List<IMimeTypeDetector> mimeTypeDetectors = new List<IMimeTypeDetector>(); private readonly HashSet<IImageFormat> imageFormats = new HashSet<IImageFormat>();
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Configuration" /> class. /// Initializes a new instance of the <see cref="Configuration" /> class.
@ -61,11 +61,11 @@ namespace ImageSharp
/// Initializes a new instance of the <see cref="Configuration" /> class. /// Initializes a new instance of the <see cref="Configuration" /> class.
/// </summary> /// </summary>
/// <param name="providers">A collection of providers to configure</param> /// <param name="providers">A collection of providers to configure</param>
public Configuration(params IImageFormatProvider[] providers) public Configuration(params IConfigurationModule[] providers)
{ {
if (providers != null) if (providers != null)
{ {
foreach (IImageFormatProvider p in providers) foreach (IConfigurationModule p in providers)
{ {
p.Configure(this); p.Configure(this);
} }
@ -88,24 +88,24 @@ namespace ImageSharp
internal int MaxHeaderSize { get; private set; } internal int MaxHeaderSize { get; private set; }
/// <summary> /// <summary>
/// Gets the currently registered <see cref="IMimeTypeDetector"/>s. /// Gets the currently registered <see cref="IImageFormatDetector"/>s.
/// </summary> /// </summary>
internal IEnumerable<IMimeTypeDetector> MimeTypeDetectors => this.mimeTypeDetectors; internal IEnumerable<IImageFormatDetector> FormatDetectors => this.imageFormatDetectors;
/// <summary> /// <summary>
/// Gets the currently registered <see cref="IImageDecoder"/>s. /// Gets the currently registered <see cref="IImageDecoder"/>s.
/// </summary> /// </summary>
internal IEnumerable<KeyValuePair<string, IImageDecoder>> ImageDecoders => this.mimeTypeDecoders; internal IEnumerable<KeyValuePair<IImageFormat, IImageDecoder>> ImageDecoders => this.mimeTypeDecoders;
/// <summary> /// <summary>
/// Gets the currently registered <see cref="IImageEncoder"/>s. /// Gets the currently registered <see cref="IImageEncoder"/>s.
/// </summary> /// </summary>
internal IEnumerable<KeyValuePair<string, IImageEncoder>> ImageEncoders => this.mimeTypeEncoders; internal IEnumerable<KeyValuePair<IImageFormat, IImageEncoder>> ImageEncoders => this.mimeTypeEncoders;
/// <summary> /// <summary>
/// Gets the currently registered file extensions. /// Gets the currently registered <see cref="IImageFormat"/>s.
/// </summary> /// </summary>
internal IEnumerable<KeyValuePair<string, string>> ImageExtensionToMimeTypeMapping => this.extensionsMap; internal IEnumerable<IImageFormat> ImageFormats => this.imageFormats;
#if !NETSTANDARD1_1 #if !NETSTANDARD1_1
/// <summary> /// <summary>
@ -117,35 +117,69 @@ namespace ImageSharp
/// <summary> /// <summary>
/// Registers a new format provider. /// Registers a new format provider.
/// </summary> /// </summary>
/// <param name="formatProvider">The format providers to call configure on.</param> /// <param name="configuration">The configuration provider to call configure on.</param>
public void AddImageFormat(IImageFormatProvider formatProvider) public void Configure(IConfigurationModule configuration)
{ {
Guard.NotNull(formatProvider, nameof(formatProvider)); Guard.NotNull(configuration, nameof(configuration));
formatProvider.Configure(this); configuration.Configure(this);
} }
/// <inheritdoc /> /// <summary>
public void SetMimeTypeEncoder(string mimeType, IImageEncoder encoder) /// Registers a new format provider.
/// </summary>
/// <param name="format">The format to register as a well know format.</param>
public void AddImageFormat(IImageFormat format)
{ {
Guard.NotNullOrEmpty(mimeType, nameof(mimeType)); Guard.NotNull(format, nameof(format));
Guard.NotNull(encoder, nameof(encoder)); Guard.NotNull(format.MimeTypes, nameof(format.MimeTypes));
this.mimeTypeEncoders.AddOrUpdate(mimeType?.Trim(), encoder, (s, e) => encoder); 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 FindFormatByFileExtensions(string extension)
{
return this.imageFormats.FirstOrDefault(x => x.FileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase));
} }
/// <inheritdoc /> /// <summary>
public void SetFileExtensionToMimeTypeMapping(string extension, string mimeType) /// 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)
{ {
Guard.NotNullOrEmpty(extension, nameof(extension)); return this.imageFormats.FirstOrDefault(x => x.MimeTypes.Contains(mimeType, StringComparer.OrdinalIgnoreCase));
Guard.NotNullOrEmpty(mimeType, nameof(mimeType));
this.extensionsMap.AddOrUpdate(extension?.Trim(), mimeType, (s, e) => mimeType);
} }
/// <inheritdoc /> /// <summary>
public void SetMimeTypeDecoder(string mimeType, IImageDecoder decoder) /// 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.NotNullOrEmpty(mimeType, nameof(mimeType)); 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)); Guard.NotNull(decoder, nameof(decoder));
this.mimeTypeDecoders.AddOrUpdate(mimeType, decoder, (s, e) => decoder); this.AddImageFormat(imageFormat);
this.mimeTypeDecoders.AddOrUpdate(imageFormat, decoder, (s, e) => decoder);
} }
/// <summary> /// <summary>
@ -153,43 +187,46 @@ namespace ImageSharp
/// </summary> /// </summary>
public void ClearMimeTypeDetectors() public void ClearMimeTypeDetectors()
{ {
this.mimeTypeDetectors.Clear(); this.imageFormatDetectors.Clear();
} }
/// <inheritdoc /> /// <summary>
public void AddMimeTypeDetector(IMimeTypeDetector detector) /// 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)); Guard.NotNull(detector, nameof(detector));
this.mimeTypeDetectors.Add(detector); this.imageFormatDetectors.Add(detector);
this.SetMaxHeaderSize(); this.SetMaxHeaderSize();
} }
/// <summary> /// <summary>
/// Creates the default instance with the following <see cref="IImageFormatProvider"/>s preregistered: /// Creates the default instance with the following <see cref="IConfigurationModule"/>s preregistered:
/// <para><see cref="PngImageFormatProvider"/></para> /// <para><see cref="PngConfigurationModule"/></para>
/// <para><see cref="JpegImageFormatProvider"/></para> /// <para><see cref="JpegConfigurationModule"/></para>
/// <para><see cref="GifImageFormatProvider"/></para> /// <para><see cref="GifConfigurationModule"/></para>
/// <para><see cref="BmpImageFormatProvider"/></para> /// <para><see cref="BmpConfigurationModule"/></para>
/// </summary> /// </summary>
/// <returns>The default configuration of <see cref="Configuration"/></returns> /// <returns>The default configuration of <see cref="Configuration"/></returns>
internal static Configuration CreateDefaultInstance() internal static Configuration CreateDefaultInstance()
{ {
return new Configuration( return new Configuration(
new PngImageFormatProvider(), new PngConfigurationModule(),
new JpegImageFormatProvider(), new JpegConfigurationModule(),
new GifImageFormatProvider(), new GifConfigurationModule(),
new BmpImageFormatProvider()); new BmpConfigurationModule());
} }
/// <summary> /// <summary>
/// For the specified mime type find the decoder. /// For the specified mime type find the decoder.
/// </summary> /// </summary>
/// <param name="mimeType">The mime type to discover</param> /// <param name="format">The format to discover</param>
/// <returns>The <see cref="IImageDecoder"/> if found otherwise null</returns> /// <returns>The <see cref="IImageDecoder"/> if found otherwise null</returns>
internal IImageDecoder FindMimeTypeDecoder(string mimeType) internal IImageDecoder FindDecoder(IImageFormat format)
{ {
Guard.NotNullOrEmpty(mimeType, nameof(mimeType)); Guard.NotNull(format, nameof(format));
if (this.mimeTypeDecoders.TryGetValue(mimeType, out IImageDecoder decoder)) if (this.mimeTypeDecoders.TryGetValue(format, out IImageDecoder decoder))
{ {
return decoder; return decoder;
} }
@ -200,12 +237,12 @@ namespace ImageSharp
/// <summary> /// <summary>
/// For the specified mime type find the encoder. /// For the specified mime type find the encoder.
/// </summary> /// </summary>
/// <param name="mimeType">The mime type to discover</param> /// <param name="format">The format to discover</param>
/// <returns>The <see cref="IImageEncoder"/> if found otherwise null</returns> /// <returns>The <see cref="IImageEncoder"/> if found otherwise null</returns>
internal IImageEncoder FindMimeTypeEncoder(string mimeType) internal IImageEncoder FindEncoder(IImageFormat format)
{ {
Guard.NotNullOrEmpty(mimeType, nameof(mimeType)); Guard.NotNull(format, nameof(format));
if (this.mimeTypeEncoders.TryGetValue(mimeType, out IImageEncoder encoder)) if (this.mimeTypeEncoders.TryGetValue(format, out IImageEncoder encoder))
{ {
return encoder; return encoder;
} }
@ -213,46 +250,12 @@ namespace ImageSharp
return null; return null;
} }
/// <summary>
/// For the specified mime type find the encoder.
/// </summary>
/// <param name="extensions">The extensions to discover</param>
/// <returns>The <see cref="IImageEncoder"/> if found otherwise null</returns>
internal IImageEncoder FindFileExtensionsEncoder(string extensions)
{
extensions = extensions?.TrimStart('.');
Guard.NotNullOrEmpty(extensions, nameof(extensions));
if (this.extensionsMap.TryGetValue(extensions, out string mimeType))
{
return this.FindMimeTypeEncoder(mimeType);
}
return null;
}
/// <summary>
/// For the specified extension find the mime type.
/// </summary>
/// <param name="extensions">the extensions to discover</param>
/// <returns>The mime type if found otherwise null</returns>
internal string FindFileExtensionsMimeType(string extensions)
{
extensions = extensions?.TrimStart('.');
Guard.NotNullOrEmpty(extensions, nameof(extensions));
if (this.extensionsMap.TryGetValue(extensions, out string mimeType))
{
return mimeType;
}
return null;
}
/// <summary> /// <summary>
/// Sets the max header size. /// Sets the max header size.
/// </summary> /// </summary>
private void SetMaxHeaderSize() private void SetMaxHeaderSize()
{ {
this.MaxHeaderSize = this.mimeTypeDetectors.Max(x => x.HeaderSize); this.MaxHeaderSize = this.imageFormatDetectors.Max(x => x.HeaderSize);
} }
} }
} }

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

@ -0,0 +1,27 @@
// <copyright file="ConfigurationModule.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using ImageSharp.PixelFormats;
/// <summary>
/// Registers the image encoders, decoders and mime type detectors for the bmp format.
/// </summary>
public class BmpConfigurationModule : IConfigurationModule
{
/// <inheritdoc/>
public void Configure(Configuration config)
{
config.SetEncoder(ImageFormats.Bitmap, new BmpEncoder());
config.SetDecoder(ImageFormats.Bitmap, new BmpDecoder());
config.AddImageFormatDetector(new BmpImageFormatDetector());
}
}
}

31
src/ImageSharp/Formats/Bmp/BmpFormat.cs

@ -0,0 +1,31 @@
// <copyright file="GifFormat.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using ImageSharp.PixelFormats;
/// <summary>
/// Registers the image encoders, decoders and mime type detectors for the jpeg format.
/// </summary>
internal sealed class BmpFormat : IImageFormat
{
/// <inheritdoc/>
public string Name => "BMP";
/// <inheritdoc/>
public string DefaultMimeType => "image/bmp";
/// <inheritdoc/>
public IEnumerable<string> MimeTypes => BmpConstants.MimeTypes;
/// <inheritdoc/>
public IEnumerable<string> FileExtensions => BmpConstants.FileExtensions;
}
}

8
src/ImageSharp/Formats/Bmp/BmpMimeTypeDetector.cs → src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs

@ -14,23 +14,23 @@ namespace ImageSharp.Formats
/// <summary> /// <summary>
/// Detects bmp file headers /// Detects bmp file headers
/// </summary> /// </summary>
internal class BmpMimeTypeDetector : IMimeTypeDetector internal class BmpImageFormatDetector : IImageFormatDetector
{ {
/// <inheritdoc/> /// <inheritdoc/>
public int HeaderSize => 2; public int HeaderSize => 2;
/// <inheritdoc/> /// <inheritdoc/>
public string DetectMimeType(Span<byte> header) public IImageFormat DetectFormat(ReadOnlySpan<byte> header)
{ {
if (this.IsSupportedFileFormat(header)) if (this.IsSupportedFileFormat(header))
{ {
return "image/bmp"; return ImageFormats.Bitmap;
} }
return null; return null;
} }
private bool IsSupportedFileFormat(Span<byte> header) private bool IsSupportedFileFormat(ReadOnlySpan<byte> header)
{ {
return header.Length >= this.HeaderSize && return header.Length >= this.HeaderSize &&
header[0] == 0x42 && // B header[0] == 0x42 && // B

45
src/ImageSharp/Formats/Bmp/BmpImageFormatProvider.cs

@ -1,45 +0,0 @@
// <copyright file="PngImageFormatProvider.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using ImageSharp.PixelFormats;
/// <summary>
/// Registers the image encoders, decoders and mime type detectors for the bmp format.
/// </summary>
public class BmpImageFormatProvider : IImageFormatProvider
{
/// <inheritdoc/>
public void Configure(IImageFormatHost host)
{
var encoder = new BmpEncoder();
foreach (string mimeType in BmpConstants.MimeTypes)
{
host.SetMimeTypeEncoder(mimeType, encoder);
}
foreach (string ext in BmpConstants.FileExtensions)
{
foreach (string mimeType in BmpConstants.MimeTypes)
{
host.SetFileExtensionToMimeTypeMapping(ext, mimeType);
}
}
var decoder = new BmpDecoder();
foreach (string mimeType in BmpConstants.MimeTypes)
{
host.SetMimeTypeDecoder(mimeType, decoder);
}
host.AddMimeTypeDetector(new BmpMimeTypeDetector());
}
}
}

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

@ -0,0 +1,28 @@
// <copyright file="PngImageFormatProvider.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using ImageSharp.PixelFormats;
/// <summary>
/// Registers the image encoders, decoders and mime type detectors for the gif format.
/// </summary>
public class GifConfigurationModule : IConfigurationModule
{
/// <inheritdoc/>
public void Configure(Configuration config)
{
config.SetEncoder(ImageFormats.Gif, new GifEncoder());
config.SetDecoder(ImageFormats.Gif, new GifDecoder());
config.AddImageFormatDetector(new GifImageFormatDetector());
}
}
}

31
src/ImageSharp/Formats/Gif/GifFormat.cs

@ -0,0 +1,31 @@
// <copyright file="GifFormat.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using ImageSharp.PixelFormats;
/// <summary>
/// Registers the image encoders, decoders and mime type detectors for the jpeg format.
/// </summary>
internal sealed class GifFormat : IImageFormat
{
/// <inheritdoc/>
public string Name => "GIF";
/// <inheritdoc/>
public string DefaultMimeType => "image/gif";
/// <inheritdoc/>
public IEnumerable<string> MimeTypes => GifConstants.MimeTypes;
/// <inheritdoc/>
public IEnumerable<string> FileExtensions => GifConstants.FileExtensions;
}
}

8
src/ImageSharp/Formats/Gif/GifMimeTypeDetector.cs → src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs

@ -14,23 +14,23 @@ namespace ImageSharp.Formats
/// <summary> /// <summary>
/// Detects gif file headers /// Detects gif file headers
/// </summary> /// </summary>
public class GifMimeTypeDetector : IMimeTypeDetector public class GifImageFormatDetector : IImageFormatDetector
{ {
/// <inheritdoc/> /// <inheritdoc/>
public int HeaderSize => 6; public int HeaderSize => 6;
/// <inheritdoc/> /// <inheritdoc/>
public string DetectMimeType(Span<byte> header) public IImageFormat DetectFormat(ReadOnlySpan<byte> header)
{ {
if (this.IsSupportedFileFormat(header)) if (this.IsSupportedFileFormat(header))
{ {
return "image/gif"; return ImageFormats.Gif;
} }
return null; return null;
} }
private bool IsSupportedFileFormat(Span<byte> header) private bool IsSupportedFileFormat(ReadOnlySpan<byte> header)
{ {
return header.Length >= this.HeaderSize && return header.Length >= this.HeaderSize &&
header[0] == 0x47 && // G header[0] == 0x47 && // G

45
src/ImageSharp/Formats/Gif/GifImageFormatProvider.cs

@ -1,45 +0,0 @@
// <copyright file="PngImageFormatProvider.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using ImageSharp.PixelFormats;
/// <summary>
/// Registers the image encoders, decoders and mime type detectors for the gif format.
/// </summary>
public class GifImageFormatProvider : IImageFormatProvider
{
/// <inheritdoc/>
public void Configure(IImageFormatHost host)
{
var encoder = new GifEncoder();
foreach (string mimeType in GifConstants.MimeTypes)
{
host.SetMimeTypeEncoder(mimeType, encoder);
}
foreach (string ext in GifConstants.FileExtensions)
{
foreach (string mimeType in GifConstants.MimeTypes)
{
host.SetFileExtensionToMimeTypeMapping(ext, mimeType);
}
}
var decoder = new GifDecoder();
foreach (string mimeType in GifConstants.MimeTypes)
{
host.SetMimeTypeDecoder(mimeType, decoder);
}
host.AddMimeTypeDetector(new GifMimeTypeDetector());
}
}
}

39
src/ImageSharp/Formats/IImageFormat.cs

@ -0,0 +1,39 @@
// <copyright file="IImageFormat.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats
{
using System;
using System.Collections.Generic;
using System.IO;
using ImageSharp.PixelFormats;
/// <summary>
/// Describes an image format.
/// </summary>
public interface IImageFormat
{
/// <summary>
/// Gets the name that describes this image format.
/// </summary>
string Name { get; }
/// <summary>
/// Gets the default mimetype that the image foramt uses
/// </summary>
string DefaultMimeType { get; }
/// <summary>
/// Gets all the mimetypes that have been used by this image foramt.
/// </summary>
IEnumerable<string> MimeTypes { get; }
/// <summary>
/// Gets the file extensions this image format commonly uses.
/// </summary>
IEnumerable<string> FileExtensions { get; }
}
}

6
src/ImageSharp/Formats/IMimeTypeDetector.cs → src/ImageSharp/Formats/IImageFormatDetector.cs

@ -1,4 +1,4 @@
// <copyright file="IMimeTypeDetector.cs" company="James Jackson-South"> // <copyright file="IImageFormatDetector.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors. // Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
@ -12,7 +12,7 @@ namespace ImageSharp.Formats
/// <summary> /// <summary>
/// Used for detecting mime types from a file header /// Used for detecting mime types from a file header
/// </summary> /// </summary>
public interface IMimeTypeDetector public interface IImageFormatDetector
{ {
/// <summary> /// <summary>
/// Gets the size of the header for this image type. /// Gets the size of the header for this image type.
@ -25,6 +25,6 @@ namespace ImageSharp.Formats
/// </summary> /// </summary>
/// <param name="header">The <see cref="T:byte[]"/> containing the file header.</param> /// <param name="header">The <see cref="T:byte[]"/> containing the file header.</param>
/// <returns>returns the mime type of detected othersie returns null</returns> /// <returns>returns the mime type of detected othersie returns null</returns>
string DetectMimeType(Span<byte> header); IImageFormat DetectFormat(ReadOnlySpan<byte> header);
} }
} }

56
src/ImageSharp/Formats/IImageFormatProvider.cs

@ -1,56 +0,0 @@
// <copyright file="IImageFormatProvider.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats
{
using System;
using System.Collections.Generic;
using System.Text;
/// <summary>
/// Represents an interface that can register image encoders, decoders and mime type detectors.
/// </summary>
public interface IImageFormatProvider
{
/// <summary>
/// Called when loaded so the provider and register its encoders, decoders and mime type detectors into an IImageFormatHost.
/// </summary>
/// <param name="host">The host that will retain the encoders, decodes and mime type detectors.</param>
void Configure(IImageFormatHost host);
}
/// <summary>
/// Represents an interface that can have encoders, decoders and mime type detectors loaded into.
/// </summary>
public interface IImageFormatHost
{
/// <summary>
/// Sets a specific image encoder as the encoder for a specific mime type.
/// </summary>
/// <param name="mimeType">the target mimetype</param>
/// <param name="encoder">the encoder to use</param>
void SetMimeTypeEncoder(string mimeType, IImageEncoder encoder); // could/should this be an Action<IImageEncoder>???
/// <summary>
/// Sets a mapping value between a file extension and a mime type.
/// </summary>
/// <param name="extension">The target mime type</param>
/// <param name="mimetype">The mime type this extension equates to</param>
void SetFileExtensionToMimeTypeMapping(string extension, string mimetype);
/// <summary>
/// Sets a specific image decoder as the decoder for a specific mime type.
/// </summary>
/// <param name="mimeType">The target mime type</param>
/// <param name="decoder">The decoder to use</param>
void SetMimeTypeDecoder(string mimeType, IImageDecoder decoder);
/// <summary>
/// Adds a new detector for detecting mime types.
/// </summary>
/// <param name="detector">The detector to add</param>
void AddMimeTypeDetector(IMimeTypeDetector detector);
}
}

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

@ -0,0 +1,28 @@
// <copyright file="PngImageFormatProvider.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using ImageSharp.PixelFormats;
/// <summary>
/// Registers the image encoders, decoders and mime type detectors for the jpeg format.
/// </summary>
public class JpegConfigurationModule : IConfigurationModule
{
/// <inheritdoc/>
public void Configure(Configuration config)
{
config.SetEncoder(ImageFormats.Jpeg, new JpegEncoder());
config.SetDecoder(ImageFormats.Jpeg, new JpegDecoder());
config.AddImageFormatDetector(new JpegImageFormatDetector());
}
}
}

31
src/ImageSharp/Formats/Jpeg/JpegFormat.cs

@ -0,0 +1,31 @@
// <copyright file="JpegFormat.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using ImageSharp.PixelFormats;
/// <summary>
/// Registers the image encoders, decoders and mime type detectors for the jpeg format.
/// </summary>
internal sealed class JpegFormat : IImageFormat
{
/// <inheritdoc/>
public string Name => "JPEG";
/// <inheritdoc/>
public string DefaultMimeType => "image/jpeg";
/// <inheritdoc/>
public IEnumerable<string> MimeTypes => JpegConstants.MimeTypes;
/// <inheritdoc/>
public IEnumerable<string> FileExtensions => JpegConstants.FileExtensions;
}
}

14
src/ImageSharp/Formats/Jpeg/JpegMimeTypeDetector.cs → src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs

@ -14,23 +14,23 @@ namespace ImageSharp.Formats
/// <summary> /// <summary>
/// Detects Jpeg file headers /// Detects Jpeg file headers
/// </summary> /// </summary>
public class JpegMimeTypeDetector : IMimeTypeDetector public class JpegImageFormatDetector : IImageFormatDetector
{ {
/// <inheritdoc/> /// <inheritdoc/>
public int HeaderSize => 11; public int HeaderSize => 11;
/// <inheritdoc/> /// <inheritdoc/>
public string DetectMimeType(Span<byte> header) public IImageFormat DetectFormat(ReadOnlySpan<byte> header)
{ {
if (this.IsSupportedFileFormat(header)) if (this.IsSupportedFileFormat(header))
{ {
return "image/jpeg"; return ImageFormats.Jpeg;
} }
return null; return null;
} }
private bool IsSupportedFileFormat(Span<byte> header) private bool IsSupportedFileFormat(ReadOnlySpan<byte> header)
{ {
return header.Length >= this.HeaderSize && return header.Length >= this.HeaderSize &&
(this.IsJfif(header) || this.IsExif(header) || this.IsJpeg(header)); (this.IsJfif(header) || this.IsExif(header) || this.IsJpeg(header));
@ -41,7 +41,7 @@ namespace ImageSharp.Formats
/// </summary> /// </summary>
/// <param name="header">The bytes representing the file header.</param> /// <param name="header">The bytes representing the file header.</param>
/// <returns>The <see cref="bool"/></returns> /// <returns>The <see cref="bool"/></returns>
private bool IsJfif(Span<byte> header) private bool IsJfif(ReadOnlySpan<byte> header)
{ {
bool isJfif = bool isJfif =
header[6] == 0x4A && // J header[6] == 0x4A && // J
@ -58,7 +58,7 @@ namespace ImageSharp.Formats
/// </summary> /// </summary>
/// <param name="header">The bytes representing the file header.</param> /// <param name="header">The bytes representing the file header.</param>
/// <returns>The <see cref="bool"/></returns> /// <returns>The <see cref="bool"/></returns>
private bool IsExif(Span<byte> header) private bool IsExif(ReadOnlySpan<byte> header)
{ {
bool isExif = bool isExif =
header[6] == 0x45 && // E header[6] == 0x45 && // E
@ -76,7 +76,7 @@ namespace ImageSharp.Formats
/// </summary> /// </summary>
/// <param name="header">The bytes representing the file header.</param> /// <param name="header">The bytes representing the file header.</param>
/// <returns>The <see cref="bool"/></returns> /// <returns>The <see cref="bool"/></returns>
private bool IsJpeg(Span<byte> header) private bool IsJpeg(ReadOnlySpan<byte> header)
{ {
bool isJpg = bool isJpg =
header[0] == 0xFF && // 255 header[0] == 0xFF && // 255

45
src/ImageSharp/Formats/Jpeg/JpegImageFormatProvider.cs

@ -1,45 +0,0 @@
// <copyright file="PngImageFormatProvider.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using ImageSharp.PixelFormats;
/// <summary>
/// Registers the image encoders, decoders and mime type detectors for the jpeg format.
/// </summary>
public class JpegImageFormatProvider : IImageFormatProvider
{
/// <inheritdoc/>
public void Configure(IImageFormatHost host)
{
var pngEncoder = new JpegEncoder();
foreach (string mimeType in JpegConstants.MimeTypes)
{
host.SetMimeTypeEncoder(mimeType, pngEncoder);
}
foreach (string ext in JpegConstants.FileExtensions)
{
foreach (string mimeType in JpegConstants.MimeTypes)
{
host.SetFileExtensionToMimeTypeMapping(ext, mimeType);
}
}
var pngDecoder = new JpegDecoder();
foreach (string mimeType in JpegConstants.MimeTypes)
{
host.SetMimeTypeDecoder(mimeType, pngDecoder);
}
host.AddMimeTypeDetector(new JpegMimeTypeDetector());
}
}
}

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

@ -0,0 +1,27 @@
// <copyright file="PngConfigurationModule.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using ImageSharp.PixelFormats;
/// <summary>
/// Registers the image encoders, decoders and mime type detectors for the png format.
/// </summary>
public class PngConfigurationModule : IConfigurationModule
{
/// <inheritdoc/>
public void Configure(Configuration host)
{
host.SetEncoder(ImageFormats.Png, new PngEncoder());
host.SetDecoder(ImageFormats.Png, new PngDecoder());
host.AddImageFormatDetector(new PngImageFormatDetector());
}
}
}

31
src/ImageSharp/Formats/Png/PngFormat.cs

@ -0,0 +1,31 @@
// <copyright file="PngFormat.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using ImageSharp.PixelFormats;
/// <summary>
/// Registers the image encoders, decoders and mime type detectors for the jpeg format.
/// </summary>
internal sealed class PngFormat : IImageFormat
{
/// <inheritdoc/>
public string Name => "PNG";
/// <inheritdoc/>
public string DefaultMimeType => "image/png";
/// <inheritdoc/>
public IEnumerable<string> MimeTypes => PngConstants.MimeTypes;
/// <inheritdoc/>
public IEnumerable<string> FileExtensions => PngConstants.FileExtensions;
}
}

10
src/ImageSharp/Formats/Png/PngMimeTypeDetector.cs → src/ImageSharp/Formats/Png/PngImageFormatDetector.cs

@ -1,4 +1,4 @@
// <copyright file="PngMimeTypeDetector.cs" company="James Jackson-South"> // <copyright file="PngImageFormatDetector.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors. // Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
@ -14,23 +14,23 @@ namespace ImageSharp.Formats
/// <summary> /// <summary>
/// Detects png file headers /// Detects png file headers
/// </summary> /// </summary>
public class PngMimeTypeDetector : IMimeTypeDetector public class PngImageFormatDetector : IImageFormatDetector
{ {
/// <inheritdoc/> /// <inheritdoc/>
public int HeaderSize => 8; public int HeaderSize => 8;
/// <inheritdoc/> /// <inheritdoc/>
public string DetectMimeType(Span<byte> header) public IImageFormat DetectFormat(ReadOnlySpan<byte> header)
{ {
if (this.IsSupportedFileFormat(header)) if (this.IsSupportedFileFormat(header))
{ {
return "image/png"; return ImageFormats.Png;
} }
return null; return null;
} }
private bool IsSupportedFileFormat(Span<byte> header) private bool IsSupportedFileFormat(ReadOnlySpan<byte> header)
{ {
return header.Length >= this.HeaderSize && return header.Length >= this.HeaderSize &&
header[0] == 0x89 && header[0] == 0x89 &&

45
src/ImageSharp/Formats/Png/PngImageFormatProvider.cs

@ -1,45 +0,0 @@
// <copyright file="PngImageFormatProvider.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using ImageSharp.PixelFormats;
/// <summary>
/// Registers the image encoders, decoders and mime type detectors for the png format.
/// </summary>
public class PngImageFormatProvider : IImageFormatProvider
{
/// <inheritdoc/>
public void Configure(IImageFormatHost host)
{
var pngEncoder = new PngEncoder();
foreach (string mimeType in PngConstants.MimeTypes)
{
host.SetMimeTypeEncoder(mimeType, pngEncoder);
}
foreach (string ext in PngConstants.FileExtensions)
{
foreach (string mimeType in PngConstants.MimeTypes)
{
host.SetFileExtensionToMimeTypeMapping(ext, mimeType);
}
}
var pngDecoder = new PngDecoder();
foreach (string mimeType in PngConstants.MimeTypes)
{
host.SetMimeTypeDecoder(mimeType, pngDecoder);
}
host.AddMimeTypeDetector(new PngMimeTypeDetector());
}
}
}

23
src/ImageSharp/IConfigurationModule.cs

@ -0,0 +1,23 @@
// <copyright file="IConfigurationModule.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.Collections.Generic;
using System.Text;
/// <summary>
/// Represents an interface that can register image encoders, decoders and image format detectors.
/// </summary>
public interface IConfigurationModule
{
/// <summary>
/// Called when loaded into a configuration object so the module can register items into the configuration.
/// </summary>
/// <param name="configuration">The configuration that will retain the encoders, decodes and mime type detectors.</param>
void Configure(Configuration configuration);
}
}

31
src/ImageSharp/Image/Image.Decode.cs

@ -9,7 +9,7 @@ namespace ImageSharp
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Formats; using Formats;
using ImageSharp.Memory;
using ImageSharp.PixelFormats; using ImageSharp.PixelFormats;
/// <content> /// <content>
@ -23,7 +23,7 @@ namespace ImageSharp
/// <param name="stream">The image stream to read the header from.</param> /// <param name="stream">The image stream to read the header from.</param>
/// <param name="config">The configuration.</param> /// <param name="config">The configuration.</param>
/// <returns>The mime type or null if none found.</returns> /// <returns>The mime type or null if none found.</returns>
private static string InternalDiscoverMimeType(Stream stream, Configuration config) private static IImageFormat InternalDetectFormat(Stream stream, Configuration config)
{ {
// This is probably a candidate for making into a public API in the future! // This is probably a candidate for making into a public API in the future!
int maxHeaderSize = config.MaxHeaderSize; int maxHeaderSize = config.MaxHeaderSize;
@ -32,17 +32,12 @@ namespace ImageSharp
return null; return null;
} }
byte[] header = ArrayPool<byte>.Shared.Rent(maxHeaderSize); using (var buffer = new Buffer<byte>(maxHeaderSize))
try
{ {
long startPosition = stream.Position; long startPosition = stream.Position;
stream.Read(header, 0, maxHeaderSize); stream.Read(buffer.Array, 0, maxHeaderSize);
stream.Position = startPosition; stream.Position = startPosition;
return config.MimeTypeDetectors.Select(x => x.DetectMimeType(header)).LastOrDefault(x => x != null); return config.FormatDetectors.Select(x => x.DetectFormat(buffer)).LastOrDefault(x => x != null);
}
finally
{
ArrayPool<byte>.Shared.Return(header);
} }
} }
@ -51,14 +46,14 @@ namespace ImageSharp
/// </summary> /// </summary>
/// <param name="stream">The image stream to read the header from.</param> /// <param name="stream">The image stream to read the header from.</param>
/// <param name="config">The configuration.</param> /// <param name="config">The configuration.</param>
/// <param name="mimeType">The mimeType.</param> /// <param name="format">The IImageFormat.</param>
/// <returns>The image format or null if none found.</returns> /// <returns>The image format or null if none found.</returns>
private static IImageDecoder DiscoverDecoder(Stream stream, Configuration config, out string mimeType) private static IImageDecoder DiscoverDecoder(Stream stream, Configuration config, out IImageFormat format)
{ {
mimeType = InternalDiscoverMimeType(stream, config); format = InternalDetectFormat(stream, config);
if (mimeType != null) if (format != null)
{ {
return config.FindMimeTypeDecoder(mimeType); return config.FindDecoder(format);
} }
return null; return null;
@ -74,18 +69,18 @@ namespace ImageSharp
/// <returns> /// <returns>
/// A new <see cref="Image{TPixel}"/>. /// A new <see cref="Image{TPixel}"/>.
/// </returns> /// </returns>
private static (Image<TPixel> img, string mimeType) Decode<TPixel>(Stream stream, Configuration config) private static (Image<TPixel> img, IImageFormat format) Decode<TPixel>(Stream stream, Configuration config)
#pragma warning restore SA1008 // Opening parenthesis must be spaced correctly #pragma warning restore SA1008 // Opening parenthesis must be spaced correctly
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
IImageDecoder decoder = DiscoverDecoder(stream, config, out string mimeType); IImageDecoder decoder = DiscoverDecoder(stream, config, out IImageFormat format);
if (decoder == null) if (decoder == null)
{ {
return (null, null); return (null, null);
} }
Image<TPixel> img = decoder.Decode<TPixel>(config, stream); Image<TPixel> img = decoder.Decode<TPixel>(config, stream);
return (img, mimeType); return (img, format);
} }
} }
} }

34
src/ImageSharp/Image/Image.FromBytes.cs

@ -16,26 +16,26 @@ namespace ImageSharp
public static partial class Image public static partial class Image
{ {
/// <summary> /// <summary>
/// By reading the header on the provided byte array this calculates the images mime type. /// By reading the header on the provided byte array this calculates the images format.
/// </summary> /// </summary>
/// <param name="data">The byte array containing image data to read the header from.</param> /// <param name="data">The byte array containing image data to read the header from.</param>
/// <returns>The mime type or null if none found.</returns> /// <returns>The format or null if none found.</returns>
public static string DiscoverMimeType(byte[] data) public static IImageFormat DetectFormat(byte[] data)
{ {
return DiscoverMimeType(null, data); return DetectFormat(null, data);
} }
/// <summary> /// <summary>
/// By reading the header on the provided byte array this calculates the images mime type. /// By reading the header on the provided byte array this calculates the images format.
/// </summary> /// </summary>
/// <param name="config">The configuration.</param> /// <param name="config">The configuration.</param>
/// <param name="data">The byte array containing image data to read the header from.</param> /// <param name="data">The byte array containing image data to read the header from.</param>
/// <returns>The mime type or null if none found.</returns> /// <returns>The mime type or null if none found.</returns>
public static string DiscoverMimeType(Configuration config, byte[] data) public static IImageFormat DetectFormat(Configuration config, byte[] data)
{ {
using (Stream stream = new MemoryStream(data)) using (Stream stream = new MemoryStream(data))
{ {
return DiscoverMimeType(config, stream); return DetectFormat(config, stream);
} }
} }
@ -50,9 +50,9 @@ namespace ImageSharp
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given byte array. /// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given byte array.
/// </summary> /// </summary>
/// <param name="data">The byte array containing image data.</param> /// <param name="data">The byte array containing image data.</param>
/// <param name="mimeType">The mime type of the decoded image.</param> /// <param name="format">The mime type of the decoded image.</param>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns> /// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(byte[] data, out string mimeType) => Load<Rgba32>(null, data, out mimeType); public static Image<Rgba32> Load(byte[] data, out IImageFormat format) => Load<Rgba32>(null, data, out format);
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given byte array. /// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given byte array.
@ -67,9 +67,9 @@ namespace ImageSharp
/// </summary> /// </summary>
/// <param name="config">The config for the decoder.</param> /// <param name="config">The config for the decoder.</param>
/// <param name="data">The byte array containing image data.</param> /// <param name="data">The byte array containing image data.</param>
/// <param name="mimeType">The mime type of the decoded image.</param> /// <param name="format">The mime type of the decoded image.</param>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns> /// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(Configuration config, byte[] data, out string mimeType) => Load<Rgba32>(config, data, out mimeType); public static Image<Rgba32> Load(Configuration config, byte[] data, out IImageFormat format) => Load<Rgba32>(config, data, out format);
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given byte array. /// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given byte array.
@ -104,13 +104,13 @@ namespace ImageSharp
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given byte array. /// Create a new instance of the <see cref="Image{TPixel}"/> class from the given byte array.
/// </summary> /// </summary>
/// <param name="data">The byte array containing image data.</param> /// <param name="data">The byte array containing image data.</param>
/// <param name="mimeType">The mime type of the decoded image.</param> /// <param name="format">The mime type of the decoded image.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns> /// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(byte[] data, out string mimeType) public static Image<TPixel> Load<TPixel>(byte[] data, out IImageFormat format)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
return Load<TPixel>(null, data, out mimeType); return Load<TPixel>(null, data, out format);
} }
/// <summary> /// <summary>
@ -134,15 +134,15 @@ namespace ImageSharp
/// </summary> /// </summary>
/// <param name="config">The configuration options.</param> /// <param name="config">The configuration options.</param>
/// <param name="data">The byte array containing image data.</param> /// <param name="data">The byte array containing image data.</param>
/// <param name="mimeType">The mime type of the decoded image.</param> /// <param name="format">The mime type of the decoded image.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns> /// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(Configuration config, byte[] data, out string mimeType) public static Image<TPixel> Load<TPixel>(Configuration config, byte[] data, out IImageFormat format)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
using (var memoryStream = new MemoryStream(data)) using (var memoryStream = new MemoryStream(data))
{ {
return Load<TPixel>(config, memoryStream, out mimeType); return Load<TPixel>(config, memoryStream, out format);
} }
} }

28
src/ImageSharp/Image/Image.FromFile.cs

@ -21,9 +21,9 @@ namespace ImageSharp
/// </summary> /// </summary>
/// <param name="filePath">The image file to open and to read the header from.</param> /// <param name="filePath">The image file to open and to read the header from.</param>
/// <returns>The mime type or null if none found.</returns> /// <returns>The mime type or null if none found.</returns>
public static string DiscoverMimeType(string filePath) public static IImageFormat DetectFormat(string filePath)
{ {
return DiscoverMimeType(null, filePath); return DetectFormat(null, filePath);
} }
/// <summary> /// <summary>
@ -32,12 +32,12 @@ namespace ImageSharp
/// <param name="config">The configuration.</param> /// <param name="config">The configuration.</param>
/// <param name="filePath">The image file to open and to read the header from.</param> /// <param name="filePath">The image file to open and to read the header from.</param>
/// <returns>The mime type or null if none found.</returns> /// <returns>The mime type or null if none found.</returns>
public static string DiscoverMimeType(Configuration config, string filePath) public static IImageFormat DetectFormat(Configuration config, string filePath)
{ {
config = config ?? Configuration.Default; config = config ?? Configuration.Default;
using (Stream file = config.FileSystem.OpenRead(filePath)) using (Stream file = config.FileSystem.OpenRead(filePath))
{ {
return DiscoverMimeType(config, file); return DetectFormat(config, file);
} }
} }
@ -55,12 +55,12 @@ namespace ImageSharp
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given file. /// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given file.
/// </summary> /// </summary>
/// <param name="path">The file path to the image.</param> /// <param name="path">The file path to the image.</param>
/// <param name="mimeType">The mime type of the decoded image.</param> /// <param name="format">The mime type of the decoded image.</param>
/// <exception cref="NotSupportedException"> /// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable. /// Thrown if the stream is not readable nor seekable.
/// </exception> /// </exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns> /// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(string path, out string mimeType) => Load<Rgba32>(path, out mimeType); public static Image<Rgba32> Load(string path, out IImageFormat format) => Load<Rgba32>(path, out format);
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given file. /// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given file.
@ -78,12 +78,12 @@ namespace ImageSharp
/// </summary> /// </summary>
/// <param name="config">The config for the decoder.</param> /// <param name="config">The config for the decoder.</param>
/// <param name="path">The file path to the image.</param> /// <param name="path">The file path to the image.</param>
/// <param name="mimeType">The mime type of the decoded image.</param> /// <param name="format">The mime type of the decoded image.</param>
/// <exception cref="NotSupportedException"> /// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable. /// Thrown if the stream is not readable nor seekable.
/// </exception> /// </exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns> /// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(Configuration config, string path, out string mimeType) => Load<Rgba32>(config, path, out mimeType); public static Image<Rgba32> Load(Configuration config, string path, out IImageFormat format) => Load<Rgba32>(config, path, out format);
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given file. /// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given file.
@ -127,16 +127,16 @@ namespace ImageSharp
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given file. /// Create a new instance of the <see cref="Image{TPixel}"/> class from the given file.
/// </summary> /// </summary>
/// <param name="path">The file path to the image.</param> /// <param name="path">The file path to the image.</param>
/// <param name="mimeType">The mime type of the decoded image.</param> /// <param name="format">The mime type of the decoded image.</param>
/// <exception cref="NotSupportedException"> /// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable. /// Thrown if the stream is not readable nor seekable.
/// </exception> /// </exception>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns> /// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(string path, out string mimeType) public static Image<TPixel> Load<TPixel>(string path, out IImageFormat format)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
return Load<TPixel>(null, path, out mimeType); return Load<TPixel>(null, path, out format);
} }
/// <summary> /// <summary>
@ -164,19 +164,19 @@ namespace ImageSharp
/// </summary> /// </summary>
/// <param name="config">The configuration options.</param> /// <param name="config">The configuration options.</param>
/// <param name="path">The file path to the image.</param> /// <param name="path">The file path to the image.</param>
/// <param name="mimeType">The mime type of the decoded image.</param> /// <param name="format">The mime type of the decoded image.</param>
/// <exception cref="NotSupportedException"> /// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable. /// Thrown if the stream is not readable nor seekable.
/// </exception> /// </exception>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns> /// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(Configuration config, string path, out string mimeType) public static Image<TPixel> Load<TPixel>(Configuration config, string path, out IImageFormat format)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
config = config ?? Configuration.Default; config = config ?? Configuration.Default;
using (Stream stream = config.FileSystem.OpenRead(path)) using (Stream stream = config.FileSystem.OpenRead(path))
{ {
return Load<TPixel>(config, stream, out mimeType); return Load<TPixel>(config, stream, out format);
} }
} }

36
src/ImageSharp/Image/Image.FromStream.cs

@ -24,9 +24,9 @@ namespace ImageSharp
/// </summary> /// </summary>
/// <param name="stream">The image stream to read the header from.</param> /// <param name="stream">The image stream to read the header from.</param>
/// <returns>The mime type or null if none found.</returns> /// <returns>The mime type or null if none found.</returns>
public static string DiscoverMimeType(Stream stream) public static IImageFormat DetectFormat(Stream stream)
{ {
return DiscoverMimeType(null, stream); return DetectFormat(null, stream);
} }
/// <summary> /// <summary>
@ -35,21 +35,21 @@ namespace ImageSharp
/// <param name="config">The configuration.</param> /// <param name="config">The configuration.</param>
/// <param name="stream">The image stream to read the header from.</param> /// <param name="stream">The image stream to read the header from.</param>
/// <returns>The mime type or null if none found.</returns> /// <returns>The mime type or null if none found.</returns>
public static string DiscoverMimeType(Configuration config, Stream stream) public static IImageFormat DetectFormat(Configuration config, Stream stream)
{ {
return WithSeekableStream(stream, s => InternalDiscoverMimeType(s, config ?? Configuration.Default)); return WithSeekableStream(stream, s => InternalDetectFormat(s, config ?? Configuration.Default));
} }
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given stream. /// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given stream.
/// </summary> /// </summary>
/// <param name="stream">The stream containing image information.</param> /// <param name="stream">The stream containing image information.</param>
/// <param name="mimeType">the mime type of the decoded image.</param> /// <param name="format">the mime type of the decoded image.</param>
/// <exception cref="NotSupportedException"> /// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable. /// Thrown if the stream is not readable nor seekable.
/// </exception> /// </exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>> /// <returns>A new <see cref="Image{Rgba32}"/>.</returns>>
public static Image<Rgba32> Load(Stream stream, out string mimeType) => Load<Rgba32>(stream, out mimeType); public static Image<Rgba32> Load(Stream stream, out IImageFormat format) => Load<Rgba32>(stream, out format);
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given stream. /// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given stream.
@ -88,12 +88,12 @@ namespace ImageSharp
/// </summary> /// </summary>
/// <param name="config">The config for the decoder.</param> /// <param name="config">The config for the decoder.</param>
/// <param name="stream">The stream containing image information.</param> /// <param name="stream">The stream containing image information.</param>
/// <param name="mimeType">the mime type of the decoded image.</param> /// <param name="format">the mime type of the decoded image.</param>
/// <exception cref="NotSupportedException"> /// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable. /// Thrown if the stream is not readable nor seekable.
/// </exception> /// </exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>> /// <returns>A new <see cref="Image{Rgba32}"/>.</returns>>
public static Image<Rgba32> Load(Configuration config, Stream stream, out string mimeType) => Load<Rgba32>(config, stream, out mimeType); public static Image<Rgba32> Load(Configuration config, Stream stream, out IImageFormat format) => Load<Rgba32>(config, stream, out format);
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream. /// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
@ -114,16 +114,16 @@ namespace ImageSharp
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream. /// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
/// </summary> /// </summary>
/// <param name="stream">The stream containing image information.</param> /// <param name="stream">The stream containing image information.</param>
/// <param name="mimeType">the mime type of the decoded image.</param> /// <param name="format">the mime type of the decoded image.</param>
/// <exception cref="NotSupportedException"> /// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable. /// Thrown if the stream is not readable nor seekable.
/// </exception> /// </exception>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>> /// <returns>A new <see cref="Image{TPixel}"/>.</returns>>
public static Image<TPixel> Load<TPixel>(Stream stream, out string mimeType) public static Image<TPixel> Load<TPixel>(Stream stream, out IImageFormat format)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
return Load<TPixel>(null, stream, out mimeType); return Load<TPixel>(null, stream, out format);
} }
/// <summary> /// <summary>
@ -180,20 +180,20 @@ namespace ImageSharp
/// </summary> /// </summary>
/// <param name="config">The configuration options.</param> /// <param name="config">The configuration options.</param>
/// <param name="stream">The stream containing image information.</param> /// <param name="stream">The stream containing image information.</param>
/// <param name="mimeType">the mime type of the decoded image.</param> /// <param name="format">the mime type of the decoded image.</param>
/// <exception cref="NotSupportedException"> /// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable. /// Thrown if the stream is not readable nor seekable.
/// </exception> /// </exception>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>> /// <returns>A new <see cref="Image{TPixel}"/>.</returns>>
public static Image<TPixel> Load<TPixel>(Configuration config, Stream stream, out string mimeType) public static Image<TPixel> Load<TPixel>(Configuration config, Stream stream, out IImageFormat format)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
config = config ?? Configuration.Default; config = config ?? Configuration.Default;
mimeType = null; format = null;
(Image<TPixel> img, string mimeType) data = WithSeekableStream(stream, s => Decode<TPixel>(s, config)); (Image<TPixel> img, IImageFormat format) data = WithSeekableStream(stream, s => Decode<TPixel>(s, config));
mimeType = data.mimeType; format = data.format;
if (data.img != null) if (data.img != null)
{ {
@ -203,9 +203,9 @@ namespace 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<string, IImageDecoder> val in config.ImageDecoders) foreach (KeyValuePair<IImageFormat, IImageDecoder> val in config.ImageDecoders)
{ {
stringBuilder.AppendLine($" - {val.Key} : {val.Value.GetType().Name}"); stringBuilder.AppendLine($" - {val.Key.Name} : {val.Value.GetType().Name}");
} }
throw new NotSupportedException(stringBuilder.ToString()); throw new NotSupportedException(stringBuilder.ToString());

52
src/ImageSharp/Image/Image{TPixel}.cs

@ -152,22 +152,22 @@ namespace ImageSharp
/// Saves the image to the given stream using the currently loaded image format. /// Saves the image to the given stream using the currently loaded image format.
/// </summary> /// </summary>
/// <param name="stream">The stream to save the image to.</param> /// <param name="stream">The stream to save the image to.</param>
/// <param name="mimeType">The mime type to save the image to.</param> /// <param name="format">The format to save the image to.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception> /// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
/// <returns>The <see cref="Image{TPixel}"/></returns> /// <returns>The <see cref="Image{TPixel}"/></returns>
public Image<TPixel> Save(Stream stream, string mimeType) public Image<TPixel> Save(Stream stream, IImageFormat format)
{ {
Guard.NotNullOrEmpty(mimeType, nameof(mimeType)); Guard.NotNull(format, nameof(format));
IImageEncoder encoder = this.Configuration.FindMimeTypeEncoder(mimeType); IImageEncoder encoder = this.Configuration.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<string, IImageEncoder> val in this.Configuration.ImageEncoders) foreach (KeyValuePair<IImageFormat, IImageEncoder> val in this.Configuration.ImageEncoders)
{ {
stringBuilder.AppendLine($" - {val.Key} : {val.Value.GetType().Name}"); stringBuilder.AppendLine($" - {val.Key.Name} : {val.Value.GetType().Name}");
} }
throw new NotSupportedException(stringBuilder.ToString()); throw new NotSupportedException(stringBuilder.ToString());
@ -207,26 +207,28 @@ namespace ImageSharp
Guard.NotNullOrEmpty(filePath, nameof(filePath)); Guard.NotNullOrEmpty(filePath, nameof(filePath));
string ext = Path.GetExtension(filePath).Trim('.'); string ext = Path.GetExtension(filePath).Trim('.');
IImageEncoder encoder = this.Configuration.FindFileExtensionsEncoder(ext); var format = this.Configuration.FindFormatByFileExtensions(ext);
if (encoder == null) if (format == null)
{ {
var stringBuilder = new StringBuilder(); var stringBuilder = new StringBuilder();
string mime = this.Configuration.FindFileExtensionsMimeType(ext); stringBuilder.AppendLine($"Can't find a format that is associated with the file extention '{ext}'. Registered formats with there extensions include:");
if (mime == null) foreach (IImageFormat fmt in this.Configuration.ImageFormats)
{ {
stringBuilder.AppendLine($"Can't find a mime type for the file extention '{ext}'. Registered file extension maps include:"); stringBuilder.AppendLine($" - {fmt.Name} : {string.Join(", ", fmt.FileExtensions)}");
foreach (KeyValuePair<string, string> map in this.Configuration.ImageExtensionToMimeTypeMapping)
{
stringBuilder.AppendLine($" - {map.Key} : {map.Value}");
}
} }
else
throw new NotSupportedException(stringBuilder.ToString());
}
IImageEncoder encoder = this.Configuration.FindEncoder(format);
if (encoder == null)
{
var stringBuilder = new StringBuilder();
stringBuilder.AppendLine($"Can't find encoder for file extention '{ext}' using image format '{format.Name}'. Registered encoders include:");
foreach (KeyValuePair<IImageFormat, IImageEncoder> enc in this.Configuration.ImageEncoders)
{ {
stringBuilder.AppendLine($"Can't find encoder for file extention '{ext}' using mime type '{mime}'. Registered encoders include:"); stringBuilder.AppendLine($" - {enc.Key} : {enc.Value.GetType().Name}");
foreach (KeyValuePair<string, IImageEncoder> enc in this.Configuration.ImageEncoders)
{
stringBuilder.AppendLine($" - {enc.Key} : {enc.Value.GetType().Name}");
}
} }
throw new NotSupportedException(stringBuilder.ToString()); throw new NotSupportedException(stringBuilder.ToString());
@ -262,15 +264,15 @@ namespace ImageSharp
/// Returns a Base64 encoded string from the given image. /// Returns a Base64 encoded string from the given image.
/// </summary> /// </summary>
/// <example><see href="data:image/gif;base64,R0lGODlhAQABAIABAEdJRgAAACwAAAAAAQABAAACAkQBAA=="/></example> /// <example><see href="data:image/gif;base64,R0lGODlhAQABAIABAEdJRgAAACwAAAAAAQABAAACAkQBAA=="/></example>
/// <param name="mimeType">The mimeType.</param> /// <param name="format">The format.</param>
/// <returns>The <see cref="string"/></returns> /// <returns>The <see cref="string"/></returns>
public string ToBase64String(string mimeType) public string ToBase64String(IImageFormat format)
{ {
using (var stream = new MemoryStream()) using (var stream = new MemoryStream())
{ {
this.Save(stream, mimeType); this.Save(stream, format);
stream.Flush(); stream.Flush();
return $"data:{mimeType};base64,{Convert.ToBase64String(stream.ToArray())}"; return $"data:{format.DefaultMimeType};base64,{Convert.ToBase64String(stream.ToArray())}";
} }
} }

39
src/ImageSharp/ImageFormats.cs

@ -0,0 +1,39 @@
// <copyright file="IImageFormat.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.Collections.Generic;
using System.IO;
using ImageSharp.Formats;
using ImageSharp.PixelFormats;
/// <summary>
/// The static collection of all the default image formats
/// </summary>
public static class ImageFormats
{
/// <summary>
/// The format details for the jpegs.
/// </summary>
public static readonly IImageFormat Jpeg = new JpegFormat();
/// <summary>
/// The format details for the pngs.
/// </summary>
public static readonly IImageFormat Png = new PngFormat();
/// <summary>
/// The format details for the gifs.
/// </summary>
public static readonly IImageFormat Gif = new GifFormat();
/// <summary>
/// The format details for the bitmaps.
/// </summary>
public static readonly IImageFormat Bitmap = new BmpFormat();
}
}

10
src/ImageSharp/Memory/Buffer.cs

@ -115,6 +115,16 @@ namespace ImageSharp.Memory
} }
} }
/// <summary>
/// Converts <see cref="Buffer{T}"/> to an <see cref="ReadOnlySpan{T}"/>.
/// </summary>
/// <param name="buffer">The <see cref="Buffer{T}"/> to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator ReadOnlySpan<T>(Buffer<T> buffer)
{
return new ReadOnlySpan<T>(buffer.Array, 0, buffer.Length);
}
/// <summary> /// <summary>
/// Converts <see cref="Buffer{T}"/> to an <see cref="Span{T}"/>. /// Converts <see cref="Buffer{T}"/> to an <see cref="Span{T}"/>.
/// </summary> /// </summary>

76
tests/ImageSharp.Tests/ConfigurationTests.cs

@ -40,8 +40,8 @@ namespace ImageSharp.Tests
[Fact] [Fact]
public void IfAutoloadWellknwonFormatesIsTrueAllFormateAreLoaded() public void IfAutoloadWellknwonFormatesIsTrueAllFormateAreLoaded()
{ {
Assert.Equal(6, DefaultConfiguration.ImageEncoders.Count()); Assert.Equal(4, DefaultConfiguration.ImageEncoders.Count());
Assert.Equal(6, DefaultConfiguration.ImageDecoders.Count()); Assert.Equal(4, DefaultConfiguration.ImageDecoders.Count());
} }
/// <summary> /// <summary>
@ -73,11 +73,11 @@ namespace ImageSharp.Tests
} }
[Fact] [Fact]
public void AddMimeTypeDetectorNullthrows() public void AddImageFormatDetectorNullthrows()
{ {
Assert.Throws<ArgumentNullException>(() => Assert.Throws<ArgumentNullException>(() =>
{ {
DefaultConfiguration.AddMimeTypeDetector(null); DefaultConfiguration.AddImageFormatDetector(null);
}); });
} }
@ -86,49 +86,32 @@ namespace ImageSharp.Tests
{ {
Assert.Throws<ArgumentNullException>(() => Assert.Throws<ArgumentNullException>(() =>
{ {
DefaultConfiguration.SetMimeTypeEncoder(null, new Mock<IImageEncoder>().Object); DefaultConfiguration.SetEncoder(null, new Mock<IImageEncoder>().Object);
}); });
Assert.Throws<ArgumentNullException>(() => Assert.Throws<ArgumentNullException>(() =>
{ {
DefaultConfiguration.SetMimeTypeEncoder("sdsdsd", null); DefaultConfiguration.SetEncoder(ImageFormats.Bitmap, null);
}); });
Assert.Throws<ArgumentNullException>(() => Assert.Throws<ArgumentNullException>(() =>
{ {
DefaultConfiguration.SetMimeTypeEncoder(null, null); DefaultConfiguration.SetEncoder(null, null);
}); });
} }
[Fact] [Fact]
public void RegisterNullFileExtEncoder() public void RegisterNullSetDecoder()
{ {
Assert.Throws<ArgumentNullException>(() => Assert.Throws<ArgumentNullException>(() =>
{ {
DefaultConfiguration.SetFileExtensionToMimeTypeMapping(null, "str"); DefaultConfiguration.SetDecoder(null, new Mock<IImageDecoder>().Object);
}); });
Assert.Throws<ArgumentNullException>(() => Assert.Throws<ArgumentNullException>(() =>
{ {
DefaultConfiguration.SetFileExtensionToMimeTypeMapping("sdsdsd", null); DefaultConfiguration.SetDecoder(ImageFormats.Bitmap, null);
}); });
Assert.Throws<ArgumentNullException>(() => Assert.Throws<ArgumentNullException>(() =>
{ {
DefaultConfiguration.SetFileExtensionToMimeTypeMapping(null, null); DefaultConfiguration.SetDecoder(null, null);
});
}
[Fact]
public void RegisterNullMimeTypeDecoder()
{
Assert.Throws<ArgumentNullException>(() =>
{
DefaultConfiguration.SetMimeTypeDecoder(null, new Mock<IImageDecoder>().Object);
});
Assert.Throws<ArgumentNullException>(() =>
{
DefaultConfiguration.SetMimeTypeDecoder("sdsdsd", null);
});
Assert.Throws<ArgumentNullException>(() =>
{
DefaultConfiguration.SetMimeTypeDecoder(null, null);
}); });
} }
@ -136,28 +119,13 @@ namespace ImageSharp.Tests
public void RegisterMimeTypeEncoderReplacesLast() public void RegisterMimeTypeEncoderReplacesLast()
{ {
var encoder1 = new Mock<IImageEncoder>().Object; var encoder1 = new Mock<IImageEncoder>().Object;
ConfigurationEmpty.SetMimeTypeEncoder("test", encoder1); ConfigurationEmpty.SetEncoder(TestFormat.GlobalTestFormat, encoder1);
var found = ConfigurationEmpty.FindMimeTypeEncoder("TEST"); var found = ConfigurationEmpty.FindEncoder(TestFormat.GlobalTestFormat);
Assert.Equal(encoder1, found); Assert.Equal(encoder1, found);
var encoder2 = new Mock<IImageEncoder>().Object; var encoder2 = new Mock<IImageEncoder>().Object;
ConfigurationEmpty.SetMimeTypeEncoder("TEST", encoder2); ConfigurationEmpty.SetEncoder(TestFormat.GlobalTestFormat, encoder2);
var found2 = ConfigurationEmpty.FindMimeTypeEncoder("test"); var found2 = ConfigurationEmpty.FindEncoder(TestFormat.GlobalTestFormat);
Assert.Equal(encoder2, found2);
Assert.NotEqual(found, found2);
}
[Fact]
public void RegisterFileExtEnecoderReplacesLast()
{
var encoder1 = "mime1";
ConfigurationEmpty.SetFileExtensionToMimeTypeMapping("TEST", encoder1);
var found = ConfigurationEmpty.FindFileExtensionsMimeType("test");
Assert.Equal(encoder1, found);
var encoder2 = "mime2";
ConfigurationEmpty.SetFileExtensionToMimeTypeMapping("test", encoder2);
var found2 = ConfigurationEmpty.FindFileExtensionsMimeType("TEST");
Assert.Equal(encoder2, found2); Assert.Equal(encoder2, found2);
Assert.NotEqual(found, found2); Assert.NotEqual(found, found2);
} }
@ -166,13 +134,13 @@ namespace ImageSharp.Tests
public void RegisterMimeTypeDecoderReplacesLast() public void RegisterMimeTypeDecoderReplacesLast()
{ {
var decoder1 = new Mock<IImageDecoder>().Object; var decoder1 = new Mock<IImageDecoder>().Object;
ConfigurationEmpty.SetMimeTypeDecoder("test", decoder1); ConfigurationEmpty.SetDecoder(TestFormat.GlobalTestFormat, decoder1);
var found = ConfigurationEmpty.FindMimeTypeDecoder("TEST"); var found = ConfigurationEmpty.FindDecoder(TestFormat.GlobalTestFormat);
Assert.Equal(decoder1, found); Assert.Equal(decoder1, found);
var decoder2 = new Mock<IImageDecoder>().Object; var decoder2 = new Mock<IImageDecoder>().Object;
ConfigurationEmpty.SetMimeTypeDecoder("TEST", decoder2); ConfigurationEmpty.SetDecoder(TestFormat.GlobalTestFormat, decoder2);
var found2 = ConfigurationEmpty.FindMimeTypeDecoder("test"); var found2 = ConfigurationEmpty.FindDecoder(TestFormat.GlobalTestFormat);
Assert.Equal(decoder2, found2); Assert.Equal(decoder2, found2);
Assert.NotEqual(found, found2); Assert.NotEqual(found, found2);
} }
@ -181,7 +149,7 @@ namespace ImageSharp.Tests
[Fact] [Fact]
public void ConstructorCallConfigureOnFormatProvider() public void ConstructorCallConfigureOnFormatProvider()
{ {
var provider = new Mock<IImageFormatProvider>(); var provider = new Mock<IConfigurationModule>();
var config = new Configuration(provider.Object); var config = new Configuration(provider.Object);
provider.Verify(x => x.Configure(config)); provider.Verify(x => x.Configure(config));
@ -190,9 +158,9 @@ namespace ImageSharp.Tests
[Fact] [Fact]
public void AddFormatCallsConfig() public void AddFormatCallsConfig()
{ {
var provider = new Mock<IImageFormatProvider>(); var provider = new Mock<IConfigurationModule>();
var config = new Configuration(); var config = new Configuration();
config.AddImageFormat(provider.Object); config.Configure(provider.Object);
provider.Verify(x => x.Configure(config)); provider.Verify(x => x.Configure(config));
} }

6
tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs

@ -6,7 +6,7 @@
namespace ImageSharp.Tests namespace ImageSharp.Tests
{ {
using System.IO; using System.IO;
using ImageSharp.Formats;
using ImageSharp.PixelFormats; using ImageSharp.PixelFormats;
using Xunit; using Xunit;
@ -36,7 +36,7 @@ namespace ImageSharp.Tests
using (Image<Rgba32> image = file.CreateImage()) using (Image<Rgba32> image = file.CreateImage())
{ {
string filename = path + "/" + file.FileNameWithoutExtension + ".txt"; string filename = path + "/" + file.FileNameWithoutExtension + ".txt";
File.WriteAllText(filename, image.ToBase64String("image/png")); File.WriteAllText(filename, image.ToBase64String(ImageFormats.Png));
} }
} }
} }
@ -135,7 +135,7 @@ namespace ImageSharp.Tests
foreach (TestFile file in Files) foreach (TestFile file in Files)
{ {
byte[] serialized; byte[] serialized;
using (Image<Rgba32> image = Image.Load(file.Bytes, out string mimeType)) using (Image<Rgba32> image = Image.Load(file.Bytes, out IImageFormat mimeType))
using (MemoryStream memoryStream = new MemoryStream()) using (MemoryStream memoryStream = new MemoryStream())
{ {
image.Save(memoryStream, mimeType); image.Save(memoryStream, mimeType);

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

@ -17,23 +17,27 @@ namespace ImageSharp.Tests
/// <summary> /// <summary>
/// Tests the <see cref="Image"/> class. /// Tests the <see cref="Image"/> class.
/// </summary> /// </summary>
public class DiscoverMimeTypeTests public class DiscoverImageFormatTests
{ {
private readonly Mock<IFileSystem> fileSystem; private readonly Mock<IFileSystem> fileSystem;
private readonly string FilePath; private readonly string FilePath;
private readonly Mock<IMimeTypeDetector> localMimeTypeDetector; private readonly Mock<IImageFormatDetector> localMimeTypeDetector;
private readonly Mock<IImageFormat> localImageFormatMock;
public IImageFormat localImageFormat => localImageFormatMock.Object;
public Configuration LocalConfiguration { get; private set; } public Configuration LocalConfiguration { get; private set; }
public byte[] Marker { get; private set; } public byte[] Marker { get; private set; }
public MemoryStream DataStream { get; private set; } public MemoryStream DataStream { get; private set; }
public byte[] DecodedData { get; private set; } public byte[] DecodedData { get; private set; }
private const string localMimeType = "image/local"; private const string localMimeType = "image/local";
public DiscoverMimeTypeTests() public DiscoverImageFormatTests()
{ {
this.localMimeTypeDetector = new Mock<IMimeTypeDetector>(); this.localImageFormatMock = new Mock<IImageFormat>();
this.localMimeTypeDetector = new Mock<IImageFormatDetector>();
this.localMimeTypeDetector.Setup(x => x.HeaderSize).Returns(1); this.localMimeTypeDetector.Setup(x => x.HeaderSize).Returns(1);
this.localMimeTypeDetector.Setup(x => x.DetectMimeType(It.IsAny<Span<byte>>())).Returns(localMimeType); this.localMimeTypeDetector.Setup(x => x.DetectFormat(It.IsAny<ReadOnlySpan<byte>>())).Returns(localImageFormatMock.Object);
this.fileSystem = new Mock<IFileSystem>(); this.fileSystem = new Mock<IFileSystem>();
@ -41,7 +45,7 @@ namespace ImageSharp.Tests
{ {
FileSystem = this.fileSystem.Object FileSystem = this.fileSystem.Object
}; };
this.LocalConfiguration.AddMimeTypeDetector(this.localMimeTypeDetector.Object); this.LocalConfiguration.AddImageFormatDetector(this.localMimeTypeDetector.Object);
TestFormat.RegisterGloablTestFormat(); TestFormat.RegisterGloablTestFormat();
this.Marker = Guid.NewGuid().ToByteArray(); this.Marker = Guid.NewGuid().ToByteArray();
@ -55,52 +59,52 @@ namespace ImageSharp.Tests
} }
[Fact] [Fact]
public void DiscoverMimeTypeByteArray() public void DiscoverImageFormatByteArray()
{ {
var type = Image.DiscoverMimeType(DataStream.ToArray()); var type = Image.DetectFormat(DataStream.ToArray());
Assert.Equal(TestFormat.GlobalTestFormat.MimeType, type); Assert.Equal(TestFormat.GlobalTestFormat, type);
} }
[Fact] [Fact]
public void DiscoverMimeTypeByteArray_WithConfig() public void DiscoverImageFormatByteArray_WithConfig()
{ {
var type = Image.DiscoverMimeType(this.LocalConfiguration, DataStream.ToArray()); var type = Image.DetectFormat(this.LocalConfiguration, DataStream.ToArray());
Assert.Equal(localMimeType, type); Assert.Equal(localImageFormat, type);
} }
[Fact] [Fact]
public void DiscoverMimeTypeFile() public void DiscoverImageFormatFile()
{ {
var type = Image.DiscoverMimeType(this.FilePath); var type = Image.DetectFormat(this.FilePath);
Assert.Equal(TestFormat.GlobalTestFormat.MimeType, type); Assert.Equal(TestFormat.GlobalTestFormat, type);
} }
[Fact] [Fact]
public void DiscoverMimeTypeFilePath_WithConfig() public void DiscoverImageFormatFilePath_WithConfig()
{ {
var type = Image.DiscoverMimeType(this.LocalConfiguration, FilePath); var type = Image.DetectFormat(this.LocalConfiguration, FilePath);
Assert.Equal(localMimeType, type); Assert.Equal(localImageFormat, type);
} }
[Fact] [Fact]
public void DiscoverMimeTypeStream() public void DiscoverImageFormatStream()
{ {
var type = Image.DiscoverMimeType(this.DataStream); var type = Image.DetectFormat(this.DataStream);
Assert.Equal(TestFormat.GlobalTestFormat.MimeType, type); Assert.Equal(TestFormat.GlobalTestFormat, type);
} }
[Fact] [Fact]
public void DiscoverMimeTypeFileStream_WithConfig() public void DiscoverImageFormatFileStream_WithConfig()
{ {
var type = Image.DiscoverMimeType(this.LocalConfiguration, DataStream); var type = Image.DetectFormat(this.LocalConfiguration, DataStream);
Assert.Equal(localMimeType, type); Assert.Equal(localImageFormat, type);
} }
[Fact] [Fact]
public void DiscoverMimeTypeNoDetectorsRegisterdShouldReturnNull() public void DiscoverImageFormatNoDetectorsRegisterdShouldReturnNull()
{ {
var type = Image.DiscoverMimeType(new Configuration(), DataStream); var type = Image.DetectFormat(new Configuration(), DataStream);
Assert.Null(type); Assert.Null(type);
} }
} }

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

@ -23,7 +23,8 @@ namespace ImageSharp.Tests
private Image<Rgba32> returnImage; private Image<Rgba32> returnImage;
private Mock<IImageDecoder> localDecoder; private Mock<IImageDecoder> localDecoder;
private readonly string FilePath; private readonly string FilePath;
private readonly Mock<IMimeTypeDetector> localMimeTypeDetector; private readonly Mock<IImageFormatDetector> localMimeTypeDetector;
private readonly Mock<IImageFormat> localImageFormatMock;
public Configuration LocalConfiguration { get; private set; } public Configuration LocalConfiguration { get; private set; }
public byte[] Marker { get; private set; } public byte[] Marker { get; private set; }
@ -34,10 +35,12 @@ namespace ImageSharp.Tests
{ {
this.returnImage = new Image<Rgba32>(1, 1); this.returnImage = new Image<Rgba32>(1, 1);
this.localImageFormatMock = new Mock<IImageFormat>();
this.localDecoder = new Mock<IImageDecoder>(); this.localDecoder = new Mock<IImageDecoder>();
this.localMimeTypeDetector = new Mock<IMimeTypeDetector>(); this.localMimeTypeDetector = new Mock<IImageFormatDetector>();
this.localMimeTypeDetector.Setup(x => x.HeaderSize).Returns(1); this.localMimeTypeDetector.Setup(x => x.HeaderSize).Returns(1);
this.localMimeTypeDetector.Setup(x => x.DetectMimeType(It.IsAny<Span<byte>>())).Returns("test"); this.localMimeTypeDetector.Setup(x => x.DetectFormat(It.IsAny<ReadOnlySpan<byte>>())).Returns(localImageFormatMock.Object);
this.localDecoder.Setup(x => x.Decode<Rgba32>(It.IsAny<Configuration>(), It.IsAny<Stream>())) this.localDecoder.Setup(x => x.Decode<Rgba32>(It.IsAny<Configuration>(), It.IsAny<Stream>()))
@ -56,8 +59,8 @@ namespace ImageSharp.Tests
{ {
FileSystem = this.fileSystem.Object FileSystem = this.fileSystem.Object
}; };
this.LocalConfiguration.AddMimeTypeDetector(this.localMimeTypeDetector.Object); this.LocalConfiguration.AddImageFormatDetector(this.localMimeTypeDetector.Object);
this.LocalConfiguration.SetMimeTypeDecoder("test", this.localDecoder.Object); this.LocalConfiguration.SetDecoder(localImageFormatMock.Object, this.localDecoder.Object);
TestFormat.RegisterGloablTestFormat(); TestFormat.RegisterGloablTestFormat();
this.Marker = Guid.NewGuid().ToByteArray(); this.Marker = Guid.NewGuid().ToByteArray();
@ -78,7 +81,6 @@ namespace ImageSharp.Tests
Assert.NotNull(img); Assert.NotNull(img);
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default); TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default);
} }
[Fact] [Fact]

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

@ -24,13 +24,17 @@ namespace ImageSharp.Tests
private readonly Mock<IFileSystem> fileSystem; private readonly Mock<IFileSystem> fileSystem;
private readonly Mock<IImageEncoder> encoder; private readonly Mock<IImageEncoder> encoder;
private readonly Mock<IImageEncoder> encoderNotInFormat; private readonly Mock<IImageEncoder> encoderNotInFormat;
private Mock<IMimeTypeDetector> localMimeTypeDetector; private Mock<IImageFormatDetector> localMimeTypeDetector;
private Mock<IImageFormat> localImageFormat;
public ImageSaveTests() public ImageSaveTests()
{ {
this.localMimeTypeDetector = new Mock<IMimeTypeDetector>(); this.localImageFormat = new Mock<IImageFormat>();
this.localImageFormat.Setup(x => x.FileExtensions).Returns(new[] { "png" });
this.localMimeTypeDetector = new Mock<IImageFormatDetector>();
this.localMimeTypeDetector.Setup(x => x.HeaderSize).Returns(1); this.localMimeTypeDetector.Setup(x => x.HeaderSize).Returns(1);
this.localMimeTypeDetector.Setup(x => x.DetectMimeType(It.IsAny<Span<byte>>())).Returns("img/test"); this.localMimeTypeDetector.Setup(x => x.DetectFormat(It.IsAny<Span<byte>>())).Returns(localImageFormat.Object);
this.encoder = new Mock<IImageEncoder>(); this.encoder = new Mock<IImageEncoder>();
@ -41,9 +45,8 @@ namespace ImageSharp.Tests
{ {
FileSystem = this.fileSystem.Object FileSystem = this.fileSystem.Object
}; };
config.AddMimeTypeDetector(this.localMimeTypeDetector.Object); config.AddImageFormatDetector(this.localMimeTypeDetector.Object);
config.SetMimeTypeEncoder("img/test", this.encoder.Object); config.SetEncoder(localImageFormat.Object, this.encoder.Object);
config.SetFileExtensionToMimeTypeMapping("png", "img/test");
this.Image = new Image<Rgba32>(config, 1, 1); this.Image = new Image<Rgba32>(config, 1, 1);
} }
@ -72,7 +75,7 @@ namespace ImageSharp.Tests
[Fact] [Fact]
public void ToBase64String() public void ToBase64String()
{ {
var str = this.Image.ToBase64String("img/test"); var str = this.Image.ToBase64String(localImageFormat.Object);
this.encoder.Verify(x => x.Encode<Rgba32>(this.Image, It.IsAny<Stream>())); this.encoder.Verify(x => x.Encode<Rgba32>(this.Image, It.IsAny<Stream>()));
} }
@ -81,7 +84,7 @@ namespace ImageSharp.Tests
public void SaveStreamWithMime() public void SaveStreamWithMime()
{ {
Stream stream = new MemoryStream(); Stream stream = new MemoryStream();
this.Image.Save(stream, "img/test"); this.Image.Save(stream, localImageFormat.Object);
this.encoder.Verify(x => x.Encode<Rgba32>(this.Image, stream)); this.encoder.Verify(x => x.Encode<Rgba32>(this.Image, stream));
} }

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

@ -76,7 +76,7 @@ namespace ImageSharp.Tests
using (Image<Rgba32> img = Image.Load(file, out var mime)) using (Image<Rgba32> img = Image.Load(file, out var mime))
{ {
Assert.Equal("image/png", mime); Assert.Equal("image/png", mime.DefaultMimeType);
} }
} }
@ -105,7 +105,7 @@ namespace ImageSharp.Tests
} }
using (Image<Rgba32> img = Image.Load(file, out var mime)) using (Image<Rgba32> img = Image.Load(file, out var mime))
{ {
Assert.Equal("image/png", mime); Assert.Equal("image/png", mime.DefaultMimeType);
} }
} }
} }

33
tests/ImageSharp.Tests/TestFormat.cs

@ -19,13 +19,13 @@ namespace ImageSharp.Tests
/// <summary> /// <summary>
/// A test image file. /// A test image file.
/// </summary> /// </summary>
public class TestFormat : IImageFormatProvider public class TestFormat : IConfigurationModule, IImageFormat
{ {
public static TestFormat GlobalTestFormat { get; } = new TestFormat(); public static TestFormat GlobalTestFormat { get; } = new TestFormat();
public static void RegisterGloablTestFormat() public static void RegisterGloablTestFormat()
{ {
Configuration.Default.AddImageFormat(GlobalTestFormat); Configuration.Default.Configure(GlobalTestFormat);
} }
public TestFormat() public TestFormat()
@ -93,7 +93,15 @@ namespace ImageSharp.Tests
public int HeaderSize => this.header.Length; public int HeaderSize => this.header.Length;
public bool IsSupportedFileFormat(Span<byte> header) public string Name => this.Extension;
public string DefaultMimeType => this.MimeType;
public IEnumerable<string> MimeTypes => new[] { this.MimeType };
public IEnumerable<string> FileExtensions => this.SupportedExtensions;
public bool IsSupportedFileFormat(ReadOnlySpan<byte> header)
{ {
if (header.Length < this.header.Length) if (header.Length < this.header.Length)
{ {
@ -109,16 +117,11 @@ namespace ImageSharp.Tests
return true; return true;
} }
public void Configure(IImageFormatHost host) public void Configure(Configuration host)
{ {
host.AddMimeTypeDetector(new TestHeader(this)); host.AddImageFormatDetector(new TestHeader(this));
foreach (var ext in this.SupportedExtensions) host.SetEncoder(this, new TestEncoder(this));
{ host.SetDecoder(this, new TestDecoder(this));
host.SetFileExtensionToMimeTypeMapping(ext, this.MimeType);
}
host.SetMimeTypeEncoder(this.MimeType, new TestEncoder(this));
host.SetMimeTypeDecoder(this.MimeType, new TestDecoder(this));
} }
public struct DecodeOperation public struct DecodeOperation
@ -150,17 +153,17 @@ namespace ImageSharp.Tests
} }
} }
public class TestHeader : IMimeTypeDetector public class TestHeader : IImageFormatDetector
{ {
private TestFormat testFormat; private TestFormat testFormat;
public int HeaderSize => testFormat.HeaderSize; public int HeaderSize => testFormat.HeaderSize;
public string DetectMimeType(Span<byte> header) public IImageFormat DetectFormat(ReadOnlySpan<byte> header)
{ {
if (testFormat.IsSupportedFileFormat(header)) if (testFormat.IsSupportedFileFormat(header))
return testFormat.MimeType; return testFormat;
return null; return null;
} }

4
tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs

@ -124,13 +124,13 @@ namespace ImageSharp.Tests
private static IImageEncoder GetImageFormatByExtension(string extension) private static IImageEncoder GetImageFormatByExtension(string extension)
{ {
extension = extension?.TrimStart('.'); extension = extension?.TrimStart('.');
return Configuration.Default.FindFileExtensionsEncoder(extension); var format = Configuration.Default.FindFormatByFileExtensions(extension);
return Configuration.Default.FindEncoder(format);
} }
private string GetTestOutputDir() private string GetTestOutputDir()
{ {
string testGroupName = Path.GetFileNameWithoutExtension(this.TestGroupName); string testGroupName = Path.GetFileNameWithoutExtension(this.TestGroupName);
return CreateOutputDirectory(testGroupName); return CreateOutputDirectory(testGroupName);
} }
} }

Loading…
Cancel
Save