Browse Source

Strong type meta query + format singletons

af/merge-core
James Jackson-South 8 years ago
parent
commit
dc4ec30a14
  1. 8
      src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs
  2. 14
      src/ImageSharp/Formats/Bmp/BmpFormat.cs
  3. 2
      src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs
  4. 15
      src/ImageSharp/Formats/Bmp/BmpMetaData.cs
  5. 2
      src/ImageSharp/Formats/Bmp/ImageExtensions.cs
  6. 9
      src/ImageSharp/Formats/Gif/GifConfigurationModule.cs
  7. 5
      src/ImageSharp/Formats/Gif/GifConstants.cs
  8. 6
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs
  9. 6
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  10. 14
      src/ImageSharp/Formats/Gif/GifFormat.cs
  11. 4
      src/ImageSharp/Formats/Gif/GifFrameMetaData.cs
  12. 2
      src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs
  13. 4
      src/ImageSharp/Formats/Gif/GifMetaData.cs
  14. 49
      src/ImageSharp/Formats/Gif/GifMetaDataExtensions.cs
  15. 2
      src/ImageSharp/Formats/Gif/ImageExtensions.cs
  16. 38
      src/ImageSharp/Formats/ImageFormatBase{T}.cs
  17. 2
      src/ImageSharp/Formats/Jpeg/ImageExtensions.cs
  18. 9
      src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs
  19. 14
      src/ImageSharp/Formats/Jpeg/JpegFormat.cs
  20. 2
      src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs
  21. 15
      src/ImageSharp/Formats/Jpeg/JpegMetaData.cs
  22. 2
      src/ImageSharp/Formats/Png/ImageExtensions.cs
  23. 4
      src/ImageSharp/Formats/Png/PngConfigurationModule.cs
  24. 14
      src/ImageSharp/Formats/Png/PngFormat.cs
  25. 2
      src/ImageSharp/Formats/Png/PngImageFormatDetector.cs
  26. 15
      src/ImageSharp/Formats/Png/PngMetaData.cs
  27. 37
      src/ImageSharp/ImageFormats.cs
  28. 13
      src/ImageSharp/MetaData/IImageFormatFrameMetaData.cs
  29. 13
      src/ImageSharp/MetaData/IImageFormatMetaData.cs
  30. 30
      src/ImageSharp/MetaData/ImageFrameMetaData.cs
  31. 30
      src/ImageSharp/MetaData/ImageMetaData.cs
  32. 13
      tests/ImageSharp.Tests/ConfigurationTests.cs
  33. 2
      tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs
  34. 10
      tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs
  35. 4
      tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs
  36. 4
      tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs
  37. 4
      tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs

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

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

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

@ -8,18 +8,22 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// <summary> /// <summary>
/// Registers the image encoders, decoders and mime type detectors for the bmp format. /// Registers the image encoders, decoders and mime type detectors for the bmp format.
/// </summary> /// </summary>
internal sealed class BmpFormat : IImageFormat internal sealed class BmpFormat : ImageFormatBase<BmpFormat>
{ {
private BmpFormat()
{
}
/// <inheritdoc/> /// <inheritdoc/>
public string Name => "BMP"; public override string Name => "BMP";
/// <inheritdoc/> /// <inheritdoc/>
public string DefaultMimeType => "image/bmp"; public override string DefaultMimeType => "image/bmp";
/// <inheritdoc/> /// <inheritdoc/>
public IEnumerable<string> MimeTypes => BmpConstants.MimeTypes; public override IEnumerable<string> MimeTypes => BmpConstants.MimeTypes;
/// <inheritdoc/> /// <inheritdoc/>
public IEnumerable<string> FileExtensions => BmpConstants.FileExtensions; public override IEnumerable<string> FileExtensions => BmpConstants.FileExtensions;
} }
} }

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

@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// <inheritdoc/> /// <inheritdoc/>
public IImageFormat DetectFormat(ReadOnlySpan<byte> header) public IImageFormat DetectFormat(ReadOnlySpan<byte> header)
{ {
return this.IsSupportedFileFormat(header) ? ImageFormats.Bmp : null; return this.IsSupportedFileFormat(header) ? BmpFormat.Instance : null;
} }
private bool IsSupportedFileFormat(ReadOnlySpan<byte> header) private bool IsSupportedFileFormat(ReadOnlySpan<byte> header)

15
src/ImageSharp/Formats/Bmp/BmpMetaData.cs

@ -0,0 +1,15 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.MetaData;
namespace SixLabors.ImageSharp.Formats.Bmp
{
/// <summary>
/// Provides Bmp specific metadata information for the image.
/// </summary>
public class BmpMetaData : IImageFormatMetaData
{
// TODO: Analyse what properties we would like to preserve.
}
}

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

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

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

@ -9,12 +9,11 @@ namespace SixLabors.ImageSharp.Formats.Gif
public sealed class GifConfigurationModule : IConfigurationModule public sealed class GifConfigurationModule : IConfigurationModule
{ {
/// <inheritdoc/> /// <inheritdoc/>
public void Configure(Configuration config) public void Configure(Configuration configuration)
{ {
config.ImageFormatsManager.SetEncoder(ImageFormats.Gif, new GifEncoder()); configuration.ImageFormatsManager.SetEncoder(GifFormat.Instance, new GifEncoder());
config.ImageFormatsManager.SetDecoder(ImageFormats.Gif, new GifDecoder()); configuration.ImageFormatsManager.SetDecoder(GifFormat.Instance, new GifDecoder());
configuration.ImageFormatsManager.AddImageFormatDetector(new GifImageFormatDetector());
config.ImageFormatsManager.AddImageFormatDetector(new GifImageFormatDetector());
} }
} }
} }

5
src/ImageSharp/Formats/Gif/GifConstants.cs

@ -26,11 +26,6 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// </summary> /// </summary>
internal static readonly byte[] MagicNumber = Encoding.UTF8.GetBytes(FileType + FileVersion); internal static readonly byte[] MagicNumber = Encoding.UTF8.GetBytes(FileType + FileVersion);
/// <summary>
/// Gets the key used for storing and retriving metadata.
/// </summary>
public const string MetaDataKey = FileType;
/// <summary> /// <summary>
/// The extension block introducer <value>!</value>. /// The extension block introducer <value>!</value>.
/// </summary> /// </summary>

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

@ -164,7 +164,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
this.globalColorTable?.Dispose(); this.globalColorTable?.Dispose();
} }
image?.MetaData.AddOrUpdateGifMetaData(this.gifMetaData); image?.MetaData.AddOrUpdateFormatMetaData(GifFormat.Instance, this.gifMetaData);
return image; return image;
} }
@ -224,7 +224,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
this.globalColorTable?.Dispose(); this.globalColorTable?.Dispose();
} }
this.metaData.AddOrUpdateGifMetaData(this.gifMetaData); this.metaData.AddOrUpdateFormatMetaData(GifFormat.Instance, this.gifMetaData);
return new ImageInfo( return new ImageInfo(
new PixelTypeInfo(this.logicalScreenDescriptor.BitsPerPixel), new PixelTypeInfo(this.logicalScreenDescriptor.BitsPerPixel),
this.logicalScreenDescriptor.Width, this.logicalScreenDescriptor.Width,
@ -561,7 +561,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
} }
gifMeta.DisposalMethod = this.graphicsControlExtension.DisposalMethod; gifMeta.DisposalMethod = this.graphicsControlExtension.DisposalMethod;
meta.AddOrUpdateGifFrameMetaData(gifMeta); meta.AddOrUpdateFormatMetaData(GifFormat.Instance, gifMeta);
} }
/// <summary> /// <summary>

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

@ -86,7 +86,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
Guard.NotNull(image, nameof(image)); Guard.NotNull(image, nameof(image));
Guard.NotNull(stream, nameof(stream)); Guard.NotNull(stream, nameof(stream));
this.gifMetaData = image.MetaData.GetGifMetaData() ?? new GifMetaData(); this.gifMetaData = image.MetaData.GetOrAddFormatMetaData<GifMetaData>(GifFormat.Instance);
this.colorTableMode = this.colorTableMode ?? this.gifMetaData.ColorTableMode; this.colorTableMode = this.colorTableMode ?? this.gifMetaData.ColorTableMode;
bool useGlobalTable = this.colorTableMode.Equals(GifColorTableMode.Global); bool useGlobalTable = this.colorTableMode.Equals(GifColorTableMode.Global);
@ -143,7 +143,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
for (int i = 0; i < image.Frames.Count; i++) for (int i = 0; i < image.Frames.Count; i++)
{ {
ImageFrame<TPixel> frame = image.Frames[i]; ImageFrame<TPixel> frame = image.Frames[i];
GifFrameMetaData frameMetaData = frame.MetaData.GetGifFrameMetaData() ?? new GifFrameMetaData(); GifFrameMetaData frameMetaData = frame.MetaData.GetOrAddFormatMetaData<GifFrameMetaData>(GifFormat.Instance);
this.WriteGraphicalControlExtension(frameMetaData, transparencyIndex, stream); this.WriteGraphicalControlExtension(frameMetaData, transparencyIndex, stream);
this.WriteImageDescriptor(frame, false, stream); this.WriteImageDescriptor(frame, false, stream);
@ -169,7 +169,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
GifFrameMetaData previousMeta = null; GifFrameMetaData previousMeta = null;
foreach (ImageFrame<TPixel> frame in image.Frames) foreach (ImageFrame<TPixel> frame in image.Frames)
{ {
GifFrameMetaData meta = frame.MetaData.GetGifFrameMetaData() ?? new GifFrameMetaData(); GifFrameMetaData meta = frame.MetaData.GetOrAddFormatMetaData<GifFrameMetaData>(GifFormat.Instance);
if (quantized is null) if (quantized is null)
{ {
// Allow each frame to be encoded at whatever color depth the frame designates if set. // Allow each frame to be encoded at whatever color depth the frame designates if set.

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

@ -8,18 +8,22 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <summary> /// <summary>
/// Registers the image encoders, decoders and mime type detectors for the gif format. /// Registers the image encoders, decoders and mime type detectors for the gif format.
/// </summary> /// </summary>
internal sealed class GifFormat : IImageFormat internal sealed class GifFormat : ImageFormatBase<GifFormat>
{ {
private GifFormat()
{
}
/// <inheritdoc/> /// <inheritdoc/>
public string Name => "GIF"; public override string Name => "GIF";
/// <inheritdoc/> /// <inheritdoc/>
public string DefaultMimeType => "image/gif"; public override string DefaultMimeType => "image/gif";
/// <inheritdoc/> /// <inheritdoc/>
public IEnumerable<string> MimeTypes => GifConstants.MimeTypes; public override IEnumerable<string> MimeTypes => GifConstants.MimeTypes;
/// <inheritdoc/> /// <inheritdoc/>
public IEnumerable<string> FileExtensions => GifConstants.FileExtensions; public override IEnumerable<string> FileExtensions => GifConstants.FileExtensions;
} }
} }

4
src/ImageSharp/Formats/Gif/GifFrameMetaData.cs

@ -1,12 +1,14 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.MetaData;
namespace SixLabors.ImageSharp.Formats.Gif namespace SixLabors.ImageSharp.Formats.Gif
{ {
/// <summary> /// <summary>
/// Provides Gif specific metadata information for the image frame. /// Provides Gif specific metadata information for the image frame.
/// </summary> /// </summary>
public class GifFrameMetaData public class GifFrameMetaData : IImageFormatFrameMetaData
{ {
/// <summary> /// <summary>
/// Gets or sets the length of the color table for paletted images. /// Gets or sets the length of the color table for paletted images.

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

@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <inheritdoc/> /// <inheritdoc/>
public IImageFormat DetectFormat(ReadOnlySpan<byte> header) public IImageFormat DetectFormat(ReadOnlySpan<byte> header)
{ {
return this.IsSupportedFileFormat(header) ? ImageFormats.Gif : null; return this.IsSupportedFileFormat(header) ? GifFormat.Instance : null;
} }
private bool IsSupportedFileFormat(ReadOnlySpan<byte> header) private bool IsSupportedFileFormat(ReadOnlySpan<byte> header)

4
src/ImageSharp/Formats/Gif/GifMetaData.cs

@ -1,12 +1,14 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.MetaData;
namespace SixLabors.ImageSharp.Formats.Gif namespace SixLabors.ImageSharp.Formats.Gif
{ {
/// <summary> /// <summary>
/// Provides Gif specific metadata information for the image. /// Provides Gif specific metadata information for the image.
/// </summary> /// </summary>
public class GifMetaData public class GifMetaData : IImageFormatMetaData
{ {
/// <summary> /// <summary>
/// Gets or sets the number of times any animation is repeated. /// Gets or sets the number of times any animation is repeated.

49
src/ImageSharp/Formats/Gif/GifMetaDataExtensions.cs

@ -1,49 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.MetaData;
namespace SixLabors.ImageSharp.Formats.Gif
{
/// <summary>
/// Extension methods for storing meta data specific to Gif images.
/// </summary>
public static class GifMetaDataExtensions
{
/// <summary>
/// Adds or updates the Gif specific meta data to the image.
/// </summary>
/// <param name="meta">The image meta data.</param>
/// <param name="value">The gif meta data.</param>
public static void AddOrUpdateGifMetaData(this ImageMetaData meta, GifMetaData value) => meta.AddOrUpdateMetaData(GifConstants.MetaDataKey, value);
/// <summary>
/// Gets the Gif format specific meta data from the image.
/// </summary>
/// <param name="meta">The image meta data.</param>
/// <returns>The <see cref="GifMetaData"/> or null.</returns>
public static GifMetaData GetGifMetaData(this ImageMetaData meta)
{
meta.TryGetMetaData(GifConstants.MetaDataKey, out GifMetaData value);
return value;
}
/// <summary>
/// Adds or updates the Gif specific meta data to the image frame.
/// </summary>
/// <param name="meta">The image meta data.</param>
/// <param name="value">The gif meta data.</param>
public static void AddOrUpdateGifFrameMetaData(this ImageFrameMetaData meta, GifFrameMetaData value) => meta.AddOrUpdateMetaData(GifConstants.MetaDataKey, value);
/// <summary>
/// Gets the Gif format specific meta data from the image frame.
/// </summary>
/// <param name="meta">The image meta data.</param>
/// <returns>The <see cref="GifMetaData"/> or null.</returns>
public static GifFrameMetaData GetGifFrameMetaData(this ImageFrameMetaData meta)
{
meta.TryGetMetaData(GifConstants.MetaDataKey, out GifFrameMetaData value);
return value;
}
}
}

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

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

38
src/ImageSharp/Formats/ImageFormatBase{T}.cs

@ -0,0 +1,38 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Collections.Generic;
namespace SixLabors.ImageSharp.Formats
{
/// <summary>
/// The base class for all image formats.
/// Inheriting classes should implement the singleton pattern by creating a private constructor.
/// </summary>
/// <typeparam name="T">The type of image format.</typeparam>
public abstract class ImageFormatBase<T> : IImageFormat
where T : class, IImageFormat
{
private static readonly Lazy<T> Lazy = new Lazy<T>(CreateInstance);
/// <summary>
/// Gets the current instance.
/// </summary>
public static T Instance => Lazy.Value;
/// <inheritdoc/>
public abstract string Name { get; }
/// <inheritdoc/>
public abstract string DefaultMimeType { get; }
/// <inheritdoc/>
public abstract IEnumerable<string> MimeTypes { get; }
/// <inheritdoc/>
public abstract IEnumerable<string> FileExtensions { get; }
private static T CreateInstance() => (T)Activator.CreateInstance(typeof(T), true);
}
}

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

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

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

@ -9,12 +9,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
public sealed class JpegConfigurationModule : IConfigurationModule public sealed class JpegConfigurationModule : IConfigurationModule
{ {
/// <inheritdoc/> /// <inheritdoc/>
public void Configure(Configuration config) public void Configure(Configuration configuration)
{ {
config.ImageFormatsManager.SetEncoder(ImageFormats.Jpeg, new JpegEncoder()); configuration.ImageFormatsManager.SetEncoder(JpegFormat.Instance, new JpegEncoder());
config.ImageFormatsManager.SetDecoder(ImageFormats.Jpeg, new JpegDecoder()); configuration.ImageFormatsManager.SetDecoder(JpegFormat.Instance, new JpegDecoder());
configuration.ImageFormatsManager.AddImageFormatDetector(new JpegImageFormatDetector());
config.ImageFormatsManager.AddImageFormatDetector(new JpegImageFormatDetector());
} }
} }
} }

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

@ -8,18 +8,22 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// <summary> /// <summary>
/// Registers the image encoders, decoders and mime type detectors for the jpeg format. /// Registers the image encoders, decoders and mime type detectors for the jpeg format.
/// </summary> /// </summary>
internal sealed class JpegFormat : IImageFormat internal sealed class JpegFormat : ImageFormatBase<JpegFormat>
{ {
private JpegFormat()
{
}
/// <inheritdoc/> /// <inheritdoc/>
public string Name => "JPEG"; public override string Name => "JPEG";
/// <inheritdoc/> /// <inheritdoc/>
public string DefaultMimeType => "image/jpeg"; public override string DefaultMimeType => "image/jpeg";
/// <inheritdoc/> /// <inheritdoc/>
public IEnumerable<string> MimeTypes => JpegConstants.MimeTypes; public override IEnumerable<string> MimeTypes => JpegConstants.MimeTypes;
/// <inheritdoc/> /// <inheritdoc/>
public IEnumerable<string> FileExtensions => JpegConstants.FileExtensions; public override IEnumerable<string> FileExtensions => JpegConstants.FileExtensions;
} }
} }

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

@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// <inheritdoc/> /// <inheritdoc/>
public IImageFormat DetectFormat(ReadOnlySpan<byte> header) public IImageFormat DetectFormat(ReadOnlySpan<byte> header)
{ {
return this.IsSupportedFileFormat(header) ? ImageFormats.Jpeg : null; return this.IsSupportedFileFormat(header) ? JpegFormat.Instance : null;
} }
private bool IsSupportedFileFormat(ReadOnlySpan<byte> header) private bool IsSupportedFileFormat(ReadOnlySpan<byte> header)

15
src/ImageSharp/Formats/Jpeg/JpegMetaData.cs

@ -0,0 +1,15 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.MetaData;
namespace SixLabors.ImageSharp.Formats.Jpeg
{
/// <summary>
/// Provides Jpeg specific metadata information for the image.
/// </summary>
public class JpegMetaData : IImageFormatMetaData
{
// TODO: Analyse what properties we would like to preserve.
}
}

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

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

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

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

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

@ -8,18 +8,22 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <summary> /// <summary>
/// Registers the image encoders, decoders and mime type detectors for the png format. /// Registers the image encoders, decoders and mime type detectors for the png format.
/// </summary> /// </summary>
internal sealed class PngFormat : IImageFormat internal sealed class PngFormat : ImageFormatBase<PngFormat>
{ {
private PngFormat()
{
}
/// <inheritdoc/> /// <inheritdoc/>
public string Name => "PNG"; public override string Name => "PNG";
/// <inheritdoc/> /// <inheritdoc/>
public string DefaultMimeType => "image/png"; public override string DefaultMimeType => "image/png";
/// <inheritdoc/> /// <inheritdoc/>
public IEnumerable<string> MimeTypes => PngConstants.MimeTypes; public override IEnumerable<string> MimeTypes => PngConstants.MimeTypes;
/// <inheritdoc/> /// <inheritdoc/>
public IEnumerable<string> FileExtensions => PngConstants.FileExtensions; public override IEnumerable<string> FileExtensions => PngConstants.FileExtensions;
} }
} }

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

@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <inheritdoc/> /// <inheritdoc/>
public IImageFormat DetectFormat(ReadOnlySpan<byte> header) public IImageFormat DetectFormat(ReadOnlySpan<byte> header)
{ {
return this.IsSupportedFileFormat(header) ? ImageFormats.Png : null; return this.IsSupportedFileFormat(header) ? PngFormat.Instance : null;
} }
private bool IsSupportedFileFormat(ReadOnlySpan<byte> header) private bool IsSupportedFileFormat(ReadOnlySpan<byte> header)

15
src/ImageSharp/Formats/Png/PngMetaData.cs

@ -0,0 +1,15 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.MetaData;
namespace SixLabors.ImageSharp.Formats.Png
{
/// <summary>
/// Provides Png specific metadata information for the image.
/// </summary>
public class PngMetaData : IImageFormatMetaData
{
// TODO: Analyse what properties we would like to preserve.
}
}

37
src/ImageSharp/ImageFormats.cs

@ -1,37 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Png;
namespace SixLabors.ImageSharp
{
/// <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 Bmp = new BmpFormat();
}
}

13
src/ImageSharp/MetaData/IImageFormatFrameMetaData.cs

@ -0,0 +1,13 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.MetaData
{
/// <summary>
/// Encapsulates the format specific metadata of an image frame.
/// This interface exists to allow type saftey and avoid the performance overhead of parsing attributes.
/// </summary>
public interface IImageFormatFrameMetaData
{
}
}

13
src/ImageSharp/MetaData/IImageFormatMetaData.cs

@ -0,0 +1,13 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.MetaData
{
/// <summary>
/// Encapsulates the format specific metadata of an image.
/// This interface exists to allow type saftey and avoid the performance overhead of parsing attributes.
/// </summary>
public interface IImageFormatMetaData
{
}
}

30
src/ImageSharp/MetaData/ImageFrameMetaData.cs

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using SixLabors.ImageSharp.Formats;
namespace SixLabors.ImageSharp.MetaData namespace SixLabors.ImageSharp.MetaData
{ {
@ -11,7 +12,7 @@ namespace SixLabors.ImageSharp.MetaData
/// </summary> /// </summary>
public sealed class ImageFrameMetaData public sealed class ImageFrameMetaData
{ {
private readonly Dictionary<string, object> metaData = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase); private readonly Dictionary<IImageFormat, IImageFormatFrameMetaData> metaData = new Dictionary<IImageFormat, IImageFormatFrameMetaData>();
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ImageFrameMetaData"/> class. /// Initializes a new instance of the <see cref="ImageFrameMetaData"/> class.
@ -31,7 +32,7 @@ namespace SixLabors.ImageSharp.MetaData
{ {
DebugGuard.NotNull(other, nameof(other)); DebugGuard.NotNull(other, nameof(other));
foreach (KeyValuePair<string, object> meta in other.metaData) foreach (KeyValuePair<IImageFormat, IImageFormatFrameMetaData> meta in other.metaData)
{ {
this.metaData.Add(meta.Key, meta.Value); this.metaData.Add(meta.Key, meta.Value);
} }
@ -51,7 +52,7 @@ namespace SixLabors.ImageSharp.MetaData
/// <exception cref="ArgumentNullException">key is null.</exception> /// <exception cref="ArgumentNullException">key is null.</exception>
/// <exception cref="ArgumentNullException">value is null.</exception> /// <exception cref="ArgumentNullException">value is null.</exception>
/// <exception cref="ArgumentException">An element with the same key already exists in the <see cref="ImageMetaData"/>.</exception> /// <exception cref="ArgumentException">An element with the same key already exists in the <see cref="ImageMetaData"/>.</exception>
public void AddOrUpdateMetaData(string key, object value) public void AddOrUpdateFormatMetaData(IImageFormat key, IImageFormatFrameMetaData value)
{ {
// Don't think this needs to be threadsafe. // Don't think this needs to be threadsafe.
Guard.NotNull(value, nameof(value)); Guard.NotNull(value, nameof(value));
@ -61,27 +62,22 @@ namespace SixLabors.ImageSharp.MetaData
/// <summary> /// <summary>
/// Gets the metadata value associated with the specified key. /// Gets the metadata value associated with the specified key.
/// </summary> /// </summary>
/// <typeparam name="T">The type of value.</typeparam> /// <typeparam name="T">The type of metadata.</typeparam>
/// <param name="key">The key of the value to get.</param> /// <param name="key">The key of the value to get.</param>
/// <param name="value">
/// When this method returns, contains the metadata value associated with the specified key,
/// if the key is found; otherwise, the default value for the type of the value parameter.
/// This parameter is passed uninitialized.
/// </param>
/// <returns> /// <returns>
/// true if the <see cref="ImageMetaData"/> contains an element with /// The <typeparamref name="T"/>.
/// the specified key; otherwise, false.
/// </returns> /// </returns>
public bool TryGetMetaData<T>(string key, out T value) public T GetOrAddFormatMetaData<T>(IImageFormat key)
where T : IImageFormatFrameMetaData, new()
{ {
if (this.metaData.TryGetValue(key, out object meta)) if (this.metaData.TryGetValue(key, out IImageFormatFrameMetaData meta))
{ {
value = (T)meta; return (T)meta;
return true;
} }
value = default; var newMeta = new T();
return false; this.AddOrUpdateFormatMetaData(key, newMeta);
return newMeta;
} }
} }
} }

30
src/ImageSharp/MetaData/ImageMetaData.cs

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.MetaData.Profiles.Exif;
using SixLabors.ImageSharp.MetaData.Profiles.Icc; using SixLabors.ImageSharp.MetaData.Profiles.Icc;
@ -25,7 +26,7 @@ namespace SixLabors.ImageSharp.MetaData
/// </summary> /// </summary>
public const double DefaultVerticalResolution = 96; public const double DefaultVerticalResolution = 96;
private readonly Dictionary<string, object> metaData = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase); private readonly Dictionary<IImageFormat, IImageFormatMetaData> metaData = new Dictionary<IImageFormat, IImageFormatMetaData>();
private double horizontalResolution; private double horizontalResolution;
private double verticalResolution; private double verticalResolution;
@ -51,7 +52,7 @@ namespace SixLabors.ImageSharp.MetaData
this.VerticalResolution = other.VerticalResolution; this.VerticalResolution = other.VerticalResolution;
this.ResolutionUnits = other.ResolutionUnits; this.ResolutionUnits = other.ResolutionUnits;
foreach (KeyValuePair<string, object> meta in other.metaData) foreach (KeyValuePair<IImageFormat, IImageFormatMetaData> meta in other.metaData)
{ {
this.metaData.Add(meta.Key, meta.Value); this.metaData.Add(meta.Key, meta.Value);
} }
@ -138,7 +139,7 @@ namespace SixLabors.ImageSharp.MetaData
/// <exception cref="ArgumentNullException">key is null.</exception> /// <exception cref="ArgumentNullException">key is null.</exception>
/// <exception cref="ArgumentNullException">value is null.</exception> /// <exception cref="ArgumentNullException">value is null.</exception>
/// <exception cref="ArgumentException">An element with the same key already exists in the <see cref="ImageMetaData"/>.</exception> /// <exception cref="ArgumentException">An element with the same key already exists in the <see cref="ImageMetaData"/>.</exception>
public void AddOrUpdateMetaData(string key, object value) public void AddOrUpdateFormatMetaData(IImageFormat key, IImageFormatMetaData value)
{ {
// Don't think this needs to be threadsafe. // Don't think this needs to be threadsafe.
Guard.NotNull(value, nameof(value)); Guard.NotNull(value, nameof(value));
@ -148,27 +149,22 @@ namespace SixLabors.ImageSharp.MetaData
/// <summary> /// <summary>
/// Gets the metadata value associated with the specified key. /// Gets the metadata value associated with the specified key.
/// </summary> /// </summary>
/// <typeparam name="T">The type of value.</typeparam> /// <typeparam name="T">The type of metadata.</typeparam>
/// <param name="key">The key of the value to get.</param> /// <param name="key">The key of the value to get.</param>
/// <param name="value">
/// When this method returns, contains the metadata value associated with the specified key,
/// if the key is found; otherwise, the default value for the type of the value parameter.
/// This parameter is passed uninitialized.
/// </param>
/// <returns> /// <returns>
/// true if the <see cref="ImageMetaData"/> contains an element with /// The <typeparamref name="T"/>.
/// the specified key; otherwise, false.
/// </returns> /// </returns>
public bool TryGetMetaData<T>(string key, out T value) public T GetOrAddFormatMetaData<T>(IImageFormat key)
where T : IImageFormatMetaData, new()
{ {
if (this.metaData.TryGetValue(key, out object meta)) if (this.metaData.TryGetValue(key, out IImageFormatMetaData meta))
{ {
value = (T)meta; return (T)meta;
return true;
} }
value = default; var newMeta = new T();
return false; this.AddOrUpdateFormatMetaData(key, newMeta);
return newMeta;
} }
/// <summary> /// <summary>

13
tests/ImageSharp.Tests/ConfigurationTests.cs

@ -4,6 +4,7 @@
using System; using System;
using System.Linq; using System.Linq;
using Moq; using Moq;
using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.IO;
using Xunit; using Xunit;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
@ -37,19 +38,13 @@ namespace SixLabors.ImageSharp.Tests
/// Test that the default configuration is not null. /// Test that the default configuration is not null.
/// </summary> /// </summary>
[Fact] [Fact]
public void TestDefaultConfigurationIsNotNull() public void TestDefaultConfigurationIsNotNull() => Assert.True(Configuration.Default != null);
{
Assert.True(Configuration.Default != null);
}
/// <summary> /// <summary>
/// Test that the default configuration read origin options is set to begin. /// Test that the default configuration read origin options is set to begin.
/// </summary> /// </summary>
[Fact] [Fact]
public void TestDefaultConfigurationReadOriginIsCurrent() public void TestDefaultConfigurationReadOriginIsCurrent() => Assert.True(Configuration.Default.ReadOrigin == ReadOrigin.Current);
{
Assert.True(Configuration.Default.ReadOrigin == ReadOrigin.Current);
}
/// <summary> /// <summary>
/// Test that the default configuration parallel options max degrees of parallelism matches the /// Test that the default configuration parallel options max degrees of parallelism matches the
@ -101,7 +96,7 @@ namespace SixLabors.ImageSharp.Tests
Assert.Equal(count, config.ImageFormats.Count()); Assert.Equal(count, config.ImageFormats.Count());
config.ImageFormatsManager.AddImageFormat(ImageFormats.Bmp); config.ImageFormatsManager.AddImageFormat(BmpFormat.Instance);
Assert.Equal(count, config.ImageFormats.Count()); Assert.Equal(count, config.ImageFormats.Count());
} }

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

@ -44,7 +44,7 @@ namespace SixLabors.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(ImageFormats.Png)); File.WriteAllText(filename, image.ToBase64String(PngFormat.Instance));
} }
} }
} }

10
tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs

@ -189,8 +189,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif
inStream.Position = 0; inStream.Position = 0;
var image = Image.Load(inStream); var image = Image.Load(inStream);
GifMetaData metaData = image.MetaData.GetGifMetaData(); GifMetaData metaData = image.MetaData.GetOrAddFormatMetaData<GifMetaData>(GifFormat.Instance);
GifFrameMetaData frameMetaData = image.Frames.RootFrame.MetaData.GetGifFrameMetaData(); GifFrameMetaData frameMetaData = image.Frames.RootFrame.MetaData.GetOrAddFormatMetaData<GifFrameMetaData>(GifFormat.Instance);
GifColorTableMode colorMode = metaData.ColorTableMode; GifColorTableMode colorMode = metaData.ColorTableMode;
var encoder = new GifEncoder() var encoder = new GifEncoder()
{ {
@ -204,7 +204,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif
outStream.Position = 0; outStream.Position = 0;
var clone = Image.Load(outStream); var clone = Image.Load(outStream);
GifMetaData cloneMetaData = clone.MetaData.GetGifMetaData(); GifMetaData cloneMetaData = clone.MetaData.GetOrAddFormatMetaData<GifMetaData>(GifFormat.Instance);
Assert.Equal(metaData.ColorTableMode, cloneMetaData.ColorTableMode); Assert.Equal(metaData.ColorTableMode, cloneMetaData.ColorTableMode);
// Gifiddle and Cyotek GifInfo say this image has 64 colors. // Gifiddle and Cyotek GifInfo say this image has 64 colors.
@ -212,8 +212,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif
for (int i = 0; i < image.Frames.Count; i++) for (int i = 0; i < image.Frames.Count; i++)
{ {
GifFrameMetaData ifm = image.Frames[i].MetaData.GetGifFrameMetaData(); GifFrameMetaData ifm = image.Frames[i].MetaData.GetOrAddFormatMetaData<GifFrameMetaData>(GifFormat.Instance);
GifFrameMetaData cifm = clone.Frames[i].MetaData.GetGifFrameMetaData(); GifFrameMetaData cifm = clone.Frames[i].MetaData.GetOrAddFormatMetaData<GifFrameMetaData>(GifFormat.Instance);
Assert.Equal(ifm.ColorTableLength, cifm.ColorTableLength); Assert.Equal(ifm.ColorTableLength, cifm.ColorTableLength);
Assert.Equal(ifm.FrameDelay, cifm.FrameDelay); Assert.Equal(ifm.FrameDelay, cifm.FrameDelay);

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

@ -61,7 +61,7 @@ namespace SixLabors.ImageSharp.Tests
}); });
Assert.Throws<ArgumentNullException>(() => Assert.Throws<ArgumentNullException>(() =>
{ {
this.DefaultFormatsManager.SetEncoder(ImageFormats.Bmp, null); this.DefaultFormatsManager.SetEncoder(BmpFormat.Instance, null);
}); });
Assert.Throws<ArgumentNullException>(() => Assert.Throws<ArgumentNullException>(() =>
{ {
@ -78,7 +78,7 @@ namespace SixLabors.ImageSharp.Tests
}); });
Assert.Throws<ArgumentNullException>(() => Assert.Throws<ArgumentNullException>(() =>
{ {
this.DefaultFormatsManager.SetDecoder(ImageFormats.Bmp, null); this.DefaultFormatsManager.SetDecoder(BmpFormat.Instance, null);
}); });
Assert.Throws<ArgumentNullException>(() => Assert.Throws<ArgumentNullException>(() =>
{ {

4
tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs

@ -27,10 +27,10 @@ namespace SixLabors.ImageSharp.Tests
}; };
var metaData = new ImageFrameMetaData(); var metaData = new ImageFrameMetaData();
metaData.AddOrUpdateGifFrameMetaData(gifFrameMetaData); metaData.AddOrUpdateFormatMetaData(GifFormat.Instance, gifFrameMetaData);
var clone = new ImageFrameMetaData(metaData); var clone = new ImageFrameMetaData(metaData);
GifFrameMetaData cloneGifFrameMetaData = clone.GetGifFrameMetaData(); GifFrameMetaData cloneGifFrameMetaData = clone.GetOrAddFormatMetaData<GifFrameMetaData>(GifFormat.Instance);
Assert.Equal(frameDelay, cloneGifFrameMetaData.FrameDelay); Assert.Equal(frameDelay, cloneGifFrameMetaData.FrameDelay);
Assert.Equal(colorTableLength, cloneGifFrameMetaData.ColorTableLength); Assert.Equal(colorTableLength, cloneGifFrameMetaData.ColorTableLength);

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

@ -62,13 +62,13 @@ namespace SixLabors.ImageSharp.Tests
IImageEncoder bmpEncoder = IsWindows ? (IImageEncoder)SystemDrawingReferenceEncoder.Bmp : new BmpEncoder(); IImageEncoder bmpEncoder = IsWindows ? (IImageEncoder)SystemDrawingReferenceEncoder.Bmp : new BmpEncoder();
cfg.ConfigureCodecs( cfg.ConfigureCodecs(
ImageFormats.Png, PngFormat.Instance,
MagickReferenceDecoder.Instance, MagickReferenceDecoder.Instance,
pngEncoder, pngEncoder,
new PngImageFormatDetector()); new PngImageFormatDetector());
cfg.ConfigureCodecs( cfg.ConfigureCodecs(
ImageFormats.Bmp, BmpFormat.Instance,
SystemDrawingReferenceDecoder.Instance, SystemDrawingReferenceDecoder.Instance,
bmpEncoder, bmpEncoder,
new BmpImageFormatDetector()); new BmpImageFormatDetector());

Loading…
Cancel
Save