From dc4ec30a14d82bd901ccb257a2de4277d0d52e80 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 7 Sep 2018 22:01:18 +0100 Subject: [PATCH] Strong type meta query + format singletons --- .../Formats/Bmp/BmpConfigurationModule.cs | 8 +-- src/ImageSharp/Formats/Bmp/BmpFormat.cs | 14 ++++-- .../Formats/Bmp/BmpImageFormatDetector.cs | 2 +- src/ImageSharp/Formats/Bmp/BmpMetaData.cs | 15 ++++++ src/ImageSharp/Formats/Bmp/ImageExtensions.cs | 2 +- .../Formats/Gif/GifConfigurationModule.cs | 9 ++-- src/ImageSharp/Formats/Gif/GifConstants.cs | 5 -- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 6 +-- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 6 +-- src/ImageSharp/Formats/Gif/GifFormat.cs | 14 ++++-- .../Formats/Gif/GifFrameMetaData.cs | 4 +- .../Formats/Gif/GifImageFormatDetector.cs | 2 +- src/ImageSharp/Formats/Gif/GifMetaData.cs | 4 +- .../Formats/Gif/GifMetaDataExtensions.cs | 49 ------------------- src/ImageSharp/Formats/Gif/ImageExtensions.cs | 2 +- src/ImageSharp/Formats/ImageFormatBase{T}.cs | 38 ++++++++++++++ .../Formats/Jpeg/ImageExtensions.cs | 2 +- .../Formats/Jpeg/JpegConfigurationModule.cs | 9 ++-- src/ImageSharp/Formats/Jpeg/JpegFormat.cs | 14 ++++-- .../Formats/Jpeg/JpegImageFormatDetector.cs | 2 +- src/ImageSharp/Formats/Jpeg/JpegMetaData.cs | 15 ++++++ src/ImageSharp/Formats/Png/ImageExtensions.cs | 2 +- .../Formats/Png/PngConfigurationModule.cs | 4 +- src/ImageSharp/Formats/Png/PngFormat.cs | 14 ++++-- .../Formats/Png/PngImageFormatDetector.cs | 2 +- src/ImageSharp/Formats/Png/PngMetaData.cs | 15 ++++++ src/ImageSharp/ImageFormats.cs | 37 -------------- .../MetaData/IImageFormatFrameMetaData.cs | 13 +++++ .../MetaData/IImageFormatMetaData.cs | 13 +++++ src/ImageSharp/MetaData/ImageFrameMetaData.cs | 30 +++++------- src/ImageSharp/MetaData/ImageMetaData.cs | 30 +++++------- tests/ImageSharp.Tests/ConfigurationTests.cs | 13 ++--- .../Formats/GeneralFormatTests.cs | 2 +- .../Formats/Gif/GifEncoderTests.cs | 10 ++-- .../Formats/ImageFormatManagerTests.cs | 4 +- .../MetaData/ImageFrameMetaDataTests.cs | 4 +- .../TestUtilities/TestEnvironment.Formats.cs | 4 +- 37 files changed, 221 insertions(+), 198 deletions(-) create mode 100644 src/ImageSharp/Formats/Bmp/BmpMetaData.cs delete mode 100644 src/ImageSharp/Formats/Gif/GifMetaDataExtensions.cs create mode 100644 src/ImageSharp/Formats/ImageFormatBase{T}.cs create mode 100644 src/ImageSharp/Formats/Jpeg/JpegMetaData.cs create mode 100644 src/ImageSharp/Formats/Png/PngMetaData.cs delete mode 100644 src/ImageSharp/ImageFormats.cs create mode 100644 src/ImageSharp/MetaData/IImageFormatFrameMetaData.cs create mode 100644 src/ImageSharp/MetaData/IImageFormatMetaData.cs diff --git a/src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs b/src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs index 956acc157..57117cc07 100644 --- a/src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs +++ b/src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs @@ -9,11 +9,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp public sealed class BmpConfigurationModule : IConfigurationModule { /// - public void Configure(Configuration config) + public void Configure(Configuration configuration) { - config.ImageFormatsManager.SetEncoder(ImageFormats.Bmp, new BmpEncoder()); - config.ImageFormatsManager.SetDecoder(ImageFormats.Bmp, new BmpDecoder()); - config.ImageFormatsManager.AddImageFormatDetector(new BmpImageFormatDetector()); + configuration.ImageFormatsManager.SetEncoder(BmpFormat.Instance, new BmpEncoder()); + configuration.ImageFormatsManager.SetDecoder(BmpFormat.Instance, new BmpDecoder()); + configuration.ImageFormatsManager.AddImageFormatDetector(new BmpImageFormatDetector()); } } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Bmp/BmpFormat.cs b/src/ImageSharp/Formats/Bmp/BmpFormat.cs index 64c6574c1..de3f6f3f4 100644 --- a/src/ImageSharp/Formats/Bmp/BmpFormat.cs +++ b/src/ImageSharp/Formats/Bmp/BmpFormat.cs @@ -8,18 +8,22 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// /// Registers the image encoders, decoders and mime type detectors for the bmp format. /// - internal sealed class BmpFormat : IImageFormat + internal sealed class BmpFormat : ImageFormatBase { + private BmpFormat() + { + } + /// - public string Name => "BMP"; + public override string Name => "BMP"; /// - public string DefaultMimeType => "image/bmp"; + public override string DefaultMimeType => "image/bmp"; /// - public IEnumerable MimeTypes => BmpConstants.MimeTypes; + public override IEnumerable MimeTypes => BmpConstants.MimeTypes; /// - public IEnumerable FileExtensions => BmpConstants.FileExtensions; + public override IEnumerable FileExtensions => BmpConstants.FileExtensions; } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs b/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs index bb884019b..6a740d47d 100644 --- a/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// public IImageFormat DetectFormat(ReadOnlySpan header) { - return this.IsSupportedFileFormat(header) ? ImageFormats.Bmp : null; + return this.IsSupportedFileFormat(header) ? BmpFormat.Instance : null; } private bool IsSupportedFileFormat(ReadOnlySpan header) diff --git a/src/ImageSharp/Formats/Bmp/BmpMetaData.cs b/src/ImageSharp/Formats/Bmp/BmpMetaData.cs new file mode 100644 index 000000000..1e350200a --- /dev/null +++ b/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 +{ + /// + /// Provides Bmp specific metadata information for the image. + /// + public class BmpMetaData : IImageFormatMetaData + { + // TODO: Analyse what properties we would like to preserve. + } +} diff --git a/src/ImageSharp/Formats/Bmp/ImageExtensions.cs b/src/ImageSharp/Formats/Bmp/ImageExtensions.cs index 57e4615ba..aa1c353db 100644 --- a/src/ImageSharp/Formats/Bmp/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Bmp/ImageExtensions.cs @@ -34,6 +34,6 @@ namespace SixLabors.ImageSharp /// Thrown if the stream is null. public static void SaveAsBmp(this Image source, Stream stream, BmpEncoder encoder) where TPixel : struct, IPixel - => source.Save(stream, encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(ImageFormats.Bmp)); + => source.Save(stream, encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(BmpFormat.Instance)); } } diff --git a/src/ImageSharp/Formats/Gif/GifConfigurationModule.cs b/src/ImageSharp/Formats/Gif/GifConfigurationModule.cs index 0bb62779e..861d3e036 100644 --- a/src/ImageSharp/Formats/Gif/GifConfigurationModule.cs +++ b/src/ImageSharp/Formats/Gif/GifConfigurationModule.cs @@ -9,12 +9,11 @@ namespace SixLabors.ImageSharp.Formats.Gif public sealed class GifConfigurationModule : IConfigurationModule { /// - public void Configure(Configuration config) + public void Configure(Configuration configuration) { - config.ImageFormatsManager.SetEncoder(ImageFormats.Gif, new GifEncoder()); - config.ImageFormatsManager.SetDecoder(ImageFormats.Gif, new GifDecoder()); - - config.ImageFormatsManager.AddImageFormatDetector(new GifImageFormatDetector()); + configuration.ImageFormatsManager.SetEncoder(GifFormat.Instance, new GifEncoder()); + configuration.ImageFormatsManager.SetDecoder(GifFormat.Instance, new GifDecoder()); + configuration.ImageFormatsManager.AddImageFormatDetector(new GifImageFormatDetector()); } } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/GifConstants.cs b/src/ImageSharp/Formats/Gif/GifConstants.cs index cc80b0cce..8167d0d2e 100644 --- a/src/ImageSharp/Formats/Gif/GifConstants.cs +++ b/src/ImageSharp/Formats/Gif/GifConstants.cs @@ -26,11 +26,6 @@ namespace SixLabors.ImageSharp.Formats.Gif /// internal static readonly byte[] MagicNumber = Encoding.UTF8.GetBytes(FileType + FileVersion); - /// - /// Gets the key used for storing and retriving metadata. - /// - public const string MetaDataKey = FileType; - /// /// The extension block introducer !. /// diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index 092ac859d..f50381264 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -164,7 +164,7 @@ namespace SixLabors.ImageSharp.Formats.Gif this.globalColorTable?.Dispose(); } - image?.MetaData.AddOrUpdateGifMetaData(this.gifMetaData); + image?.MetaData.AddOrUpdateFormatMetaData(GifFormat.Instance, this.gifMetaData); return image; } @@ -224,7 +224,7 @@ namespace SixLabors.ImageSharp.Formats.Gif this.globalColorTable?.Dispose(); } - this.metaData.AddOrUpdateGifMetaData(this.gifMetaData); + this.metaData.AddOrUpdateFormatMetaData(GifFormat.Instance, this.gifMetaData); return new ImageInfo( new PixelTypeInfo(this.logicalScreenDescriptor.BitsPerPixel), this.logicalScreenDescriptor.Width, @@ -561,7 +561,7 @@ namespace SixLabors.ImageSharp.Formats.Gif } gifMeta.DisposalMethod = this.graphicsControlExtension.DisposalMethod; - meta.AddOrUpdateGifFrameMetaData(gifMeta); + meta.AddOrUpdateFormatMetaData(GifFormat.Instance, gifMeta); } /// diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index b37344658..20f2f1d33 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -86,7 +86,7 @@ namespace SixLabors.ImageSharp.Formats.Gif Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); - this.gifMetaData = image.MetaData.GetGifMetaData() ?? new GifMetaData(); + this.gifMetaData = image.MetaData.GetOrAddFormatMetaData(GifFormat.Instance); this.colorTableMode = this.colorTableMode ?? this.gifMetaData.ColorTableMode; 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++) { ImageFrame frame = image.Frames[i]; - GifFrameMetaData frameMetaData = frame.MetaData.GetGifFrameMetaData() ?? new GifFrameMetaData(); + GifFrameMetaData frameMetaData = frame.MetaData.GetOrAddFormatMetaData(GifFormat.Instance); this.WriteGraphicalControlExtension(frameMetaData, transparencyIndex, stream); this.WriteImageDescriptor(frame, false, stream); @@ -169,7 +169,7 @@ namespace SixLabors.ImageSharp.Formats.Gif GifFrameMetaData previousMeta = null; foreach (ImageFrame frame in image.Frames) { - GifFrameMetaData meta = frame.MetaData.GetGifFrameMetaData() ?? new GifFrameMetaData(); + GifFrameMetaData meta = frame.MetaData.GetOrAddFormatMetaData(GifFormat.Instance); if (quantized is null) { // Allow each frame to be encoded at whatever color depth the frame designates if set. diff --git a/src/ImageSharp/Formats/Gif/GifFormat.cs b/src/ImageSharp/Formats/Gif/GifFormat.cs index 6353690f4..2d14abb44 100644 --- a/src/ImageSharp/Formats/Gif/GifFormat.cs +++ b/src/ImageSharp/Formats/Gif/GifFormat.cs @@ -8,18 +8,22 @@ namespace SixLabors.ImageSharp.Formats.Gif /// /// Registers the image encoders, decoders and mime type detectors for the gif format. /// - internal sealed class GifFormat : IImageFormat + internal sealed class GifFormat : ImageFormatBase { + private GifFormat() + { + } + /// - public string Name => "GIF"; + public override string Name => "GIF"; /// - public string DefaultMimeType => "image/gif"; + public override string DefaultMimeType => "image/gif"; /// - public IEnumerable MimeTypes => GifConstants.MimeTypes; + public override IEnumerable MimeTypes => GifConstants.MimeTypes; /// - public IEnumerable FileExtensions => GifConstants.FileExtensions; + public override IEnumerable FileExtensions => GifConstants.FileExtensions; } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs b/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs index cc04d4831..a7b68e6e8 100644 --- a/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs +++ b/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs @@ -1,12 +1,14 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using SixLabors.ImageSharp.MetaData; + namespace SixLabors.ImageSharp.Formats.Gif { /// /// Provides Gif specific metadata information for the image frame. /// - public class GifFrameMetaData + public class GifFrameMetaData : IImageFormatFrameMetaData { /// /// Gets or sets the length of the color table for paletted images. diff --git a/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs b/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs index bfbd334b0..b8f9a03f1 100644 --- a/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// public IImageFormat DetectFormat(ReadOnlySpan header) { - return this.IsSupportedFileFormat(header) ? ImageFormats.Gif : null; + return this.IsSupportedFileFormat(header) ? GifFormat.Instance : null; } private bool IsSupportedFileFormat(ReadOnlySpan header) diff --git a/src/ImageSharp/Formats/Gif/GifMetaData.cs b/src/ImageSharp/Formats/Gif/GifMetaData.cs index f58f5dff3..cc0716ec5 100644 --- a/src/ImageSharp/Formats/Gif/GifMetaData.cs +++ b/src/ImageSharp/Formats/Gif/GifMetaData.cs @@ -1,12 +1,14 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using SixLabors.ImageSharp.MetaData; + namespace SixLabors.ImageSharp.Formats.Gif { /// /// Provides Gif specific metadata information for the image. /// - public class GifMetaData + public class GifMetaData : IImageFormatMetaData { /// /// Gets or sets the number of times any animation is repeated. diff --git a/src/ImageSharp/Formats/Gif/GifMetaDataExtensions.cs b/src/ImageSharp/Formats/Gif/GifMetaDataExtensions.cs deleted file mode 100644 index 04b542d2d..000000000 --- a/src/ImageSharp/Formats/Gif/GifMetaDataExtensions.cs +++ /dev/null @@ -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 -{ - /// - /// Extension methods for storing meta data specific to Gif images. - /// - public static class GifMetaDataExtensions - { - /// - /// Adds or updates the Gif specific meta data to the image. - /// - /// The image meta data. - /// The gif meta data. - public static void AddOrUpdateGifMetaData(this ImageMetaData meta, GifMetaData value) => meta.AddOrUpdateMetaData(GifConstants.MetaDataKey, value); - - /// - /// Gets the Gif format specific meta data from the image. - /// - /// The image meta data. - /// The or null. - public static GifMetaData GetGifMetaData(this ImageMetaData meta) - { - meta.TryGetMetaData(GifConstants.MetaDataKey, out GifMetaData value); - return value; - } - - /// - /// Adds or updates the Gif specific meta data to the image frame. - /// - /// The image meta data. - /// The gif meta data. - public static void AddOrUpdateGifFrameMetaData(this ImageFrameMetaData meta, GifFrameMetaData value) => meta.AddOrUpdateMetaData(GifConstants.MetaDataKey, value); - - /// - /// Gets the Gif format specific meta data from the image frame. - /// - /// The image meta data. - /// The or null. - public static GifFrameMetaData GetGifFrameMetaData(this ImageFrameMetaData meta) - { - meta.TryGetMetaData(GifConstants.MetaDataKey, out GifFrameMetaData value); - return value; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/ImageExtensions.cs b/src/ImageSharp/Formats/Gif/ImageExtensions.cs index 1c41285a9..8ddd4247e 100644 --- a/src/ImageSharp/Formats/Gif/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Gif/ImageExtensions.cs @@ -34,6 +34,6 @@ namespace SixLabors.ImageSharp /// Thrown if the stream is null. public static void SaveAsGif(this Image source, Stream stream, GifEncoder encoder) where TPixel : struct, IPixel - => source.Save(stream, encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(ImageFormats.Gif)); + => source.Save(stream, encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(GifFormat.Instance)); } } diff --git a/src/ImageSharp/Formats/ImageFormatBase{T}.cs b/src/ImageSharp/Formats/ImageFormatBase{T}.cs new file mode 100644 index 000000000..85273db2b --- /dev/null +++ b/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 +{ + /// + /// The base class for all image formats. + /// Inheriting classes should implement the singleton pattern by creating a private constructor. + /// + /// The type of image format. + public abstract class ImageFormatBase : IImageFormat + where T : class, IImageFormat + { + private static readonly Lazy Lazy = new Lazy(CreateInstance); + + /// + /// Gets the current instance. + /// + public static T Instance => Lazy.Value; + + /// + public abstract string Name { get; } + + /// + public abstract string DefaultMimeType { get; } + + /// + public abstract IEnumerable MimeTypes { get; } + + /// + public abstract IEnumerable FileExtensions { get; } + + private static T CreateInstance() => (T)Activator.CreateInstance(typeof(T), true); + } +} diff --git a/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs b/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs index 1d3be063d..cb7fc1944 100644 --- a/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs @@ -34,6 +34,6 @@ namespace SixLabors.ImageSharp /// Thrown if the stream is null. public static void SaveAsJpeg(this Image source, Stream stream, JpegEncoder encoder) where TPixel : struct, IPixel - => source.Save(stream, encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(ImageFormats.Jpeg)); + => source.Save(stream, encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(JpegFormat.Instance)); } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs b/src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs index c3bf801ac..9840a2ae8 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs @@ -9,12 +9,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg public sealed class JpegConfigurationModule : IConfigurationModule { /// - public void Configure(Configuration config) + public void Configure(Configuration configuration) { - config.ImageFormatsManager.SetEncoder(ImageFormats.Jpeg, new JpegEncoder()); - config.ImageFormatsManager.SetDecoder(ImageFormats.Jpeg, new JpegDecoder()); - - config.ImageFormatsManager.AddImageFormatDetector(new JpegImageFormatDetector()); + configuration.ImageFormatsManager.SetEncoder(JpegFormat.Instance, new JpegEncoder()); + configuration.ImageFormatsManager.SetDecoder(JpegFormat.Instance, new JpegDecoder()); + configuration.ImageFormatsManager.AddImageFormatDetector(new JpegImageFormatDetector()); } } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/JpegFormat.cs b/src/ImageSharp/Formats/Jpeg/JpegFormat.cs index 9a18f14d3..21757dcb3 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegFormat.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegFormat.cs @@ -8,18 +8,22 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// /// Registers the image encoders, decoders and mime type detectors for the jpeg format. /// - internal sealed class JpegFormat : IImageFormat + internal sealed class JpegFormat : ImageFormatBase { + private JpegFormat() + { + } + /// - public string Name => "JPEG"; + public override string Name => "JPEG"; /// - public string DefaultMimeType => "image/jpeg"; + public override string DefaultMimeType => "image/jpeg"; /// - public IEnumerable MimeTypes => JpegConstants.MimeTypes; + public override IEnumerable MimeTypes => JpegConstants.MimeTypes; /// - public IEnumerable FileExtensions => JpegConstants.FileExtensions; + public override IEnumerable FileExtensions => JpegConstants.FileExtensions; } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs b/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs index e25957efc..7594f4477 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// public IImageFormat DetectFormat(ReadOnlySpan header) { - return this.IsSupportedFileFormat(header) ? ImageFormats.Jpeg : null; + return this.IsSupportedFileFormat(header) ? JpegFormat.Instance : null; } private bool IsSupportedFileFormat(ReadOnlySpan header) diff --git a/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs b/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs new file mode 100644 index 000000000..eec0efa80 --- /dev/null +++ b/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 +{ + /// + /// Provides Jpeg specific metadata information for the image. + /// + public class JpegMetaData : IImageFormatMetaData + { + // TODO: Analyse what properties we would like to preserve. + } +} diff --git a/src/ImageSharp/Formats/Png/ImageExtensions.cs b/src/ImageSharp/Formats/Png/ImageExtensions.cs index a65845e02..c73ec6f57 100644 --- a/src/ImageSharp/Formats/Png/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Png/ImageExtensions.cs @@ -35,6 +35,6 @@ namespace SixLabors.ImageSharp /// Thrown if the stream is null. public static void SaveAsPng(this Image source, Stream stream, PngEncoder encoder) where TPixel : struct, IPixel - => source.Save(stream, encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(ImageFormats.Png)); + => source.Save(stream, encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(PngFormat.Instance)); } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Png/PngConfigurationModule.cs b/src/ImageSharp/Formats/Png/PngConfigurationModule.cs index 64dad23bc..3c9fddbad 100644 --- a/src/ImageSharp/Formats/Png/PngConfigurationModule.cs +++ b/src/ImageSharp/Formats/Png/PngConfigurationModule.cs @@ -11,8 +11,8 @@ namespace SixLabors.ImageSharp.Formats.Png /// public void Configure(Configuration configuration) { - configuration.ImageFormatsManager.SetEncoder(ImageFormats.Png, new PngEncoder()); - configuration.ImageFormatsManager.SetDecoder(ImageFormats.Png, new PngDecoder()); + configuration.ImageFormatsManager.SetEncoder(PngFormat.Instance, new PngEncoder()); + configuration.ImageFormatsManager.SetDecoder(PngFormat.Instance, new PngDecoder()); configuration.ImageFormatsManager.AddImageFormatDetector(new PngImageFormatDetector()); } } diff --git a/src/ImageSharp/Formats/Png/PngFormat.cs b/src/ImageSharp/Formats/Png/PngFormat.cs index 142f66071..00ebbde52 100644 --- a/src/ImageSharp/Formats/Png/PngFormat.cs +++ b/src/ImageSharp/Formats/Png/PngFormat.cs @@ -8,18 +8,22 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Registers the image encoders, decoders and mime type detectors for the png format. /// - internal sealed class PngFormat : IImageFormat + internal sealed class PngFormat : ImageFormatBase { + private PngFormat() + { + } + /// - public string Name => "PNG"; + public override string Name => "PNG"; /// - public string DefaultMimeType => "image/png"; + public override string DefaultMimeType => "image/png"; /// - public IEnumerable MimeTypes => PngConstants.MimeTypes; + public override IEnumerable MimeTypes => PngConstants.MimeTypes; /// - public IEnumerable FileExtensions => PngConstants.FileExtensions; + public override IEnumerable FileExtensions => PngConstants.FileExtensions; } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs b/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs index c1c039a1b..5deed86e3 100644 --- a/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// public IImageFormat DetectFormat(ReadOnlySpan header) { - return this.IsSupportedFileFormat(header) ? ImageFormats.Png : null; + return this.IsSupportedFileFormat(header) ? PngFormat.Instance : null; } private bool IsSupportedFileFormat(ReadOnlySpan header) diff --git a/src/ImageSharp/Formats/Png/PngMetaData.cs b/src/ImageSharp/Formats/Png/PngMetaData.cs new file mode 100644 index 000000000..1d76cf580 --- /dev/null +++ b/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 +{ + /// + /// Provides Png specific metadata information for the image. + /// + public class PngMetaData : IImageFormatMetaData + { + // TODO: Analyse what properties we would like to preserve. + } +} diff --git a/src/ImageSharp/ImageFormats.cs b/src/ImageSharp/ImageFormats.cs deleted file mode 100644 index bc437e5a5..000000000 --- a/src/ImageSharp/ImageFormats.cs +++ /dev/null @@ -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 -{ - /// - /// The static collection of all the default image formats - /// - public static class ImageFormats - { - /// - /// The format details for the jpegs. - /// - public static readonly IImageFormat Jpeg = new JpegFormat(); - - /// - /// The format details for the pngs. - /// - public static readonly IImageFormat Png = new PngFormat(); - - /// - /// The format details for the gifs. - /// - public static readonly IImageFormat Gif = new GifFormat(); - - /// - /// The format details for the bitmaps. - /// - public static readonly IImageFormat Bmp = new BmpFormat(); - } -} \ No newline at end of file diff --git a/src/ImageSharp/MetaData/IImageFormatFrameMetaData.cs b/src/ImageSharp/MetaData/IImageFormatFrameMetaData.cs new file mode 100644 index 000000000..5df6fa433 --- /dev/null +++ b/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 +{ + /// + /// Encapsulates the format specific metadata of an image frame. + /// This interface exists to allow type saftey and avoid the performance overhead of parsing attributes. + /// + public interface IImageFormatFrameMetaData + { + } +} \ No newline at end of file diff --git a/src/ImageSharp/MetaData/IImageFormatMetaData.cs b/src/ImageSharp/MetaData/IImageFormatMetaData.cs new file mode 100644 index 000000000..ded8df801 --- /dev/null +++ b/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 +{ + /// + /// Encapsulates the format specific metadata of an image. + /// This interface exists to allow type saftey and avoid the performance overhead of parsing attributes. + /// + public interface IImageFormatMetaData + { + } +} \ No newline at end of file diff --git a/src/ImageSharp/MetaData/ImageFrameMetaData.cs b/src/ImageSharp/MetaData/ImageFrameMetaData.cs index 55678789e..31bad29b8 100644 --- a/src/ImageSharp/MetaData/ImageFrameMetaData.cs +++ b/src/ImageSharp/MetaData/ImageFrameMetaData.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.MetaData { @@ -11,7 +12,7 @@ namespace SixLabors.ImageSharp.MetaData /// public sealed class ImageFrameMetaData { - private readonly Dictionary metaData = new Dictionary(StringComparer.OrdinalIgnoreCase); + private readonly Dictionary metaData = new Dictionary(); /// /// Initializes a new instance of the class. @@ -31,7 +32,7 @@ namespace SixLabors.ImageSharp.MetaData { DebugGuard.NotNull(other, nameof(other)); - foreach (KeyValuePair meta in other.metaData) + foreach (KeyValuePair meta in other.metaData) { this.metaData.Add(meta.Key, meta.Value); } @@ -51,7 +52,7 @@ namespace SixLabors.ImageSharp.MetaData /// key is null. /// value is null. /// An element with the same key already exists in the . - public void AddOrUpdateMetaData(string key, object value) + public void AddOrUpdateFormatMetaData(IImageFormat key, IImageFormatFrameMetaData value) { // Don't think this needs to be threadsafe. Guard.NotNull(value, nameof(value)); @@ -61,27 +62,22 @@ namespace SixLabors.ImageSharp.MetaData /// /// Gets the metadata value associated with the specified key. /// - /// The type of value. + /// The type of metadata. /// The key of the value to get. - /// - /// 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. - /// /// - /// true if the contains an element with - /// the specified key; otherwise, false. + /// The . /// - public bool TryGetMetaData(string key, out T value) + public T GetOrAddFormatMetaData(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 true; + return (T)meta; } - value = default; - return false; + var newMeta = new T(); + this.AddOrUpdateFormatMetaData(key, newMeta); + return newMeta; } } } \ No newline at end of file diff --git a/src/ImageSharp/MetaData/ImageMetaData.cs b/src/ImageSharp/MetaData/ImageMetaData.cs index 8233798c2..d907e8b8a 100644 --- a/src/ImageSharp/MetaData/ImageMetaData.cs +++ b/src/ImageSharp/MetaData/ImageMetaData.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.MetaData.Profiles.Icc; @@ -25,7 +26,7 @@ namespace SixLabors.ImageSharp.MetaData /// public const double DefaultVerticalResolution = 96; - private readonly Dictionary metaData = new Dictionary(StringComparer.OrdinalIgnoreCase); + private readonly Dictionary metaData = new Dictionary(); private double horizontalResolution; private double verticalResolution; @@ -51,7 +52,7 @@ namespace SixLabors.ImageSharp.MetaData this.VerticalResolution = other.VerticalResolution; this.ResolutionUnits = other.ResolutionUnits; - foreach (KeyValuePair meta in other.metaData) + foreach (KeyValuePair meta in other.metaData) { this.metaData.Add(meta.Key, meta.Value); } @@ -138,7 +139,7 @@ namespace SixLabors.ImageSharp.MetaData /// key is null. /// value is null. /// An element with the same key already exists in the . - public void AddOrUpdateMetaData(string key, object value) + public void AddOrUpdateFormatMetaData(IImageFormat key, IImageFormatMetaData value) { // Don't think this needs to be threadsafe. Guard.NotNull(value, nameof(value)); @@ -148,27 +149,22 @@ namespace SixLabors.ImageSharp.MetaData /// /// Gets the metadata value associated with the specified key. /// - /// The type of value. + /// The type of metadata. /// The key of the value to get. - /// - /// 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. - /// /// - /// true if the contains an element with - /// the specified key; otherwise, false. + /// The . /// - public bool TryGetMetaData(string key, out T value) + public T GetOrAddFormatMetaData(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 true; + return (T)meta; } - value = default; - return false; + var newMeta = new T(); + this.AddOrUpdateFormatMetaData(key, newMeta); + return newMeta; } /// diff --git a/tests/ImageSharp.Tests/ConfigurationTests.cs b/tests/ImageSharp.Tests/ConfigurationTests.cs index 4bec25f7a..6a8479b2b 100644 --- a/tests/ImageSharp.Tests/ConfigurationTests.cs +++ b/tests/ImageSharp.Tests/ConfigurationTests.cs @@ -4,6 +4,7 @@ using System; using System.Linq; using Moq; +using SixLabors.ImageSharp.Formats.Bmp; using SixLabors.ImageSharp.IO; using Xunit; // ReSharper disable InconsistentNaming @@ -37,19 +38,13 @@ namespace SixLabors.ImageSharp.Tests /// Test that the default configuration is not null. /// [Fact] - public void TestDefaultConfigurationIsNotNull() - { - Assert.True(Configuration.Default != null); - } + public void TestDefaultConfigurationIsNotNull() => Assert.True(Configuration.Default != null); /// /// Test that the default configuration read origin options is set to begin. /// [Fact] - public void TestDefaultConfigurationReadOriginIsCurrent() - { - Assert.True(Configuration.Default.ReadOrigin == ReadOrigin.Current); - } + public void TestDefaultConfigurationReadOriginIsCurrent() => Assert.True(Configuration.Default.ReadOrigin == ReadOrigin.Current); /// /// 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()); - config.ImageFormatsManager.AddImageFormat(ImageFormats.Bmp); + config.ImageFormatsManager.AddImageFormat(BmpFormat.Instance); Assert.Equal(count, config.ImageFormats.Count()); } diff --git a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs index 23b806767..f8b035ca8 100644 --- a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs +++ b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs @@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Tests using (Image image = file.CreateImage()) { string filename = path + "/" + file.FileNameWithoutExtension + ".txt"; - File.WriteAllText(filename, image.ToBase64String(ImageFormats.Png)); + File.WriteAllText(filename, image.ToBase64String(PngFormat.Instance)); } } } diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs index 2b08bf20d..4ddcded5e 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs @@ -189,8 +189,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif inStream.Position = 0; var image = Image.Load(inStream); - GifMetaData metaData = image.MetaData.GetGifMetaData(); - GifFrameMetaData frameMetaData = image.Frames.RootFrame.MetaData.GetGifFrameMetaData(); + GifMetaData metaData = image.MetaData.GetOrAddFormatMetaData(GifFormat.Instance); + GifFrameMetaData frameMetaData = image.Frames.RootFrame.MetaData.GetOrAddFormatMetaData(GifFormat.Instance); GifColorTableMode colorMode = metaData.ColorTableMode; var encoder = new GifEncoder() { @@ -204,7 +204,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif outStream.Position = 0; var clone = Image.Load(outStream); - GifMetaData cloneMetaData = clone.MetaData.GetGifMetaData(); + GifMetaData cloneMetaData = clone.MetaData.GetOrAddFormatMetaData(GifFormat.Instance); Assert.Equal(metaData.ColorTableMode, cloneMetaData.ColorTableMode); // 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++) { - GifFrameMetaData ifm = image.Frames[i].MetaData.GetGifFrameMetaData(); - GifFrameMetaData cifm = clone.Frames[i].MetaData.GetGifFrameMetaData(); + GifFrameMetaData ifm = image.Frames[i].MetaData.GetOrAddFormatMetaData(GifFormat.Instance); + GifFrameMetaData cifm = clone.Frames[i].MetaData.GetOrAddFormatMetaData(GifFormat.Instance); Assert.Equal(ifm.ColorTableLength, cifm.ColorTableLength); Assert.Equal(ifm.FrameDelay, cifm.FrameDelay); diff --git a/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs b/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs index f10a4ce84..464b1564b 100644 --- a/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs +++ b/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs @@ -61,7 +61,7 @@ namespace SixLabors.ImageSharp.Tests }); Assert.Throws(() => { - this.DefaultFormatsManager.SetEncoder(ImageFormats.Bmp, null); + this.DefaultFormatsManager.SetEncoder(BmpFormat.Instance, null); }); Assert.Throws(() => { @@ -78,7 +78,7 @@ namespace SixLabors.ImageSharp.Tests }); Assert.Throws(() => { - this.DefaultFormatsManager.SetDecoder(ImageFormats.Bmp, null); + this.DefaultFormatsManager.SetDecoder(BmpFormat.Instance, null); }); Assert.Throws(() => { diff --git a/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs b/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs index c250d973b..00d03dce4 100644 --- a/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs +++ b/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs @@ -27,10 +27,10 @@ namespace SixLabors.ImageSharp.Tests }; var metaData = new ImageFrameMetaData(); - metaData.AddOrUpdateGifFrameMetaData(gifFrameMetaData); + metaData.AddOrUpdateFormatMetaData(GifFormat.Instance, gifFrameMetaData); var clone = new ImageFrameMetaData(metaData); - GifFrameMetaData cloneGifFrameMetaData = clone.GetGifFrameMetaData(); + GifFrameMetaData cloneGifFrameMetaData = clone.GetOrAddFormatMetaData(GifFormat.Instance); Assert.Equal(frameDelay, cloneGifFrameMetaData.FrameDelay); Assert.Equal(colorTableLength, cloneGifFrameMetaData.ColorTableLength); diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs index 90c999f7c..334b6552a 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs @@ -62,13 +62,13 @@ namespace SixLabors.ImageSharp.Tests IImageEncoder bmpEncoder = IsWindows ? (IImageEncoder)SystemDrawingReferenceEncoder.Bmp : new BmpEncoder(); cfg.ConfigureCodecs( - ImageFormats.Png, + PngFormat.Instance, MagickReferenceDecoder.Instance, pngEncoder, new PngImageFormatDetector()); cfg.ConfigureCodecs( - ImageFormats.Bmp, + BmpFormat.Instance, SystemDrawingReferenceDecoder.Instance, bmpEncoder, new BmpImageFormatDetector());