From ea44e6ce158069d089bf119ac1ed353e981987ca Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Tue, 20 Jun 2017 22:28:11 +0100 Subject: [PATCH 01/13] refactor encoders/decoders refactor encoders to remove IImageFormat and split the logic across Encoders and Decoders. remove IXXXOptions and moved setting onto encoders/decoders directly. add out param on Image.Load APIs to output mime type of loaded image. --- src/ImageSharp/Configuration.cs | 153 +++------ src/ImageSharp/Formats/Bmp/BmpConstants.cs | 25 ++ src/ImageSharp/Formats/Bmp/BmpDecoder.cs | 20 +- src/ImageSharp/Formats/Bmp/BmpEncoder.cs | 28 +- src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs | 20 +- .../Formats/Bmp/BmpEncoderOptions.cs | 45 --- src/ImageSharp/Formats/Bmp/BmpFormat.cs | 41 --- .../Formats/Bmp/IBmpEncoderOptions.cs | 18 -- src/ImageSharp/Formats/DecoderOptions.cs | 37 --- src/ImageSharp/Formats/EncoderOptions.cs | 37 --- src/ImageSharp/Formats/Gif/GifConstants.cs | 13 +- src/ImageSharp/Formats/Gif/GifDecoder.cs | 47 ++- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 27 +- .../Formats/Gif/GifDecoderOptions.cs | 47 --- src/ImageSharp/Formats/Gif/GifEncoder.cs | 51 ++- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 41 ++- .../Formats/Gif/GifEncoderOptions.cs | 65 ---- src/ImageSharp/Formats/Gif/GifFormat.cs | 45 --- .../Formats/Gif/IGifDecoderOptions.cs | 20 -- .../Formats/Gif/IGifEncoderOptions.cs | 38 --- src/ImageSharp/Formats/Gif/ImageExtensions.cs | 8 +- src/ImageSharp/Formats/IDecoderOptions.cs | 18 -- src/ImageSharp/Formats/IEncoderOptions.cs | 18 -- src/ImageSharp/Formats/IImageDecoder.cs | 30 +- src/ImageSharp/Formats/IImageEncoder.cs | 14 +- src/ImageSharp/Formats/IImageFormat.cs | 60 ---- .../Formats/Jpeg/IJpegEncoderOptions.cs | 26 -- .../Formats/Jpeg/ImageExtensions.cs | 8 +- src/ImageSharp/Formats/Jpeg/JpegConstants.cs | 12 + src/ImageSharp/Formats/Jpeg/JpegDecoder.cs | 76 ++++- .../Formats/Jpeg/JpegDecoderCore.cs | 18 +- src/ImageSharp/Formats/Jpeg/JpegEncoder.cs | 50 ++- .../Formats/Jpeg/JpegEncoderCore.cs | 51 ++- .../Formats/Jpeg/JpegEncoderOptions.cs | 56 ---- src/ImageSharp/Formats/Jpeg/JpegFormat.cs | 89 ----- .../Formats/Png/IPngDecoderOptions.cs | 20 -- .../Formats/Png/IPngEncoderOptions.cs | 54 ---- src/ImageSharp/Formats/Png/ImageExtensions.cs | 8 +- src/ImageSharp/Formats/Png/PngConstants.cs | 30 ++ src/ImageSharp/Formats/Png/PngDecoder.cs | 43 ++- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 42 +-- .../Formats/Png/PngDecoderOptions.cs | 49 --- src/ImageSharp/Formats/Png/PngEncoder.cs | 71 +++- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 84 +++-- .../Formats/Png/PngEncoderOptions.cs | 82 ----- src/ImageSharp/Formats/Png/PngFormat.cs | 47 --- src/ImageSharp/Image/IImage.cs | 5 - src/ImageSharp/Image/Image.Decode.cs | 22 +- src/ImageSharp/Image/Image.FromBytes.cs | 66 ++-- src/ImageSharp/Image/Image.FromFile.cs | 66 ++-- src/ImageSharp/Image/Image.FromStream.cs | 60 ++-- src/ImageSharp/Image/Image{TPixel}.cs | 156 ++------- src/ImageSharp/ImageSharp.csproj | 1 + src/ImageSharp/MetaData/ImageMetaData.cs | 6 - tests/ImageSharp.Benchmarks/BenchmarkBase.cs | 4 - .../Image/EncodeIndexedPng.cs | 12 +- .../ImageSharp.Benchmarks/Image/EncodePng.cs | 2 +- tests/ImageSharp.Tests/ConfigurationTests.cs | 204 +----------- .../ImageSharp.Tests/Drawing/BeziersTests.cs | 28 +- .../ImageSharp.Tests/Drawing/DrawPathTests.cs | 29 +- .../Drawing/FillPatternTests.cs | 10 +- .../Drawing/FillSolidBrushTests.cs | 34 +- .../Drawing/LineComplexPolygonTests.cs | 55 ++-- tests/ImageSharp.Tests/Drawing/LineTests.cs | 119 +++---- .../ImageSharp.Tests/Drawing/PolygonTests.cs | 15 +- .../Drawing/RecolorImageTest.cs | 16 +- .../Drawing/SolidBezierTests.cs | 10 +- .../Drawing/SolidComplexPolygonTests.cs | 35 +- .../Drawing/SolidPolygonTests.cs | 96 ++---- .../Formats/Bmp/BmpEncoderTests.cs | 2 +- .../Formats/GeneralFormatTests.cs | 22 +- .../Formats/Gif/GifDecoderTests.cs | 6 +- .../Formats/Gif/GifEncoderTests.cs | 8 +- .../Formats/Jpg/JpegDecoderTests.cs | 13 +- .../Formats/Jpg/JpegEncoderTests.cs | 16 +- .../Formats/Jpg/JpegProfilingBenchmarks.cs | 5 +- .../Formats/Png/PngDecoderTests.cs | 6 +- .../Formats/Png/PngEncoderTests.cs | 4 +- .../Formats/Png/PngSmokeTests.cs | 3 +- .../ImageSharp.Tests/Image/ImageLoadTests.cs | 303 ++---------------- .../ImageSharp.Tests/Image/ImageSaveTests.cs | 121 +------ tests/ImageSharp.Tests/Image/ImageTests.cs | 30 +- .../MetaData/ImageMetaDataTests.cs | 2 - tests/ImageSharp.Tests/TestFile.cs | 7 +- tests/ImageSharp.Tests/TestFormat.cs | 34 +- .../TestUtilities/ImagingTestCaseUtility.cs | 12 +- 86 files changed, 1094 insertions(+), 2433 deletions(-) create mode 100644 src/ImageSharp/Formats/Bmp/BmpConstants.cs delete mode 100644 src/ImageSharp/Formats/Bmp/BmpEncoderOptions.cs delete mode 100644 src/ImageSharp/Formats/Bmp/BmpFormat.cs delete mode 100644 src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs delete mode 100644 src/ImageSharp/Formats/DecoderOptions.cs delete mode 100644 src/ImageSharp/Formats/EncoderOptions.cs delete mode 100644 src/ImageSharp/Formats/Gif/GifDecoderOptions.cs delete mode 100644 src/ImageSharp/Formats/Gif/GifEncoderOptions.cs delete mode 100644 src/ImageSharp/Formats/Gif/GifFormat.cs delete mode 100644 src/ImageSharp/Formats/Gif/IGifDecoderOptions.cs delete mode 100644 src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs delete mode 100644 src/ImageSharp/Formats/IDecoderOptions.cs delete mode 100644 src/ImageSharp/Formats/IEncoderOptions.cs delete mode 100644 src/ImageSharp/Formats/IImageFormat.cs delete mode 100644 src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs delete mode 100644 src/ImageSharp/Formats/Jpeg/JpegEncoderOptions.cs delete mode 100644 src/ImageSharp/Formats/Jpeg/JpegFormat.cs delete mode 100644 src/ImageSharp/Formats/Png/IPngDecoderOptions.cs delete mode 100644 src/ImageSharp/Formats/Png/IPngEncoderOptions.cs create mode 100644 src/ImageSharp/Formats/Png/PngConstants.cs delete mode 100644 src/ImageSharp/Formats/Png/PngDecoderOptions.cs delete mode 100644 src/ImageSharp/Formats/Png/PngEncoderOptions.cs delete mode 100644 src/ImageSharp/Formats/Png/PngFormat.cs diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs index fa983d355..5734d70fb 100644 --- a/src/ImageSharp/Configuration.cs +++ b/src/ImageSharp/Configuration.cs @@ -30,27 +30,20 @@ namespace ImageSharp private readonly object syncRoot = new object(); /// - /// The list of supported . + /// The list of supported . /// - private readonly List imageFormatsList = new List(); + private readonly List encoders = new List(); /// - /// Initializes a new instance of the class. + /// The list of supported . /// - public Configuration() - { - } + private readonly List decoders = new List(); /// /// Initializes a new instance of the class. /// - /// The inital set of image formats. - public Configuration(params IImageFormat[] providers) + public Configuration() { - foreach (IImageFormat p in providers) - { - this.AddImageFormat(p); - } } /// @@ -59,9 +52,14 @@ namespace ImageSharp public static Configuration Default { get; } = Lazy.Value; /// - /// Gets the collection of supported + /// Gets the collection of supported /// - public IReadOnlyCollection ImageFormats => new ReadOnlyCollection(this.imageFormatsList); + public IReadOnlyCollection ImageEncoders => new ReadOnlyCollection(this.encoders); + + /// + /// Gets the collection of supported + /// + public IReadOnlyCollection ImageDecoders => new ReadOnlyCollection(this.decoders); /// /// Gets the global parallel options for processing tasks in parallel. @@ -81,118 +79,57 @@ namespace ImageSharp #endif /// - /// Adds a new to the collection of supported image formats. - /// - /// The new format to add. - public void AddImageFormat(IImageFormat format) - { - Guard.NotNull(format, nameof(format)); - Guard.NotNull(format.Encoder, nameof(format), "The encoder should not be null."); - Guard.NotNull(format.Decoder, nameof(format), "The decoder should not be null."); - Guard.NotNullOrEmpty(format.MimeType, nameof(format), "The mime type should not be null or empty."); - Guard.NotNullOrEmpty(format.Extension, nameof(format), "The extension should not be null or empty."); - Guard.NotNullOrEmpty(format.SupportedExtensions, nameof(format), "The supported extensions not be null or empty."); - - this.AddImageFormatLocked(format); - } - - /// - /// Creates the default instance, with Png, Jpeg, Gif and Bmp preregisterd (if they have been referenced) + /// Adds a new to the collection of supported image formats. /// - /// The default configuration of - internal static Configuration CreateDefaultInstance() + /// The new format to add. + public void AddImageFormat(IImageDecoder decoder) { - Configuration config = new Configuration(); - - // lets try auto loading the known image formats - config.AddImageFormat(new Formats.PngFormat()); - config.AddImageFormat(new Formats.JpegFormat()); - config.AddImageFormat(new Formats.GifFormat()); - config.AddImageFormat(new Formats.BmpFormat()); - return config; - } + Guard.NotNull(decoder, nameof(decoder)); + Guard.NotNullOrEmpty(decoder.FileExtensions, nameof(decoder.FileExtensions)); + Guard.NotNullOrEmpty(decoder.MimeTypes, nameof(decoder.MimeTypes)); - /// - /// Tries the add image format. - /// - /// Name of the type. - /// True if type discoverd and is a valid - internal bool TryAddImageFormat(string typeName) - { - Type type = Type.GetType(typeName, false); - if (type != null) + lock (this.syncRoot) { - IImageFormat format = Activator.CreateInstance(type) as IImageFormat; - if (format != null - && format.Encoder != null - && format.Decoder != null - && !string.IsNullOrEmpty(format.MimeType) - && format.SupportedExtensions?.Any() == true) - { - // we can use the locked version as we have already validated in the if. - this.AddImageFormatLocked(format); - return true; - } - } + this.decoders.Add(decoder); - return false; + this.SetMaxHeaderSize(); + } } /// - /// Adds image format. The class is locked to make it thread safe. + /// Adds a new to the collection of supported image formats. /// - /// The image format. - private void AddImageFormatLocked(IImageFormat format) + /// The new format to add. + public void AddImageFormat(IImageEncoder encoder) { + Guard.NotNull(encoder, nameof(encoder)); + Guard.NotNullOrEmpty(encoder.FileExtensions, nameof(encoder.FileExtensions)); + Guard.NotNullOrEmpty(encoder.MimeTypes, nameof(encoder.MimeTypes)); lock (this.syncRoot) { - if (this.GuardDuplicate(format)) - { - this.imageFormatsList.Add(format); - - this.SetMaxHeaderSize(); - } + this.encoders.Add(encoder); } } /// - /// Checks to ensure duplicate image formats are not added. + /// Creates the default instance, with Png, Jpeg, Gif and Bmp preregisterd (if they have been referenced) /// - /// The image format. - /// Thrown if a duplicate is added. - /// - /// The . - /// - private bool GuardDuplicate(IImageFormat format) + /// The default configuration of + internal static Configuration CreateDefaultInstance() { - if (!format.SupportedExtensions.Contains(format.Extension, StringComparer.OrdinalIgnoreCase)) - { - throw new ArgumentException("The supported extensions should contain the default extension.", nameof(format)); - } - - // ReSharper disable once ConvertClosureToMethodGroup - // Prevents method group allocation - if (format.SupportedExtensions.Any(e => string.IsNullOrWhiteSpace(e))) - { - throw new ArgumentException("The supported extensions should not contain empty values.", nameof(format)); - } - - // If there is already a format with the same extension or a format that supports that - // extension return false. - foreach (IImageFormat imageFormat in this.imageFormatsList) - { - if (imageFormat.Extension.Equals(format.Extension, StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - if (imageFormat.SupportedExtensions.Intersect(format.SupportedExtensions, StringComparer.OrdinalIgnoreCase).Any()) - { - return false; - } - } + Configuration config = new Configuration(); - return true; + // lets try auto loading the known image formats + config.AddImageFormat(new Formats.PngEncoder()); + config.AddImageFormat(new Formats.JpegEncoder()); + config.AddImageFormat(new Formats.GifEncoder()); + config.AddImageFormat(new Formats.BmpEncoder()); + + config.AddImageFormat(new Formats.PngDecoder()); + config.AddImageFormat(new Formats.JpegDecoder()); + config.AddImageFormat(new Formats.GifDecoder()); + config.AddImageFormat(new Formats.BmpDecoder()); + return config; } /// @@ -200,7 +137,7 @@ namespace ImageSharp /// private void SetMaxHeaderSize() { - this.MaxHeaderSize = this.imageFormatsList.Max(x => x.HeaderSize); + this.MaxHeaderSize = this.decoders.Max(x => x.HeaderSize); } } } diff --git a/src/ImageSharp/Formats/Bmp/BmpConstants.cs b/src/ImageSharp/Formats/Bmp/BmpConstants.cs new file mode 100644 index 000000000..f2454f24d --- /dev/null +++ b/src/ImageSharp/Formats/Bmp/BmpConstants.cs @@ -0,0 +1,25 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System.Collections.Generic; + + /// + /// Defines constants relating to BMPs + /// + internal static class BmpConstants + { + /// + /// The list of mimetypes that equate to a bmp + /// + public static readonly IEnumerable MimeTypes = new[] { "image/bmp", "image/x-windows-bmp" }; + + /// + /// The list of mimetypes that equate to a bmp + /// + public static readonly IEnumerable FileExtensions = new[] { "bm", "bmp", "dip" }; + } +} diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs index 9090e9a8c..9ff331490 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs @@ -6,6 +6,7 @@ namespace ImageSharp.Formats { using System; + using System.Collections.Generic; using System.IO; using ImageSharp.PixelFormats; @@ -28,7 +29,24 @@ namespace ImageSharp.Formats public class BmpDecoder : IImageDecoder { /// - public Image Decode(Configuration configuration, Stream stream, IDecoderOptions options) + public IEnumerable MimeTypes => BmpConstants.MimeTypes; + + /// + public IEnumerable FileExtensions => BmpConstants.FileExtensions; + + /// + public int HeaderSize => 2; + + /// + public bool IsSupportedFileFormat(Span header) + { + return header.Length >= this.HeaderSize && + header[0] == 0x42 && // B + header[1] == 0x4D; // M + } + + /// + public Image Decode(Configuration configuration, Stream stream) where TPixel : struct, IPixel { diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoder.cs b/src/ImageSharp/Formats/Bmp/BmpEncoder.cs index dc2bc0e97..25db0eda0 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoder.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoder.cs @@ -6,6 +6,7 @@ namespace ImageSharp.Formats { using System; + using System.Collections.Generic; using System.IO; using ImageSharp.PixelFormats; @@ -16,26 +17,23 @@ namespace ImageSharp.Formats /// The encoder can currently only write 24-bit rgb images to streams. public class BmpEncoder : IImageEncoder { + /// + /// Gets or sets the number of bits per pixel. + /// + public BmpBitsPerPixel BitsPerPixel { get; set; } = BmpBitsPerPixel.Pixel24; + /// - public void Encode(Image image, Stream stream, IEncoderOptions options) - where TPixel : struct, IPixel - { - IBmpEncoderOptions bmpOptions = BmpEncoderOptions.Create(options); + public IEnumerable MimeTypes => BmpConstants.MimeTypes; - this.Encode(image, stream, bmpOptions); - } + /// + public IEnumerable FileExtensions => BmpConstants.FileExtensions; - /// - /// Encodes the image to the specified stream from the . - /// - /// The pixel format. - /// The to encode from. - /// The to encode the image data to. - /// The options for the encoder. - public void Encode(Image image, Stream stream, IBmpEncoderOptions options) + /// + public void Encode(Image image, Stream stream) where TPixel : struct, IPixel { - BmpEncoderCore encoder = new BmpEncoderCore(options); + BmpEncoderCore encoder = new BmpEncoderCore(); + encoder.BitsPerPixel = this.BitsPerPixel; encoder.Encode(image, stream); } } diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index 617edde8e..615ff23ee 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -17,11 +17,6 @@ namespace ImageSharp.Formats /// internal sealed class BmpEncoderCore { - /// - /// The options for the encoder. - /// - private readonly IBmpEncoderOptions options; - /// /// The amount to pad each row by. /// @@ -30,12 +25,15 @@ namespace ImageSharp.Formats /// /// Initializes a new instance of the class. /// - /// The options for the encoder. - public BmpEncoderCore(IBmpEncoderOptions options) + public BmpEncoderCore() { - this.options = options ?? new BmpEncoderOptions(); } + /// + /// Gets or sets the BitsPerPixel + /// + public BmpBitsPerPixel BitsPerPixel { get; internal set; } = BmpBitsPerPixel.Pixel24; + /// /// Encodes the image to the specified stream from the . /// @@ -49,9 +47,9 @@ namespace ImageSharp.Formats Guard.NotNull(stream, nameof(stream)); // Cast to int will get the bytes per pixel - short bpp = (short)(8 * (int)this.options.BitsPerPixel); + short bpp = (short)(8 * (int)this.BitsPerPixel); int bytesPerLine = 4 * (((image.Width * bpp) + 31) / 32); - this.padding = bytesPerLine - (image.Width * (int)this.options.BitsPerPixel); + this.padding = bytesPerLine - (image.Width * (int)this.BitsPerPixel); // Do not use IDisposable pattern here as we want to preserve the stream. EndianBinaryWriter writer = new EndianBinaryWriter(Endianness.LittleEndian, stream); @@ -136,7 +134,7 @@ namespace ImageSharp.Formats { using (PixelAccessor pixels = image.Lock()) { - switch (this.options.BitsPerPixel) + switch (this.BitsPerPixel) { case BmpBitsPerPixel.Pixel32: this.Write32Bit(writer, pixels); diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderOptions.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderOptions.cs deleted file mode 100644 index a0f9ff8e0..000000000 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderOptions.cs +++ /dev/null @@ -1,45 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Formats -{ - /// - /// Encapsulates the options for the . - /// - public sealed class BmpEncoderOptions : EncoderOptions, IBmpEncoderOptions - { - /// - /// Initializes a new instance of the class. - /// - public BmpEncoderOptions() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The options for the encoder. - private BmpEncoderOptions(IEncoderOptions options) - : base(options) - { - } - - /// - /// Gets or sets the number of bits per pixel. - /// - public BmpBitsPerPixel BitsPerPixel { get; set; } = BmpBitsPerPixel.Pixel24; - - /// - /// Converts the options to a instance with a cast - /// or by creating a new instance with the specfied options. - /// - /// The options for the encoder. - /// The options for the . - internal static IBmpEncoderOptions Create(IEncoderOptions options) - { - return options as IBmpEncoderOptions ?? new BmpEncoderOptions(options); - } - } -} diff --git a/src/ImageSharp/Formats/Bmp/BmpFormat.cs b/src/ImageSharp/Formats/Bmp/BmpFormat.cs deleted file mode 100644 index bf73d3162..000000000 --- a/src/ImageSharp/Formats/Bmp/BmpFormat.cs +++ /dev/null @@ -1,41 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Formats -{ - using System.Collections.Generic; - - /// - /// Encapsulates the means to encode and decode bitmap images. - /// - public class BmpFormat : IImageFormat - { - /// - public string MimeType => "image/bmp"; - - /// - public string Extension => "bmp"; - - /// - public IEnumerable SupportedExtensions => new string[] { "bmp", "dip" }; - - /// - public IImageDecoder Decoder => new BmpDecoder(); - - /// - public IImageEncoder Encoder => new BmpEncoder(); - - /// - public int HeaderSize => 2; - - /// - public bool IsSupportedFileFormat(byte[] header) - { - return header.Length >= this.HeaderSize && - header[0] == 0x42 && // B - header[1] == 0x4D; // M - } - } -} diff --git a/src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs b/src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs deleted file mode 100644 index 6cf37cbae..000000000 --- a/src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs +++ /dev/null @@ -1,18 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Formats -{ - /// - /// Encapsulates the options for the . - /// - public interface IBmpEncoderOptions : IEncoderOptions - { - /// - /// Gets the number of bits per pixel. - /// - BmpBitsPerPixel BitsPerPixel { get; } - } -} diff --git a/src/ImageSharp/Formats/DecoderOptions.cs b/src/ImageSharp/Formats/DecoderOptions.cs deleted file mode 100644 index 5257b07b3..000000000 --- a/src/ImageSharp/Formats/DecoderOptions.cs +++ /dev/null @@ -1,37 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp -{ - /// - /// Encapsulates the shared decoder options. - /// - public class DecoderOptions : IDecoderOptions - { - /// - /// Initializes a new instance of the class. - /// - public DecoderOptions() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The decoder options - protected DecoderOptions(IDecoderOptions options) - { - if (options != null) - { - this.IgnoreMetadata = options.IgnoreMetadata; - } - } - - /// - /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. - /// - public bool IgnoreMetadata { get; set; } = false; - } -} diff --git a/src/ImageSharp/Formats/EncoderOptions.cs b/src/ImageSharp/Formats/EncoderOptions.cs deleted file mode 100644 index 27a7e9781..000000000 --- a/src/ImageSharp/Formats/EncoderOptions.cs +++ /dev/null @@ -1,37 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp -{ - /// - /// Encapsulates the shared encoder options. - /// - public class EncoderOptions : IEncoderOptions - { - /// - /// Initializes a new instance of the class. - /// - public EncoderOptions() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The encoder options - protected EncoderOptions(IEncoderOptions options) - { - if (options != null) - { - this.IgnoreMetadata = options.IgnoreMetadata; - } - } - - /// - /// Gets or sets a value indicating whether the metadata should be ignored when the image is being encoded. - /// - public bool IgnoreMetadata { get; set; } = false; - } -} diff --git a/src/ImageSharp/Formats/Gif/GifConstants.cs b/src/ImageSharp/Formats/Gif/GifConstants.cs index 4af291c2b..5c4d806d7 100644 --- a/src/ImageSharp/Formats/Gif/GifConstants.cs +++ b/src/ImageSharp/Formats/Gif/GifConstants.cs @@ -5,6 +5,7 @@ namespace ImageSharp.Formats { + using System.Collections.Generic; using System.Text; /// @@ -90,6 +91,16 @@ namespace ImageSharp.Formats /// /// Gets the default encoding to use when reading comments. /// - public static Encoding DefaultEncoding { get; } = Encoding.GetEncoding("ASCII"); + public static readonly Encoding DefaultEncoding = Encoding.GetEncoding("ASCII"); + + /// + /// The list of mimetypes that equate to a bmp + /// + public static readonly IEnumerable MimeTypes = new[] { "image/gif" }; + + /// + /// The list of mimetypes that equate to a bmp + /// + public static readonly IEnumerable FileExtensions = new[] { "gif" }; } } diff --git a/src/ImageSharp/Formats/Gif/GifDecoder.cs b/src/ImageSharp/Formats/Gif/GifDecoder.cs index 88aaccf6a..506b37dc8 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoder.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoder.cs @@ -6,8 +6,9 @@ namespace ImageSharp.Formats { using System; + using System.Collections.Generic; using System.IO; - + using System.Text; using ImageSharp.PixelFormats; /// @@ -16,27 +17,43 @@ namespace ImageSharp.Formats public class GifDecoder : IImageDecoder { /// - public Image Decode(Configuration configuration, Stream stream, IDecoderOptions options) + public IEnumerable MimeTypes => GifConstants.MimeTypes; - where TPixel : struct, IPixel - { - IGifDecoderOptions gifOptions = GifDecoderOptions.Create(options); + /// + public IEnumerable FileExtensions => GifConstants.FileExtensions; - return this.Decode(configuration, stream, gifOptions); - } + /// + /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. + /// + public bool IgnoreMetadata { get; set; } = false; /// - /// Decodes the image from the specified stream to the . + /// Gets or sets the encoding that should be used when reading comments. /// - /// The pixel format. - /// The configuration. - /// The containing image data. - /// The options for the decoder. - /// The image thats been decoded. - public Image Decode(Configuration configuration, Stream stream, IGifDecoderOptions options) + public Encoding TextEncoding { get; set; } = GifConstants.DefaultEncoding; + + /// + public int HeaderSize => 6; + + /// + public bool IsSupportedFileFormat(Span header) + { + return header.Length >= this.HeaderSize && + header[0] == 0x47 && // G + header[1] == 0x49 && // I + header[2] == 0x46 && // F + header[3] == 0x38 && // 8 + (header[4] == 0x39 || header[4] == 0x37) && // 9 or 7 + header[5] == 0x61; // a + } + + /// + public Image Decode(Configuration configuration, Stream stream) where TPixel : struct, IPixel { - return new GifDecoderCore(options, configuration).Decode(stream); + var decoder = new GifDecoderCore(this.TextEncoding, configuration); + decoder.IgnoreMetadata = this.IgnoreMetadata; + return decoder.Decode(stream); } } } diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index 5b56c4c02..0bd64b057 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -25,11 +25,6 @@ namespace ImageSharp.Formats /// private readonly byte[] buffer = new byte[16]; - /// - /// The decoder options. - /// - private readonly IGifDecoderOptions options; - /// /// The global configuration. /// @@ -83,14 +78,24 @@ namespace ImageSharp.Formats /// /// Initializes a new instance of the class. /// - /// The decoder options. + /// The decoder encoding. /// The configuration. - public GifDecoderCore(IGifDecoderOptions options, Configuration configuration) + public GifDecoderCore(Encoding encoding, Configuration configuration) { - this.options = options ?? new GifDecoderOptions(); + this.TextEncoding = encoding ?? GifConstants.DefaultEncoding; this.configuration = configuration ?? Configuration.Default; } + /// + /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. + /// + public bool IgnoreMetadata { get; internal set; } + + /// + /// Gets the text encoding + /// + public Encoding TextEncoding { get; private set; } + /// /// Decodes the stream to the image. /// @@ -268,7 +273,7 @@ namespace ImageSharp.Formats throw new ImageFormatException($"Gif comment length '{length}' exceeds max '{GifConstants.MaxCommentLength}'"); } - if (this.options.IgnoreMetadata) + if (this.IgnoreMetadata) { this.currentStream.Seek(length, SeekOrigin.Current); continue; @@ -279,7 +284,7 @@ namespace ImageSharp.Formats try { this.currentStream.Read(commentsBuffer, 0, length); - string comments = this.options.TextEncoding.GetString(commentsBuffer, 0, length); + string comments = this.TextEncoding.GetString(commentsBuffer, 0, length); this.metaData.Properties.Add(new ImageProperty(GifConstants.Comments, comments)); } finally @@ -363,8 +368,6 @@ namespace ImageSharp.Formats if (this.previousFrame == null) { - this.metaData.Quality = colorTableLength / 3; - // This initializes the image to become fully transparent because the alpha channel is zero. this.image = new Image(this.configuration, imageWidth, imageHeight, this.metaData); diff --git a/src/ImageSharp/Formats/Gif/GifDecoderOptions.cs b/src/ImageSharp/Formats/Gif/GifDecoderOptions.cs deleted file mode 100644 index bc7709f75..000000000 --- a/src/ImageSharp/Formats/Gif/GifDecoderOptions.cs +++ /dev/null @@ -1,47 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Formats -{ - using System.Text; - - /// - /// Encapsulates the options for the . - /// - public sealed class GifDecoderOptions : DecoderOptions, IGifDecoderOptions - { - /// - /// Initializes a new instance of the class. - /// - public GifDecoderOptions() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The options for the decoder. - private GifDecoderOptions(IDecoderOptions options) - : base(options) - { - } - - /// - /// Gets or sets the encoding that should be used when reading comments. - /// - public Encoding TextEncoding { get; set; } = GifConstants.DefaultEncoding; - - /// - /// Converts the options to a instance with a cast - /// or by creating a new instance with the specfied options. - /// - /// The options for the decoder. - /// The options for the . - internal static IGifDecoderOptions Create(IDecoderOptions options) - { - return options as IGifDecoderOptions ?? new GifDecoderOptions(options); - } - } -} diff --git a/src/ImageSharp/Formats/Gif/GifEncoder.cs b/src/ImageSharp/Formats/Gif/GifEncoder.cs index b5cadd834..f7dba9266 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoder.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoder.cs @@ -6,9 +6,11 @@ namespace ImageSharp.Formats { using System; + using System.Collections.Generic; using System.IO; - + using System.Text; using ImageSharp.PixelFormats; + using ImageSharp.Quantizers; /// /// Image encoder for writing image data to a stream in gif format. @@ -16,25 +18,46 @@ namespace ImageSharp.Formats public class GifEncoder : IImageEncoder { /// - public void Encode(Image image, Stream stream, IEncoderOptions options) - where TPixel : struct, IPixel - { - IGifEncoderOptions gifOptions = GifEncoderOptions.Create(options); + public IEnumerable MimeTypes => GifConstants.MimeTypes; - this.Encode(image, stream, gifOptions); - } + /// + public IEnumerable FileExtensions => GifConstants.FileExtensions; /// - /// Encodes the image to the specified stream from the . + /// Gets or sets a value indicating whether the metadata should be ignored when the image is being encoded. /// - /// The pixel format. - /// The to encode from. - /// The to encode the image data to. - /// The options for the encoder. - public void Encode(Image image, Stream stream, IGifEncoderOptions options) + public bool IgnoreMetadata { get; set; } = false; + + /// + /// Gets or sets the encoding that should be used when writing comments. + /// + public Encoding TextEncoding { get; set; } = GifConstants.DefaultEncoding; + + /// + /// Gets or sets the quality of output for images. + /// + /// For gifs the value ranges from 1 to 256. + public int Quality { get; set; } + + /// + /// Gets or sets the transparency threshold. + /// + public byte Threshold { get; set; } = 128; + + /// + /// Gets or sets the quantizer for reducing the color count. + /// + public IQuantizer Quantizer { get; set; } + + /// + public void Encode(Image image, Stream stream) where TPixel : struct, IPixel { - GifEncoderCore encoder = new GifEncoderCore(options); + GifEncoderCore encoder = new GifEncoderCore(this.TextEncoding); + encoder.Quantizer = this.Quantizer; + encoder.Threshold = this.Threshold; + encoder.Quality = this.Quality; + encoder.IgnoreMetadata = this.IgnoreMetadata; encoder.Encode(image, stream); } } diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 5ef7ca165..bc7014f19 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -9,7 +9,7 @@ namespace ImageSharp.Formats using System.Buffers; using System.IO; using System.Linq; - + using System.Text; using ImageSharp.PixelFormats; using IO; @@ -25,11 +25,6 @@ namespace ImageSharp.Formats /// private readonly byte[] buffer = new byte[16]; - /// - /// The options for the encoder. - /// - private readonly IGifEncoderOptions options; - /// /// The number of bits requires to store the image palette. /// @@ -43,17 +38,37 @@ namespace ImageSharp.Formats /// /// Initializes a new instance of the class. /// - /// The options for the encoder. - public GifEncoderCore(IGifEncoderOptions options) + /// The encoding for the encoder. + public GifEncoderCore(Encoding encoding) { - this.options = options ?? new GifEncoderOptions(); + this.TextEncoding = encoding ?? GifConstants.DefaultEncoding; } + /// + /// Gets the TextEncoding + /// + public Encoding TextEncoding { get; private set; } + /// /// Gets or sets the quantizer for reducing the color count. /// public IQuantizer Quantizer { get; set; } + /// + /// Gets or sets the threshold. + /// + public byte Threshold { get; internal set; } + + /// + /// Gets or sets the quality of output for images. + /// + public int Quality { get; internal set; } + + /// + /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. + /// + public bool IgnoreMetadata { get; internal set; } + /// /// Encodes the image to the specified stream from the . /// @@ -66,13 +81,13 @@ namespace ImageSharp.Formats Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); - this.Quantizer = this.options.Quantizer ?? new OctreeQuantizer(); + this.Quantizer = this.Quantizer ?? new OctreeQuantizer(); // Do not use IDisposable pattern here as we want to preserve the stream. var writer = new EndianBinaryWriter(Endianness.LittleEndian, stream); // Ensure that quality can be set but has a fallback. - int quality = this.options.Quality > 0 ? this.options.Quality : image.MetaData.Quality; + int quality = this.Quality; quality = quality > 0 ? quality.Clamp(1, 256) : 256; // Get the number of bits. @@ -240,7 +255,7 @@ namespace ImageSharp.Formats private void WriteComments(Image image, EndianBinaryWriter writer) where TPixel : struct, IPixel { - if (this.options.IgnoreMetadata) + if (this.IgnoreMetadata) { return; } @@ -251,7 +266,7 @@ namespace ImageSharp.Formats return; } - byte[] comments = this.options.TextEncoding.GetBytes(property.Value); + byte[] comments = this.TextEncoding.GetBytes(property.Value); int count = Math.Min(comments.Length, 255); diff --git a/src/ImageSharp/Formats/Gif/GifEncoderOptions.cs b/src/ImageSharp/Formats/Gif/GifEncoderOptions.cs deleted file mode 100644 index 5d7c6e40b..000000000 --- a/src/ImageSharp/Formats/Gif/GifEncoderOptions.cs +++ /dev/null @@ -1,65 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Formats -{ - using System.Text; - - using Quantizers; - - /// - /// Encapsulates the options for the . - /// - public sealed class GifEncoderOptions : EncoderOptions, IGifEncoderOptions - { - /// - /// Initializes a new instance of the class. - /// - public GifEncoderOptions() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The options for the encoder. - private GifEncoderOptions(IEncoderOptions options) - : base(options) - { - } - - /// - /// Gets or sets the encoding that should be used when writing comments. - /// - public Encoding TextEncoding { get; set; } = GifConstants.DefaultEncoding; - - /// - /// Gets or sets the quality of output for images. - /// - /// For gifs the value ranges from 1 to 256. - public int Quality { get; set; } - - /// - /// Gets or sets the transparency threshold. - /// - public byte Threshold { get; set; } = 128; - - /// - /// Gets or sets the quantizer for reducing the color count. - /// - public IQuantizer Quantizer { get; set; } - - /// - /// Converts the options to a instance with a - /// cast or by creating a new instance with the specfied options. - /// - /// The options for the encoder. - /// The options for the . - internal static IGifEncoderOptions Create(IEncoderOptions options) - { - return options as IGifEncoderOptions ?? new GifEncoderOptions(options); - } - } -} diff --git a/src/ImageSharp/Formats/Gif/GifFormat.cs b/src/ImageSharp/Formats/Gif/GifFormat.cs deleted file mode 100644 index 2851b0b6b..000000000 --- a/src/ImageSharp/Formats/Gif/GifFormat.cs +++ /dev/null @@ -1,45 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Formats -{ - using System.Collections.Generic; - - /// - /// Encapsulates the means to encode and decode gif images. - /// - public class GifFormat : IImageFormat - { - /// - public string Extension => "gif"; - - /// - public string MimeType => "image/gif"; - - /// - public IEnumerable SupportedExtensions => new string[] { "gif" }; - - /// - public IImageDecoder Decoder => new GifDecoder(); - - /// - public IImageEncoder Encoder => new GifEncoder(); - - /// - public int HeaderSize => 6; - - /// - public bool IsSupportedFileFormat(byte[] header) - { - return header.Length >= this.HeaderSize && - header[0] == 0x47 && // G - header[1] == 0x49 && // I - header[2] == 0x46 && // F - header[3] == 0x38 && // 8 - (header[4] == 0x39 || header[4] == 0x37) && // 9 or 7 - header[5] == 0x61; // a - } - } -} diff --git a/src/ImageSharp/Formats/Gif/IGifDecoderOptions.cs b/src/ImageSharp/Formats/Gif/IGifDecoderOptions.cs deleted file mode 100644 index 729bf1d11..000000000 --- a/src/ImageSharp/Formats/Gif/IGifDecoderOptions.cs +++ /dev/null @@ -1,20 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Formats -{ - using System.Text; - - /// - /// Encapsulates the options for the . - /// - public interface IGifDecoderOptions : IDecoderOptions - { - /// - /// Gets the encoding that should be used when reading comments. - /// - Encoding TextEncoding { get; } - } -} diff --git a/src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs b/src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs deleted file mode 100644 index c1d6b7ad8..000000000 --- a/src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs +++ /dev/null @@ -1,38 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Formats -{ - using System.Text; - - using Quantizers; - - /// - /// Encapsulates the options for the . - /// - public interface IGifEncoderOptions : IEncoderOptions - { - /// - /// Gets the encoding that should be used when writing comments. - /// - Encoding TextEncoding { get; } - - /// - /// Gets the quality of output for images. - /// - /// For gifs the value ranges from 1 to 256. - int Quality { get; } - - /// - /// Gets the transparency threshold. - /// - byte Threshold { get; } - - /// - /// Gets the quantizer for reducing the color count. - /// - IQuantizer Quantizer { get; } - } -} diff --git a/src/ImageSharp/Formats/Gif/ImageExtensions.cs b/src/ImageSharp/Formats/Gif/ImageExtensions.cs index d64203f6c..ea9c9b504 100644 --- a/src/ImageSharp/Formats/Gif/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Gif/ImageExtensions.cs @@ -39,16 +39,16 @@ namespace ImageSharp /// The pixel format. /// The image this method extends. /// The stream to save the image to. - /// The options for the encoder. + /// The options for the encoder. /// Thrown if the stream is null. /// /// The . /// - public static Image SaveAsGif(this Image source, Stream stream, IGifEncoderOptions options) + public static Image SaveAsGif(this Image source, Stream stream, GifEncoder encoder) where TPixel : struct, IPixel { - GifEncoder encoder = new GifEncoder(); - encoder.Encode(source, stream, options); + encoder = encoder ?? new GifEncoder(); + encoder.Encode(source, stream); return source; } diff --git a/src/ImageSharp/Formats/IDecoderOptions.cs b/src/ImageSharp/Formats/IDecoderOptions.cs deleted file mode 100644 index cdfd90d5e..000000000 --- a/src/ImageSharp/Formats/IDecoderOptions.cs +++ /dev/null @@ -1,18 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp -{ - /// - /// Encapsulates the shared decoder options. - /// - public interface IDecoderOptions - { - /// - /// Gets a value indicating whether the metadata should be ignored when the image is being decoded. - /// - bool IgnoreMetadata { get; } - } -} diff --git a/src/ImageSharp/Formats/IEncoderOptions.cs b/src/ImageSharp/Formats/IEncoderOptions.cs deleted file mode 100644 index 0fd3d1c43..000000000 --- a/src/ImageSharp/Formats/IEncoderOptions.cs +++ /dev/null @@ -1,18 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp -{ - /// - /// Encapsulates the shared encoder options. - /// - public interface IEncoderOptions - { - /// - /// Gets a value indicating whether the metadata should be ignored when the image is being encoded. - /// - bool IgnoreMetadata { get; } - } -} diff --git a/src/ImageSharp/Formats/IImageDecoder.cs b/src/ImageSharp/Formats/IImageDecoder.cs index 4fd25df13..ff655d718 100644 --- a/src/ImageSharp/Formats/IImageDecoder.cs +++ b/src/ImageSharp/Formats/IImageDecoder.cs @@ -6,6 +6,7 @@ namespace ImageSharp.Formats { using System; + using System.Collections.Generic; using System.IO; using ImageSharp.PixelFormats; @@ -15,15 +16,40 @@ namespace ImageSharp.Formats /// public interface IImageDecoder { + /// + /// Gets the collection of mime types that this decoder supports decoding on. + /// + IEnumerable MimeTypes { get; } + + /// + /// Gets the collection of file extensionsthis decoder supports decoding. + /// + IEnumerable FileExtensions { get; } + + /// + /// Gets the size of the header for this image type. + /// + /// The size of the header. + int HeaderSize { get; } + + /// + /// Returns a value indicating whether the supports the specified + /// file header. + /// + /// The containing the file header. + /// + /// True if the decoder supports the file header; otherwise, false. + /// + bool IsSupportedFileFormat(Span header); + /// /// Decodes the image from the specified stream to the . /// /// The pixel format. /// The configuration for the image. /// The containing image data. - /// The options for the decoder. /// The decoded image - Image Decode(Configuration configuration, Stream stream, IDecoderOptions options) + Image Decode(Configuration configuration, Stream stream) where TPixel : struct, IPixel; } } diff --git a/src/ImageSharp/Formats/IImageEncoder.cs b/src/ImageSharp/Formats/IImageEncoder.cs index a28511c17..465f8eec5 100644 --- a/src/ImageSharp/Formats/IImageEncoder.cs +++ b/src/ImageSharp/Formats/IImageEncoder.cs @@ -6,6 +6,7 @@ namespace ImageSharp.Formats { using System; + using System.Collections.Generic; using System.IO; using ImageSharp.PixelFormats; @@ -15,14 +16,23 @@ namespace ImageSharp.Formats /// public interface IImageEncoder { + /// + /// Gets the collection of mime types that this decoder supports encoding for. + /// + IEnumerable MimeTypes { get; } + + /// + /// Gets the collection of file extensionsthis decoder supports encoding for. + /// + IEnumerable FileExtensions { get; } + /// /// Encodes the image to the specified stream from the . /// /// The pixel format. /// The to encode from. /// The to encode the image data to. - /// The options for the encoder. - void Encode(Image image, Stream stream, IEncoderOptions options) + void Encode(Image image, Stream stream) where TPixel : struct, IPixel; } } diff --git a/src/ImageSharp/Formats/IImageFormat.cs b/src/ImageSharp/Formats/IImageFormat.cs deleted file mode 100644 index de2e400fa..000000000 --- a/src/ImageSharp/Formats/IImageFormat.cs +++ /dev/null @@ -1,60 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Formats -{ - using System.Collections.Generic; - - /// - /// Encapsulates a supported image format, providing means to encode and decode an image. - /// Individual formats implements in this interface must be registered in the - /// - public interface IImageFormat - { - /// - /// Gets the standard identifier used on the Internet to indicate the type of data that a file contains. - /// - string MimeType { get; } - - /// - /// Gets the default file extension for this format. - /// - string Extension { get; } - - /// - /// Gets the supported file extensions for this format. - /// - /// - /// The supported file extension. - /// - IEnumerable SupportedExtensions { get; } - - /// - /// Gets the image encoder for encoding an image from a stream. - /// - IImageEncoder Encoder { get; } - - /// - /// Gets the image decoder for decoding an image from a stream. - /// - IImageDecoder Decoder { get; } - - /// - /// Gets the size of the header for this image type. - /// - /// The size of the header. - int HeaderSize { get; } - - /// - /// Returns a value indicating whether the supports the specified - /// file header. - /// - /// The containing the file header. - /// - /// True if the decoder supports the file header; otherwise, false. - /// - bool IsSupportedFileFormat(byte[] header); - } -} diff --git a/src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs b/src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs deleted file mode 100644 index a54517965..000000000 --- a/src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs +++ /dev/null @@ -1,26 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Formats -{ - /// - /// Encapsulates the options for the . - /// - public interface IJpegEncoderOptions : IEncoderOptions - { - /// - /// Gets the quality, that will be used to encode the image. Quality - /// index must be between 0 and 100 (compression from max to min). - /// - /// The quality of the jpg image from 0 to 100. - int Quality { get; } - - /// - /// Gets the subsample ration, that will be used to encode the image. - /// - /// The subsample ratio of the jpg image. - JpegSubsample? Subsample { get; } - } -} diff --git a/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs b/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs index 420af6b74..8fbf9e5a7 100644 --- a/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs @@ -39,16 +39,16 @@ namespace ImageSharp /// The pixel format. /// The image this method extends. /// The stream to save the image to. - /// The options for the encoder. + /// The options for the encoder. /// Thrown if the stream is null. /// /// The . /// - public static Image SaveAsJpeg(this Image source, Stream stream, IJpegEncoderOptions options) + public static Image SaveAsJpeg(this Image source, Stream stream, JpegEncoder encoder) where TPixel : struct, IPixel { - JpegEncoder encoder = new JpegEncoder(); - encoder.Encode(source, stream, options); + encoder = encoder ?? new JpegEncoder(); + encoder.Encode(source, stream); return source; } diff --git a/src/ImageSharp/Formats/Jpeg/JpegConstants.cs b/src/ImageSharp/Formats/Jpeg/JpegConstants.cs index dcda39842..959813611 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegConstants.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegConstants.cs @@ -5,6 +5,8 @@ namespace ImageSharp.Formats { + using System.Collections.Generic; + /// /// Defines jpeg constants defined in the specification. /// @@ -15,6 +17,16 @@ namespace ImageSharp.Formats /// public const ushort MaxLength = 65535; + /// + /// The list of mimetypes that equate to a jpeg + /// + public static readonly IEnumerable MimeTypes = new[] { "image/jpeg", "image/pjpeg" }; + + /// + /// The list of mimetypes that equate to a jpeg + /// + public static readonly IEnumerable FileExtensions = new[] { "jpg", "jpeg", "jfif" }; + /// /// Represents high detail chroma horizontal subsampling. /// diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs index 56d025504..09575a12e 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs @@ -6,6 +6,7 @@ namespace ImageSharp.Formats { using System; + using System.Collections.Generic; using System.IO; using ImageSharp.PixelFormats; @@ -15,16 +16,87 @@ namespace ImageSharp.Formats /// public class JpegDecoder : IImageDecoder { + /// + /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. + /// + public bool IgnoreMetadata { get; set; } + + /// + public IEnumerable MimeTypes => JpegConstants.MimeTypes; + + /// + public IEnumerable FileExtensions => JpegConstants.FileExtensions; + + /// + public int HeaderSize => 11; + + /// + public bool IsSupportedFileFormat(Span header) + { + return header.Length >= this.HeaderSize && + (IsJfif(header) || IsExif(header) || IsJpeg(header)); + } + /// - public Image Decode(Configuration configuration, Stream stream, IDecoderOptions options) + public Image Decode(Configuration configuration, Stream stream) where TPixel : struct, IPixel { Guard.NotNull(stream, "stream"); - using (JpegDecoderCore decoder = new JpegDecoderCore(options, configuration)) + using (JpegDecoderCore decoder = new JpegDecoderCore(configuration)) { + decoder.IgnoreMetadata = this.IgnoreMetadata; return decoder.Decode(stream); } } + + /// + /// Returns a value indicating whether the given bytes identify Jfif data. + /// + /// The bytes representing the file header. + /// The + private static bool IsJfif(Span header) + { + bool isJfif = + header[6] == 0x4A && // J + header[7] == 0x46 && // F + header[8] == 0x49 && // I + header[9] == 0x46 && // F + header[10] == 0x00; + + return isJfif; + } + + /// + /// Returns a value indicating whether the given bytes identify EXIF data. + /// + /// The bytes representing the file header. + /// The + private static bool IsExif(Span header) + { + bool isExif = + header[6] == 0x45 && // E + header[7] == 0x78 && // X + header[8] == 0x69 && // I + header[9] == 0x66 && // F + header[10] == 0x00; + + return isExif; + } + + /// + /// Returns a value indicating whether the given bytes identify Jpeg data. + /// This is a last chance resort for jpegs that contain ICC information. + /// + /// The bytes representing the file header. + /// The + private static bool IsJpeg(Span header) + { + bool isJpg = + header[0] == 0xFF && // 255 + header[1] == 0xD8; // 216 + + return isJpg; + } } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 971684371..f6456620e 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -45,11 +45,6 @@ namespace ImageSharp.Formats /// private static YCbCrToRgbTables yCbCrToRgbTables = YCbCrToRgbTables.Create(); - /// - /// The decoder options. - /// - private readonly IDecoderOptions options; - /// /// The global configuration /// @@ -103,12 +98,10 @@ namespace ImageSharp.Formats /// /// Initializes a new instance of the class. /// - /// The decoder options. /// The configuration. - public JpegDecoderCore(IDecoderOptions options, Configuration configuration) + public JpegDecoderCore(Configuration configuration) { this.configuration = configuration ?? Configuration.Default; - this.options = options ?? new DecoderOptions(); this.HuffmanTrees = HuffmanTree.CreateHuffmanTrees(); this.QuantizationTables = new Block8x8F[MaxTq + 1]; this.Temp = new byte[2 * Block8x8F.ScalarCount]; @@ -190,6 +183,11 @@ namespace ImageSharp.Formats /// public int TotalMCUCount => this.MCUCountX * this.MCUCountY; + /// + /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. + /// + public bool IgnoreMetadata { get; internal set; } + /// /// Decodes the image from the specified and sets /// the data to image. @@ -938,7 +936,7 @@ namespace ImageSharp.Formats /// The image. private void ProcessApp1Marker(int remaining, ImageMetaData metadata) { - if (remaining < 6 || this.options.IgnoreMetadata) + if (remaining < 6 || this.IgnoreMetadata) { this.InputProcessor.Skip(remaining); return; @@ -968,7 +966,7 @@ namespace ImageSharp.Formats { // Length is 14 though we only need to check 12. const int Icclength = 14; - if (remaining < Icclength || this.options.IgnoreMetadata) + if (remaining < Icclength || this.IgnoreMetadata) { this.InputProcessor.Skip(remaining); return; diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs index 152fd2c64..f76df0585 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs @@ -5,6 +5,8 @@ namespace ImageSharp.Formats { + using System; + using System.Collections.Generic; using System.IO; using ImageSharp.PixelFormats; @@ -14,14 +16,29 @@ namespace ImageSharp.Formats /// public class JpegEncoder : IImageEncoder { + /// + /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. + /// + public bool IgnoreMetadata { get; set; } + + /// + /// Gets or sets the quality, that will be used to encode the image. Quality + /// index must be between 0 and 100 (compression from max to min). + /// + /// The quality of the jpg image from 0 to 100. + public int Quality { get; set; } + + /// + /// Gets or sets the subsample ration, that will be used to encode the image. + /// + /// The subsample ratio of the jpg image. + public JpegSubsample? Subsample { get; set; } + /// - public void Encode(Image image, Stream stream, IEncoderOptions options) - where TPixel : struct, IPixel - { - IJpegEncoderOptions gifOptions = JpegEncoderOptions.Create(options); + public IEnumerable MimeTypes => JpegConstants.MimeTypes; - this.Encode(image, stream, gifOptions); - } + /// + public IEnumerable FileExtensions => JpegConstants.FileExtensions; /// /// Encodes the image to the specified stream from the . @@ -29,12 +46,23 @@ namespace ImageSharp.Formats /// The pixel format. /// The to encode from. /// The to encode the image data to. - /// The options for the encoder. - public void Encode(Image image, Stream stream, IJpegEncoderOptions options) - where TPixel : struct, IPixel + public void Encode(Image image, Stream stream) + where TPixel : struct, IPixel { - JpegEncoderCore encode = new JpegEncoderCore(options); - encode.Encode(image, stream); + JpegEncoderCore encoder = new JpegEncoderCore(); + + var quality = this.Quality; + if (quality == 0) + { + quality = 75; + } + + encoder.Quality = quality; + encoder.Subsample = this.Subsample ?? (quality >= 91 ? JpegSubsample.Ratio444 : JpegSubsample.Ratio420); + + encoder.IgnoreMetadata = this.IgnoreMetadata; + + encoder.Encode(image, stream); } } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index b65a56e73..168e47311 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -124,11 +124,6 @@ namespace ImageSharp.Formats /// private readonly byte[] huffmanBuffer = new byte[179]; - /// - /// The options for the encoder. - /// - private readonly IJpegEncoderOptions options; - /// /// The accumulated bits to write to the stream. /// @@ -154,20 +149,30 @@ namespace ImageSharp.Formats /// private Stream outputStream; - /// - /// The subsampling method to use. - /// - private JpegSubsample subsample; - /// /// Initializes a new instance of the class. /// - /// The options for the encoder. - public JpegEncoderCore(IJpegEncoderOptions options) + public JpegEncoderCore() { - this.options = options ?? new JpegEncoderOptions(); } + /// + /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. + /// + public bool IgnoreMetadata { get; internal set; } = false; + + /// + /// Gets or sets the quality, that will be used to encode the image. Quality + /// index must be between 0 and 100 (compression from max to min). + /// + /// The quality of the jpg image from 0 to 100. + public int Quality { get; internal set; } + + /// + /// Gets or sets the subsampling method to use. + /// + public JpegSubsample? Subsample { get; internal set; } + /// /// Encode writes the image to the jpeg baseline format with the given options. /// @@ -186,21 +191,13 @@ namespace ImageSharp.Formats throw new ImageFormatException($"Image is too large to encode at {image.Width}x{image.Height}."); } - // Ensure that quality can be set but has a fallback. - int quality = this.options.Quality > 0 ? this.options.Quality : image.MetaData.Quality; - if (quality == 0) - { - quality = 75; - } - - quality = quality.Clamp(1, 100); - this.outputStream = stream; - this.subsample = this.options.Subsample ?? (quality >= 91 ? JpegSubsample.Ratio444 : JpegSubsample.Ratio420); + + int quality = this.Quality.Clamp(1, 100); // Convert from a quality rating to a scaling factor. int scale; - if (quality < 50) + if (this.Quality < 50) { scale = 5000 / quality; } @@ -788,7 +785,7 @@ namespace ImageSharp.Formats private void WriteProfiles(Image image) where TPixel : struct, IPixel { - if (this.options.IgnoreMetadata) + if (this.IgnoreMetadata) { return; } @@ -810,7 +807,7 @@ namespace ImageSharp.Formats byte[] subsamples = { 0x22, 0x11, 0x11 }; byte[] chroma = { 0x00, 0x01, 0x01 }; - switch (this.subsample) + switch (this.Subsample) { case JpegSubsample.Ratio444: subsamples = new byte[] { 0x11, 0x11, 0x11 }; @@ -866,7 +863,7 @@ namespace ImageSharp.Formats // TODO: We should allow grayscale writing. this.outputStream.Write(SosHeaderYCbCr, 0, SosHeaderYCbCr.Length); - switch (this.subsample) + switch (this.Subsample) { case JpegSubsample.Ratio444: this.Encode444(pixels); diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderOptions.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderOptions.cs deleted file mode 100644 index 73e483164..000000000 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderOptions.cs +++ /dev/null @@ -1,56 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Formats -{ - /// - /// Encapsulates the options for the . - /// - public sealed class JpegEncoderOptions : EncoderOptions, IJpegEncoderOptions - { - /// - /// Initializes a new instance of the class. - /// - public JpegEncoderOptions() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The options for the encoder. - private JpegEncoderOptions(IEncoderOptions options) - : base(options) - { - } - - /// - /// Gets or sets the quality, that will be used to encode the image. Quality - /// index must be between 0 and 100 (compression from max to min). - /// - /// - /// If the quality is less than or equal to 90, the subsampling ratio will switch to - /// - /// The quality of the jpg image from 0 to 100. - public int Quality { get; set; } - - /// - /// Gets or sets the subsample ration, that will be used to encode the image. - /// - /// The subsample ratio of the jpg image. - public JpegSubsample? Subsample { get; set; } - - /// - /// Converts the options to a instance with a - /// cast or by creating a new instance with the specfied options. - /// - /// The options for the encoder. - /// The options for the . - internal static IJpegEncoderOptions Create(IEncoderOptions options) - { - return options as IJpegEncoderOptions ?? new JpegEncoderOptions(options); - } - } -} diff --git a/src/ImageSharp/Formats/Jpeg/JpegFormat.cs b/src/ImageSharp/Formats/Jpeg/JpegFormat.cs deleted file mode 100644 index b93c6ae69..000000000 --- a/src/ImageSharp/Formats/Jpeg/JpegFormat.cs +++ /dev/null @@ -1,89 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Formats -{ - using System.Collections.Generic; - - /// - /// Encapsulates the means to encode and decode jpeg images. - /// - public class JpegFormat : IImageFormat - { - /// - public string MimeType => "image/jpeg"; - - /// - public string Extension => "jpg"; - - /// - public IEnumerable SupportedExtensions => new string[] { "jpg", "jpeg", "jfif" }; - - /// - public IImageDecoder Decoder => new JpegDecoder(); - - /// - public IImageEncoder Encoder => new JpegEncoder(); - - /// - public int HeaderSize => 11; - - /// - public bool IsSupportedFileFormat(byte[] header) - { - return header.Length >= this.HeaderSize && - (IsJfif(header) || IsExif(header) || IsJpeg(header)); - } - - /// - /// Returns a value indicating whether the given bytes identify Jfif data. - /// - /// The bytes representing the file header. - /// The - private static bool IsJfif(byte[] header) - { - bool isJfif = - header[6] == 0x4A && // J - header[7] == 0x46 && // F - header[8] == 0x49 && // I - header[9] == 0x46 && // F - header[10] == 0x00; - - return isJfif; - } - - /// - /// Returns a value indicating whether the given bytes identify EXIF data. - /// - /// The bytes representing the file header. - /// The - private static bool IsExif(byte[] header) - { - bool isExif = - header[6] == 0x45 && // E - header[7] == 0x78 && // X - header[8] == 0x69 && // I - header[9] == 0x66 && // F - header[10] == 0x00; - - return isExif; - } - - /// - /// Returns a value indicating whether the given bytes identify Jpeg data. - /// This is a last chance resort for jpegs that contain ICC information. - /// - /// The bytes representing the file header. - /// The - private static bool IsJpeg(byte[] header) - { - bool isJpg = - header[0] == 0xFF && // 255 - header[1] == 0xD8; // 216 - - return isJpg; - } - } -} diff --git a/src/ImageSharp/Formats/Png/IPngDecoderOptions.cs b/src/ImageSharp/Formats/Png/IPngDecoderOptions.cs deleted file mode 100644 index cc6d194bf..000000000 --- a/src/ImageSharp/Formats/Png/IPngDecoderOptions.cs +++ /dev/null @@ -1,20 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Formats -{ - using System.Text; - - /// - /// Encapsulates the options for the . - /// - public interface IPngDecoderOptions : IDecoderOptions - { - /// - /// Gets the encoding that should be used when reading text chunks. - /// - Encoding TextEncoding { get; } - } -} diff --git a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs deleted file mode 100644 index 0008080d3..000000000 --- a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs +++ /dev/null @@ -1,54 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Formats -{ - using Quantizers; - - /// - /// Encapsulates the options for the . - /// - public interface IPngEncoderOptions : IEncoderOptions - { - /// - /// Gets the quality of output for images. - /// - int Quality { get; } - - /// - /// Gets the png color type - /// - PngColorType PngColorType { get; } - - /// - /// Gets the compression level 1-9. - /// - int CompressionLevel { get; } - - /// - /// Gets the gamma value, that will be written - /// the the stream, when the property - /// is set to true. - /// - /// The gamma value of the image. - float Gamma { get; } - - /// - /// Gets quantizer for reducing the color count. - /// - IQuantizer Quantizer { get; } - - /// - /// Gets the transparency threshold. - /// - byte Threshold { get; } - - /// - /// Gets a value indicating whether this instance should write - /// gamma information to the stream. - /// - bool WriteGamma { get; } - } -} diff --git a/src/ImageSharp/Formats/Png/ImageExtensions.cs b/src/ImageSharp/Formats/Png/ImageExtensions.cs index 44f242b3f..c81738576 100644 --- a/src/ImageSharp/Formats/Png/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Png/ImageExtensions.cs @@ -38,16 +38,16 @@ namespace ImageSharp /// The pixel format. /// The image this method extends. /// The stream to save the image to. - /// The options for the encoder. + /// The options for the encoder. /// Thrown if the stream is null. /// /// The . /// - public static Image SaveAsPng(this Image source, Stream stream, IPngEncoderOptions options) + public static Image SaveAsPng(this Image source, Stream stream, PngEncoder encoder) where TPixel : struct, IPixel { - PngEncoder encoder = new PngEncoder(); - encoder.Encode(source, stream, options); + encoder = encoder ?? new PngEncoder(); + encoder.Encode(source, stream); return source; } diff --git a/src/ImageSharp/Formats/Png/PngConstants.cs b/src/ImageSharp/Formats/Png/PngConstants.cs new file mode 100644 index 000000000..b44ab7663 --- /dev/null +++ b/src/ImageSharp/Formats/Png/PngConstants.cs @@ -0,0 +1,30 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// +namespace ImageSharp.Formats +{ + using System.Collections.Generic; + using System.Text; + + /// + /// Defines png constants defined in the specification. + /// + internal static class PngConstants + { + /// + /// The default encoding for text metadata + /// + public static readonly Encoding DefaultEncoding = Encoding.GetEncoding("ASCII"); + + /// + /// The list of mimetypes that equate to a jpeg + /// + public static readonly IEnumerable MimeTypes = new[] { "image/png" }; + + /// + /// The list of mimetypes that equate to a jpeg + /// + public static readonly IEnumerable FileExtensions = new[] { "png" }; + } +} diff --git a/src/ImageSharp/Formats/Png/PngDecoder.cs b/src/ImageSharp/Formats/Png/PngDecoder.cs index 3a34147e2..da00ff906 100644 --- a/src/ImageSharp/Formats/Png/PngDecoder.cs +++ b/src/ImageSharp/Formats/Png/PngDecoder.cs @@ -6,8 +6,9 @@ namespace ImageSharp.Formats { using System; + using System.Collections.Generic; using System.IO; - + using System.Text; using ImageSharp.PixelFormats; /// @@ -32,14 +33,37 @@ namespace ImageSharp.Formats /// public class PngDecoder : IImageDecoder { + /// + /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. + /// + public bool IgnoreMetadata { get; set; } + /// - public Image Decode(Configuration configuration, Stream stream, IDecoderOptions options) + public IEnumerable MimeTypes => PngConstants.MimeTypes; - where TPixel : struct, IPixel - { - IPngDecoderOptions pngOptions = PngDecoderOptions.Create(options); + /// + public IEnumerable FileExtensions => PngConstants.FileExtensions; - return this.Decode(configuration, stream, pngOptions); + /// + public int HeaderSize => 8; + + /// + /// Gets or sets the encoding that should be used when reading text chunks. + /// + public Encoding TextEncoding { get; set; } = PngConstants.DefaultEncoding; + + /// + public bool IsSupportedFileFormat(Span header) + { + return header.Length >= this.HeaderSize && + header[0] == 0x89 && + header[1] == 0x50 && // P + header[2] == 0x4E && // N + header[3] == 0x47 && // G + header[4] == 0x0D && // CR + header[5] == 0x0A && // LF + header[6] == 0x1A && // EOF + header[7] == 0x0A; // LF } /// @@ -48,12 +72,13 @@ namespace ImageSharp.Formats /// The pixel format. /// The configuration for the image. /// The containing image data. - /// The options for the decoder. /// The decoded image. - public Image Decode(Configuration configuration, Stream stream, IPngDecoderOptions options) + public Image Decode(Configuration configuration, Stream stream) where TPixel : struct, IPixel { - return new PngDecoderCore(options, configuration).Decode(stream); + var decoder = new PngDecoderCore(configuration, this.TextEncoding); + decoder.IgnoreMetadata = this.IgnoreMetadata; + return decoder.Decode(stream); } } } diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 2ff6a4308..b1b98eca5 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -11,7 +11,7 @@ namespace ImageSharp.Formats using System.IO; using System.Linq; using System.Runtime.CompilerServices; - + using System.Text; using ImageSharp.Memory; using ImageSharp.PixelFormats; @@ -74,11 +74,6 @@ namespace ImageSharp.Formats /// private readonly char[] chars = new char[4]; - /// - /// The decoder options. - /// - private readonly IPngDecoderOptions options; - /// /// Reusable crc for validating chunks. /// @@ -154,21 +149,31 @@ namespace ImageSharp.Formats /// private int currentRowBytesRead; + /// + /// Gets or sets the png color type + /// + private PngColorType pngColorType; + /// /// Initializes a new instance of the class. /// - /// The decoder options. /// The configuration. - public PngDecoderCore(IPngDecoderOptions options, Configuration configuration) + /// The text encoding. + public PngDecoderCore(Configuration configuration, Encoding encoding) { this.configuration = configuration ?? Configuration.Default; - this.options = options ?? new PngDecoderOptions(); + this.TextEncoding = encoding ?? PngConstants.DefaultEncoding; } /// - /// Gets or sets the png color type + /// Gets the encoding to use + /// + public Encoding TextEncoding { get; private set; } + + /// + /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. /// - public PngColorType PngColorType { get; set; } + public bool IgnoreMetadata { get; internal set; } /// /// Decodes the stream to the image. @@ -221,7 +226,6 @@ namespace ImageSharp.Formats byte[] pal = new byte[currentChunk.Length]; Buffer.BlockCopy(currentChunk.Data, 0, pal, 0, currentChunk.Length); this.palette = pal; - metadata.Quality = pal.Length / 3; break; case PngChunkTypes.PaletteAlpha: byte[] alpha = new byte[currentChunk.Length]; @@ -344,7 +348,7 @@ namespace ImageSharp.Formats /// The private int CalculateBytesPerPixel() { - switch (this.PngColorType) + switch (this.pngColorType) { case PngColorType.Grayscale: return 1; @@ -572,7 +576,7 @@ namespace ImageSharp.Formats Span rowSpan = pixels.GetRowSpan(this.currentRow); var scanlineBuffer = new Span(defilteredScanline, 1); - switch (this.PngColorType) + switch (this.pngColorType) { case PngColorType.Grayscale: int factor = 255 / ((int)Math.Pow(2, this.header.BitDepth) - 1); @@ -731,7 +735,7 @@ namespace ImageSharp.Formats { var color = default(TPixel); - switch (this.PngColorType) + switch (this.pngColorType) { case PngColorType.Grayscale: int factor = 255 / ((int)Math.Pow(2, this.header.BitDepth) - 1); @@ -896,7 +900,7 @@ namespace ImageSharp.Formats /// The maximum length to read. private void ReadTextChunk(ImageMetaData metadata, byte[] data, int length) { - if (this.options.IgnoreMetadata) + if (this.IgnoreMetadata) { return; } @@ -912,8 +916,8 @@ namespace ImageSharp.Formats } } - string name = this.options.TextEncoding.GetString(data, 0, zeroIndex); - string value = this.options.TextEncoding.GetString(data, zeroIndex + 1, length - zeroIndex - 1); + string name = this.TextEncoding.GetString(data, 0, zeroIndex); + string value = this.TextEncoding.GetString(data, zeroIndex + 1, length - zeroIndex - 1); metadata.Properties.Add(new ImageProperty(name, value)); } @@ -967,7 +971,7 @@ namespace ImageSharp.Formats throw new NotSupportedException("The png specification only defines 'None' and 'Adam7' as interlaced methods."); } - this.PngColorType = this.header.ColorType; + this.pngColorType = this.header.ColorType; } /// diff --git a/src/ImageSharp/Formats/Png/PngDecoderOptions.cs b/src/ImageSharp/Formats/Png/PngDecoderOptions.cs deleted file mode 100644 index e8990ec45..000000000 --- a/src/ImageSharp/Formats/Png/PngDecoderOptions.cs +++ /dev/null @@ -1,49 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Formats -{ - using System.Text; - - /// - /// Encapsulates the options for the . - /// - public sealed class PngDecoderOptions : DecoderOptions, IPngDecoderOptions - { - private static readonly Encoding DefaultEncoding = Encoding.GetEncoding("ASCII"); - - /// - /// Initializes a new instance of the class. - /// - public PngDecoderOptions() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The options for the decoder. - private PngDecoderOptions(IDecoderOptions options) - : base(options) - { - } - - /// - /// Gets or sets the encoding that should be used when reading text chunks. - /// - public Encoding TextEncoding { get; set; } = DefaultEncoding; - - /// - /// Converts the options to a instance with a cast - /// or by creating a new instance with the specfied options. - /// - /// The options for the decoder. - /// The options for the . - internal static IPngDecoderOptions Create(IDecoderOptions options) - { - return options as IPngDecoderOptions ?? new PngDecoderOptions(options); - } - } -} diff --git a/src/ImageSharp/Formats/Png/PngEncoder.cs b/src/ImageSharp/Formats/Png/PngEncoder.cs index f89b624f7..023e465e9 100644 --- a/src/ImageSharp/Formats/Png/PngEncoder.cs +++ b/src/ImageSharp/Formats/Png/PngEncoder.cs @@ -5,9 +5,11 @@ namespace ImageSharp.Formats { + using System.Collections.Generic; using System.IO; using ImageSharp.PixelFormats; + using ImageSharp.Quantizers; /// /// Image encoder for writing image data to a stream in png format. @@ -15,13 +17,55 @@ namespace ImageSharp.Formats public class PngEncoder : IImageEncoder { /// - public void Encode(Image image, Stream stream, IEncoderOptions options) - where TPixel : struct, IPixel - { - IPngEncoderOptions pngOptions = PngEncoderOptions.Create(options); + public IEnumerable MimeTypes => PngConstants.MimeTypes; - this.Encode(image, stream, pngOptions); - } + /// + public IEnumerable FileExtensions => PngConstants.FileExtensions; + + /// + /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. + /// + public bool IgnoreMetadata { get; set; } + + /// + /// Gets or sets the quality of output for images. + /// + public int Quality { get; set; } + + /// + /// Gets or sets the png color type + /// + public PngColorType PngColorType { get; set; } = PngColorType.RgbWithAlpha; + + /// + /// Gets or sets the compression level 1-9. + /// Defaults to 6. + /// + public int CompressionLevel { get; set; } = 6; + + /// + /// Gets or sets the gamma value, that will be written + /// the the stream, when the property + /// is set to true. The default value is 2.2F. + /// + /// The gamma value of the image. + public float Gamma { get; set; } = 2.2F; + + /// + /// Gets or sets quantizer for reducing the color count. + /// + public IQuantizer Quantizer { get; set; } + + /// + /// Gets or sets the transparency threshold. + /// + public byte Threshold { get; set; } = 255; + + /// + /// Gets or sets a value indicating whether this instance should write + /// gamma information to the stream. The default value is false. + /// + public bool WriteGamma { get; set; } /// /// Encodes the image to the specified stream from the . @@ -29,12 +73,21 @@ namespace ImageSharp.Formats /// The pixel format. /// The to encode from. /// The to encode the image data to. - /// The options for the encoder. - public void Encode(Image image, Stream stream, IPngEncoderOptions options) + public void Encode(Image image, Stream stream) where TPixel : struct, IPixel { - using (var encode = new PngEncoderCore(options)) + using (var encode = new PngEncoderCore()) { + encode.IgnoreMetadata = this.IgnoreMetadata; + + encode.Quality = this.Quality > 0 ? this.Quality.Clamp(1, int.MaxValue) : int.MaxValue; + encode.PngColorType = this.PngColorType; + encode.CompressionLevel = this.CompressionLevel; + encode.Gamma = this.Gamma; + encode.Quantizer = this.Quantizer; + encode.Threshold = this.Threshold; + encode.WriteGamma = this.WriteGamma; + encode.Encode(image, stream); } } diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 645df0548..c96d60dbd 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -43,11 +43,6 @@ namespace ImageSharp.Formats /// private readonly Crc32 crc = new Crc32(); - /// - /// The options for the encoder. - /// - private readonly IPngEncoderOptions options; - /// /// Contains the raw pixel data from an indexed image. /// @@ -113,11 +108,6 @@ namespace ImageSharp.Formats /// private Buffer paeth; - /// - /// The quality of output for images. - /// - private int quality; - /// /// The png color type. /// @@ -131,12 +121,50 @@ namespace ImageSharp.Formats /// /// Initializes a new instance of the class. /// - /// The options for the encoder. - public PngEncoderCore(IPngEncoderOptions options) + public PngEncoderCore() { - this.options = options ?? new PngEncoderOptions(); } + /// + /// Gets or sets a value indicating whether to ignore metadata + /// + public bool IgnoreMetadata { get; internal set; } + + /// + /// Gets or sets the Quality value + /// + public int Quality { get; internal set; } + + /// + /// Gets or sets the Quality value + /// + public PngColorType PngColorType { get; internal set; } + + /// + /// Gets or sets the CompressionLevel value + /// + public int CompressionLevel { get; internal set; } + + /// + /// Gets or sets the Gamma value + /// + public float Gamma { get; internal set; } + + /// + /// Gets or sets the Quantizer value + /// + public IQuantizer Quantizer { get; internal set; } + + /// + /// Gets or sets the Threshold value + /// + public byte Threshold { get; internal set; } + + /// + /// Gets or sets a value indicating whether to Write Gamma + /// + public bool WriteGamma { get; internal set; } + /// /// Encodes the image to the specified stream from the . /// @@ -164,27 +192,23 @@ namespace ImageSharp.Formats stream.Write(this.chunkDataBuffer, 0, 8); - // Ensure that quality can be set but has a fallback. - this.quality = this.options.Quality > 0 ? this.options.Quality : image.MetaData.Quality; - this.quality = this.quality > 0 ? this.quality.Clamp(1, int.MaxValue) : int.MaxValue; - - this.pngColorType = this.options.PngColorType; - this.quantizer = this.options.Quantizer; + this.pngColorType = this.PngColorType; + this.quantizer = this.Quantizer; // Set correct color type if the color count is 256 or less. - if (this.quality <= 256) + if (this.Quality <= 256) { this.pngColorType = PngColorType.Palette; } - if (this.pngColorType == PngColorType.Palette && this.quality > 256) + if (this.pngColorType == PngColorType.Palette && this.Quality > 256) { - this.quality = 256; + this.Quality = 256; } // Set correct bit depth. - this.bitDepth = this.quality <= 256 - ? (byte)ImageMaths.GetBitsNeededForColorDepth(this.quality).Clamp(1, 8) + this.bitDepth = this.Quality <= 256 + ? (byte)ImageMaths.GetBitsNeededForColorDepth(this.Quality).Clamp(1, 8) : (byte)8; // Png only supports in four pixel depths: 1, 2, 4, and 8 bits when using the PLTE chunk @@ -514,7 +538,7 @@ namespace ImageSharp.Formats private QuantizedImage WritePaletteChunk(Stream stream, PngHeader header, ImageBase image) where TPixel : struct, IPixel { - if (this.quality > 256) + if (this.Quality > 256) { return null; } @@ -525,7 +549,7 @@ namespace ImageSharp.Formats } // Quantize the image returning a palette. This boxing is icky. - QuantizedImage quantized = ((IQuantizer)this.quantizer).Quantize(image, this.quality); + QuantizedImage quantized = ((IQuantizer)this.quantizer).Quantize(image, this.Quality); // Grab the palette and write it to the stream. TPixel[] palette = quantized.Palette; @@ -552,7 +576,7 @@ namespace ImageSharp.Formats colorTable[offset + 1] = bytes[1]; colorTable[offset + 2] = bytes[2]; - if (alpha > this.options.Threshold) + if (alpha > this.Threshold) { alpha = 255; } @@ -610,9 +634,9 @@ namespace ImageSharp.Formats /// The containing image data. private void WriteGammaChunk(Stream stream) { - if (this.options.WriteGamma) + if (this.WriteGamma) { - int gammaValue = (int)(this.options.Gamma * 100000F); + int gammaValue = (int)(this.Gamma * 100000F); byte[] size = BitConverter.GetBytes(gammaValue); @@ -655,7 +679,7 @@ namespace ImageSharp.Formats try { memoryStream = new MemoryStream(); - using (var deflateStream = new ZlibDeflateStream(memoryStream, this.options.CompressionLevel)) + using (var deflateStream = new ZlibDeflateStream(memoryStream, this.CompressionLevel)) { for (int y = 0; y < this.height; y++) { diff --git a/src/ImageSharp/Formats/Png/PngEncoderOptions.cs b/src/ImageSharp/Formats/Png/PngEncoderOptions.cs deleted file mode 100644 index 90175c6d6..000000000 --- a/src/ImageSharp/Formats/Png/PngEncoderOptions.cs +++ /dev/null @@ -1,82 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Formats -{ - using Quantizers; - - /// - /// Encapsulates the options for the . - /// - public sealed class PngEncoderOptions : EncoderOptions, IPngEncoderOptions - { - /// - /// Initializes a new instance of the class. - /// - public PngEncoderOptions() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The options for the encoder. - private PngEncoderOptions(IEncoderOptions options) - : base(options) - { - } - - /// - /// Gets or sets the quality of output for images. - /// - public int Quality { get; set; } - - /// - /// Gets or sets the png color type - /// - public PngColorType PngColorType { get; set; } = PngColorType.RgbWithAlpha; - - /// - /// Gets or sets the compression level 1-9. - /// Defaults to 6. - /// - public int CompressionLevel { get; set; } = 6; - - /// - /// Gets or sets the gamma value, that will be written - /// the the stream, when the property - /// is set to true. The default value is 2.2F. - /// - /// The gamma value of the image. - public float Gamma { get; set; } = 2.2F; - - /// - /// Gets or sets quantizer for reducing the color count. - /// - public IQuantizer Quantizer { get; set; } - - /// - /// Gets or sets the transparency threshold. - /// - public byte Threshold { get; set; } = 255; - - /// - /// Gets or sets a value indicating whether this instance should write - /// gamma information to the stream. The default value is false. - /// - public bool WriteGamma { get; set; } - - /// - /// Converts the options to a instance with a - /// cast or by creating a new instance with the specfied options. - /// - /// The options for the encoder. - /// The options for the . - internal static IPngEncoderOptions Create(IEncoderOptions options) - { - return options as IPngEncoderOptions ?? new PngEncoderOptions(options); - } - } -} diff --git a/src/ImageSharp/Formats/Png/PngFormat.cs b/src/ImageSharp/Formats/Png/PngFormat.cs deleted file mode 100644 index 0f5a74da0..000000000 --- a/src/ImageSharp/Formats/Png/PngFormat.cs +++ /dev/null @@ -1,47 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Formats -{ - using System.Collections.Generic; - - /// - /// Encapsulates the means to encode and decode png images. - /// - public class PngFormat : IImageFormat - { - /// - public string MimeType => "image/png"; - - /// - public string Extension => "png"; - - /// - public IEnumerable SupportedExtensions => new string[] { "png" }; - - /// - public IImageDecoder Decoder => new PngDecoder(); - - /// - public IImageEncoder Encoder => new PngEncoder(); - - /// - public int HeaderSize => 8; - - /// - public bool IsSupportedFileFormat(byte[] header) - { - return header.Length >= this.HeaderSize && - header[0] == 0x89 && - header[1] == 0x50 && // P - header[2] == 0x4E && // N - header[3] == 0x47 && // G - header[4] == 0x0D && // CR - header[5] == 0x0A && // LF - header[6] == 0x1A && // EOF - header[7] == 0x0A; // LF - } - } -} diff --git a/src/ImageSharp/Image/IImage.cs b/src/ImageSharp/Image/IImage.cs index 55abdb244..b9e8e392a 100644 --- a/src/ImageSharp/Image/IImage.cs +++ b/src/ImageSharp/Image/IImage.cs @@ -12,11 +12,6 @@ namespace ImageSharp /// internal interface IImage : IImageBase { - /// - /// Gets the currently loaded image format. - /// - IImageFormat CurrentImageFormat { get; } - /// /// Gets the meta data of the image. /// diff --git a/src/ImageSharp/Image/Image.Decode.cs b/src/ImageSharp/Image/Image.Decode.cs index c162f1772..2730da8f2 100644 --- a/src/ImageSharp/Image/Image.Decode.cs +++ b/src/ImageSharp/Image/Image.Decode.cs @@ -23,7 +23,7 @@ namespace ImageSharp /// The image stream to read the header from. /// The configuration. /// The image format or null if none found. - private static IImageFormat DiscoverFormat(Stream stream, Configuration config) + private static IImageDecoder DiscoverDecoder(Stream stream, Configuration config) { // This is probably a candidate for making into a public API in the future! int maxHeaderSize = config.MaxHeaderSize; @@ -32,14 +32,14 @@ namespace ImageSharp return null; } - IImageFormat format; + IImageDecoder format; byte[] header = ArrayPool.Shared.Rent(maxHeaderSize); try { long startPosition = stream.Position; stream.Read(header, 0, maxHeaderSize); stream.Position = startPosition; - format = config.ImageFormats.FirstOrDefault(x => x.IsSupportedFileFormat(header)); + format = config.ImageDecoders.LastOrDefault(x => x.IsSupportedFileFormat(header)); // we should use last in case user has registerd a new one with their own settings } finally { @@ -49,28 +49,28 @@ namespace ImageSharp return format; } +#pragma warning disable SA1008 // Opening parenthesis must be spaced correctly /// /// Decodes the image stream to the current image. /// /// The stream. - /// The options for the decoder. /// the configuration. /// The pixel format. /// /// A new . /// - private static Image Decode(Stream stream, IDecoderOptions options, Configuration config) + private static (Image img, IImageDecoder decoder) Decode(Stream stream, Configuration config) +#pragma warning restore SA1008 // Opening parenthesis must be spaced correctly where TPixel : struct, IPixel { - IImageFormat format = DiscoverFormat(stream, config); - if (format == null) + IImageDecoder decoder = DiscoverDecoder(stream, config); + if (decoder == null) { - return null; + return (null, null); } - Image img = format.Decoder.Decode(config, stream, options); - img.CurrentImageFormat = format; - return img; + Image img = decoder.Decode(config, stream); + return (img, decoder); } } } \ No newline at end of file diff --git a/src/ImageSharp/Image/Image.FromBytes.cs b/src/ImageSharp/Image/Image.FromBytes.cs index c7309c4b1..8cc0e8f37 100644 --- a/src/ImageSharp/Image/Image.FromBytes.cs +++ b/src/ImageSharp/Image/Image.FromBytes.cs @@ -20,15 +20,15 @@ namespace ImageSharp /// /// The byte array containing image data. /// A new . - public static Image Load(byte[] data) => Load(null, data, null); + public static Image Load(byte[] data) => Load(null, data); /// /// Create a new instance of the class from the given byte array. /// /// The byte array containing image data. - /// The options for the decoder. + /// the mime type of the decoded image. /// A new . - public static Image Load(byte[] data, IDecoderOptions options) => Load(null, data, options); + public static Image Load(byte[] data, out string mimeType) => Load(null, data, out mimeType); /// /// Create a new instance of the class from the given byte array. @@ -36,33 +36,33 @@ namespace ImageSharp /// The config for the decoder. /// The byte array containing image data. /// A new . - public static Image Load(Configuration config, byte[] data) => Load(config, data, null); + public static Image Load(Configuration config, byte[] data) => Load(config, data); /// - /// Create a new instance of the class from the given byte array. + /// Create a new instance of the class from the given byte array. /// + /// The config for the decoder. /// The byte array containing image data. - /// The decoder. + /// the mime type of the decoded image. /// A new . - public static Image Load(byte[] data, IImageDecoder decoder) => Load(data, decoder, null); + public static Image Load(Configuration config, byte[] data, out string mimeType) => Load(config, data, out mimeType); /// - /// Create a new instance of the class from the given byte array. + /// Create a new instance of the class from the given byte array. /// - /// The configuration options. /// The byte array containing image data. - /// The options for the decoder. + /// The decoder. /// A new . - public static Image Load(Configuration config, byte[] data, IDecoderOptions options) => Load(config, data, options); + public static Image Load(byte[] data, IImageDecoder decoder) => Load(data, decoder); /// - /// Create a new instance of the class from the given byte array. + /// Create a new instance of the class from the given byte array. /// + /// The config for the decoder. /// The byte array containing image data. /// The decoder. - /// The options for the decoder. /// A new . - public static Image Load(byte[] data, IImageDecoder decoder, IDecoderOptions options) => Load(data, decoder, options); + public static Image Load(Configuration config, byte[] data, IImageDecoder decoder) => Load(config, data, decoder); /// /// Create a new instance of the class from the given byte array. @@ -73,79 +73,85 @@ namespace ImageSharp public static Image Load(byte[] data) where TPixel : struct, IPixel { - return Load(null, data, null); + return Load(null, data); } /// /// Create a new instance of the class from the given byte array. /// /// The byte array containing image data. - /// The options for the decoder. + /// the mime type of the decoded image. /// The pixel format. /// A new . - public static Image Load(byte[] data, IDecoderOptions options) + public static Image Load(byte[] data, out string mimeType) where TPixel : struct, IPixel { - return Load(null, data, options); + return Load(null, data, out mimeType); } /// /// Create a new instance of the class from the given byte array. /// - /// The config for the decoder. + /// The configuration options. /// The byte array containing image data. /// The pixel format. /// A new . public static Image Load(Configuration config, byte[] data) where TPixel : struct, IPixel { - return Load(config, data, null); + using (MemoryStream ms = new MemoryStream(data)) + { + return Load(config, ms); + } } /// /// Create a new instance of the class from the given byte array. /// + /// The configuration options. /// The byte array containing image data. - /// The decoder. + /// the mime type of the decoded image. /// The pixel format. /// A new . - public static Image Load(byte[] data, IImageDecoder decoder) + public static Image Load(Configuration config, byte[] data, out string mimeType) where TPixel : struct, IPixel { - return Load(data, decoder, null); + using (MemoryStream ms = new MemoryStream(data)) + { + return Load(config, ms, out mimeType); + } } /// /// Create a new instance of the class from the given byte array. /// - /// The configuration options. /// The byte array containing image data. - /// The options for the decoder. + /// The decoder. /// The pixel format. /// A new . - public static Image Load(Configuration config, byte[] data, IDecoderOptions options) + public static Image Load(byte[] data, IImageDecoder decoder) where TPixel : struct, IPixel { using (MemoryStream ms = new MemoryStream(data)) { - return Load(config, ms, options); + return Load(ms, decoder); } } /// /// Create a new instance of the class from the given byte array. /// + /// The Configuration. /// The byte array containing image data. /// The decoder. - /// The options for the decoder. /// The pixel format. /// A new . - public static Image Load(byte[] data, IImageDecoder decoder, IDecoderOptions options) + public static Image Load(Configuration config, byte[] data, IImageDecoder decoder) where TPixel : struct, IPixel { using (MemoryStream ms = new MemoryStream(data)) { - return Load(ms, decoder, options); + return Load(config, ms, decoder); } } } diff --git a/src/ImageSharp/Image/Image.FromFile.cs b/src/ImageSharp/Image/Image.FromFile.cs index a135c43f5..991294921 100644 --- a/src/ImageSharp/Image/Image.FromFile.cs +++ b/src/ImageSharp/Image/Image.FromFile.cs @@ -30,12 +30,12 @@ namespace ImageSharp /// Create a new instance of the class from the given file. /// /// The file path to the image. - /// The options for the decoder. + /// the mime type of the decoded image. /// /// Thrown if the stream is not readable nor seekable. /// - /// A new . - public static Image Load(string path, IDecoderOptions options) => Load(path, options); + /// A new . + public static Image Load(string path, out string mimeType) => Load(path, out mimeType); /// /// Create a new instance of the class from the given file. @@ -51,37 +51,37 @@ namespace ImageSharp /// /// Create a new instance of the class from the given file. /// + /// The config for the decoder. /// The file path to the image. - /// The decoder. + /// the mime type of the decoded image. /// /// Thrown if the stream is not readable nor seekable. /// /// A new . - public static Image Load(string path, IImageDecoder decoder) => Load(path, decoder); + public static Image Load(Configuration config, string path, out string mimeType) => Load(config, path, out mimeType); /// /// Create a new instance of the class from the given file. /// - /// The configuration options. + /// The Configuration. /// The file path to the image. - /// The options for the decoder. + /// The decoder. /// /// Thrown if the stream is not readable nor seekable. /// /// A new . - public static Image Load(Configuration config, string path, IDecoderOptions options) => Load(config, path, options); + public static Image Load(Configuration config, string path, IImageDecoder decoder) => Load(config, path, decoder); /// /// Create a new instance of the class from the given file. /// /// The file path to the image. /// The decoder. - /// The options for the decoder. /// /// Thrown if the stream is not readable nor seekable. /// /// A new . - public static Image Load(string path, IImageDecoder decoder, IDecoderOptions options) => Load(path, decoder, options); + public static Image Load(string path, IImageDecoder decoder) => Load(path, decoder); /// /// Create a new instance of the class from the given file. @@ -95,29 +95,29 @@ namespace ImageSharp public static Image Load(string path) where TPixel : struct, IPixel { - return Load(null, path, null); + return Load(null, path); } /// /// Create a new instance of the class from the given file. /// /// The file path to the image. - /// The options for the decoder. + /// the mime type of the decoded image. /// /// Thrown if the stream is not readable nor seekable. /// /// The pixel format. /// A new . - public static Image Load(string path, IDecoderOptions options) + public static Image Load(string path, out string mimeType) where TPixel : struct, IPixel { - return Load(null, path, options); + return Load(null, path, out mimeType); } /// /// Create a new instance of the class from the given file. /// - /// The config for the decoder. + /// The configuration options. /// The file path to the image. /// /// Thrown if the stream is not readable nor seekable. @@ -127,64 +127,68 @@ namespace ImageSharp public static Image Load(Configuration config, string path) where TPixel : struct, IPixel { - return Load(config, path, null); + config = config ?? Configuration.Default; + using (Stream s = config.FileSystem.OpenRead(path)) + { + return Load(config, s); + } } /// /// Create a new instance of the class from the given file. /// + /// The configuration options. /// The file path to the image. - /// The decoder. + /// the mime type of the decoded image. /// /// Thrown if the stream is not readable nor seekable. /// /// The pixel format. /// A new . - public static Image Load(string path, IImageDecoder decoder) + public static Image Load(Configuration config, string path, out string mimeType) where TPixel : struct, IPixel { - return Load(path, decoder, null); + config = config ?? Configuration.Default; + using (Stream s = config.FileSystem.OpenRead(path)) + { + return Load(config, s, out mimeType); + } } /// /// Create a new instance of the class from the given file. /// - /// The configuration options. /// The file path to the image. - /// The options for the decoder. + /// The decoder. /// /// Thrown if the stream is not readable nor seekable. /// /// The pixel format. /// A new . - public static Image Load(Configuration config, string path, IDecoderOptions options) + public static Image Load(string path, IImageDecoder decoder) where TPixel : struct, IPixel { - config = config ?? Configuration.Default; - using (Stream s = config.FileSystem.OpenRead(path)) - { - return Load(config, s, options); - } + return Load(null, path, decoder); } /// /// Create a new instance of the class from the given file. /// + /// The Configuration. /// The file path to the image. /// The decoder. - /// The options for the decoder. /// /// Thrown if the stream is not readable nor seekable. /// /// The pixel format. /// A new . - public static Image Load(string path, IImageDecoder decoder, IDecoderOptions options) + public static Image Load(Configuration config, string path, IImageDecoder decoder) where TPixel : struct, IPixel { - Configuration config = Configuration.Default; + config = config ?? Configuration.Default; using (Stream s = config.FileSystem.OpenRead(path)) { - return Load(s, decoder, options); + return Load(config, s, decoder); } } } diff --git a/src/ImageSharp/Image/Image.FromStream.cs b/src/ImageSharp/Image/Image.FromStream.cs index 1bcb5adc9..79c66af90 100644 --- a/src/ImageSharp/Image/Image.FromStream.cs +++ b/src/ImageSharp/Image/Image.FromStream.cs @@ -7,6 +7,7 @@ namespace ImageSharp { using System; using System.IO; + using System.Linq; using System.Text; using Formats; @@ -21,22 +22,22 @@ namespace ImageSharp /// Create a new instance of the class from the given stream. /// /// The stream containing image information. + /// the mime type of the decoded image. /// /// Thrown if the stream is not readable nor seekable. /// /// A new .> - public static Image Load(Stream stream) => Load(stream); + public static Image Load(Stream stream, out string mimeType) => Load(stream, out mimeType); /// /// Create a new instance of the class from the given stream. /// /// The stream containing image information. - /// The options for the decoder. /// /// Thrown if the stream is not readable nor seekable. /// /// A new .> - public static Image Load(Stream stream, IDecoderOptions options) => Load(stream, options); + public static Image Load(Stream stream) => Load(stream); /// /// Create a new instance of the class from the given stream. @@ -63,14 +64,14 @@ namespace ImageSharp /// /// Create a new instance of the class from the given stream. /// + /// The config for the decoder. /// The stream containing image information. - /// The decoder. - /// The options for the decoder. + /// the mime type of the decoded image. /// /// Thrown if the stream is not readable nor seekable. /// - /// A new .> - public static Image Load(Stream stream, IImageDecoder decoder, IDecoderOptions options) => Load(stream, decoder, options); + /// A new .> + public static Image Load(Configuration config, Stream stream, out string mimeType) => Load(config, stream, out mimeType); /// /// Create a new instance of the class from the given stream. @@ -84,44 +85,45 @@ namespace ImageSharp public static Image Load(Stream stream) where TPixel : struct, IPixel { - return Load(null, stream, null); + return Load(null, stream); } /// /// Create a new instance of the class from the given stream. /// /// The stream containing image information. - /// The options for the decoder. + /// the mime type of the decoded image. /// /// Thrown if the stream is not readable nor seekable. /// /// The pixel format. /// A new .> - public static Image Load(Stream stream, IDecoderOptions options) + public static Image Load(Stream stream, out string mimeType) where TPixel : struct, IPixel { - return Load(null, stream, options); + return Load(null, stream, out mimeType); } /// /// Create a new instance of the class from the given stream. /// - /// The config for the decoder. /// The stream containing image information. + /// The decoder. /// /// Thrown if the stream is not readable nor seekable. /// /// The pixel format. /// A new .> - public static Image Load(Configuration config, Stream stream) + public static Image Load(Stream stream, IImageDecoder decoder) where TPixel : struct, IPixel { - return Load(config, stream, null); + return WithSeekableStream(stream, s => decoder.Decode(Configuration.Default, s)); } /// /// Create a new instance of the class from the given stream. /// + /// The Configuration. /// The stream containing image information. /// The decoder. /// @@ -129,27 +131,26 @@ namespace ImageSharp /// /// The pixel format. /// A new .> - public static Image Load(Stream stream, IImageDecoder decoder) + public static Image Load(Configuration config, Stream stream, IImageDecoder decoder) where TPixel : struct, IPixel { - return Load(stream, decoder, null); + return WithSeekableStream(stream, s => decoder.Decode(config, s)); } /// /// Create a new instance of the class from the given stream. /// + /// The configuration options. /// The stream containing image information. - /// The decoder. - /// The options for the decoder. /// /// Thrown if the stream is not readable nor seekable. /// /// The pixel format. /// A new .> - public static Image Load(Stream stream, IImageDecoder decoder, IDecoderOptions options) + public static Image Load(Configuration config, Stream stream) where TPixel : struct, IPixel { - return WithSeekableStream(stream, s => decoder.Decode(Configuration.Default, s, options)); + return Load(config, stream, out var _); } /// @@ -157,27 +158,30 @@ namespace ImageSharp /// /// The configuration options. /// The stream containing image information. - /// The options for the decoder. + /// the mime type of the decoded image. /// /// Thrown if the stream is not readable nor seekable. /// /// The pixel format. /// A new .> - public static Image Load(Configuration config, Stream stream, IDecoderOptions options) - where TPixel : struct, IPixel + public static Image Load(Configuration config, Stream stream, out string mimeType) + where TPixel : struct, IPixel { config = config ?? Configuration.Default; - Image img = WithSeekableStream(stream, s => Decode(s, options, config)); + mimeType = null; + (Image img, IImageDecoder decoder) data = WithSeekableStream(stream, s => Decode(s, config)); + + mimeType = data.decoder?.MimeTypes.FirstOrDefault(); - if (img != null) + if (data.img != null) { - return img; + return data.img; } StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.AppendLine("Image cannot be loaded. Available formats:"); + stringBuilder.AppendLine("Image cannot be loaded. Available decoders:"); - foreach (IImageFormat format in config.ImageFormats) + foreach (IImageDecoder format in config.ImageDecoders) { stringBuilder.AppendLine("-" + format); } diff --git a/src/ImageSharp/Image/Image{TPixel}.cs b/src/ImageSharp/Image/Image{TPixel}.cs index 059ccb9a0..27f3801c4 100644 --- a/src/ImageSharp/Image/Image{TPixel}.cs +++ b/src/ImageSharp/Image/Image{TPixel}.cs @@ -11,6 +11,7 @@ namespace ImageSharp using System.IO; using System.Linq; using System.Numerics; + using System.Text; using System.Threading.Tasks; using Formats; @@ -94,13 +95,7 @@ namespace ImageSharp internal Image(Configuration configuration, int width, int height, ImageMetaData metadata) : base(configuration, width, height) { - if (!this.Configuration.ImageFormats.Any()) - { - throw new InvalidOperationException("No image formats have been configured."); - } - this.MetaData = metadata ?? new ImageMetaData(); - this.CurrentImageFormat = this.Configuration.ImageFormats.First(); } /// @@ -138,11 +133,6 @@ namespace ImageSharp /// The list of frame images. public IList> Frames { get; } = new List>(); - /// - /// Gets the currently loaded image format. - /// - public IImageFormat CurrentImageFormat { get; internal set; } - /// /// Applies the processor to the image. /// @@ -162,48 +152,28 @@ namespace ImageSharp /// Saves the image to the given stream using the currently loaded image format. /// /// The stream to save the image to. + /// The mime type to save the image to. /// Thrown if the stream is null. /// The - public Image Save(Stream stream) + public Image Save(Stream stream, string mimeType) { - return this.Save(stream, (IEncoderOptions)null); - } + Guard.NotNullOrEmpty(mimeType, nameof(mimeType)); + IImageEncoder encoder = this.Configuration.ImageEncoders?.LastOrDefault(x => x?.MimeTypes?.Contains(mimeType, StringComparer.OrdinalIgnoreCase) == true); - /// - /// Saves the image to the given stream using the currently loaded image format. - /// - /// The stream to save the image to. - /// The options for the encoder. - /// Thrown if the stream is null. - /// The - public Image Save(Stream stream, IEncoderOptions options) - { - return this.Save(stream, this.CurrentImageFormat?.Encoder, options); - } + if (encoder == null) + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.AppendLine("Can't find encoder for provided mime type. Available encoded:"); - /// - /// Saves the image to the given stream using the given image format. - /// - /// The stream to save the image to. - /// The format to save the image as. - /// The - public Image Save(Stream stream, IImageFormat format) - { - return this.Save(stream, format, null); - } + foreach (IImageEncoder format in this.Configuration.ImageEncoders) + { + stringBuilder.AppendLine("-" + format); + } - /// - /// Saves the image to the given stream using the given image format. - /// - /// The stream to save the image to. - /// The format to save the image as. - /// The options for the encoder. - /// The - public Image Save(Stream stream, IImageFormat format, IEncoderOptions options) - { - Guard.NotNull(format, nameof(format)); + throw new NotSupportedException(stringBuilder.ToString()); + } - return this.Save(stream, format.Encoder, options); + return this.Save(stream, encoder); } /// @@ -216,26 +186,11 @@ namespace ImageSharp /// The . /// public Image Save(Stream stream, IImageEncoder encoder) - { - return this.Save(stream, encoder, null); - } - - /// - /// Saves the image to the given stream using the given image encoder. - /// - /// The stream to save the image to. - /// The encoder to save the image with. - /// The options for the encoder. - /// Thrown if the stream or encoder is null. - /// - /// The . - /// - public Image Save(Stream stream, IImageEncoder encoder, IEncoderOptions options) { Guard.NotNull(stream, nameof(stream)); Guard.NotNull(encoder, nameof(encoder)); - encoder.Encode(this, stream, options); + encoder.Encode(this, stream); return this; } @@ -249,52 +204,24 @@ namespace ImageSharp /// The public Image Save(string filePath) { - return this.Save(filePath, (IEncoderOptions)null); - } + Guard.NotNullOrEmpty(filePath, nameof(filePath)); - /// - /// Saves the image to the given stream using the currently loaded image format. - /// - /// The file path to save the image to. - /// The options for the encoder. - /// Thrown if the stream is null. - /// The - public Image Save(string filePath, IEncoderOptions options) - { string ext = Path.GetExtension(filePath).Trim('.'); - IImageFormat format = this.Configuration.ImageFormats.SingleOrDefault(f => f.SupportedExtensions.Contains(ext, StringComparer.OrdinalIgnoreCase)); - if (format == null) + IImageEncoder encoder = this.Configuration.ImageEncoders?.LastOrDefault(x => x?.FileExtensions?.Contains(ext, StringComparer.OrdinalIgnoreCase) == true); + if (encoder == null) { - throw new InvalidOperationException($"No image formats have been registered for the file extension '{ext}'."); - } + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.AppendLine($"Can't find encoder for file extention '{ext}'. Available encoded:"); - return this.Save(filePath, format, options); - } + foreach (IImageEncoder format in this.Configuration.ImageEncoders) + { + stringBuilder.AppendLine("-" + format); + } - /// - /// Saves the image to the given stream using the currently loaded image format. - /// - /// The file path to save the image to. - /// The format to save the image as. - /// Thrown if the format is null. - /// The - public Image Save(string filePath, IImageFormat format) - { - return this.Save(filePath, format, null); - } + throw new NotSupportedException(stringBuilder.ToString()); + } - /// - /// Saves the image to the given stream using the currently loaded image format. - /// - /// The file path to save the image to. - /// The format to save the image as. - /// The options for the encoder. - /// Thrown if the format is null. - /// The - public Image Save(string filePath, IImageFormat format, IEncoderOptions options) - { - Guard.NotNull(format, nameof(format)); - return this.Save(filePath, format.Encoder, options); + return this.Save(filePath, encoder); } /// @@ -305,24 +232,11 @@ namespace ImageSharp /// Thrown if the encoder is null. /// The public Image Save(string filePath, IImageEncoder encoder) - { - return this.Save(filePath, encoder, null); - } - - /// - /// Saves the image to the given stream using the currently loaded image format. - /// - /// The file path to save the image to. - /// The encoder to save the image with. - /// The options for the encoder. - /// Thrown if the encoder is null. - /// The - public Image Save(string filePath, IImageEncoder encoder, IEncoderOptions options) { Guard.NotNull(encoder, nameof(encoder)); using (Stream fs = this.Configuration.FileSystem.Create(filePath)) { - return this.Save(fs, encoder, options); + return this.Save(fs, encoder); } } #endif @@ -330,21 +244,22 @@ namespace ImageSharp /// public override string ToString() { - return $"Image: {this.Width}x{this.Height}"; + return $"Image<{typeof(TPixel).Name}>: {this.Width}x{this.Height}"; } /// /// Returns a Base64 encoded string from the given image. /// /// + /// The mimeType. /// The - public string ToBase64String() + public string ToBase64String(string mimeType) { using (MemoryStream stream = new MemoryStream()) { - this.Save(stream); + this.Save(stream, mimeType); stream.Flush(); - return $"data:{this.CurrentImageFormat.MimeType};base64,{Convert.ToBase64String(stream.ToArray())}"; + return $"data:{mimeType};base64,{Convert.ToBase64String(stream.ToArray())}"; } } @@ -417,7 +332,6 @@ namespace ImageSharp /// private void CopyProperties(IImage other) { - this.CurrentImageFormat = other.CurrentImageFormat; this.MetaData = new ImageMetaData(other.MetaData); } } diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 17f7bf58f..6cc981f96 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -43,6 +43,7 @@ + ..\..\ImageSharp.ruleset diff --git a/src/ImageSharp/MetaData/ImageMetaData.cs b/src/ImageSharp/MetaData/ImageMetaData.cs index 91ea9ac4b..5361b486d 100644 --- a/src/ImageSharp/MetaData/ImageMetaData.cs +++ b/src/ImageSharp/MetaData/ImageMetaData.cs @@ -50,7 +50,6 @@ namespace ImageSharp this.HorizontalResolution = other.HorizontalResolution; this.VerticalResolution = other.VerticalResolution; - this.Quality = other.Quality; this.FrameDelay = other.FrameDelay; this.DisposalMethod = other.DisposalMethod; this.RepeatCount = other.RepeatCount; @@ -127,11 +126,6 @@ namespace ImageSharp /// A list of image properties. public IList Properties { get; } = new List(); - /// - /// Gets or sets the quality of the image. This affects the output quality of lossy image formats. - /// - public int Quality { get; set; } - /// /// Gets or sets the number of times any animation is repeated. /// 0 means to repeat indefinitely. diff --git a/tests/ImageSharp.Benchmarks/BenchmarkBase.cs b/tests/ImageSharp.Benchmarks/BenchmarkBase.cs index d6e8ac692..41574d109 100644 --- a/tests/ImageSharp.Benchmarks/BenchmarkBase.cs +++ b/tests/ImageSharp.Benchmarks/BenchmarkBase.cs @@ -13,10 +13,6 @@ protected BenchmarkBase() { // Add Image Formats - Configuration.Default.AddImageFormat(new JpegFormat()); - Configuration.Default.AddImageFormat(new PngFormat()); - Configuration.Default.AddImageFormat(new BmpFormat()); - Configuration.Default.AddImageFormat(new GifFormat()); } } } diff --git a/tests/ImageSharp.Benchmarks/Image/EncodeIndexedPng.cs b/tests/ImageSharp.Benchmarks/Image/EncodeIndexedPng.cs index 88e82f079..aa3112f52 100644 --- a/tests/ImageSharp.Benchmarks/Image/EncodeIndexedPng.cs +++ b/tests/ImageSharp.Benchmarks/Image/EncodeIndexedPng.cs @@ -53,9 +53,9 @@ namespace ImageSharp.Benchmarks.Image { using (MemoryStream memoryStream = new MemoryStream()) { - PngEncoderOptions options = new PngEncoderOptions() { Quantizer = new OctreeQuantizer(), Quality = 256 }; + PngEncoder encoder = new PngEncoder() { Quantizer = new OctreeQuantizer(), Quality = 256 }; - this.bmpCore.SaveAsPng(memoryStream, options); + this.bmpCore.SaveAsPng(memoryStream, encoder); } } @@ -64,7 +64,7 @@ namespace ImageSharp.Benchmarks.Image { using (MemoryStream memoryStream = new MemoryStream()) { - PngEncoderOptions options = new PngEncoderOptions { Quantizer = new OctreeQuantizer { Dither = false }, Quality = 256 }; + PngEncoder options = new PngEncoder { Quantizer = new OctreeQuantizer { Dither = false }, Quality = 256 }; this.bmpCore.SaveAsPng(memoryStream, options); } @@ -75,7 +75,7 @@ namespace ImageSharp.Benchmarks.Image { using (MemoryStream memoryStream = new MemoryStream()) { - PngEncoderOptions options = new PngEncoderOptions { Quantizer = new PaletteQuantizer(), Quality = 256 }; + PngEncoder options = new PngEncoder { Quantizer = new PaletteQuantizer(), Quality = 256 }; this.bmpCore.SaveAsPng(memoryStream, options); } @@ -86,7 +86,7 @@ namespace ImageSharp.Benchmarks.Image { using (MemoryStream memoryStream = new MemoryStream()) { - PngEncoderOptions options = new PngEncoderOptions { Quantizer = new PaletteQuantizer { Dither = false }, Quality = 256 }; + PngEncoder options = new PngEncoder { Quantizer = new PaletteQuantizer { Dither = false }, Quality = 256 }; this.bmpCore.SaveAsPng(memoryStream, options); } @@ -97,7 +97,7 @@ namespace ImageSharp.Benchmarks.Image { using (MemoryStream memoryStream = new MemoryStream()) { - PngEncoderOptions options = new PngEncoderOptions() { Quantizer = new WuQuantizer(), Quality = 256 }; + PngEncoder options = new PngEncoder() { Quantizer = new WuQuantizer(), Quality = 256 }; this.bmpCore.SaveAsPng(memoryStream, options); } diff --git a/tests/ImageSharp.Benchmarks/Image/EncodePng.cs b/tests/ImageSharp.Benchmarks/Image/EncodePng.cs index 3ec83aa7c..81bb235ee 100644 --- a/tests/ImageSharp.Benchmarks/Image/EncodePng.cs +++ b/tests/ImageSharp.Benchmarks/Image/EncodePng.cs @@ -71,7 +71,7 @@ namespace ImageSharp.Benchmarks.Image new OctreeQuantizer() : new PaletteQuantizer(); - PngEncoderOptions options = new PngEncoderOptions() { Quantizer = quantizer }; + PngEncoder options = new PngEncoder() { Quantizer = quantizer }; this.bmpCore.SaveAsPng(memoryStream, options); } } diff --git a/tests/ImageSharp.Tests/ConfigurationTests.cs b/tests/ImageSharp.Tests/ConfigurationTests.cs index aa3c4edfc..e2d50649a 100644 --- a/tests/ImageSharp.Tests/ConfigurationTests.cs +++ b/tests/ImageSharp.Tests/ConfigurationTests.cs @@ -36,7 +36,8 @@ namespace ImageSharp.Tests { var configuration = Configuration.CreateDefaultInstance(); - Assert.Equal(4, configuration.ImageFormats.Count); + Assert.Equal(4, configuration.ImageDecoders.Count); + Assert.Equal(4, configuration.ImageDecoders.Count); } /// @@ -73,7 +74,8 @@ namespace ImageSharp.Tests [Fact] public void TestDefultConfigurationImageFormatsIsNotNull() { - Assert.True(Configuration.Default.ImageFormats != null); + Assert.True(Configuration.Default.ImageDecoders != null); + Assert.True(Configuration.Default.ImageEncoders != null); } /// @@ -85,163 +87,25 @@ namespace ImageSharp.Tests { Assert.Throws(() => { - Configuration.Default.AddImageFormat(null); + Configuration.Default.AddImageFormat((IImageEncoder)null); }); - } - - /// - /// Tests the method throws an exception - /// when the encoder is null. - /// - [Fact] - public void TestAddImageFormatThrowsWithNullEncoder() - { - var format = new TestFormat { Encoder = null }; - - Assert.Throws(() => - { - Configuration.Default.AddImageFormat(format); - }); - } - - /// - /// Tests the method throws an exception - /// when the decoder is null. - /// - [Fact] - public void TestAddImageFormatThrowsWithNullDecoder() - { - var format = new TestFormat { Decoder = null }; - - Assert.Throws(() => - { - Configuration.Default.AddImageFormat(format); - }); - } - - /// - /// Tests the method throws an exception - /// when the mime type is null or an empty string. - /// - [Fact] - public void TestAddImageFormatThrowsWithNullOrEmptyMimeType() - { - var format = new TestFormat { MimeType = null }; - Assert.Throws(() => { - Configuration.Default.AddImageFormat(format); - }); - - format = new TestFormat { MimeType = string.Empty }; - - Assert.Throws(() => - { - Configuration.Default.AddImageFormat(format); + Configuration.Default.AddImageFormat((IImageDecoder)null); }); } - /// - /// Tests the method throws an exception - /// when the extension is null or an empty string. - /// - [Fact] - public void TestAddImageFormatThrowsWithNullOrEmptyExtension() - { - var format = new TestFormat { Extension = null }; - - Assert.Throws(() => - { - Configuration.Default.AddImageFormat(format); - }); - - format = new TestFormat { Extension = string.Empty }; - - Assert.Throws(() => - { - Configuration.Default.AddImageFormat(format); - }); - } - - /// - /// Tests the method throws an exception - /// when the supported extensions list is null or empty. - /// - [Fact] - public void TestAddImageFormatThrowsWenSupportedExtensionsIsNullOrEmpty() - { - var format = new TestFormat { SupportedExtensions = null }; - - Assert.Throws(() => - { - Configuration.Default.AddImageFormat(format); - }); - - format = new TestFormat { SupportedExtensions = Enumerable.Empty() }; - - Assert.Throws(() => - { - Configuration.Default.AddImageFormat(format); - }); - } - - /// - /// Tests the method throws an exception - /// when the supported extensions list does not contain the default extension. - /// - [Fact] - public void TestAddImageFormatThrowsWithoutDefaultExtension() - { - var format = new TestFormat { Extension = "test" }; - - Assert.Throws(() => - { - Configuration.Default.AddImageFormat(format); - }); - } - - /// - /// Tests the method throws an exception - /// when the supported extensions list contains an empty string. - /// - [Fact] - public void TestAddImageFormatThrowsWithEmptySupportedExtension() - { - var format = new TestFormat - { - Extension = "test", - SupportedExtensions = new[] { "test", string.Empty } - }; - - Assert.Throws(() => - { - Configuration.Default.AddImageFormat(format); - }); - } - - /// - /// Test that the method ignores adding duplicate image formats. - /// - [Fact] - public void TestConfigurationIgnoresDuplicateImageFormats() - { - Configuration.Default.AddImageFormat(new PngFormat()); - Configuration.Default.AddImageFormat(new PngFormat()); - - Assert.True(Configuration.Default.ImageFormats.Count(i => i.GetType() == typeof(PngFormat)) == 1); - } - /// /// Test that the default image constructors use default configuration. /// [Fact] public void TestImageUsesDefaultConfiguration() { - Configuration.Default.AddImageFormat(new PngFormat()); + Configuration.Default.AddImageFormat(new PngDecoder()); var image = new Image(1, 1); Assert.Equal(image.Configuration.ParallelOptions, Configuration.Default.ParallelOptions); - Assert.Equal(image.Configuration.ImageFormats, Configuration.Default.ImageFormats); + Assert.Equal(image.Configuration.ImageDecoders, Configuration.Default.ImageDecoders); } /// @@ -250,60 +114,12 @@ namespace ImageSharp.Tests [Fact] public void TestImageCopiesConfiguration() { - Configuration.Default.AddImageFormat(new PngFormat()); + Configuration.Default.AddImageFormat(new PngDecoder()); var image = new Image(1, 1); var image2 = new Image(image); Assert.Equal(image2.Configuration.ParallelOptions, image.Configuration.ParallelOptions); - Assert.True(image2.Configuration.ImageFormats.SequenceEqual(image.Configuration.ImageFormats)); - } - - /// - /// A test image format for testing the configuration. - /// - private class TestFormat : IImageFormat - { - /// - /// Initializes a new instance of the class. - /// - public TestFormat() - { - this.Decoder = new JpegDecoder(); - this.Encoder = new JpegEncoder(); - this.Extension = "jpg"; - this.MimeType = "image/test"; - this.SupportedExtensions = new[] { "jpg" }; - } - - /// - public IImageDecoder Decoder { get; set; } - - /// - public IImageEncoder Encoder { get; set; } - - /// - public string MimeType { get; set; } - - /// - public string Extension { get; set; } - - /// - public IEnumerable SupportedExtensions { get; set; } - - /// - public int HeaderSize - { - get - { - throw new NotImplementedException(); - } - } - - /// - public bool IsSupportedFileFormat(byte[] header) - { - throw new NotImplementedException(); - } + Assert.True(image2.Configuration.ImageDecoders.SequenceEqual(image.Configuration.ImageDecoders)); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Drawing/BeziersTests.cs b/tests/ImageSharp.Tests/Drawing/BeziersTests.cs index 3d49a70b8..4b53bbb04 100644 --- a/tests/ImageSharp.Tests/Drawing/BeziersTests.cs +++ b/tests/ImageSharp.Tests/Drawing/BeziersTests.cs @@ -24,18 +24,15 @@ namespace ImageSharp.Tests.Drawing string path = this.CreateOutputDirectory("Drawing", "BezierLine"); using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Simple.png")) - { - image.BackgroundColor(Rgba32.Blue) - .DrawBeziers(Rgba32.HotPink, 5, - new[] { + image.BackgroundColor(Rgba32.Blue) + .DrawBeziers(Rgba32.HotPink, 5, + new[] { new Vector2(10, 400), new Vector2(30, 10), new Vector2(240, 30), new Vector2(300, 400) - }) - .Save(output); - } + }) + .Save($"{path}/Simple.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -66,19 +63,16 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Opacity.png")) - { - image.BackgroundColor(Rgba32.Blue) - .DrawBeziers(color, - 10, - new[] { + image.BackgroundColor(Rgba32.Blue) + .DrawBeziers(color, + 10, + new[] { new Vector2(10, 400), new Vector2(30, 10), new Vector2(240, 30), new Vector2(300, 400) - }) - .Save(output); - } + }) + .Save($"{path}/Opacity.png"); //shift background color towards forground color by the opacity amount Rgba32 mergedColor = new Rgba32(Vector4.Lerp(Rgba32.Blue.ToVector4(), Rgba32.HotPink.ToVector4(), 150f / 255f)); diff --git a/tests/ImageSharp.Tests/Drawing/DrawPathTests.cs b/tests/ImageSharp.Tests/Drawing/DrawPathTests.cs index 4ba4a3a83..50466fcdd 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawPathTests.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawPathTests.cs @@ -34,13 +34,10 @@ namespace ImageSharp.Tests.Drawing ShapePath p = new ShapePath(linerSegemnt, bazierSegment); - using (FileStream output = File.OpenWrite($"{path}/Simple.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Draw(Rgba32.HotPink, 5, p) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Draw(Rgba32.HotPink, 5, p) + .Save($"{path}/Simple.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -77,13 +74,10 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Opacity.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Draw(color, 10, p) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Draw(color, 10, p) + .Save($"{path}/Opacity.png"); //shift background color towards forground color by the opacity amount Rgba32 mergedColor = new Rgba32(Vector4.Lerp(Rgba32.Blue.ToVector4(), Rgba32.HotPink.ToVector4(), 150f / 255f)); @@ -115,11 +109,8 @@ namespace ImageSharp.Tests.Drawing image.DrawLines(pen, new Vector2[] { new Vector2(100, 2), new Vector2(-10, i) }); } - using (FileStream output = File.OpenWrite($"{path}/ClippedLines.png")) - { - image - .Save(output); - } + image + .Save($"{path}/ClippedLines.png"); using (PixelAccessor sourcePixels = image.Lock()) { Assert.Equal(Rgba32.White, sourcePixels[0, 90]); diff --git a/tests/ImageSharp.Tests/Drawing/FillPatternTests.cs b/tests/ImageSharp.Tests/Drawing/FillPatternTests.cs index 7bacebe42..bbabdf0ea 100644 --- a/tests/ImageSharp.Tests/Drawing/FillPatternTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillPatternTests.cs @@ -25,10 +25,7 @@ namespace ImageSharp.Tests.Drawing .Fill(background) .Fill(brush); - using (FileStream output = File.OpenWrite($"{path}/{name}.png")) - { - image.Save(output); - } + image.Save($"{path}/{name}.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -54,10 +51,7 @@ namespace ImageSharp.Tests.Drawing } } } - using (FileStream output = File.OpenWrite($"{path}/{name}x4.png")) - { - image.Resize(80, 80).Save(output); - } + image.Resize(80, 80).Save($"{path}/{name}x4.png"); } } diff --git a/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs b/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs index dc0b83615..ce127cfe0 100644 --- a/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs @@ -16,7 +16,7 @@ namespace ImageSharp.Tests.Drawing using Xunit; - public class FillSolidBrushTests: FileTestBase + public class FillSolidBrushTests : FileTestBase { [Fact] public void ImageShouldBeFloodFilledWithColorOnDefaultBackground() @@ -24,12 +24,9 @@ namespace ImageSharp.Tests.Drawing string path = this.CreateOutputDirectory("Fill", "SolidBrush"); using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/DefaultBack.png")) - { - image - .Fill(Rgba32.HotPink) - .Save(output); - } + image + .Fill(Rgba32.HotPink) + .Save($"{path}/DefaultBack.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -46,13 +43,10 @@ namespace ImageSharp.Tests.Drawing string path = this.CreateOutputDirectory("Fill", "SolidBrush"); using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Simple.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Fill(Rgba32.HotPink) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Fill(Rgba32.HotPink) + .Save($"{path}/Simple.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -71,13 +65,11 @@ namespace ImageSharp.Tests.Drawing { Rgba32 color = new Rgba32(Rgba32.HotPink.R, Rgba32.HotPink.G, Rgba32.HotPink.B, 150); - using (FileStream output = File.OpenWrite($"{path}/Opacity.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Fill(color) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Fill(color) + .Save($"{path}/Opacity.png"); + //shift background color towards forground color by the opacity amount Rgba32 mergedColor = new Rgba32(Vector4.Lerp(Rgba32.Blue.ToVector4(), Rgba32.HotPink.ToVector4(), 150f / 255f)); diff --git a/tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs b/tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs index 1f35a3788..e058572fb 100644 --- a/tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs @@ -34,13 +34,10 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Simple.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Draw(Rgba32.HotPink, 5, simplePath.Clip(hole1)) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Draw(Rgba32.HotPink, 5, simplePath.Clip(hole1)) + .Save($"{path}/Simple.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -84,13 +81,10 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/SimpleVanishHole.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Draw(Rgba32.HotPink, 5, simplePath.Clip(hole1)) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Draw(Rgba32.HotPink, 5, simplePath.Clip(hole1)) + .Save($"{path}/SimpleVanishHole.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -135,13 +129,10 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/SimpleOverlapping.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Draw(Rgba32.HotPink, 5, simplePath.Clip(hole1)) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Draw(Rgba32.HotPink, 5, simplePath.Clip(hole1)) + .Save($"{path}/SimpleOverlapping.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -181,13 +172,10 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Dashed.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Draw(Pens.Dash(Rgba32.HotPink, 5), simplePath.Clip(hole1)) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Draw(Pens.Dash(Rgba32.HotPink, 5), simplePath.Clip(hole1)) + .Save($"{path}/Dashed.png"); } } @@ -209,13 +197,10 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Opacity.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Draw(color, 5, simplePath.Clip(hole1)) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Draw(color, 5, simplePath.Clip(hole1)) + .Save($"{path}/Opacity.png"); //shift background color towards forground color by the opacity amount Rgba32 mergedColor = new Rgba32(Vector4.Lerp(Rgba32.Blue.ToVector4(), Rgba32.HotPink.ToVector4(), 150f / 255f)); diff --git a/tests/ImageSharp.Tests/Drawing/LineTests.cs b/tests/ImageSharp.Tests/Drawing/LineTests.cs index e751557b6..6c1e70013 100644 --- a/tests/ImageSharp.Tests/Drawing/LineTests.cs +++ b/tests/ImageSharp.Tests/Drawing/LineTests.cs @@ -23,18 +23,15 @@ namespace ImageSharp.Tests.Drawing string path = this.CreateOutputDirectory("Drawing", "Lines"); using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Simple.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .DrawLines(Rgba32.HotPink, 5, - new[] { + image + .BackgroundColor(Rgba32.Blue) + .DrawLines(Rgba32.HotPink, 5, + new[] { new Vector2(10, 10), new Vector2(200, 150), new Vector2(50, 300) - }) - .Save(output); - } + }) + .Save($"{path}/Simple.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -53,19 +50,16 @@ namespace ImageSharp.Tests.Drawing string path = this.CreateOutputDirectory("Drawing", "Lines"); using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Simple_noantialias.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .DrawLines(Rgba32.HotPink, 5, - new[] { + image + .BackgroundColor(Rgba32.Blue) + .DrawLines(Rgba32.HotPink, 5, + new[] { new Vector2(10, 10), new Vector2(200, 150), new Vector2(50, 300) - }, - new GraphicsOptions(false)) - .Save(output); - } + }, + new GraphicsOptions(false)) + .Save($"{path}/Simple_noantialias.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -84,18 +78,15 @@ namespace ImageSharp.Tests.Drawing string path = this.CreateOutputDirectory("Drawing", "Lines"); using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Dashed.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .DrawLines(Pens.Dash(Rgba32.HotPink, 5), - new[] { + image + .BackgroundColor(Rgba32.Blue) + .DrawLines(Pens.Dash(Rgba32.HotPink, 5), + new[] { new Vector2(10, 10), new Vector2(200, 150), new Vector2(50, 300) - }) - .Save(output); - } + }) + .Save($"{path}/Dashed.png"); } } @@ -105,18 +96,15 @@ namespace ImageSharp.Tests.Drawing string path = this.CreateOutputDirectory("Drawing", "Lines"); using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Dot.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .DrawLines(Pens.Dot(Rgba32.HotPink, 5), - new[] { + image + .BackgroundColor(Rgba32.Blue) + .DrawLines(Pens.Dot(Rgba32.HotPink, 5), + new[] { new Vector2(10, 10), new Vector2(200, 150), new Vector2(50, 300) - }) - .Save(output); - } + }) + .Save($"{path}/Dot.png"); } } @@ -126,18 +114,15 @@ namespace ImageSharp.Tests.Drawing string path = this.CreateOutputDirectory("Drawing", "Lines"); using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/DashDot.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .DrawLines(Pens.DashDot(Rgba32.HotPink, 5), - new[] { + image + .BackgroundColor(Rgba32.Blue) + .DrawLines(Pens.DashDot(Rgba32.HotPink, 5), + new[] { new Vector2(10, 10), new Vector2(200, 150), new Vector2(50, 300) - }) - .Save(output); - } + }) + .Save($"{path}/DashDot.png"); } } @@ -147,17 +132,14 @@ namespace ImageSharp.Tests.Drawing string path = this.CreateOutputDirectory("Drawing", "Lines"); Image image = new Image(500, 500); - using (FileStream output = File.OpenWrite($"{path}/DashDotDot.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .DrawLines(Pens.DashDotDot(Rgba32.HotPink, 5), new[] { + image + .BackgroundColor(Rgba32.Blue) + .DrawLines(Pens.DashDotDot(Rgba32.HotPink, 5), new[] { new Vector2(10, 10), new Vector2(200, 150), new Vector2(50, 300) - }) - .Save(output); - } + }) + .Save($"{path}/DashDotDot.png"); } [Fact] @@ -169,21 +151,17 @@ namespace ImageSharp.Tests.Drawing Image image = new Image(500, 500); - - using (FileStream output = File.OpenWrite($"{path}/Opacity.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .DrawLines(color, 10, new[] { + image + .BackgroundColor(Rgba32.Blue) + .DrawLines(color, 10, new[] { new Vector2(10, 10), new Vector2(200, 150), new Vector2(50, 300) - }) - .Save(output); - } + }) + .Save($"{path}/Opacity.png"); //shift background color towards forground color by the opacity amount - Rgba32 mergedColor = new Rgba32(Vector4.Lerp(Rgba32.Blue.ToVector4(), Rgba32.HotPink.ToVector4(), 150f/255f)); + Rgba32 mergedColor = new Rgba32(Vector4.Lerp(Rgba32.Blue.ToVector4(), Rgba32.HotPink.ToVector4(), 150f / 255f)); using (PixelAccessor sourcePixels = image.Lock()) { @@ -202,18 +180,15 @@ namespace ImageSharp.Tests.Drawing Image image = new Image(500, 500); - using (FileStream output = File.OpenWrite($"{path}/Rectangle.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .DrawLines(Rgba32.HotPink, 10, new[] { + image + .BackgroundColor(Rgba32.Blue) + .DrawLines(Rgba32.HotPink, 10, new[] { new Vector2(10, 10), new Vector2(200, 10), new Vector2(200, 150), new Vector2(10, 150) - }) - .Save(output); - } + }) + .Save($"{path}/Rectangle.png"); using (PixelAccessor sourcePixels = image.Lock()) { diff --git a/tests/ImageSharp.Tests/Drawing/PolygonTests.cs b/tests/ImageSharp.Tests/Drawing/PolygonTests.cs index 9bc918d37..842fc19d2 100644 --- a/tests/ImageSharp.Tests/Drawing/PolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/PolygonTests.cs @@ -24,8 +24,6 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Simple.png")) - { image .BackgroundColor(Rgba32.Blue) .DrawPolygon(Rgba32.HotPink, 5, @@ -34,8 +32,7 @@ namespace ImageSharp.Tests.Drawing new Vector2(200, 150), new Vector2(50, 300) }) - .Save(output); - } + .Save($"{path}/Simple.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -64,13 +61,10 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Opacity.png")) - { image .BackgroundColor(Rgba32.Blue) .DrawPolygon(color, 10, simplePath) - .Save(output); - } + .Save($"{path}/Opacity.png"); //shift background color towards forground color by the opacity amount Rgba32 mergedColor = new Rgba32(Vector4.Lerp(Rgba32.Blue.ToVector4(), Rgba32.HotPink.ToVector4(), 150f / 255f)); @@ -95,13 +89,10 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Rectangle.png")) - { image .BackgroundColor(Rgba32.Blue) .Draw(Rgba32.HotPink, 10, new Rectangle(10, 10, 190, 140)) - .Save(output); - } + .Save($"{path}/Rectangle.png"); using (PixelAccessor sourcePixels = image.Lock()) { diff --git a/tests/ImageSharp.Tests/Drawing/RecolorImageTest.cs b/tests/ImageSharp.Tests/Drawing/RecolorImageTest.cs index 83419caaf..4c082fc36 100644 --- a/tests/ImageSharp.Tests/Drawing/RecolorImageTest.cs +++ b/tests/ImageSharp.Tests/Drawing/RecolorImageTest.cs @@ -26,11 +26,8 @@ namespace ImageSharp.Tests { using (Image image = file.CreateImage()) { - using (FileStream output = File.OpenWrite($"{path}/{file.FileName}")) - { - image.Fill(brush) - .Save(output); - } + image.Fill(brush) + .Save($"{path}/{file.FileName}"); } } } @@ -46,12 +43,9 @@ namespace ImageSharp.Tests { using (Image image = file.CreateImage()) { - using (FileStream output = File.OpenWrite($"{path}/Shaped_{file.FileName}")) - { - int imageHeight = image.Height; - image.Fill(brush, new Rectangle(0, imageHeight/2 - imageHeight/4, image.Width, imageHeight/2)) - .Save(output); - } + int imageHeight = image.Height; + image.Fill(brush, new Rectangle(0, imageHeight / 2 - imageHeight / 4, image.Width, imageHeight / 2)) + .Save($"{path}/Shaped_{file.FileName}"); } } } diff --git a/tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs b/tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs index 6cab7778e..74f4fe8f6 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs @@ -28,13 +28,10 @@ namespace ImageSharp.Tests.Drawing }; using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Simple.png")) - { image .BackgroundColor(Rgba32.Blue) .Fill(Rgba32.HotPink, new Polygon(new BezierLineSegment(simplePath))) - .Save(output); - } + .Save($"{path}/Simple.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -63,13 +60,10 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Opacity.png")) - { image .BackgroundColor(Rgba32.Blue) .Fill(color, new Polygon(new BezierLineSegment(simplePath))) - .Save(output); - } + .Save($"{path}/Opacity.png"); //shift background color towards forground color by the opacity amount Rgba32 mergedColor = new Rgba32(Vector4.Lerp(Rgba32.Blue.ToVector4(), Rgba32.HotPink.ToVector4(), 150f / 255f)); diff --git a/tests/ImageSharp.Tests/Drawing/SolidComplexPolygonTests.cs b/tests/ImageSharp.Tests/Drawing/SolidComplexPolygonTests.cs index 5e0244d02..c3af3d5c2 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidComplexPolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidComplexPolygonTests.cs @@ -31,16 +31,13 @@ namespace ImageSharp.Tests.Drawing new Vector2(93, 85), new Vector2(65, 137))); IPath clipped = simplePath.Clip(hole1); - // var clipped = new Rectangle(10, 10, 100, 100).Clip(new Rectangle(20, 0, 20, 20)); + // var clipped = new Rectangle(10, 10, 100, 100).Clip(new Rectangle(20, 0, 20, 20)); using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Simple.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Fill(Rgba32.HotPink, clipped) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Fill(Rgba32.HotPink, clipped) + .Save($"{path}/Simple.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -69,13 +66,10 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/SimpleOverlapping.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Fill(Rgba32.HotPink, simplePath.Clip(hole1)) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Fill(Rgba32.HotPink, simplePath.Clip(hole1)) + .Save($"{path}/SimpleOverlapping.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -104,13 +98,10 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Opacity.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Fill(color, simplePath.Clip(hole1)) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Fill(color, simplePath.Clip(hole1)) + .Save($"{path}/Opacity.png"); //shift background color towards forground color by the opacity amount Rgba32 mergedColor = new Rgba32(Vector4.Lerp(Rgba32.Blue.ToVector4(), Rgba32.HotPink.ToVector4(), 150f / 255f)); diff --git a/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs b/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs index 8ffa62d81..d93bb832e 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs @@ -31,12 +31,9 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Simple.png")) - { - image - .FillPolygon(Rgba32.HotPink, simplePath, new GraphicsOptions(true)) - .Save(output); - } + image + .FillPolygon(Rgba32.HotPink, simplePath, new GraphicsOptions(true)) + .Save($"{path}/Simple.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -57,12 +54,9 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Pattern.png")) - { - image - .FillPolygon(Brushes.Horizontal(Rgba32.HotPink), simplePath, new GraphicsOptions(true)) - .Save(output); - } + image + .FillPolygon(Brushes.Horizontal(Rgba32.HotPink), simplePath, new GraphicsOptions(true)) + .Save($"{path}/Pattern.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -82,12 +76,11 @@ namespace ImageSharp.Tests.Drawing }; using (Image image = new Image(500, 500)) - using (FileStream output = File.OpenWrite($"{path}/Simple_NoAntialias.png")) { image .BackgroundColor(Rgba32.Blue) .FillPolygon(Rgba32.HotPink, simplePath, new GraphicsOptions(false)) - .Save(output); + .Save($"{path}/Simple_NoAntialias.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -114,14 +107,13 @@ namespace ImageSharp.Tests.Drawing using (Image brushImage = TestFile.Create(TestImages.Bmp.Car).CreateImage()) using (Image image = new Image(500, 500)) - using (FileStream output = File.OpenWrite($"{path}/Image.png")) { ImageBrush brush = new ImageBrush(brushImage); image .BackgroundColor(Rgba32.Blue) .FillPolygon(brush, simplePath) - .Save(output); + .Save($"{path}/Image.png"); } } @@ -138,13 +130,10 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Opacity.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .FillPolygon(color, simplePath) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .FillPolygon(color, simplePath) + .Save($"{path}/Opacity.png"); //shift background color towards forground color by the opacity amount Rgba32 mergedColor = new Rgba32(Vector4.Lerp(Rgba32.Blue.ToVector4(), Rgba32.HotPink.ToVector4(), 150f / 255f)); @@ -163,13 +152,10 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Rectangle.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Fill(Rgba32.HotPink, new SixLabors.Shapes.Rectangle(10, 10, 190, 140)) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Fill(Rgba32.HotPink, new SixLabors.Shapes.Rectangle(10, 10, 190, 140)) + .Save($"{path}/Rectangle.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -193,13 +179,10 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(100, 100)) { - using (FileStream output = File.OpenWrite($"{path}/Triangle.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Fill(Rgba32.HotPink, new RegularPolygon(50, 50, 3, 30)) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Fill(Rgba32.HotPink, new RegularPolygon(50, 50, 3, 30)) + .Save($"{path}/Triangle.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -219,13 +202,10 @@ namespace ImageSharp.Tests.Drawing config.ParallelOptions.MaxDegreeOfParallelism = 1; using (Image image = new Image(config, 100, 100)) { - using (FileStream output = File.OpenWrite($"{path}/Septagon.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Fill(Rgba32.HotPink, new RegularPolygon(50, 50, 7, 30, -(float)Math.PI)) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Fill(Rgba32.HotPink, new RegularPolygon(50, 50, 7, 30, -(float)Math.PI)) + .Save($"{path}/Septagon.png"); } } @@ -238,14 +218,11 @@ namespace ImageSharp.Tests.Drawing config.ParallelOptions.MaxDegreeOfParallelism = 1; using (Image image = new Image(config, 100, 100)) { - using (FileStream output = File.OpenWrite($"{path}/ellipse.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Fill(Rgba32.HotPink, new Ellipse(50, 50, 30, 50) - .Rotate((float)(Math.PI / 3))) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Fill(Rgba32.HotPink, new Ellipse(50, 50, 30, 50) + .Rotate((float)(Math.PI / 3))) + .Save($"{path}/ellipse.png"); } } @@ -258,21 +235,18 @@ namespace ImageSharp.Tests.Drawing config.ParallelOptions.MaxDegreeOfParallelism = 1; using (Image image = new Image(config, 200, 200)) { - using (FileStream output = File.OpenWrite($"{path}/clipped-corner.png")) - { - image - .Fill(Rgba32.Blue) - .FillPolygon(Rgba32.HotPink, new[] - { + image + .Fill(Rgba32.Blue) + .FillPolygon(Rgba32.HotPink, new[] + { new Vector2( 8, 8 ), new Vector2( 64, 8 ), new Vector2( 64, 64 ), new Vector2( 120, 64 ), new Vector2( 120, 120 ), new Vector2( 8, 120 ) - } ) - .Save(output); - } + }) + .Save($"{path}/clipped-corner.png"); } } } diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs index cf073d3d0..e5af28d8b 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs @@ -31,7 +31,7 @@ namespace ImageSharp.Tests string filename = file.GetFileNameWithoutExtension(bitsPerPixel); using (Image image = file.CreateImage()) { - image.Save($"{path}/{filename}.bmp", new BmpEncoderOptions { BitsPerPixel = bitsPerPixel }); + image.Save($"{path}/{filename}.bmp", new BmpEncoder { BitsPerPixel = bitsPerPixel }); } } } diff --git a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs index ec1a8c465..659aa317b 100644 --- a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs +++ b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs @@ -36,7 +36,7 @@ namespace ImageSharp.Tests using (Image image = file.CreateImage()) { string filename = path + "/" + file.FileNameWithoutExtension + ".txt"; - File.WriteAllText(filename, image.ToBase64String()); + File.WriteAllText(filename, image.ToBase64String("image/png")); } } } @@ -50,10 +50,7 @@ namespace ImageSharp.Tests { using (Image image = file.CreateImage()) { - using (FileStream output = File.OpenWrite($"{path}/{file.FileName}")) - { - image.Save(output); - } + image.Save($"{path}/{file.FileName}"); } } } @@ -65,14 +62,14 @@ namespace ImageSharp.Tests foreach (TestFile file in Files) { - using (Image srcImage = file.CreateImage()) + using (Image srcImage = Image.Load(file.Bytes, out var mimeType)) { using (Image image = new Image(srcImage)) { using (FileStream output = File.OpenWrite($"{path}/Octree-{file.FileName}")) { image.Quantize(Quantization.Octree) - .Save(output, image.CurrentImageFormat); + .Save(output, mimeType); } } @@ -82,7 +79,7 @@ namespace ImageSharp.Tests using (FileStream output = File.OpenWrite($"{path}/Wu-{file.FileName}")) { image.Quantize(Quantization.Wu) - .Save(output, image.CurrentImageFormat); + .Save(output, mimeType); } } @@ -91,7 +88,7 @@ namespace ImageSharp.Tests using (FileStream output = File.OpenWrite($"{path}/Palette-{file.FileName}")) { image.Quantize(Quantization.Palette) - .Save(output, image.CurrentImageFormat); + .Save(output, mimeType); } } } @@ -138,18 +135,17 @@ namespace ImageSharp.Tests foreach (TestFile file in Files) { byte[] serialized; - using (Image image = file.CreateImage()) + using (Image image = Image.Load(file.Bytes, out string mimeType)) using (MemoryStream memoryStream = new MemoryStream()) { - image.Save(memoryStream); + image.Save(memoryStream, mimeType); memoryStream.Flush(); serialized = memoryStream.ToArray(); } using (Image image2 = Image.Load(serialized)) - using (FileStream output = File.OpenWrite($"{path}/{file.FileName}")) { - image2.Save(output); + image2.Save($"{path}/{file.FileName}"); } } } diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs index 89df2d086..06bfd8990 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs @@ -33,7 +33,7 @@ namespace ImageSharp.Tests [Fact] public void Decode_IgnoreMetadataIsFalse_CommentsAreRead() { - DecoderOptions options = new DecoderOptions() + GifDecoder options = new GifDecoder() { IgnoreMetadata = false }; @@ -51,7 +51,7 @@ namespace ImageSharp.Tests [Fact] public void Decode_IgnoreMetadataIsTrue_CommentsAreIgnored() { - DecoderOptions options = new DecoderOptions() + GifDecoder options = new GifDecoder() { IgnoreMetadata = true }; @@ -67,7 +67,7 @@ namespace ImageSharp.Tests [Fact] public void Decode_TextEncodingSetToUnicode_TextIsReadWithCorrectEncoding() { - GifDecoderOptions options = new GifDecoderOptions() + GifDecoder options = new GifDecoder() { TextEncoding = Encoding.Unicode }; diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs index 70cc8e2ba..c36539686 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs @@ -29,7 +29,7 @@ namespace ImageSharp.Tests [Fact] public void Encode_IgnoreMetadataIsFalse_CommentsAreWritten() { - EncoderOptions options = new EncoderOptions() + GifEncoder options = new GifEncoder() { IgnoreMetadata = false }; @@ -40,7 +40,7 @@ namespace ImageSharp.Tests { using (MemoryStream memStream = new MemoryStream()) { - input.Save(memStream, new GifFormat(), options); + input.Save(memStream, options); memStream.Position = 0; using (Image output = Image.Load(memStream)) @@ -56,7 +56,7 @@ namespace ImageSharp.Tests [Fact] public void Encode_IgnoreMetadataIsTrue_CommentsAreNotWritten() { - GifEncoderOptions options = new GifEncoderOptions() + GifEncoder options = new GifEncoder() { IgnoreMetadata = true }; @@ -88,7 +88,7 @@ namespace ImageSharp.Tests using (MemoryStream memStream = new MemoryStream()) { - input.Save(memStream, new GifFormat()); + input.Save(memStream, new GifEncoder()); memStream.Position = 0; using (Image output = Image.Load(memStream)) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index 446c5e96a..ab4850ecf 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -62,13 +62,12 @@ namespace ImageSharp.Tests byte[] data; using (Image image = provider.GetImage()) { - JpegEncoder encoder = new JpegEncoder(); - JpegEncoderOptions options = new JpegEncoderOptions { Subsample = subsample, Quality = quality }; + JpegEncoder encoder = new JpegEncoder { Subsample = subsample, Quality = quality }; data = new byte[65536]; using (MemoryStream ms = new MemoryStream(data)) { - image.Save(ms, encoder, options); + image.Save(ms, encoder); } } @@ -91,7 +90,7 @@ namespace ImageSharp.Tests image.Save(ms, new JpegEncoder()); ms.Seek(0, SeekOrigin.Begin); - using (JpegDecoderCore decoder = new JpegDecoderCore(null, null)) + using (JpegDecoderCore decoder = new JpegDecoderCore(null)) { Image mirror = decoder.Decode(ms); @@ -125,14 +124,14 @@ namespace ImageSharp.Tests [Fact] public void Decode_IgnoreMetadataIsFalse_ExifProfileIsRead() { - DecoderOptions options = new DecoderOptions() + JpegDecoder decoder = new JpegDecoder() { IgnoreMetadata = false }; TestFile testFile = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan); - using (Image image = testFile.CreateImage(options)) + using (Image image = testFile.CreateImage(decoder)) { Assert.NotNull(image.MetaData.ExifProfile); } @@ -141,7 +140,7 @@ namespace ImageSharp.Tests [Fact] public void Decode_IgnoreMetadataIsTrue_ExifProfileIgnored() { - DecoderOptions options = new DecoderOptions() + JpegDecoder options = new JpegDecoder() { IgnoreMetadata = true }; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs index ab81c69b4..feb5f91b2 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs @@ -37,14 +37,12 @@ namespace ImageSharp.Tests { using (Image image = provider.GetImage().Resize(new ResizeOptions { Size = new Size(150, 100), Mode = ResizeMode.Max })) { - image.MetaData.Quality = quality; image.MetaData.ExifProfile = null; // Reduce the size of the file - JpegEncoder encoder = new JpegEncoder(); - JpegEncoderOptions options = new JpegEncoderOptions { Subsample = subsample, Quality = quality }; + JpegEncoder options = new JpegEncoder { Subsample = subsample, Quality = quality }; provider.Utility.TestName += $"{subsample}_Q{quality}"; provider.Utility.SaveTestOutputFile(image, "png"); - provider.Utility.SaveTestOutputFile(image, "jpg", encoder, options); + provider.Utility.SaveTestOutputFile(image, "jpg", options); } } @@ -61,9 +59,7 @@ namespace ImageSharp.Tests using (FileStream outputStream = File.OpenWrite(utility.GetTestOutputFileName("jpg"))) { - JpegEncoder encoder = new JpegEncoder(); - - image.Save(outputStream, encoder, new JpegEncoderOptions() + image.Save(outputStream, new JpegEncoder() { Subsample = subSample, Quality = quality @@ -75,7 +71,7 @@ namespace ImageSharp.Tests [Fact] public void Encode_IgnoreMetadataIsFalse_ExifProfileIsWritten() { - EncoderOptions options = new EncoderOptions() + JpegEncoder options = new JpegEncoder() { IgnoreMetadata = false }; @@ -86,7 +82,7 @@ namespace ImageSharp.Tests { using (MemoryStream memStream = new MemoryStream()) { - input.Save(memStream, new JpegFormat(), options); + input.Save(memStream, options); memStream.Position = 0; using (Image output = Image.Load(memStream)) @@ -100,7 +96,7 @@ namespace ImageSharp.Tests [Fact] public void Encode_IgnoreMetadataIsTrue_ExifProfileIgnored() { - JpegEncoderOptions options = new JpegEncoderOptions() + JpegEncoder options = new JpegEncoder() { IgnoreMetadata = true }; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs index f3412e45e..daf8da6a3 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs @@ -82,9 +82,8 @@ namespace ImageSharp.Tests { foreach (Image img in testImages) { - JpegEncoder encoder = new JpegEncoder(); - JpegEncoderOptions options = new JpegEncoderOptions { Quality = quality, Subsample = subsample }; - img.Save(ms, encoder, options); + JpegEncoder options = new JpegEncoder { Quality = quality, Subsample = subsample }; + img.Save(ms, options); ms.Seek(0, SeekOrigin.Begin); } }, diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index 5ab1fac2f..6d82b5374 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -35,7 +35,7 @@ namespace ImageSharp.Tests [Fact] public void Decode_IgnoreMetadataIsFalse_TextChunckIsRead() { - PngDecoderOptions options = new PngDecoderOptions() + PngDecoder options = new PngDecoder() { IgnoreMetadata = false }; @@ -53,7 +53,7 @@ namespace ImageSharp.Tests [Fact] public void Decode_IgnoreMetadataIsTrue_TextChunksAreIgnored() { - PngDecoderOptions options = new PngDecoderOptions() + PngDecoder options = new PngDecoder() { IgnoreMetadata = true }; @@ -69,7 +69,7 @@ namespace ImageSharp.Tests [Fact] public void Decode_TextEncodingSetToUnicode_TextIsReadWithCorrectEncoding() { - PngDecoderOptions options = new PngDecoderOptions() + PngDecoder options = new PngDecoder() { TextEncoding = Encoding.Unicode }; diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index 02edf7688..24907cfdb 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -31,13 +31,13 @@ namespace ImageSharp.Tests { using (Image image = provider.GetImage()) { - PngEncoderOptions options = new PngEncoderOptions() + PngEncoder options = new PngEncoder() { PngColorType = pngColorType }; provider.Utility.TestName += "_" + pngColorType; - provider.Utility.SaveTestOutputFile(image, "png", new PngEncoder(), options); + provider.Utility.SaveTestOutputFile(image, "png", options); } } diff --git a/tests/ImageSharp.Tests/Formats/Png/PngSmokeTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngSmokeTests.cs index 90f994f36..bb7824914 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngSmokeTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngSmokeTests.cs @@ -50,8 +50,7 @@ namespace ImageSharp.Tests.Formats.Png using (MemoryStream ms = new MemoryStream()) { // image.Save(provider.Utility.GetTestOutputFileName("bmp")); - image.MetaData.Quality = 256; - image.Save(ms, new PngEncoder()); + image.Save(ms, new PngEncoder() { Quality = 256 }); ms.Position = 0; using (Image img2 = Image.Load(ms, new PngDecoder())) { diff --git a/tests/ImageSharp.Tests/Image/ImageLoadTests.cs b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs index 7a5b8ffc5..65c2cc52c 100644 --- a/tests/ImageSharp.Tests/Image/ImageLoadTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs @@ -20,10 +20,8 @@ namespace ImageSharp.Tests public class ImageLoadTests : IDisposable { private readonly Mock fileSystem; - private readonly IDecoderOptions decoderOptions; private Image returnImage; private Mock localDecoder; - private Mock localFormat; private readonly string FilePath; public Configuration LocalConfiguration { get; private set; } @@ -36,18 +34,14 @@ namespace ImageSharp.Tests this.returnImage = new Image(1, 1); this.localDecoder = new Mock(); - this.localFormat = new Mock(); - this.localFormat.Setup(x => x.Decoder).Returns(this.localDecoder.Object); - this.localFormat.Setup(x => x.Encoder).Returns(new Mock().Object); - this.localFormat.Setup(x => x.MimeType).Returns("img/test"); - this.localFormat.Setup(x => x.Extension).Returns("png"); - this.localFormat.Setup(x => x.HeaderSize).Returns(1); - this.localFormat.Setup(x => x.IsSupportedFileFormat(It.IsAny())).Returns(true); - this.localFormat.Setup(x => x.SupportedExtensions).Returns(new string[] { "png", "jpg" }); - - this.localDecoder.Setup(x => x.Decode(It.IsAny(), It.IsAny(), It.IsAny())) - - .Callback((c, s, o) => { + this.localDecoder.Setup(x => x.MimeTypes).Returns(new[] { "img/test" }); + this.localDecoder.Setup(x => x.FileExtensions).Returns(new[] { "png", "jpg" }); + this.localDecoder.Setup(x => x.HeaderSize).Returns(1); + this.localDecoder.Setup(x => x.IsSupportedFileFormat(It.IsAny>())).Returns(true); + + this.localDecoder.Setup(x => x.Decode(It.IsAny(), It.IsAny())) + + .Callback((c, s) => { using (var ms = new MemoryStream()) { s.CopyTo(ms); @@ -58,14 +52,16 @@ namespace ImageSharp.Tests this.fileSystem = new Mock(); - this.LocalConfiguration = new Configuration(this.localFormat.Object) + this.LocalConfiguration = new Configuration() { FileSystem = this.fileSystem.Object }; + + this.LocalConfiguration.AddImageFormat(this.localDecoder.Object); + TestFormat.RegisterGloablTestFormat(); this.Marker = Guid.NewGuid().ToByteArray(); this.DataStream = TestFormat.GlobalTestFormat.CreateStream(this.Marker); - this.decoderOptions = new Mock().Object; this.FilePath = Guid.NewGuid().ToString(); this.fileSystem.Setup(x => x.OpenRead(this.FilePath)).Returns(this.DataStream); @@ -80,10 +76,8 @@ namespace ImageSharp.Tests Image img = Image.Load(this.DataStream); Assert.NotNull(img); - Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null, Configuration.Default); + TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default); } @@ -94,10 +88,8 @@ namespace ImageSharp.Tests Image img = Image.Load(stream); Assert.NotNull(img); - Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null, Configuration.Default); + TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default); } @@ -108,36 +100,11 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(TestFormat.GlobalTestFormat.Sample(), img); - Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null, Configuration.Default); - - } - - [Fact] - public void LoadFromStreamWithOptions() - { - Image img = Image.Load(this.DataStream, this.decoderOptions); - - Assert.NotNull(img); - Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions, Configuration.Default); - - } - - [Fact] - public void LoadFromStreamWithTypeAndOptions() - { - Image img = Image.Load(this.DataStream, this.decoderOptions); - - Assert.NotNull(img); - Assert.Equal(TestFormat.GlobalTestFormat.Sample(), img); - Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions, Configuration.Default); + TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default); } + [Fact] public void LoadFromStreamWithConfig() @@ -146,9 +113,8 @@ namespace ImageSharp.Tests Image img = Image.Load(this.LocalConfiguration, stream); Assert.NotNull(img); - Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, stream, null)); + this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, stream)); } @@ -160,40 +126,11 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.returnImage, img); - Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, stream, null)); + this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, stream)); } - [Fact] - public void LoadFromStreamWithConfigAndOptions() - { - Stream stream = new MemoryStream(); - Image img = Image.Load(this.LocalConfiguration, stream, this.decoderOptions); - - Assert.NotNull(img); - Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - - this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, stream, this.decoderOptions)); - - } - - [Fact] - public void LoadFromStreamWithTypeAndConfigAndOptions() - { - Stream stream = new MemoryStream(); - Image img = Image.Load(this.LocalConfiguration, stream, this.decoderOptions); - - Assert.NotNull(img); - Assert.Equal(this.returnImage, img); - Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - - this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, stream, this.decoderOptions)); - - } - - [Fact] public void LoadFromStreamWithDecoder() @@ -202,7 +139,7 @@ namespace ImageSharp.Tests Image img = Image.Load(stream, this.localDecoder.Object); Assert.NotNull(img); - this.localDecoder.Verify(x => x.Decode(Configuration.Default, stream, null)); + this.localDecoder.Verify(x => x.Decode(Configuration.Default, stream)); } [Fact] @@ -213,28 +150,7 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.returnImage, img); - this.localDecoder.Verify(x => x.Decode(Configuration.Default, stream, null)); - } - - [Fact] - public void LoadFromStreamWithDecoderAndOptions() - { - Stream stream = new MemoryStream(); - Image img = Image.Load(stream, this.localDecoder.Object, this.decoderOptions); - - Assert.NotNull(img); - this.localDecoder.Verify(x => x.Decode(Configuration.Default, stream, this.decoderOptions)); - } - - [Fact] - public void LoadFromStreamWithTypeAndDecoderAndOptions() - { - Stream stream = new MemoryStream(); - Image img = Image.Load(stream, this.localDecoder.Object, this.decoderOptions); - - Assert.NotNull(img); - Assert.Equal(this.returnImage, img); - this.localDecoder.Verify(x => x.Decode(Configuration.Default, stream, this.decoderOptions)); + this.localDecoder.Verify(x => x.Decode(Configuration.Default, stream)); } [Fact] @@ -243,10 +159,9 @@ namespace ImageSharp.Tests Image img = Image.Load(this.DataStream.ToArray()); Assert.NotNull(img); - Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null, Configuration.Default); + TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default); } @@ -257,34 +172,8 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(TestFormat.GlobalTestFormat.Sample(), img); - Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null, Configuration.Default); - - } - - [Fact] - public void LoadFromBytesWithOptions() - { - Image img = Image.Load(this.DataStream.ToArray(), this.decoderOptions); - - Assert.NotNull(img); - Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions, Configuration.Default); - - } - - [Fact] - public void LoadFromBytesWithTypeAndOptions() - { - Image img = Image.Load(this.DataStream.ToArray(), this.decoderOptions); - - Assert.NotNull(img); - Assert.Equal(TestFormat.GlobalTestFormat.Sample(), img); - Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions, Configuration.Default); + TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default); } @@ -294,9 +183,8 @@ namespace ImageSharp.Tests Image img = Image.Load(this.LocalConfiguration, this.DataStream.ToArray()); Assert.NotNull(img); - Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, It.IsAny(), null)); + this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, It.IsAny())); Assert.Equal(this.DataStream.ToArray(), this.DecodedData); } @@ -308,49 +196,19 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.returnImage, img); - Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - - this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, It.IsAny(), null)); + this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, It.IsAny())); Assert.Equal(this.DataStream.ToArray(), this.DecodedData); } - [Fact] - public void LoadFromBytesWithConfigAndOptions() - { - Image img = Image.Load(this.LocalConfiguration, this.DataStream.ToArray(), this.decoderOptions); - - Assert.NotNull(img); - Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - - this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, It.IsAny(), this.decoderOptions)); - - Assert.Equal(this.DataStream.ToArray(), this.DecodedData); - } - - [Fact] - public void LoadFromBytesWithTypeAndConfigAndOptions() - { - Image img = Image.Load(this.LocalConfiguration, this.DataStream.ToArray(), this.decoderOptions); - - Assert.NotNull(img); - Assert.Equal(this.returnImage, img); - Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - - this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, It.IsAny(), this.decoderOptions)); - - Assert.Equal(this.DataStream.ToArray(), this.DecodedData); - } - - [Fact] public void LoadFromBytesWithDecoder() { Image img = Image.Load(this.DataStream.ToArray(), this.localDecoder.Object); Assert.NotNull(img); - this.localDecoder.Verify(x => x.Decode(Configuration.Default, It.IsAny(), null)); + this.localDecoder.Verify(x => x.Decode(Configuration.Default, It.IsAny())); Assert.Equal(this.DataStream.ToArray(), this.DecodedData); } @@ -361,28 +219,7 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.returnImage, img); - this.localDecoder.Verify(x => x.Decode(Configuration.Default, It.IsAny(), null)); - Assert.Equal(this.DataStream.ToArray(), this.DecodedData); - } - - [Fact] - public void LoadFromBytesWithDecoderAndOptions() - { - Image img = Image.Load(this.DataStream.ToArray(), this.localDecoder.Object, this.decoderOptions); - - Assert.NotNull(img); - this.localDecoder.Verify(x => x.Decode(Configuration.Default, It.IsAny(), this.decoderOptions)); - Assert.Equal(this.DataStream.ToArray(), this.DecodedData); - } - - [Fact] - public void LoadFromBytesWithTypeAndDecoderAndOptions() - { - Image img = Image.Load(this.DataStream.ToArray(), this.localDecoder.Object, this.decoderOptions); - - Assert.NotNull(img); - Assert.Equal(this.returnImage, img); - this.localDecoder.Verify(x => x.Decode(Configuration.Default, It.IsAny(), this.decoderOptions)); + this.localDecoder.Verify(x => x.Decode(Configuration.Default, It.IsAny())); Assert.Equal(this.DataStream.ToArray(), this.DecodedData); } @@ -392,10 +229,9 @@ namespace ImageSharp.Tests Image img = Image.Load(this.DataStream); Assert.NotNull(img); - Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null, Configuration.Default); + TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default); } @@ -406,35 +242,8 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(TestFormat.GlobalTestFormat.Sample(), img); - Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null, Configuration.Default); - - } - - [Fact] - public void LoadFromFileWithOptions() - { - Image img = Image.Load(this.DataStream, this.decoderOptions); - - Assert.NotNull(img); - Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions, Configuration.Default); - - } - - [Fact] - public void LoadFromFileWithTypeAndOptions() - { - Image img = Image.Load(this.DataStream, this.decoderOptions); - - Assert.NotNull(img); - Assert.Equal(TestFormat.GlobalTestFormat.Sample(), img); - Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions, Configuration.Default); + TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default); } [Fact] @@ -443,9 +252,8 @@ namespace ImageSharp.Tests Image img = Image.Load(this.LocalConfiguration, this.FilePath); Assert.NotNull(img); - Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, this.DataStream, null)); + this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, this.DataStream)); } @@ -456,45 +264,17 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.returnImage, img); - Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - - this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, this.DataStream, null)); - - } - - [Fact] - public void LoadFromFileWithConfigAndOptions() - { - Image img = Image.Load(this.LocalConfiguration, this.FilePath, this.decoderOptions); - - Assert.NotNull(img); - Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - - this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, this.DataStream, this.decoderOptions)); - - } - - [Fact] - public void LoadFromFileWithTypeAndConfigAndOptions() - { - Image img = Image.Load(this.LocalConfiguration, this.FilePath, this.decoderOptions); - - Assert.NotNull(img); - Assert.Equal(this.returnImage, img); - Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - - this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, this.DataStream, this.decoderOptions)); + this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, this.DataStream)); } - [Fact] public void LoadFromFileWithDecoder() { Image img = Image.Load(this.FilePath, this.localDecoder.Object); Assert.NotNull(img); - this.localDecoder.Verify(x => x.Decode(Configuration.Default, this.DataStream, null)); + this.localDecoder.Verify(x => x.Decode(Configuration.Default, this.DataStream)); } [Fact] @@ -504,26 +284,7 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.returnImage, img); - this.localDecoder.Verify(x => x.Decode(Configuration.Default, this.DataStream, null)); - } - - [Fact] - public void LoadFromFileWithDecoderAndOptions() - { - Image img = Image.Load(this.FilePath, this.localDecoder.Object, this.decoderOptions); - - Assert.NotNull(img); - this.localDecoder.Verify(x => x.Decode(Configuration.Default, this.DataStream, this.decoderOptions)); - } - - [Fact] - public void LoadFromFileWithTypeAndDecoderAndOptions() - { - Image img = Image.Load(this.FilePath, this.localDecoder.Object, this.decoderOptions); - - Assert.NotNull(img); - Assert.Equal(this.returnImage, img); - this.localDecoder.Verify(x => x.Decode(Configuration.Default, this.DataStream, this.decoderOptions)); + this.localDecoder.Verify(x => x.Decode(Configuration.Default, this.DataStream)); } [Fact] diff --git a/tests/ImageSharp.Tests/Image/ImageSaveTests.cs b/tests/ImageSharp.Tests/Image/ImageSaveTests.cs index 9e9852cb2..46177ba5f 100644 --- a/tests/ImageSharp.Tests/Image/ImageSaveTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageSaveTests.cs @@ -22,37 +22,27 @@ namespace ImageSharp.Tests { private readonly Image Image; private readonly Mock fileSystem; - private readonly Mock format; - private readonly Mock formatNotRegistered; private readonly Mock encoder; private readonly Mock encoderNotInFormat; - private readonly IEncoderOptions encoderOptions; public ImageSaveTests() { this.encoder = new Mock(); - this.format = new Mock(); - this.format.Setup(x => x.Encoder).Returns(this.encoder.Object); - this.format.Setup(x => x.Decoder).Returns(new Mock().Object); - this.format.Setup(x => x.MimeType).Returns("img/test"); - this.format.Setup(x => x.Extension).Returns("png"); - this.format.Setup(x => x.SupportedExtensions).Returns(new string[] { "png", "jpg" }); + this.encoder.Setup(x => x.MimeTypes).Returns(new[] { "img/test" }); + this.encoder.Setup(x => x.FileExtensions).Returns(new string[] { "png", "jpg" }); this.encoderNotInFormat = new Mock(); - this.formatNotRegistered = new Mock(); - this.formatNotRegistered.Setup(x => x.Encoder).Returns(this.encoderNotInFormat.Object); - this.formatNotRegistered.Setup(x => x.Decoder).Returns(new Mock().Object); - this.formatNotRegistered.Setup(x => x.MimeType).Returns("img/test"); - this.formatNotRegistered.Setup(x => x.Extension).Returns("png"); - this.formatNotRegistered.Setup(x => x.SupportedExtensions).Returns(new string[] { "png", "jpg" }); + this.encoderNotInFormat.Setup(x => x.MimeTypes).Returns(new[] { "img/test" }); + this.encoderNotInFormat.Setup(x => x.FileExtensions).Returns(new string[] { "png", "jpg" }); this.fileSystem = new Mock(); - this.encoderOptions = new Mock().Object; - this.Image = new Image(new Configuration(this.format.Object) + var config = new Configuration() { FileSystem = this.fileSystem.Object - }, 1, 1); + }; + config.AddImageFormat(this.encoder.Object); + this.Image = new Image(config, 1, 1); } [Fact] @@ -62,19 +52,9 @@ namespace ImageSharp.Tests this.fileSystem.Setup(x => x.Create("path.png")).Returns(stream); this.Image.Save("path.png"); - this.encoder.Verify(x => x.Encode(this.Image, stream, null)); + this.encoder.Verify(x => x.Encode(this.Image, stream)); } - [Fact] - public void SavePathWithOptions() - { - Stream stream = new MemoryStream(); - this.fileSystem.Setup(x => x.Create("path.jpg")).Returns(stream); - - this.Image.Save("path.jpg", this.encoderOptions); - - this.encoder.Verify(x => x.Encode(this.Image, stream, this.encoderOptions)); - } [Fact] public void SavePathWithEncoder() @@ -84,61 +64,24 @@ namespace ImageSharp.Tests this.Image.Save("path.jpg", this.encoderNotInFormat.Object); - this.encoderNotInFormat.Verify(x => x.Encode(this.Image, stream, null)); + this.encoderNotInFormat.Verify(x => x.Encode(this.Image, stream)); } [Fact] - public void SavePathWithEncoderAndOptions() + public void ToBase64String() { - Stream stream = new MemoryStream(); - this.fileSystem.Setup(x => x.Create("path.jpg")).Returns(stream); - - this.Image.Save("path.jpg", this.encoderNotInFormat.Object, this.encoderOptions); - - this.encoderNotInFormat.Verify(x => x.Encode(this.Image, stream, this.encoderOptions)); - } - - - - [Fact] - public void SavePathWithFormat() - { - Stream stream = new MemoryStream(); - this.fileSystem.Setup(x => x.Create("path.jpg")).Returns(stream); - - this.Image.Save("path.jpg", this.encoderNotInFormat.Object); - - this.encoderNotInFormat.Verify(x => x.Encode(this.Image, stream, null)); - } - - [Fact] - public void SavePathWithFormatAndOptions() - { - Stream stream = new MemoryStream(); - this.fileSystem.Setup(x => x.Create("path.jpg")).Returns(stream); - - this.Image.Save("path.jpg", this.encoderNotInFormat.Object, this.encoderOptions); + var str = this.Image.ToBase64String("img/test"); - this.encoderNotInFormat.Verify(x => x.Encode(this.Image, stream, this.encoderOptions)); + this.encoder.Verify(x => x.Encode(this.Image, It.IsAny())); } [Fact] - public void SaveStream() + public void SaveStreamWithMime() { Stream stream = new MemoryStream(); - this.Image.Save(stream); + this.Image.Save(stream, "img/test"); - this.encoder.Verify(x => x.Encode(this.Image, stream, null)); - } - - [Fact] - public void SaveStreamWithOptions() - { - Stream stream = new MemoryStream(); - - this.Image.Save(stream, this.encoderOptions); - - this.encoder.Verify(x => x.Encode(this.Image, stream, this.encoderOptions)); + this.encoder.Verify(x => x.Encode(this.Image, stream)); } [Fact] @@ -148,37 +91,7 @@ namespace ImageSharp.Tests this.Image.Save(stream, this.encoderNotInFormat.Object); - this.encoderNotInFormat.Verify(x => x.Encode(this.Image, stream, null)); - } - - [Fact] - public void SaveStreamWithEncoderAndOptions() - { - Stream stream = new MemoryStream(); - - this.Image.Save(stream, this.encoderNotInFormat.Object, this.encoderOptions); - - this.encoderNotInFormat.Verify(x => x.Encode(this.Image, stream, this.encoderOptions)); - } - - [Fact] - public void SaveStreamWithFormat() - { - Stream stream = new MemoryStream(); - - this.Image.Save(stream, this.formatNotRegistered.Object); - - this.encoderNotInFormat.Verify(x => x.Encode(this.Image, stream, null)); - } - - [Fact] - public void SaveStreamWithFormatAndOptions() - { - Stream stream = new MemoryStream(); - - this.Image.Save(stream, this.formatNotRegistered.Object, this.encoderOptions); - - this.encoderNotInFormat.Verify(x => x.Encode(this.Image, stream, this.encoderOptions)); + this.encoderNotInFormat.Verify(x => x.Encode(this.Image, stream)); } public void Dispose() diff --git a/tests/ImageSharp.Tests/Image/ImageTests.cs b/tests/ImageSharp.Tests/Image/ImageTests.cs index a3ec4cec2..cb8607c09 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.cs @@ -74,10 +74,9 @@ namespace ImageSharp.Tests image.Save(file); } - TestFile c = TestFile.Create("../../TestOutput/Save_DetecedEncoding.png"); - using (Image img = c.CreateImage()) + using (Image img = Image.Load(file, out var mime)) { - Assert.IsType(img.CurrentImageFormat); + Assert.Equal("image/png", mime); } } @@ -85,7 +84,7 @@ namespace ImageSharp.Tests public void Save_UnknownExtensionsEncoding() { string file = TestFile.GetPath("../../TestOutput/Save_DetecedEncoding.tmp"); - InvalidOperationException ex = Assert.Throws( + NotSupportedException ex = Assert.Throws( () => { using (Image image = new Image(10, 10)) @@ -95,23 +94,6 @@ namespace ImageSharp.Tests }); } - [Fact] - public void Save_SetFormat() - { - string file = TestFile.GetPath("../../TestOutput/Save_SetFormat.dat"); - System.IO.DirectoryInfo dir = System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(file)); - using (Image image = new Image(10, 10)) - { - image.Save(file, new PngFormat()); - } - - TestFile c = TestFile.Create("../../TestOutput/Save_SetFormat.dat"); - using (Image img = c.CreateImage()) - { - Assert.IsType(img.CurrentImageFormat); - } - } - [Fact] public void Save_SetEncoding() { @@ -121,11 +103,9 @@ namespace ImageSharp.Tests { image.Save(file, new PngEncoder()); } - - TestFile c = TestFile.Create("../../TestOutput/Save_SetEncoding.dat"); - using (Image img = c.CreateImage()) + using (Image img = Image.Load(file, out var mime)) { - Assert.IsType(img.CurrentImageFormat); + Assert.Equal("image/png", mime); } } } diff --git a/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs index bc64d613a..c60c8978c 100644 --- a/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs +++ b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs @@ -28,7 +28,6 @@ namespace ImageSharp.Tests metaData.HorizontalResolution = 4; metaData.VerticalResolution = 2; metaData.Properties.Add(imageProperty); - metaData.Quality = 24; metaData.RepeatCount = 1; metaData.DisposalMethod = DisposalMethod.RestoreToBackground; @@ -39,7 +38,6 @@ namespace ImageSharp.Tests Assert.Equal(4, clone.HorizontalResolution); Assert.Equal(2, clone.VerticalResolution); Assert.Equal(imageProperty, clone.Properties[0]); - Assert.Equal(24, clone.Quality); Assert.Equal(1, clone.RepeatCount); Assert.Equal(DisposalMethod.RestoreToBackground, clone.DisposalMethod); } diff --git a/tests/ImageSharp.Tests/TestFile.cs b/tests/ImageSharp.Tests/TestFile.cs index f1b78383c..c0f9deebb 100644 --- a/tests/ImageSharp.Tests/TestFile.cs +++ b/tests/ImageSharp.Tests/TestFile.cs @@ -11,7 +11,7 @@ namespace ImageSharp.Tests using System.IO; using System.Linq; using System.Reflection; - + using ImageSharp.Formats; using ImageSharp.PixelFormats; /// @@ -135,13 +135,12 @@ namespace ImageSharp.Tests /// /// Creates a new image. /// - /// The options for the decoder. /// /// The . /// - public Image CreateImage(IDecoderOptions options) + public Image CreateImage(IImageDecoder decoder) { - return Image.Load(this.Bytes, options); + return Image.Load(this.image.Configuration, this.Bytes, decoder); } /// diff --git a/tests/ImageSharp.Tests/TestFormat.cs b/tests/ImageSharp.Tests/TestFormat.cs index 318df5ead..1d06f7328 100644 --- a/tests/ImageSharp.Tests/TestFormat.cs +++ b/tests/ImageSharp.Tests/TestFormat.cs @@ -19,13 +19,14 @@ namespace ImageSharp.Tests /// /// A test image file. /// - public class TestFormat : ImageSharp.Formats.IImageFormat + public class TestFormat { public static TestFormat GlobalTestFormat { get; } = new TestFormat(); public static void RegisterGloablTestFormat() { - Configuration.Default.AddImageFormat(GlobalTestFormat); + Configuration.Default.AddImageFormat(GlobalTestFormat.Encoder); + Configuration.Default.AddImageFormat(GlobalTestFormat.Decoder); } public TestFormat() @@ -58,9 +59,9 @@ namespace ImageSharp.Tests Dictionary _sampleImages = new Dictionary(); - public void VerifyDecodeCall(byte[] marker, IDecoderOptions options, Configuration config) + public void VerifyDecodeCall(byte[] marker, Configuration config) { - DecodeOperation[] discovered = this.DecodeCalls.Where(x => x.IsMatch(marker, options, config)).ToArray(); + DecodeOperation[] discovered = this.DecodeCalls.Where(x => x.IsMatch(marker, config)).ToArray(); Assert.True(discovered.Any(), "No calls to decode on this formate with the proveded options happend"); @@ -92,7 +93,7 @@ namespace ImageSharp.Tests public int HeaderSize => this.header.Length; - public bool IsSupportedFileFormat(byte[] header) + public bool IsSupportedFileFormat(Span header) { if (header.Length < this.header.Length) { @@ -110,15 +111,10 @@ namespace ImageSharp.Tests public struct DecodeOperation { public byte[] marker; - public IDecoderOptions options; internal Configuration config; - public bool IsMatch(byte[] testMarker, IDecoderOptions testOptions, Configuration config) + public bool IsMatch(byte[] testMarker, Configuration config) { - if (this.options != testOptions) - { - return false; - } if (this.config != config) { @@ -150,8 +146,13 @@ namespace ImageSharp.Tests this.testFormat = testFormat; } + public IEnumerable MimeTypes => new[] { testFormat.MimeType }; + + public IEnumerable FileExtensions => testFormat.SupportedExtensions; - public Image Decode(Configuration config, Stream stream, IDecoderOptions options) where TPixel : struct, IPixel + public int HeaderSize => testFormat.HeaderSize; + + public Image Decode(Configuration config, Stream stream) where TPixel : struct, IPixel { var ms = new MemoryStream(); @@ -160,13 +161,14 @@ namespace ImageSharp.Tests this.testFormat.DecodeCalls.Add(new DecodeOperation { marker = marker, - options = options, config = config }); // TODO record this happend so we an verify it. return this.testFormat.Sample(); } + + public bool IsSupportedFileFormat(Span header) => testFormat.IsSupportedFileFormat(header); } public class TestEncoder : ImageSharp.Formats.IImageEncoder @@ -178,7 +180,11 @@ namespace ImageSharp.Tests this.testFormat = testFormat; } - public void Encode(Image image, Stream stream, IEncoderOptions options) where TPixel : struct, IPixel + public IEnumerable MimeTypes => new[] { testFormat.MimeType }; + + public IEnumerable FileExtensions => testFormat.SupportedExtensions; + + public void Encode(Image image, Stream stream) where TPixel : struct, IPixel { // TODO record this happend so we an verify it. } diff --git a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs index 290123885..ee5246660 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs @@ -97,18 +97,16 @@ namespace ImageSharp.Tests /// The requested extension /// Optional encoder /// Optional encoder options - public void SaveTestOutputFile(Image image, string extension = null, IImageEncoder encoder = null, IEncoderOptions options = null, string tag = null) + public void SaveTestOutputFile(Image image, string extension = null, IImageEncoder encoder = null, string tag = null) where TPixel : struct, IPixel { string path = this.GetTestOutputFileName(extension: extension, tag:tag); extension = Path.GetExtension(path); - IImageFormat format = GetImageFormatByExtension(extension); - - encoder = encoder ?? format.Encoder; + encoder = encoder ?? GetImageFormatByExtension(extension); using (FileStream stream = File.OpenWrite(path)) { - image.Save(stream, encoder, options); + image.Save(stream, encoder); } } @@ -123,10 +121,10 @@ namespace ImageSharp.Tests this.Init(method.DeclaringType.Name, method.Name); } - private static IImageFormat GetImageFormatByExtension(string extension) + private static IImageEncoder GetImageFormatByExtension(string extension) { extension = extension?.TrimStart('.'); - return Configuration.Default.ImageFormats.First(f => f.SupportedExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase)); + return Configuration.Default.ImageEncoders.Last(f => f.FileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase)); } private string GetTestOutputDir() From 3499d7b6a2e2f5df4e55fd3aa8213b96d578f827 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Thu, 22 Jun 2017 20:00:09 +0100 Subject: [PATCH 02/13] provide IImageFormatProviders and split mimetype detection from decoders. --- src/ImageSharp/Configuration.cs | 180 +++++++++++++----- src/ImageSharp/Formats/Bmp/BmpDecoder.cs | 17 -- src/ImageSharp/Formats/Bmp/BmpEncoder.cs | 6 - .../Formats/Bmp/BmpImageFormatProvider.cs | 42 ++++ .../Formats/Bmp/BmpMimeTypeDetector.cs | 40 ++++ src/ImageSharp/Formats/Gif/GifDecoder.cs | 21 -- src/ImageSharp/Formats/Gif/GifEncoder.cs | 6 - .../Formats/Gif/GifImageFormatProvider.cs | 42 ++++ .../Formats/Gif/GifMimeTypeDetector.cs | 44 +++++ src/ImageSharp/Formats/IImageDecoder.cs | 26 --- src/ImageSharp/Formats/IImageEncoder.cs | 10 - .../Formats/IImageFormatProvider.cs | 56 ++++++ src/ImageSharp/Formats/IMimeTypeDetector.cs | 30 +++ src/ImageSharp/Formats/Jpeg/JpegDecoder.cs | 65 ------- src/ImageSharp/Formats/Jpeg/JpegEncoder.cs | 6 - .../Formats/Jpeg/JpegImageFormatProvider.cs | 42 ++++ .../Formats/Jpeg/JpegMimeTypeDetector.cs | 88 +++++++++ src/ImageSharp/Formats/Png/PngDecoder.cs | 23 --- src/ImageSharp/Formats/Png/PngEncoder.cs | 6 - .../Formats/Png/PngImageFormatProvider.cs | 42 ++++ .../Formats/Png/PngMimeTypeDetector.cs | 46 +++++ src/ImageSharp/Image/Image.Decode.cs | 26 ++- src/ImageSharp/Image/Image.FromBytes.cs | 24 +++ src/ImageSharp/Image/Image.FromFile.cs | 25 +++ src/ImageSharp/Image/Image.FromStream.cs | 33 +++- src/ImageSharp/Image/Image{TPixel}.cs | 22 +-- tests/ImageSharp.Tests/ConfigurationTests.cs | 155 +++++++++++---- .../ImageSharp.Tests/Image/ImageLoadTests.cs | 12 +- .../ImageSharp.Tests/Image/ImageSaveTests.cs | 14 +- tests/ImageSharp.Tests/TestFormat.cs | 45 ++++- .../TestUtilities/ImagingTestCaseUtility.cs | 2 +- 31 files changed, 884 insertions(+), 312 deletions(-) create mode 100644 src/ImageSharp/Formats/Bmp/BmpImageFormatProvider.cs create mode 100644 src/ImageSharp/Formats/Bmp/BmpMimeTypeDetector.cs create mode 100644 src/ImageSharp/Formats/Gif/GifImageFormatProvider.cs create mode 100644 src/ImageSharp/Formats/Gif/GifMimeTypeDetector.cs create mode 100644 src/ImageSharp/Formats/IImageFormatProvider.cs create mode 100644 src/ImageSharp/Formats/IMimeTypeDetector.cs create mode 100644 src/ImageSharp/Formats/Jpeg/JpegImageFormatProvider.cs create mode 100644 src/ImageSharp/Formats/Jpeg/JpegMimeTypeDetector.cs create mode 100644 src/ImageSharp/Formats/Png/PngImageFormatProvider.cs create mode 100644 src/ImageSharp/Formats/Png/PngMimeTypeDetector.cs diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs index 5734d70fb..43613867e 100644 --- a/src/ImageSharp/Configuration.cs +++ b/src/ImageSharp/Configuration.cs @@ -6,6 +6,7 @@ namespace ImageSharp { using System; + using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; @@ -17,7 +18,7 @@ namespace ImageSharp /// /// Provides initialization code which allows extending the library. /// - public class Configuration + public class Configuration : IImageFormatHost { /// /// A lazily initialized configuration default instance. @@ -30,14 +31,24 @@ namespace ImageSharp private readonly object syncRoot = new object(); /// - /// The list of supported . + /// The list of supported keyed to mimestypes. /// - private readonly List encoders = new List(); + private readonly ConcurrentDictionary mimeTypeEncoders = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); /// - /// The list of supported . + /// The list of supported keyed to fiel extensions. /// - private readonly List decoders = new List(); + private readonly ConcurrentDictionary extensionsEncoders = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + + /// + /// The list of supported keyed to mimestypes. + /// + private readonly ConcurrentDictionary mimeTypeDecoders = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + + /// + /// The list of supported s. + /// + private readonly List mimeTypeDetectors = new List(); /// /// Initializes a new instance of the class. @@ -46,30 +57,55 @@ namespace ImageSharp { } + /// + /// Initializes a new instance of the class. + /// + /// A collection of providers to configure + public Configuration(params IImageFormatProvider[] providers) + { + if (providers != null) + { + foreach (IImageFormatProvider p in providers) + { + p.Configure(this); + } + } + } + /// /// Gets the default instance. /// public static Configuration Default { get; } = Lazy.Value; /// - /// Gets the collection of supported + /// Gets the global parallel options for processing tasks in parallel. /// - public IReadOnlyCollection ImageEncoders => new ReadOnlyCollection(this.encoders); + public ParallelOptions ParallelOptions { get; } = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }; /// - /// Gets the collection of supported + /// Gets the maximum header size of all formats. /// - public IReadOnlyCollection ImageDecoders => new ReadOnlyCollection(this.decoders); + internal int MaxHeaderSize { get; private set; } /// - /// Gets the global parallel options for processing tasks in parallel. + /// Gets the currently registerd s. /// - public ParallelOptions ParallelOptions { get; } = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }; + internal IEnumerable MimeTypeDetectors => this.mimeTypeDetectors; /// - /// Gets the maximum header size of all formats. + /// Gets the typeof of all the current image decoders /// - internal int MaxHeaderSize { get; private set; } + internal IEnumerable AllMimeImageDecoders => this.mimeTypeDecoders.Select(x => x.Value.GetType()).Distinct().ToList(); + + /// + /// Gets the typeof of all the current image decoders + /// + internal IEnumerable AllMimeImageEncoders => this.mimeTypeEncoders.Select(x => x.Value.GetType()).Distinct().ToList(); + + /// + /// Gets the typeof of all the current image decoders + /// + internal IEnumerable AllExtImageEncoders => this.mimeTypeEncoders.Select(x => x.Value.GetType()).Distinct().ToList(); #if !NETSTANDARD1_1 /// @@ -79,36 +115,102 @@ namespace ImageSharp #endif /// - /// Adds a new to the collection of supported image formats. + /// Registers a new format provider. /// - /// The new format to add. - public void AddImageFormat(IImageDecoder decoder) + /// The format providers to call configure on. + public void AddImageFormat(IImageFormatProvider formatProvider) + { + Guard.NotNull(formatProvider, nameof(formatProvider)); + formatProvider.Configure(this); + } + + /// + public void SetMimeTypeEncoder(string mimeType, IImageEncoder encoder) { + Guard.NotNullOrEmpty(mimeType, nameof(mimeType)); + Guard.NotNull(encoder, nameof(encoder)); + this.mimeTypeEncoders.AddOrUpdate(mimeType?.Trim(), encoder, (s, e) => encoder); + } + + /// + public void SetFileExtensionEncoder(string extension, IImageEncoder encoder) + { + Guard.NotNullOrEmpty(extension, nameof(extension)); + Guard.NotNull(encoder, nameof(encoder)); + this.extensionsEncoders.AddOrUpdate(extension?.Trim(), encoder, (s, e) => encoder); + } + + /// + public void SetMimeTypeDecoder(string mimeType, IImageDecoder decoder) + { + Guard.NotNullOrEmpty(mimeType, nameof(mimeType)); Guard.NotNull(decoder, nameof(decoder)); - Guard.NotNullOrEmpty(decoder.FileExtensions, nameof(decoder.FileExtensions)); - Guard.NotNullOrEmpty(decoder.MimeTypes, nameof(decoder.MimeTypes)); + this.mimeTypeDecoders.AddOrUpdate(mimeType, decoder, (s, e) => decoder); + } + + /// + /// Removes all the registerd detectors + /// + public void ClearMimeTypeDetector() + { + this.mimeTypeDetectors.Clear(); + } + + /// + public void AddMimeTypeDetector(IMimeTypeDetector detector) + { + Guard.NotNull(detector, nameof(detector)); + this.mimeTypeDetectors.Add(detector); + this.SetMaxHeaderSize(); + } - lock (this.syncRoot) + /// + /// For the specified mimetype find the decoder. + /// + /// the mimetype to discover + /// the IImageDecoder if found othersize null + public IImageDecoder FindMimeTypeDecoder(string mimeType) + { + Guard.NotNullOrEmpty(mimeType, nameof(mimeType)); + if (this.mimeTypeDecoders.TryGetValue(mimeType, out IImageDecoder dec)) { - this.decoders.Add(decoder); + return dec; + } + + return null; + } - this.SetMaxHeaderSize(); + /// + /// For the specified mimetype find the encoder. + /// + /// the mimetype to discover + /// the IImageEncoder if found othersize null + public IImageEncoder FindMimeTypeEncoder(string mimeType) + { + Guard.NotNullOrEmpty(mimeType, nameof(mimeType)); + if (this.mimeTypeEncoders.TryGetValue(mimeType, out IImageEncoder dec)) + { + return dec; } + + return null; } /// - /// Adds a new to the collection of supported image formats. + /// For the specified mimetype find the encoder. /// - /// The new format to add. - public void AddImageFormat(IImageEncoder encoder) + /// the extensions to discover + /// the IImageEncoder if found othersize null + public IImageEncoder FindFileExtensionsEncoder(string extensions) { - Guard.NotNull(encoder, nameof(encoder)); - Guard.NotNullOrEmpty(encoder.FileExtensions, nameof(encoder.FileExtensions)); - Guard.NotNullOrEmpty(encoder.MimeTypes, nameof(encoder.MimeTypes)); - lock (this.syncRoot) + extensions = extensions?.TrimStart('.'); + Guard.NotNullOrEmpty(extensions, nameof(extensions)); + if (this.extensionsEncoders.TryGetValue(extensions, out IImageEncoder dec)) { - this.encoders.Add(encoder); + return dec; } + + return null; } /// @@ -117,19 +219,11 @@ namespace ImageSharp /// The default configuration of internal static Configuration CreateDefaultInstance() { - Configuration config = new Configuration(); - - // lets try auto loading the known image formats - config.AddImageFormat(new Formats.PngEncoder()); - config.AddImageFormat(new Formats.JpegEncoder()); - config.AddImageFormat(new Formats.GifEncoder()); - config.AddImageFormat(new Formats.BmpEncoder()); - - config.AddImageFormat(new Formats.PngDecoder()); - config.AddImageFormat(new Formats.JpegDecoder()); - config.AddImageFormat(new Formats.GifDecoder()); - config.AddImageFormat(new Formats.BmpDecoder()); - return config; + return new Configuration( + new PngImageFormatProvider(), + new JpegImageFormatProvider(), + new GifImageFormatProvider(), + new BmpImageFormatProvider()); } /// @@ -137,7 +231,7 @@ namespace ImageSharp /// private void SetMaxHeaderSize() { - this.MaxHeaderSize = this.decoders.Max(x => x.HeaderSize); + this.MaxHeaderSize = this.mimeTypeDetectors.Max(x => x.HeaderSize); } } } diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs index 9ff331490..e1dc489f4 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs @@ -28,23 +28,6 @@ namespace ImageSharp.Formats /// public class BmpDecoder : IImageDecoder { - /// - public IEnumerable MimeTypes => BmpConstants.MimeTypes; - - /// - public IEnumerable FileExtensions => BmpConstants.FileExtensions; - - /// - public int HeaderSize => 2; - - /// - public bool IsSupportedFileFormat(Span header) - { - return header.Length >= this.HeaderSize && - header[0] == 0x42 && // B - header[1] == 0x4D; // M - } - /// public Image Decode(Configuration configuration, Stream stream) diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoder.cs b/src/ImageSharp/Formats/Bmp/BmpEncoder.cs index 25db0eda0..f47bedb81 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoder.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoder.cs @@ -22,12 +22,6 @@ namespace ImageSharp.Formats /// public BmpBitsPerPixel BitsPerPixel { get; set; } = BmpBitsPerPixel.Pixel24; - /// - public IEnumerable MimeTypes => BmpConstants.MimeTypes; - - /// - public IEnumerable FileExtensions => BmpConstants.FileExtensions; - /// public void Encode(Image image, Stream stream) where TPixel : struct, IPixel diff --git a/src/ImageSharp/Formats/Bmp/BmpImageFormatProvider.cs b/src/ImageSharp/Formats/Bmp/BmpImageFormatProvider.cs new file mode 100644 index 000000000..145e1fdb6 --- /dev/null +++ b/src/ImageSharp/Formats/Bmp/BmpImageFormatProvider.cs @@ -0,0 +1,42 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Text; + using ImageSharp.PixelFormats; + + /// + /// Detects gif file headers + /// + public class BmpImageFormatProvider : IImageFormatProvider + { + /// + public void Configure(IImageFormatHost host) + { + var encoder = new BmpEncoder(); + foreach (string mimeType in BmpConstants.MimeTypes) + { + host.SetMimeTypeEncoder(mimeType, encoder); + } + + foreach (string mimeType in BmpConstants.FileExtensions) + { + host.SetFileExtensionEncoder(mimeType, encoder); + } + + var decoder = new BmpDecoder(); + foreach (string mimeType in BmpConstants.MimeTypes) + { + host.SetMimeTypeDecoder(mimeType, decoder); + } + + host.AddMimeTypeDetector(new BmpMimeTypeDetector()); + } + } +} diff --git a/src/ImageSharp/Formats/Bmp/BmpMimeTypeDetector.cs b/src/ImageSharp/Formats/Bmp/BmpMimeTypeDetector.cs new file mode 100644 index 000000000..c13181d6a --- /dev/null +++ b/src/ImageSharp/Formats/Bmp/BmpMimeTypeDetector.cs @@ -0,0 +1,40 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Text; + using ImageSharp.PixelFormats; + + /// + /// Detects bmp file headers + /// + internal class BmpMimeTypeDetector : IMimeTypeDetector + { + /// + public int HeaderSize => 2; + + /// + public string DetectMimeType(Span header) + { + if (this.IsSupportedFileFormat(header)) + { + return "image/bmp"; + } + + return null; + } + + private bool IsSupportedFileFormat(Span header) + { + return header.Length >= this.HeaderSize && + header[0] == 0x42 && // B + header[1] == 0x4D; // M + } + } +} diff --git a/src/ImageSharp/Formats/Gif/GifDecoder.cs b/src/ImageSharp/Formats/Gif/GifDecoder.cs index 506b37dc8..c922767b8 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoder.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoder.cs @@ -16,12 +16,6 @@ namespace ImageSharp.Formats /// public class GifDecoder : IImageDecoder { - /// - public IEnumerable MimeTypes => GifConstants.MimeTypes; - - /// - public IEnumerable FileExtensions => GifConstants.FileExtensions; - /// /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. /// @@ -32,21 +26,6 @@ namespace ImageSharp.Formats /// public Encoding TextEncoding { get; set; } = GifConstants.DefaultEncoding; - /// - public int HeaderSize => 6; - - /// - public bool IsSupportedFileFormat(Span header) - { - return header.Length >= this.HeaderSize && - header[0] == 0x47 && // G - header[1] == 0x49 && // I - header[2] == 0x46 && // F - header[3] == 0x38 && // 8 - (header[4] == 0x39 || header[4] == 0x37) && // 9 or 7 - header[5] == 0x61; // a - } - /// public Image Decode(Configuration configuration, Stream stream) where TPixel : struct, IPixel diff --git a/src/ImageSharp/Formats/Gif/GifEncoder.cs b/src/ImageSharp/Formats/Gif/GifEncoder.cs index f7dba9266..3ded88429 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoder.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoder.cs @@ -17,12 +17,6 @@ namespace ImageSharp.Formats /// public class GifEncoder : IImageEncoder { - /// - public IEnumerable MimeTypes => GifConstants.MimeTypes; - - /// - public IEnumerable FileExtensions => GifConstants.FileExtensions; - /// /// Gets or sets a value indicating whether the metadata should be ignored when the image is being encoded. /// diff --git a/src/ImageSharp/Formats/Gif/GifImageFormatProvider.cs b/src/ImageSharp/Formats/Gif/GifImageFormatProvider.cs new file mode 100644 index 000000000..7e521353f --- /dev/null +++ b/src/ImageSharp/Formats/Gif/GifImageFormatProvider.cs @@ -0,0 +1,42 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Text; + using ImageSharp.PixelFormats; + + /// + /// Detects gif file headers + /// + public class GifImageFormatProvider : IImageFormatProvider + { + /// + public void Configure(IImageFormatHost host) + { + var encoder = new GifEncoder(); + foreach (string mimeType in GifConstants.MimeTypes) + { + host.SetMimeTypeEncoder(mimeType, encoder); + } + + foreach (string mimeType in GifConstants.FileExtensions) + { + host.SetFileExtensionEncoder(mimeType, encoder); + } + + var decoder = new GifDecoder(); + foreach (string mimeType in GifConstants.MimeTypes) + { + host.SetMimeTypeDecoder(mimeType, decoder); + } + + host.AddMimeTypeDetector(new GifMimeTypeDetector()); + } + } +} diff --git a/src/ImageSharp/Formats/Gif/GifMimeTypeDetector.cs b/src/ImageSharp/Formats/Gif/GifMimeTypeDetector.cs new file mode 100644 index 000000000..f4ad8fa8e --- /dev/null +++ b/src/ImageSharp/Formats/Gif/GifMimeTypeDetector.cs @@ -0,0 +1,44 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Text; + using ImageSharp.PixelFormats; + + /// + /// Detects gif file headers + /// + public class GifMimeTypeDetector : IMimeTypeDetector + { + /// + public int HeaderSize => 6; + + /// + public string DetectMimeType(Span header) + { + if (this.IsSupportedFileFormat(header)) + { + return "image/gif"; + } + + return null; + } + + private bool IsSupportedFileFormat(Span header) + { + return header.Length >= this.HeaderSize && + header[0] == 0x47 && // G + header[1] == 0x49 && // I + header[2] == 0x46 && // F + header[3] == 0x38 && // 8 + (header[4] == 0x39 || header[4] == 0x37) && // 9 or 7 + header[5] == 0x61; // a + } + } +} diff --git a/src/ImageSharp/Formats/IImageDecoder.cs b/src/ImageSharp/Formats/IImageDecoder.cs index ff655d718..66eabb1b8 100644 --- a/src/ImageSharp/Formats/IImageDecoder.cs +++ b/src/ImageSharp/Formats/IImageDecoder.cs @@ -16,32 +16,6 @@ namespace ImageSharp.Formats /// public interface IImageDecoder { - /// - /// Gets the collection of mime types that this decoder supports decoding on. - /// - IEnumerable MimeTypes { get; } - - /// - /// Gets the collection of file extensionsthis decoder supports decoding. - /// - IEnumerable FileExtensions { get; } - - /// - /// Gets the size of the header for this image type. - /// - /// The size of the header. - int HeaderSize { get; } - - /// - /// Returns a value indicating whether the supports the specified - /// file header. - /// - /// The containing the file header. - /// - /// True if the decoder supports the file header; otherwise, false. - /// - bool IsSupportedFileFormat(Span header); - /// /// Decodes the image from the specified stream to the . /// diff --git a/src/ImageSharp/Formats/IImageEncoder.cs b/src/ImageSharp/Formats/IImageEncoder.cs index 465f8eec5..4ad41ebc2 100644 --- a/src/ImageSharp/Formats/IImageEncoder.cs +++ b/src/ImageSharp/Formats/IImageEncoder.cs @@ -16,16 +16,6 @@ namespace ImageSharp.Formats /// public interface IImageEncoder { - /// - /// Gets the collection of mime types that this decoder supports encoding for. - /// - IEnumerable MimeTypes { get; } - - /// - /// Gets the collection of file extensionsthis decoder supports encoding for. - /// - IEnumerable FileExtensions { get; } - /// /// Encodes the image to the specified stream from the . /// diff --git a/src/ImageSharp/Formats/IImageFormatProvider.cs b/src/ImageSharp/Formats/IImageFormatProvider.cs new file mode 100644 index 000000000..c7d354ec6 --- /dev/null +++ b/src/ImageSharp/Formats/IImageFormatProvider.cs @@ -0,0 +1,56 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + using System.Collections.Generic; + using System.Text; + + /// + /// Represents an abstract class that can register image encoders, decoders and mime type detectors + /// + public interface IImageFormatProvider + { + /// + /// Called when loaded so the provider and register its encoders, decodes and mime type detectors into an IImageFormatHost. + /// + /// The host that will retain the encoders, decodes and mime type detectors. + void Configure(IImageFormatHost host); + } + + /// + /// Represents an abstract class that can have encoders decoders and mimetype detecotrs loaded into. + /// + public interface IImageFormatHost + { + /// + /// Sets a specific image encoder as the encoder for a specific mimetype + /// + /// the target mimetype + /// the encoder to use + void SetMimeTypeEncoder(string mimeType, IImageEncoder encoder); // could/should this be an Action??? + + /// + /// Sets a specific image encoder as the encoder for a specific mimetype + /// + /// the target mimetype + /// the encoder to use + void SetFileExtensionEncoder(string extension, IImageEncoder encoder); + + /// + /// Sets a specific image decoder as the decoder for a specific mimetype + /// + /// the target mimetype + /// the decoder to use + void SetMimeTypeDecoder(string mimeType, IImageDecoder decoder); + + /// + /// Adds a new detector for detecting in mime types + /// + /// The detector + void AddMimeTypeDetector(IMimeTypeDetector detector); + } +} diff --git a/src/ImageSharp/Formats/IMimeTypeDetector.cs b/src/ImageSharp/Formats/IMimeTypeDetector.cs new file mode 100644 index 000000000..f55be7151 --- /dev/null +++ b/src/ImageSharp/Formats/IMimeTypeDetector.cs @@ -0,0 +1,30 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + using System.Collections.Generic; + using System.Text; + + /// + /// Used for detecting mime types from a file header + /// + public interface IMimeTypeDetector + { + /// + /// Gets the size of the header for this image type. + /// + /// The size of the header. + int HeaderSize { get; } + + /// + /// Detect mimetype + /// + /// The containing the file header. + /// returns the mime type of detected othersie returns null + string DetectMimeType(Span header); + } +} diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs index 09575a12e..b809908e9 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs @@ -21,22 +21,6 @@ namespace ImageSharp.Formats /// public bool IgnoreMetadata { get; set; } - /// - public IEnumerable MimeTypes => JpegConstants.MimeTypes; - - /// - public IEnumerable FileExtensions => JpegConstants.FileExtensions; - - /// - public int HeaderSize => 11; - - /// - public bool IsSupportedFileFormat(Span header) - { - return header.Length >= this.HeaderSize && - (IsJfif(header) || IsExif(header) || IsJpeg(header)); - } - /// public Image Decode(Configuration configuration, Stream stream) where TPixel : struct, IPixel @@ -49,54 +33,5 @@ namespace ImageSharp.Formats return decoder.Decode(stream); } } - - /// - /// Returns a value indicating whether the given bytes identify Jfif data. - /// - /// The bytes representing the file header. - /// The - private static bool IsJfif(Span header) - { - bool isJfif = - header[6] == 0x4A && // J - header[7] == 0x46 && // F - header[8] == 0x49 && // I - header[9] == 0x46 && // F - header[10] == 0x00; - - return isJfif; - } - - /// - /// Returns a value indicating whether the given bytes identify EXIF data. - /// - /// The bytes representing the file header. - /// The - private static bool IsExif(Span header) - { - bool isExif = - header[6] == 0x45 && // E - header[7] == 0x78 && // X - header[8] == 0x69 && // I - header[9] == 0x66 && // F - header[10] == 0x00; - - return isExif; - } - - /// - /// Returns a value indicating whether the given bytes identify Jpeg data. - /// This is a last chance resort for jpegs that contain ICC information. - /// - /// The bytes representing the file header. - /// The - private static bool IsJpeg(Span header) - { - bool isJpg = - header[0] == 0xFF && // 255 - header[1] == 0xD8; // 216 - - return isJpg; - } } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs index f76df0585..d0be9eaf8 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs @@ -34,12 +34,6 @@ namespace ImageSharp.Formats /// The subsample ratio of the jpg image. public JpegSubsample? Subsample { get; set; } - /// - public IEnumerable MimeTypes => JpegConstants.MimeTypes; - - /// - public IEnumerable FileExtensions => JpegConstants.FileExtensions; - /// /// Encodes the image to the specified stream from the . /// diff --git a/src/ImageSharp/Formats/Jpeg/JpegImageFormatProvider.cs b/src/ImageSharp/Formats/Jpeg/JpegImageFormatProvider.cs new file mode 100644 index 000000000..6cd49e20e --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/JpegImageFormatProvider.cs @@ -0,0 +1,42 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Text; + using ImageSharp.PixelFormats; + + /// + /// Detects png file headers + /// + public class JpegImageFormatProvider : IImageFormatProvider + { + /// + public void Configure(IImageFormatHost host) + { + var pngEncoder = new JpegEncoder(); + foreach (string mimeType in JpegConstants.MimeTypes) + { + host.SetMimeTypeEncoder(mimeType, pngEncoder); + } + + foreach (string mimeType in JpegConstants.FileExtensions) + { + host.SetFileExtensionEncoder(mimeType, pngEncoder); + } + + var pngDecoder = new JpegDecoder(); + foreach (string mimeType in JpegConstants.MimeTypes) + { + host.SetMimeTypeDecoder(mimeType, pngDecoder); + } + + host.AddMimeTypeDetector(new JpegMimeTypeDetector()); + } + } +} diff --git a/src/ImageSharp/Formats/Jpeg/JpegMimeTypeDetector.cs b/src/ImageSharp/Formats/Jpeg/JpegMimeTypeDetector.cs new file mode 100644 index 000000000..f84a91f70 --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/JpegMimeTypeDetector.cs @@ -0,0 +1,88 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Text; + using ImageSharp.PixelFormats; + + /// + /// Detects Jpeg file headers + /// + public class JpegMimeTypeDetector : IMimeTypeDetector + { + /// + public int HeaderSize => 11; + + /// + public string DetectMimeType(Span header) + { + if (this.IsSupportedFileFormat(header)) + { + return "image/jpeg"; + } + + return null; + } + + private bool IsSupportedFileFormat(Span header) + { + return header.Length >= this.HeaderSize && + (this.IsJfif(header) || this.IsExif(header) || this.IsJpeg(header)); + } + + /// + /// Returns a value indicating whether the given bytes identify Jfif data. + /// + /// The bytes representing the file header. + /// The + private bool IsJfif(Span header) + { + bool isJfif = + header[6] == 0x4A && // J + header[7] == 0x46 && // F + header[8] == 0x49 && // I + header[9] == 0x46 && // F + header[10] == 0x00; + + return isJfif; + } + + /// + /// Returns a value indicating whether the given bytes identify EXIF data. + /// + /// The bytes representing the file header. + /// The + private bool IsExif(Span header) + { + bool isExif = + header[6] == 0x45 && // E + header[7] == 0x78 && // X + header[8] == 0x69 && // I + header[9] == 0x66 && // F + header[10] == 0x00; + + return isExif; + } + + /// + /// Returns a value indicating whether the given bytes identify Jpeg data. + /// This is a last chance resort for jpegs that contain ICC information. + /// + /// The bytes representing the file header. + /// The + private bool IsJpeg(Span header) + { + bool isJpg = + header[0] == 0xFF && // 255 + header[1] == 0xD8; // 216 + + return isJpg; + } + } +} diff --git a/src/ImageSharp/Formats/Png/PngDecoder.cs b/src/ImageSharp/Formats/Png/PngDecoder.cs index da00ff906..c9fab8e3f 100644 --- a/src/ImageSharp/Formats/Png/PngDecoder.cs +++ b/src/ImageSharp/Formats/Png/PngDecoder.cs @@ -38,34 +38,11 @@ namespace ImageSharp.Formats /// public bool IgnoreMetadata { get; set; } - /// - public IEnumerable MimeTypes => PngConstants.MimeTypes; - - /// - public IEnumerable FileExtensions => PngConstants.FileExtensions; - - /// - public int HeaderSize => 8; - /// /// Gets or sets the encoding that should be used when reading text chunks. /// public Encoding TextEncoding { get; set; } = PngConstants.DefaultEncoding; - /// - public bool IsSupportedFileFormat(Span header) - { - return header.Length >= this.HeaderSize && - header[0] == 0x89 && - header[1] == 0x50 && // P - header[2] == 0x4E && // N - header[3] == 0x47 && // G - header[4] == 0x0D && // CR - header[5] == 0x0A && // LF - header[6] == 0x1A && // EOF - header[7] == 0x0A; // LF - } - /// /// Decodes the image from the specified stream to the . /// diff --git a/src/ImageSharp/Formats/Png/PngEncoder.cs b/src/ImageSharp/Formats/Png/PngEncoder.cs index 023e465e9..d15161ded 100644 --- a/src/ImageSharp/Formats/Png/PngEncoder.cs +++ b/src/ImageSharp/Formats/Png/PngEncoder.cs @@ -16,12 +16,6 @@ namespace ImageSharp.Formats /// public class PngEncoder : IImageEncoder { - /// - public IEnumerable MimeTypes => PngConstants.MimeTypes; - - /// - public IEnumerable FileExtensions => PngConstants.FileExtensions; - /// /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. /// diff --git a/src/ImageSharp/Formats/Png/PngImageFormatProvider.cs b/src/ImageSharp/Formats/Png/PngImageFormatProvider.cs new file mode 100644 index 000000000..5708cc812 --- /dev/null +++ b/src/ImageSharp/Formats/Png/PngImageFormatProvider.cs @@ -0,0 +1,42 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Text; + using ImageSharp.PixelFormats; + + /// + /// Detects png file headers + /// + public class PngImageFormatProvider : IImageFormatProvider + { + /// + public void Configure(IImageFormatHost host) + { + var pngEncoder = new PngEncoder(); + foreach (string mimeType in PngConstants.MimeTypes) + { + host.SetMimeTypeEncoder(mimeType, pngEncoder); + } + + foreach (string mimeType in PngConstants.FileExtensions) + { + host.SetFileExtensionEncoder(mimeType, pngEncoder); + } + + var pngDecoder = new PngDecoder(); + foreach (string mimeType in PngConstants.MimeTypes) + { + host.SetMimeTypeDecoder(mimeType, pngDecoder); + } + + host.AddMimeTypeDetector(new PngMimeTypeDetector()); + } + } +} diff --git a/src/ImageSharp/Formats/Png/PngMimeTypeDetector.cs b/src/ImageSharp/Formats/Png/PngMimeTypeDetector.cs new file mode 100644 index 000000000..6b5d43fbd --- /dev/null +++ b/src/ImageSharp/Formats/Png/PngMimeTypeDetector.cs @@ -0,0 +1,46 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Text; + using ImageSharp.PixelFormats; + + /// + /// Detects png file headers + /// + public class PngMimeTypeDetector : IMimeTypeDetector + { + /// + public int HeaderSize => 8; + + /// + public string DetectMimeType(Span header) + { + if (this.IsSupportedFileFormat(header)) + { + return "image/png"; + } + + return null; + } + + private bool IsSupportedFileFormat(Span header) + { + return header.Length >= this.HeaderSize && + header[0] == 0x89 && + header[1] == 0x50 && // P + header[2] == 0x4E && // N + header[3] == 0x47 && // G + header[4] == 0x0D && // CR + header[5] == 0x0A && // LF + header[6] == 0x1A && // EOF + header[7] == 0x0A; // LF + } + } +} diff --git a/src/ImageSharp/Image/Image.Decode.cs b/src/ImageSharp/Image/Image.Decode.cs index 2730da8f2..96d5df45f 100644 --- a/src/ImageSharp/Image/Image.Decode.cs +++ b/src/ImageSharp/Image/Image.Decode.cs @@ -22,8 +22,8 @@ namespace ImageSharp /// /// The image stream to read the header from. /// The configuration. - /// The image format or null if none found. - private static IImageDecoder DiscoverDecoder(Stream stream, Configuration config) + /// The mimetype or null if none found. + private static string InternalDiscoverMimeType(Stream stream, Configuration config) { // This is probably a candidate for making into a public API in the future! int maxHeaderSize = config.MaxHeaderSize; @@ -32,19 +32,31 @@ namespace ImageSharp return null; } - IImageDecoder format; byte[] header = ArrayPool.Shared.Rent(maxHeaderSize); try { long startPosition = stream.Position; stream.Read(header, 0, maxHeaderSize); stream.Position = startPosition; - format = config.ImageDecoders.LastOrDefault(x => x.IsSupportedFileFormat(header)); // we should use last in case user has registerd a new one with their own settings + return config.MimeTypeDetectors.Select(x => x.DetectMimeType(header)).LastOrDefault(x => x != null); } finally { ArrayPool.Shared.Return(header); } + } + + /// + /// By reading the header on the provided stream this calculates the images format. + /// + /// The image stream to read the header from. + /// The configuration. + /// The mimeType. + /// The image format or null if none found. + private static IImageDecoder DiscoverDecoder(Stream stream, Configuration config, out string mimeType) + { + + format = config.FindMimeTypeDecoder(mimeType); return format; } @@ -59,18 +71,18 @@ namespace ImageSharp /// /// A new . /// - private static (Image img, IImageDecoder decoder) Decode(Stream stream, Configuration config) + private static (Image img, string mimeType) Decode(Stream stream, Configuration config) #pragma warning restore SA1008 // Opening parenthesis must be spaced correctly where TPixel : struct, IPixel { - IImageDecoder decoder = DiscoverDecoder(stream, config); + IImageDecoder decoder = DiscoverDecoder(stream, config, out string mimeType); if (decoder == null) { return (null, null); } Image img = decoder.Decode(config, stream); - return (img, decoder); + return (img, mimeType); } } } \ No newline at end of file diff --git a/src/ImageSharp/Image/Image.FromBytes.cs b/src/ImageSharp/Image/Image.FromBytes.cs index 8cc0e8f37..948fadf0c 100644 --- a/src/ImageSharp/Image/Image.FromBytes.cs +++ b/src/ImageSharp/Image/Image.FromBytes.cs @@ -15,6 +15,30 @@ namespace ImageSharp /// public static partial class Image { + /// + /// By reading the header on the provided byte array this calculates the images mimetype. + /// + /// The byte array containing image data to read the header from. + /// The mimetype or null if none found. + public static string DiscoverMimeType(byte[] data) + { + return DiscoverMimeType(null, data); + } + + /// + /// By reading the header on the provided byte array this calculates the images mimetype. + /// + /// The configuration. + /// The byte array containing image data to read the header from. + /// The mimetype or null if none found. + public static string DiscoverMimeType(Configuration config, byte[] data) + { + using (Stream stream = new MemoryStream(data)) + { + return DiscoverMimeType(config, stream); + } + } + /// /// Create a new instance of the class from the given byte array. /// diff --git a/src/ImageSharp/Image/Image.FromFile.cs b/src/ImageSharp/Image/Image.FromFile.cs index 991294921..96d509752 100644 --- a/src/ImageSharp/Image/Image.FromFile.cs +++ b/src/ImageSharp/Image/Image.FromFile.cs @@ -16,6 +16,31 @@ namespace ImageSharp /// public static partial class Image { + /// + /// By reading the header on the provided file this calculates the images mimetype. + /// + /// The image file to open and to read the header from. + /// The mimetype or null if none found. + public static string DiscoverMimeType(string filePath) + { + return DiscoverMimeType(null, filePath); + } + + /// + /// By reading the header on the provided file this calculates the images mimetype. + /// + /// The configuration. + /// The image file to open and to read the header from. + /// The mimetype or null if none found. + public static string DiscoverMimeType(Configuration config, string filePath) + { + config = config ?? Configuration.Default; + using (Stream file = config.FileSystem.OpenRead(filePath)) + { + return DiscoverMimeType(config, file); + } + } + /// /// Create a new instance of the class from the given file. /// diff --git a/src/ImageSharp/Image/Image.FromStream.cs b/src/ImageSharp/Image/Image.FromStream.cs index 79c66af90..1aa93525c 100644 --- a/src/ImageSharp/Image/Image.FromStream.cs +++ b/src/ImageSharp/Image/Image.FromStream.cs @@ -18,6 +18,27 @@ namespace ImageSharp /// public static partial class Image { + /// + /// By reading the header on the provided stream this calculates the images mimetype. + /// + /// The image stream to read the header from. + /// The mimetype or null if none found. + public static string DiscoverMimeType(Stream stream) + { + return DiscoverMimeType(null, stream); + } + + /// + /// By reading the header on the provided stream this calculates the images mimetype. + /// + /// The configuration. + /// The image stream to read the header from. + /// The mimetype or null if none found. + public static string DiscoverMimeType(Configuration config, Stream stream) + { + return WithSeekableStream(stream, s => InternalDiscoverMimeType(s, config ?? Configuration.Default)); + } + /// /// Create a new instance of the class from the given stream. /// @@ -169,21 +190,21 @@ namespace ImageSharp { config = config ?? Configuration.Default; mimeType = null; - (Image img, IImageDecoder decoder) data = WithSeekableStream(stream, s => Decode(s, config)); + (Image img, string mimeType) data = WithSeekableStream(stream, s => Decode(s, config)); - mimeType = data.decoder?.MimeTypes.FirstOrDefault(); + mimeType = data.mimeType; if (data.img != null) { return data.img; } - StringBuilder stringBuilder = new StringBuilder(); + var stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Image cannot be loaded. Available decoders:"); - foreach (IImageDecoder format in config.ImageDecoders) + foreach (Type format in config.AllMimeImageDecoders) { - stringBuilder.AppendLine("-" + format); + stringBuilder.AppendLine(" - " + format.Name); } throw new NotSupportedException(stringBuilder.ToString()); @@ -202,7 +223,7 @@ namespace ImageSharp } // We want to be able to load images from things like HttpContext.Request.Body - using (MemoryStream ms = new MemoryStream()) + using (var ms = new MemoryStream()) { stream.CopyTo(ms); ms.Position = 0; diff --git a/src/ImageSharp/Image/Image{TPixel}.cs b/src/ImageSharp/Image/Image{TPixel}.cs index 27f3801c4..af9cc3914 100644 --- a/src/ImageSharp/Image/Image{TPixel}.cs +++ b/src/ImageSharp/Image/Image{TPixel}.cs @@ -158,16 +158,16 @@ namespace ImageSharp public Image Save(Stream stream, string mimeType) { Guard.NotNullOrEmpty(mimeType, nameof(mimeType)); - IImageEncoder encoder = this.Configuration.ImageEncoders?.LastOrDefault(x => x?.MimeTypes?.Contains(mimeType, StringComparer.OrdinalIgnoreCase) == true); + IImageEncoder encoder = this.Configuration.FindMimeTypeEncoder(mimeType); if (encoder == null) { - StringBuilder stringBuilder = new StringBuilder(); + var stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Can't find encoder for provided mime type. Available encoded:"); - foreach (IImageEncoder format in this.Configuration.ImageEncoders) + foreach (Type format in this.Configuration.AllMimeImageEncoders) { - stringBuilder.AppendLine("-" + format); + stringBuilder.AppendLine(" - " + format); } throw new NotSupportedException(stringBuilder.ToString()); @@ -207,15 +207,15 @@ namespace ImageSharp Guard.NotNullOrEmpty(filePath, nameof(filePath)); string ext = Path.GetExtension(filePath).Trim('.'); - IImageEncoder encoder = this.Configuration.ImageEncoders?.LastOrDefault(x => x?.FileExtensions?.Contains(ext, StringComparer.OrdinalIgnoreCase) == true); + IImageEncoder encoder = this.Configuration.FindFileExtensionsEncoder(ext); if (encoder == null) { - StringBuilder stringBuilder = new StringBuilder(); + var stringBuilder = new StringBuilder(); stringBuilder.AppendLine($"Can't find encoder for file extention '{ext}'. Available encoded:"); - foreach (IImageEncoder format in this.Configuration.ImageEncoders) + foreach (Type format in this.Configuration.AllExtImageEncoders) { - stringBuilder.AppendLine("-" + format); + stringBuilder.AppendLine(" - " + format); } throw new NotSupportedException(stringBuilder.ToString()); @@ -255,7 +255,7 @@ namespace ImageSharp /// The public string ToBase64String(string mimeType) { - using (MemoryStream stream = new MemoryStream()) + using (var stream = new MemoryStream()) { this.Save(stream, mimeType); stream.Flush(); @@ -274,7 +274,7 @@ namespace ImageSharp { scaleFunc = PackedPixelConverterHelper.ComputeScaleFunction(scaleFunc); - Image target = new Image(this.Configuration, this.Width, this.Height); + var target = new Image(this.Configuration, this.Width, this.Height); target.CopyProperties(this); using (PixelAccessor pixels = this.Lock()) @@ -288,7 +288,7 @@ namespace ImageSharp { for (int x = 0; x < target.Width; x++) { - TPixel2 color = default(TPixel2); + var color = default(TPixel2); color.PackFromVector4(scaleFunc(pixels[x, y].ToVector4())); targetPixels[x, y] = color; } diff --git a/tests/ImageSharp.Tests/ConfigurationTests.cs b/tests/ImageSharp.Tests/ConfigurationTests.cs index e2d50649a..e8927c75c 100644 --- a/tests/ImageSharp.Tests/ConfigurationTests.cs +++ b/tests/ImageSharp.Tests/ConfigurationTests.cs @@ -13,7 +13,7 @@ namespace ImageSharp.Tests using ImageSharp.Formats; using ImageSharp.IO; using ImageSharp.PixelFormats; - + using Moq; using Xunit; /// @@ -21,23 +21,27 @@ namespace ImageSharp.Tests /// public class ConfigurationTests { + public Configuration ConfigurationEmpty { get; private set; } + public Configuration DefaultConfiguration { get; private set; } + + public ConfigurationTests() + { + this.DefaultConfiguration = Configuration.CreateDefaultInstance(); + this.ConfigurationEmpty = Configuration.CreateDefaultInstance(); + } + [Fact] public void DefaultsToLocalFileSystem() { - var configuration = Configuration.CreateDefaultInstance(); - - ImageSharp.IO.IFileSystem fs = configuration.FileSystem; - - Assert.IsType(fs); + Assert.IsType(DefaultConfiguration.FileSystem); + Assert.IsType(ConfigurationEmpty.FileSystem); } [Fact] public void IfAutoloadWellknwonFormatesIsTrueAllFormateAreLoaded() { - var configuration = Configuration.CreateDefaultInstance(); - - Assert.Equal(4, configuration.ImageDecoders.Count); - Assert.Equal(4, configuration.ImageDecoders.Count); + Assert.Equal(4, DefaultConfiguration.AllMimeImageDecoders.Count()); + Assert.Equal(4, DefaultConfiguration.AllMimeImageDecoders.Count()); } /// @@ -68,58 +72,129 @@ namespace ImageSharp.Tests Assert.True(Configuration.Default.ParallelOptions.MaxDegreeOfParallelism == Environment.ProcessorCount); } - /// - /// Test that the default configuration parallel options is not null. - /// [Fact] - public void TestDefultConfigurationImageFormatsIsNotNull() + public void AddMimeTypeDetectorNullthrows() { - Assert.True(Configuration.Default.ImageDecoders != null); - Assert.True(Configuration.Default.ImageEncoders != null); + Assert.Throws(() => + { + DefaultConfiguration.AddMimeTypeDetector(null); + }); } - /// - /// Tests the method throws an exception - /// when the format is null. - /// [Fact] - public void TestAddImageFormatThrowsWithNullFormat() + public void RegisterNullMimeTypeEncoder() { Assert.Throws(() => { - Configuration.Default.AddImageFormat((IImageEncoder)null); + DefaultConfiguration.SetMimeTypeEncoder(null, new Mock().Object); }); Assert.Throws(() => { - Configuration.Default.AddImageFormat((IImageDecoder)null); + DefaultConfiguration.SetMimeTypeEncoder("sdsdsd", null); + }); + Assert.Throws(() => + { + DefaultConfiguration.SetMimeTypeEncoder(null, null); + }); + } + + [Fact] + public void RegisterNullFileExtEncoder() + { + Assert.Throws(() => + { + DefaultConfiguration.SetFileExtensionEncoder(null, new Mock().Object); + }); + Assert.Throws(() => + { + DefaultConfiguration.SetFileExtensionEncoder("sdsdsd", null); + }); + Assert.Throws(() => + { + DefaultConfiguration.SetFileExtensionEncoder(null, null); }); } - /// - /// Test that the default image constructors use default configuration. - /// [Fact] - public void TestImageUsesDefaultConfiguration() + public void RegisterNullMimeTypeDecoder() { - Configuration.Default.AddImageFormat(new PngDecoder()); + Assert.Throws(() => + { + DefaultConfiguration.SetMimeTypeDecoder(null, new Mock().Object); + }); + Assert.Throws(() => + { + DefaultConfiguration.SetMimeTypeDecoder("sdsdsd", null); + }); + Assert.Throws(() => + { + DefaultConfiguration.SetMimeTypeDecoder(null, null); + }); + } - var image = new Image(1, 1); - Assert.Equal(image.Configuration.ParallelOptions, Configuration.Default.ParallelOptions); - Assert.Equal(image.Configuration.ImageDecoders, Configuration.Default.ImageDecoders); + [Fact] + public void RegisterMimeTypeEncoderReplacesLast() + { + var encoder1 = new Mock().Object; + ConfigurationEmpty.SetMimeTypeEncoder("test", encoder1); + var found = ConfigurationEmpty.FindMimeTypeEncoder("TEST"); + Assert.Equal(encoder1, found); + + var encoder2 = new Mock().Object; + ConfigurationEmpty.SetMimeTypeEncoder("TEST", encoder2); + var found2 = ConfigurationEmpty.FindMimeTypeEncoder("test"); + Assert.Equal(encoder2, found2); + Assert.NotEqual(found, found2); + } + + [Fact] + public void RegisterFileExtEnecoderReplacesLast() + { + var encoder1 = new Mock().Object; + ConfigurationEmpty.SetFileExtensionEncoder("TEST", encoder1); + var found = ConfigurationEmpty.FindFileExtensionsEncoder("test"); + Assert.Equal(encoder1, found); + + var encoder2 = new Mock().Object; + ConfigurationEmpty.SetFileExtensionEncoder("test", encoder2); + var found2 = ConfigurationEmpty.FindFileExtensionsEncoder("TEST"); + Assert.Equal(encoder2, found2); + Assert.NotEqual(found, found2); + } + + [Fact] + public void RegisterMimeTypeDecoderReplacesLast() + { + var decoder1 = new Mock().Object; + ConfigurationEmpty.SetMimeTypeDecoder("test", decoder1); + var found = ConfigurationEmpty.FindMimeTypeDecoder("TEST"); + Assert.Equal(decoder1, found); + + var decoder2 = new Mock().Object; + ConfigurationEmpty.SetMimeTypeDecoder("TEST", decoder2); + var found2 = ConfigurationEmpty.FindMimeTypeDecoder("test"); + Assert.Equal(decoder2, found2); + Assert.NotEqual(found, found2); + } + + + [Fact] + public void ConstructorCallConfigureOnFormatProvider() + { + var provider = new Mock(); + var config = new Configuration(provider.Object); + + provider.Verify(x => x.Configure(config)); } - /// - /// Test that the default image constructor copies the configuration. - /// [Fact] - public void TestImageCopiesConfiguration() + public void AddFormatCallsConfig() { - Configuration.Default.AddImageFormat(new PngDecoder()); + var provider = new Mock(); + var config = new Configuration(); + config.AddImageFormat(provider.Object); - var image = new Image(1, 1); - var image2 = new Image(image); - Assert.Equal(image2.Configuration.ParallelOptions, image.Configuration.ParallelOptions); - Assert.True(image2.Configuration.ImageDecoders.SequenceEqual(image.Configuration.ImageDecoders)); + provider.Verify(x => x.Configure(config)); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Image/ImageLoadTests.cs b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs index 65c2cc52c..efd7b6935 100644 --- a/tests/ImageSharp.Tests/Image/ImageLoadTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs @@ -23,6 +23,7 @@ namespace ImageSharp.Tests private Image returnImage; private Mock localDecoder; private readonly string FilePath; + private readonly Mock localMimeTypeDetector; public Configuration LocalConfiguration { get; private set; } public byte[] Marker { get; private set; } @@ -34,10 +35,9 @@ namespace ImageSharp.Tests this.returnImage = new Image(1, 1); this.localDecoder = new Mock(); - this.localDecoder.Setup(x => x.MimeTypes).Returns(new[] { "img/test" }); - this.localDecoder.Setup(x => x.FileExtensions).Returns(new[] { "png", "jpg" }); - this.localDecoder.Setup(x => x.HeaderSize).Returns(1); - this.localDecoder.Setup(x => x.IsSupportedFileFormat(It.IsAny>())).Returns(true); + this.localMimeTypeDetector = new Mock(); + this.localMimeTypeDetector.Setup(x => x.HeaderSize).Returns(1); + this.localMimeTypeDetector.Setup(x => x.DetectMimeType(It.IsAny>())).Returns("test"); this.localDecoder.Setup(x => x.Decode(It.IsAny(), It.IsAny())) @@ -56,8 +56,8 @@ namespace ImageSharp.Tests { FileSystem = this.fileSystem.Object }; - - this.LocalConfiguration.AddImageFormat(this.localDecoder.Object); + this.LocalConfiguration.AddMimeTypeDetector(this.localMimeTypeDetector.Object); + this.LocalConfiguration.SetMimeTypeDecoder("test", this.localDecoder.Object); TestFormat.RegisterGloablTestFormat(); this.Marker = Guid.NewGuid().ToByteArray(); diff --git a/tests/ImageSharp.Tests/Image/ImageSaveTests.cs b/tests/ImageSharp.Tests/Image/ImageSaveTests.cs index 46177ba5f..e2e0b1364 100644 --- a/tests/ImageSharp.Tests/Image/ImageSaveTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageSaveTests.cs @@ -24,24 +24,26 @@ namespace ImageSharp.Tests private readonly Mock fileSystem; private readonly Mock encoder; private readonly Mock encoderNotInFormat; + private Mock localMimeTypeDetector; public ImageSaveTests() { - this.encoder = new Mock(); - this.encoder.Setup(x => x.MimeTypes).Returns(new[] { "img/test" }); - this.encoder.Setup(x => x.FileExtensions).Returns(new string[] { "png", "jpg" }); + this.localMimeTypeDetector = new Mock(); + this.localMimeTypeDetector.Setup(x => x.HeaderSize).Returns(1); + this.localMimeTypeDetector.Setup(x => x.DetectMimeType(It.IsAny>())).Returns("img/test"); + this.encoder = new Mock(); this.encoderNotInFormat = new Mock(); - this.encoderNotInFormat.Setup(x => x.MimeTypes).Returns(new[] { "img/test" }); - this.encoderNotInFormat.Setup(x => x.FileExtensions).Returns(new string[] { "png", "jpg" }); this.fileSystem = new Mock(); var config = new Configuration() { FileSystem = this.fileSystem.Object }; - config.AddImageFormat(this.encoder.Object); + config.AddMimeTypeDetector(this.localMimeTypeDetector.Object); + config.SetMimeTypeEncoder("img/test", this.encoder.Object); + config.SetFileExtensionEncoder("png", this.encoder.Object); this.Image = new Image(config, 1, 1); } diff --git a/tests/ImageSharp.Tests/TestFormat.cs b/tests/ImageSharp.Tests/TestFormat.cs index 1d06f7328..701b02c09 100644 --- a/tests/ImageSharp.Tests/TestFormat.cs +++ b/tests/ImageSharp.Tests/TestFormat.cs @@ -19,14 +19,13 @@ namespace ImageSharp.Tests /// /// A test image file. /// - public class TestFormat + public class TestFormat : IImageFormatProvider { public static TestFormat GlobalTestFormat { get; } = new TestFormat(); public static void RegisterGloablTestFormat() { - Configuration.Default.AddImageFormat(GlobalTestFormat.Encoder); - Configuration.Default.AddImageFormat(GlobalTestFormat.Decoder); + Configuration.Default.AddImageFormat(GlobalTestFormat); } public TestFormat() @@ -66,7 +65,8 @@ namespace ImageSharp.Tests Assert.True(discovered.Any(), "No calls to decode on this formate with the proveded options happend"); - foreach (DecodeOperation d in discovered) { + foreach (DecodeOperation d in discovered) + { this.DecodeCalls.Remove(d); } } @@ -80,7 +80,7 @@ namespace ImageSharp.Tests { this._sampleImages.Add(typeof(TPixel), new Image(1, 1)); } - + return (Image)this._sampleImages[typeof(TPixel)]; } } @@ -108,12 +108,25 @@ namespace ImageSharp.Tests } return true; } + + public void Configure(IImageFormatHost host) + { + host.AddMimeTypeDetector(new TestHeader(this)); + foreach (var ext in this.SupportedExtensions) + { + host.SetFileExtensionEncoder(ext, new TestEncoder(this)); + } + + host.SetMimeTypeEncoder(this.MimeType, new TestEncoder(this)); + host.SetMimeTypeDecoder(this.MimeType, new TestDecoder(this)); + } + public struct DecodeOperation { public byte[] marker; internal Configuration config; - public bool IsMatch(byte[] testMarker, Configuration config) + public bool IsMatch(byte[] testMarker, Configuration config) { if (this.config != config) @@ -137,6 +150,26 @@ namespace ImageSharp.Tests } } + public class TestHeader : IMimeTypeDetector + { + + private TestFormat testFormat; + + public int HeaderSize => testFormat.HeaderSize; + + public string DetectMimeType(Span header) + { + if (testFormat.IsSupportedFileFormat(header)) + return testFormat.MimeType; + + return null; + } + + public TestHeader(TestFormat testFormat) + { + this.testFormat = testFormat; + } + } public class TestDecoder : ImageSharp.Formats.IImageDecoder { private TestFormat testFormat; diff --git a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs index ee5246660..21b167ca2 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs @@ -124,7 +124,7 @@ namespace ImageSharp.Tests private static IImageEncoder GetImageFormatByExtension(string extension) { extension = extension?.TrimStart('.'); - return Configuration.Default.ImageEncoders.Last(f => f.FileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase)); + return Configuration.Default.FindFileExtensionsEncoder(extension); } private string GetTestOutputDir() From fe61328183d3b075e6a8798a61af694b341d6219 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sat, 24 Jun 2017 10:07:32 +0100 Subject: [PATCH 03/13] fix formats + added sample for switching out encoders/decoders --- ImageSharp.sln | 19 +++++- .../ChangeDefaultEncoderOptions.csproj | 12 ++++ .../ChangeDefaultEncoderOptions/Program.cs | 35 +++++++++++ src/ImageSharp/Configuration.cs | 59 ++++++++++++------- .../Formats/Bmp/BmpImageFormatProvider.cs | 7 ++- src/ImageSharp/Formats/Gif/GifDecoder.cs | 6 ++ src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 12 ++++ src/ImageSharp/Formats/Gif/GifEncoder.cs | 13 ++-- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 21 ++++--- .../Formats/Gif/GifImageFormatProvider.cs | 7 ++- .../Formats/IImageFormatProvider.cs | 4 +- .../Formats/Jpeg/JpegImageFormatProvider.cs | 7 ++- src/ImageSharp/Formats/Png/PngEncoder.cs | 8 +-- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 16 ++--- .../Formats/Png/PngImageFormatProvider.cs | 7 ++- src/ImageSharp/Image/Image.Decode.cs | 9 ++- src/ImageSharp/Image/Image.FromStream.cs | 5 +- src/ImageSharp/Image/Image{TPixel}.cs | 23 ++++++-- .../Image/EncodeIndexedPng.cs | 10 ++-- tests/ImageSharp.Tests/ConfigurationTests.cs | 22 +++---- .../Formats/Gif/GifDecoderTests.cs | 13 ++++ .../Formats/Png/PngSmokeTests.cs | 2 +- .../ImageSharp.Tests/Image/ImageSaveTests.cs | 2 +- tests/ImageSharp.Tests/TestFormat.cs | 2 +- 24 files changed, 234 insertions(+), 87 deletions(-) create mode 100644 samples/ChangeDefaultEncoderOptions/ChangeDefaultEncoderOptions.csproj create mode 100644 samples/ChangeDefaultEncoderOptions/Program.cs diff --git a/ImageSharp.sln b/ImageSharp.sln index 35998e1aa..aa8ec2b45 100644 --- a/ImageSharp.sln +++ b/ImageSharp.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26430.6 +VisualStudioVersion = 15.0.26430.14 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{C317F1B1-D75E-4C6D-83EB-80367343E0D7}" ProjectSection(SolutionItems) = preProject @@ -47,7 +47,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageSharp.Sandbox46", "tes EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{7CC6D57E-B916-43B8-B315-A0BB92F260A2}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AvatarWithRoundedCorner", "samples\AvatarWithRoundedCorner\AvatarWithRoundedCorner.csproj", "{844FC582-4E78-4371-847D-EFD4D1103578}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AvatarWithRoundedCorner", "samples\AvatarWithRoundedCorner\AvatarWithRoundedCorner.csproj", "{844FC582-4E78-4371-847D-EFD4D1103578}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChangeDefaultEncoderOptions", "samples\ChangeDefaultEncoderOptions\ChangeDefaultEncoderOptions.csproj", "{07EE511D-4BAB-4323-BAFC-3AF2BF9366F0}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -143,6 +145,18 @@ Global {844FC582-4E78-4371-847D-EFD4D1103578}.Release|x64.Build.0 = Release|Any CPU {844FC582-4E78-4371-847D-EFD4D1103578}.Release|x86.ActiveCfg = Release|Any CPU {844FC582-4E78-4371-847D-EFD4D1103578}.Release|x86.Build.0 = Release|Any CPU + {07EE511D-4BAB-4323-BAFC-3AF2BF9366F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {07EE511D-4BAB-4323-BAFC-3AF2BF9366F0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {07EE511D-4BAB-4323-BAFC-3AF2BF9366F0}.Debug|x64.ActiveCfg = Debug|Any CPU + {07EE511D-4BAB-4323-BAFC-3AF2BF9366F0}.Debug|x64.Build.0 = Debug|Any CPU + {07EE511D-4BAB-4323-BAFC-3AF2BF9366F0}.Debug|x86.ActiveCfg = Debug|Any CPU + {07EE511D-4BAB-4323-BAFC-3AF2BF9366F0}.Debug|x86.Build.0 = Debug|Any CPU + {07EE511D-4BAB-4323-BAFC-3AF2BF9366F0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {07EE511D-4BAB-4323-BAFC-3AF2BF9366F0}.Release|Any CPU.Build.0 = Release|Any CPU + {07EE511D-4BAB-4323-BAFC-3AF2BF9366F0}.Release|x64.ActiveCfg = Release|Any CPU + {07EE511D-4BAB-4323-BAFC-3AF2BF9366F0}.Release|x64.Build.0 = Release|Any CPU + {07EE511D-4BAB-4323-BAFC-3AF2BF9366F0}.Release|x86.ActiveCfg = Release|Any CPU + {07EE511D-4BAB-4323-BAFC-3AF2BF9366F0}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -156,5 +170,6 @@ Global {2BF743D8-2A06-412D-96D7-F448F00C5EA5} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} {96188137-5FA6-4924-AB6E-4EFF79C6E0BB} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} {844FC582-4E78-4371-847D-EFD4D1103578} = {7CC6D57E-B916-43B8-B315-A0BB92F260A2} + {07EE511D-4BAB-4323-BAFC-3AF2BF9366F0} = {7CC6D57E-B916-43B8-B315-A0BB92F260A2} EndGlobalSection EndGlobal diff --git a/samples/ChangeDefaultEncoderOptions/ChangeDefaultEncoderOptions.csproj b/samples/ChangeDefaultEncoderOptions/ChangeDefaultEncoderOptions.csproj new file mode 100644 index 000000000..5797be0f5 --- /dev/null +++ b/samples/ChangeDefaultEncoderOptions/ChangeDefaultEncoderOptions.csproj @@ -0,0 +1,12 @@ + + + + Exe + netcoreapp1.1 + + + + + + + \ No newline at end of file diff --git a/samples/ChangeDefaultEncoderOptions/Program.cs b/samples/ChangeDefaultEncoderOptions/Program.cs new file mode 100644 index 000000000..5ba6f52b5 --- /dev/null +++ b/samples/ChangeDefaultEncoderOptions/Program.cs @@ -0,0 +1,35 @@ +using System; +using ImageSharp; + +namespace ChangeDefaultEncoderOptions +{ + class Program + { + static void Main(string[] args) + { + // lets switch out the default encoder for jpeg to one + // that saves at 90 quality and ignores the matadata + Configuration.Default.SetMimeTypeEncoder("image/jpeg", new ImageSharp.Formats.JpegEncoder() + { + Quality = 90, + IgnoreMetadata = true + }); + + // now lets say we don't want animated gifs, lets skip decoding the alternative frames + Configuration.Default.SetMimeTypeDecoder("image/gif", new ImageSharp.Formats.GifDecoder() + { + IgnoreFrames = true, + IgnoreMetadata = true + }); + + // and just to be douple sure we don't want animations lets disable them on encode too. + Configuration.Default.SetMimeTypeEncoder("image/gif", new ImageSharp.Formats.GifEncoder() + { + IgnoreFrames = true, + IgnoreMetadata = true + }); + + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs index 43613867e..890a0cbf9 100644 --- a/src/ImageSharp/Configuration.cs +++ b/src/ImageSharp/Configuration.cs @@ -38,7 +38,7 @@ namespace ImageSharp /// /// The list of supported keyed to fiel extensions. /// - private readonly ConcurrentDictionary extensionsEncoders = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private readonly ConcurrentDictionary extensionsMap = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); /// /// The list of supported keyed to mimestypes. @@ -95,17 +95,17 @@ namespace ImageSharp /// /// Gets the typeof of all the current image decoders /// - internal IEnumerable AllMimeImageDecoders => this.mimeTypeDecoders.Select(x => x.Value.GetType()).Distinct().ToList(); + internal IEnumerable> ImageDecoders => this.mimeTypeDecoders; /// /// Gets the typeof of all the current image decoders /// - internal IEnumerable AllMimeImageEncoders => this.mimeTypeEncoders.Select(x => x.Value.GetType()).Distinct().ToList(); + internal IEnumerable> ImageEncoders => this.mimeTypeEncoders; /// /// Gets the typeof of all the current image decoders /// - internal IEnumerable AllExtImageEncoders => this.mimeTypeEncoders.Select(x => x.Value.GetType()).Distinct().ToList(); + internal IEnumerable> ImageExtensionToMimeTypeMapping => this.extensionsMap; #if !NETSTANDARD1_1 /// @@ -133,11 +133,11 @@ namespace ImageSharp } /// - public void SetFileExtensionEncoder(string extension, IImageEncoder encoder) + public void SetFileExtensionToMimeTypeMapping(string extension, string mimetype) { Guard.NotNullOrEmpty(extension, nameof(extension)); - Guard.NotNull(encoder, nameof(encoder)); - this.extensionsEncoders.AddOrUpdate(extension?.Trim(), encoder, (s, e) => encoder); + Guard.NotNullOrEmpty(mimetype, nameof(mimetype)); + this.extensionsMap.AddOrUpdate(extension?.Trim(), mimetype, (s, e) => mimetype); } /// @@ -151,7 +151,7 @@ namespace ImageSharp /// /// Removes all the registerd detectors /// - public void ClearMimeTypeDetector() + public void ClearMimeTypeDetectors() { this.mimeTypeDetectors.Clear(); } @@ -164,12 +164,25 @@ namespace ImageSharp this.SetMaxHeaderSize(); } + /// + /// Creates the default instance, with Png, Jpeg, Gif and Bmp preregisterd (if they have been referenced) + /// + /// The default configuration of + internal static Configuration CreateDefaultInstance() + { + return new Configuration( + new PngImageFormatProvider(), + new JpegImageFormatProvider(), + new GifImageFormatProvider(), + new BmpImageFormatProvider()); + } + /// /// For the specified mimetype find the decoder. /// /// the mimetype to discover /// the IImageDecoder if found othersize null - public IImageDecoder FindMimeTypeDecoder(string mimeType) + internal IImageDecoder FindMimeTypeDecoder(string mimeType) { Guard.NotNullOrEmpty(mimeType, nameof(mimeType)); if (this.mimeTypeDecoders.TryGetValue(mimeType, out IImageDecoder dec)) @@ -185,7 +198,7 @@ namespace ImageSharp /// /// the mimetype to discover /// the IImageEncoder if found othersize null - public IImageEncoder FindMimeTypeEncoder(string mimeType) + internal IImageEncoder FindMimeTypeEncoder(string mimeType) { Guard.NotNullOrEmpty(mimeType, nameof(mimeType)); if (this.mimeTypeEncoders.TryGetValue(mimeType, out IImageEncoder dec)) @@ -201,29 +214,33 @@ namespace ImageSharp /// /// the extensions to discover /// the IImageEncoder if found othersize null - public IImageEncoder FindFileExtensionsEncoder(string extensions) + internal IImageEncoder FindFileExtensionsEncoder(string extensions) { extensions = extensions?.TrimStart('.'); Guard.NotNullOrEmpty(extensions, nameof(extensions)); - if (this.extensionsEncoders.TryGetValue(extensions, out IImageEncoder dec)) + if (this.extensionsMap.TryGetValue(extensions, out string mime)) { - return dec; + return this.FindMimeTypeEncoder(mime); } return null; } /// - /// Creates the default instance, with Png, Jpeg, Gif and Bmp preregisterd (if they have been referenced) + /// For the specified mimetype find the encoder. /// - /// The default configuration of - internal static Configuration CreateDefaultInstance() + /// the extensions to discover + /// the IImageEncoder if found othersize null + internal string FindFileExtensionsMimeType(string extensions) { - return new Configuration( - new PngImageFormatProvider(), - new JpegImageFormatProvider(), - new GifImageFormatProvider(), - new BmpImageFormatProvider()); + extensions = extensions?.TrimStart('.'); + Guard.NotNullOrEmpty(extensions, nameof(extensions)); + if (this.extensionsMap.TryGetValue(extensions, out string mime)) + { + return mime; + } + + return null; } /// diff --git a/src/ImageSharp/Formats/Bmp/BmpImageFormatProvider.cs b/src/ImageSharp/Formats/Bmp/BmpImageFormatProvider.cs index 145e1fdb6..1c4cada76 100644 --- a/src/ImageSharp/Formats/Bmp/BmpImageFormatProvider.cs +++ b/src/ImageSharp/Formats/Bmp/BmpImageFormatProvider.cs @@ -25,9 +25,12 @@ namespace ImageSharp.Formats host.SetMimeTypeEncoder(mimeType, encoder); } - foreach (string mimeType in BmpConstants.FileExtensions) + foreach (string ext in BmpConstants.FileExtensions) { - host.SetFileExtensionEncoder(mimeType, encoder); + foreach (string mimeType in BmpConstants.MimeTypes) + { + host.SetFileExtensionToMimeTypeMapping(ext, mimeType); + } } var decoder = new BmpDecoder(); diff --git a/src/ImageSharp/Formats/Gif/GifDecoder.cs b/src/ImageSharp/Formats/Gif/GifDecoder.cs index c922767b8..caf39c2e1 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoder.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoder.cs @@ -21,6 +21,11 @@ namespace ImageSharp.Formats /// public bool IgnoreMetadata { get; set; } = false; + /// + /// Gets or sets a value indicating whether the additional frames should be ignored when the image is being decoded. + /// + public bool IgnoreFrames { get; set; } = false; + /// /// Gets or sets the encoding that should be used when reading comments. /// @@ -32,6 +37,7 @@ namespace ImageSharp.Formats { var decoder = new GifDecoderCore(this.TextEncoding, configuration); decoder.IgnoreMetadata = this.IgnoreMetadata; + decoder.IgnoreFrames = this.IgnoreFrames; return decoder.Decode(stream); } } diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index 0bd64b057..ad34009b6 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -96,6 +96,11 @@ namespace ImageSharp.Formats /// public Encoding TextEncoding { get; private set; } + /// + /// Gets or sets a value indicating whether the additional frames should be ignored when the image is being decoded. + /// + public bool IgnoreFrames { get; internal set; } + /// /// Decodes the stream to the image. /// @@ -357,6 +362,13 @@ namespace ImageSharp.Formats /// The private unsafe void ReadFrameColors(byte[] indices, byte[] colorTable, int colorTableLength, GifImageDescriptor descriptor) { + if (this.IgnoreFrames && this.image != null) + { + // we already have our images skip this + // TODO move this higher up the stack to prevent some of the data loading higher up. + return; + } + int imageWidth = this.logicalScreenDescriptor.Width; int imageHeight = this.logicalScreenDescriptor.Height; diff --git a/src/ImageSharp/Formats/Gif/GifEncoder.cs b/src/ImageSharp/Formats/Gif/GifEncoder.cs index 3ded88429..eb87000a8 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoder.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoder.cs @@ -22,16 +22,20 @@ namespace ImageSharp.Formats /// public bool IgnoreMetadata { get; set; } = false; + /// + /// Gets or sets a value indicating whether the additional frames should be ignored when the image is being encoded. + /// + public bool IgnoreFrames { get; set; } = false; + /// /// Gets or sets the encoding that should be used when writing comments. /// public Encoding TextEncoding { get; set; } = GifConstants.DefaultEncoding; /// - /// Gets or sets the quality of output for images. + /// Gets or sets the size of the color palette to use. For gifs the value ranges from 1 to 256. Leave as zero for default size. /// - /// For gifs the value ranges from 1 to 256. - public int Quality { get; set; } + public int PaletteSize { get; set; } = 0; /// /// Gets or sets the transparency threshold. @@ -50,8 +54,9 @@ namespace ImageSharp.Formats GifEncoderCore encoder = new GifEncoderCore(this.TextEncoding); encoder.Quantizer = this.Quantizer; encoder.Threshold = this.Threshold; - encoder.Quality = this.Quality; + encoder.PaletteSize = this.PaletteSize; encoder.IgnoreMetadata = this.IgnoreMetadata; + encoder.IgnoreFrames = this.IgnoreFrames; encoder.Encode(image, stream); } } diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index bc7014f19..ccaa9a019 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -62,13 +62,18 @@ namespace ImageSharp.Formats /// /// Gets or sets the quality of output for images. /// - public int Quality { get; internal set; } + public int PaletteSize { get; internal set; } /// /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. /// public bool IgnoreMetadata { get; internal set; } + /// + /// Gets or sets a value indicating whether the additional frames should be ignored when the image is being encoded. + /// + public bool IgnoreFrames { get; internal set; } + /// /// Encodes the image to the specified stream from the . /// @@ -87,20 +92,20 @@ namespace ImageSharp.Formats var writer = new EndianBinaryWriter(Endianness.LittleEndian, stream); // Ensure that quality can be set but has a fallback. - int quality = this.Quality; - quality = quality > 0 ? quality.Clamp(1, 256) : 256; + int paletteSize = this.PaletteSize; + paletteSize = paletteSize > 0 ? paletteSize.Clamp(1, 256) : 256; // Get the number of bits. - this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(quality); + this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(paletteSize); - // Quantize the image returning a palette. - this.hasFrames = image.Frames.Any(); + this.hasFrames = !this.IgnoreFrames && image.Frames.Any(); // Dithering when animating gifs is a bad idea as we introduce pixel tearing across frames. var ditheredQuantizer = (IQuantizer)this.Quantizer; ditheredQuantizer.Dither = !this.hasFrames; - QuantizedImage quantized = ditheredQuantizer.Quantize(image, quality); + // Quantize the image returning a palette. + QuantizedImage quantized = ditheredQuantizer.Quantize(image, paletteSize); int index = this.GetTransparentIndex(quantized); @@ -126,7 +131,7 @@ namespace ImageSharp.Formats for (int i = 0; i < image.Frames.Count; i++) { ImageFrame frame = image.Frames[i]; - QuantizedImage quantizedFrame = ditheredQuantizer.Quantize(frame, quality); + QuantizedImage quantizedFrame = ditheredQuantizer.Quantize(frame, paletteSize); this.WriteGraphicalControlExtension(frame.MetaData, writer, this.GetTransparentIndex(quantizedFrame)); this.WriteImageDescriptor(frame, writer); diff --git a/src/ImageSharp/Formats/Gif/GifImageFormatProvider.cs b/src/ImageSharp/Formats/Gif/GifImageFormatProvider.cs index 7e521353f..54dd29411 100644 --- a/src/ImageSharp/Formats/Gif/GifImageFormatProvider.cs +++ b/src/ImageSharp/Formats/Gif/GifImageFormatProvider.cs @@ -25,9 +25,12 @@ namespace ImageSharp.Formats host.SetMimeTypeEncoder(mimeType, encoder); } - foreach (string mimeType in GifConstants.FileExtensions) + foreach (string ext in GifConstants.FileExtensions) { - host.SetFileExtensionEncoder(mimeType, encoder); + foreach (string mimeType in GifConstants.MimeTypes) + { + host.SetFileExtensionToMimeTypeMapping(ext, mimeType); + } } var decoder = new GifDecoder(); diff --git a/src/ImageSharp/Formats/IImageFormatProvider.cs b/src/ImageSharp/Formats/IImageFormatProvider.cs index c7d354ec6..81f78729b 100644 --- a/src/ImageSharp/Formats/IImageFormatProvider.cs +++ b/src/ImageSharp/Formats/IImageFormatProvider.cs @@ -37,8 +37,8 @@ namespace ImageSharp.Formats /// Sets a specific image encoder as the encoder for a specific mimetype /// /// the target mimetype - /// the encoder to use - void SetFileExtensionEncoder(string extension, IImageEncoder encoder); + /// the mimetype this extenion equates to + void SetFileExtensionToMimeTypeMapping(string extension, string mimetype); /// /// Sets a specific image decoder as the decoder for a specific mimetype diff --git a/src/ImageSharp/Formats/Jpeg/JpegImageFormatProvider.cs b/src/ImageSharp/Formats/Jpeg/JpegImageFormatProvider.cs index 6cd49e20e..ca2d019fe 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegImageFormatProvider.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegImageFormatProvider.cs @@ -25,9 +25,12 @@ namespace ImageSharp.Formats host.SetMimeTypeEncoder(mimeType, pngEncoder); } - foreach (string mimeType in JpegConstants.FileExtensions) + foreach (string ext in JpegConstants.FileExtensions) { - host.SetFileExtensionEncoder(mimeType, pngEncoder); + foreach (string mimeType in JpegConstants.MimeTypes) + { + host.SetFileExtensionToMimeTypeMapping(ext, mimeType); + } } var pngDecoder = new JpegDecoder(); diff --git a/src/ImageSharp/Formats/Png/PngEncoder.cs b/src/ImageSharp/Formats/Png/PngEncoder.cs index d15161ded..954150e8e 100644 --- a/src/ImageSharp/Formats/Png/PngEncoder.cs +++ b/src/ImageSharp/Formats/Png/PngEncoder.cs @@ -17,14 +17,14 @@ namespace ImageSharp.Formats public class PngEncoder : IImageEncoder { /// - /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. + /// Gets or sets a value indicating whether the metadata should be ignored when the image is being encoded. /// public bool IgnoreMetadata { get; set; } /// - /// Gets or sets the quality of output for images. + /// Gets or sets the size of the color palette to use. Set to zero to leav png encoding to use pixel data. /// - public int Quality { get; set; } + public int PaletteSize { get; set; } = 0; /// /// Gets or sets the png color type @@ -74,7 +74,7 @@ namespace ImageSharp.Formats { encode.IgnoreMetadata = this.IgnoreMetadata; - encode.Quality = this.Quality > 0 ? this.Quality.Clamp(1, int.MaxValue) : int.MaxValue; + encode.PaletteSize = this.PaletteSize > 0 ? this.PaletteSize.Clamp(1, int.MaxValue) : int.MaxValue; encode.PngColorType = this.PngColorType; encode.CompressionLevel = this.CompressionLevel; encode.Gamma = this.Gamma; diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index c96d60dbd..c0cd0ffaf 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -133,7 +133,7 @@ namespace ImageSharp.Formats /// /// Gets or sets the Quality value /// - public int Quality { get; internal set; } + public int PaletteSize { get; internal set; } /// /// Gets or sets the Quality value @@ -196,19 +196,19 @@ namespace ImageSharp.Formats this.quantizer = this.Quantizer; // Set correct color type if the color count is 256 or less. - if (this.Quality <= 256) + if (this.PaletteSize <= 256) { this.pngColorType = PngColorType.Palette; } - if (this.pngColorType == PngColorType.Palette && this.Quality > 256) + if (this.pngColorType == PngColorType.Palette && this.PaletteSize > 256) { - this.Quality = 256; + this.PaletteSize = 256; } // Set correct bit depth. - this.bitDepth = this.Quality <= 256 - ? (byte)ImageMaths.GetBitsNeededForColorDepth(this.Quality).Clamp(1, 8) + this.bitDepth = this.PaletteSize <= 256 + ? (byte)ImageMaths.GetBitsNeededForColorDepth(this.PaletteSize).Clamp(1, 8) : (byte)8; // Png only supports in four pixel depths: 1, 2, 4, and 8 bits when using the PLTE chunk @@ -538,7 +538,7 @@ namespace ImageSharp.Formats private QuantizedImage WritePaletteChunk(Stream stream, PngHeader header, ImageBase image) where TPixel : struct, IPixel { - if (this.Quality > 256) + if (this.PaletteSize > 256) { return null; } @@ -549,7 +549,7 @@ namespace ImageSharp.Formats } // Quantize the image returning a palette. This boxing is icky. - QuantizedImage quantized = ((IQuantizer)this.quantizer).Quantize(image, this.Quality); + QuantizedImage quantized = ((IQuantizer)this.quantizer).Quantize(image, this.PaletteSize); // Grab the palette and write it to the stream. TPixel[] palette = quantized.Palette; diff --git a/src/ImageSharp/Formats/Png/PngImageFormatProvider.cs b/src/ImageSharp/Formats/Png/PngImageFormatProvider.cs index 5708cc812..fc5ac4450 100644 --- a/src/ImageSharp/Formats/Png/PngImageFormatProvider.cs +++ b/src/ImageSharp/Formats/Png/PngImageFormatProvider.cs @@ -25,9 +25,12 @@ namespace ImageSharp.Formats host.SetMimeTypeEncoder(mimeType, pngEncoder); } - foreach (string mimeType in PngConstants.FileExtensions) + foreach (string ext in PngConstants.FileExtensions) { - host.SetFileExtensionEncoder(mimeType, pngEncoder); + foreach (string mimeType in PngConstants.MimeTypes) + { + host.SetFileExtensionToMimeTypeMapping(ext, mimeType); + } } var pngDecoder = new PngDecoder(); diff --git a/src/ImageSharp/Image/Image.Decode.cs b/src/ImageSharp/Image/Image.Decode.cs index 96d5df45f..00725d72b 100644 --- a/src/ImageSharp/Image/Image.Decode.cs +++ b/src/ImageSharp/Image/Image.Decode.cs @@ -55,10 +55,13 @@ namespace ImageSharp /// The image format or null if none found. private static IImageDecoder DiscoverDecoder(Stream stream, Configuration config, out string mimeType) { - - format = config.FindMimeTypeDecoder(mimeType); + mimeType = InternalDiscoverMimeType(stream, config); + if (mimeType != null) + { + return config.FindMimeTypeDecoder(mimeType); + } - return format; + return null; } #pragma warning disable SA1008 // Opening parenthesis must be spaced correctly diff --git a/src/ImageSharp/Image/Image.FromStream.cs b/src/ImageSharp/Image/Image.FromStream.cs index 1aa93525c..5bd87b145 100644 --- a/src/ImageSharp/Image/Image.FromStream.cs +++ b/src/ImageSharp/Image/Image.FromStream.cs @@ -6,6 +6,7 @@ namespace ImageSharp { using System; + using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; @@ -202,9 +203,9 @@ namespace ImageSharp var stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Image cannot be loaded. Available decoders:"); - foreach (Type format in config.AllMimeImageDecoders) + foreach (KeyValuePair val in config.ImageDecoders) { - stringBuilder.AppendLine(" - " + format.Name); + stringBuilder.AppendLine($" - {val.Key} : {val.Value.GetType().Name}"); } throw new NotSupportedException(stringBuilder.ToString()); diff --git a/src/ImageSharp/Image/Image{TPixel}.cs b/src/ImageSharp/Image/Image{TPixel}.cs index af9cc3914..d8aff5041 100644 --- a/src/ImageSharp/Image/Image{TPixel}.cs +++ b/src/ImageSharp/Image/Image{TPixel}.cs @@ -165,9 +165,9 @@ namespace ImageSharp var stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Can't find encoder for provided mime type. Available encoded:"); - foreach (Type format in this.Configuration.AllMimeImageEncoders) + foreach (KeyValuePair val in this.Configuration.ImageEncoders) { - stringBuilder.AppendLine(" - " + format); + stringBuilder.AppendLine($" - {val.Key} : {val.Value.GetType().Name}"); } throw new NotSupportedException(stringBuilder.ToString()); @@ -211,11 +211,22 @@ namespace ImageSharp if (encoder == null) { var stringBuilder = new StringBuilder(); - stringBuilder.AppendLine($"Can't find encoder for file extention '{ext}'. Available encoded:"); - - foreach (Type format in this.Configuration.AllExtImageEncoders) + string mime = this.Configuration.FindFileExtensionsMimeType(ext); + if (mime == null) + { + stringBuilder.AppendLine($"Can't find a mime type for the file extention '{ext}'. Registerd File extension maps include:"); + foreach (KeyValuePair map in this.Configuration.ImageExtensionToMimeTypeMapping) + { + stringBuilder.AppendLine($" - {map.Key} : {map.Value}"); + } + } + else { - stringBuilder.AppendLine(" - " + format); + stringBuilder.AppendLine($"Can't find encoder for file extention '{ext}' using mime type '{mime}'. Registerd encoders include:"); + foreach (KeyValuePair enc in this.Configuration.ImageEncoders) + { + stringBuilder.AppendLine($" - {enc.Key} : {enc.Value.GetType().Name}"); + } } throw new NotSupportedException(stringBuilder.ToString()); diff --git a/tests/ImageSharp.Benchmarks/Image/EncodeIndexedPng.cs b/tests/ImageSharp.Benchmarks/Image/EncodeIndexedPng.cs index aa3112f52..02e3211a7 100644 --- a/tests/ImageSharp.Benchmarks/Image/EncodeIndexedPng.cs +++ b/tests/ImageSharp.Benchmarks/Image/EncodeIndexedPng.cs @@ -53,7 +53,7 @@ namespace ImageSharp.Benchmarks.Image { using (MemoryStream memoryStream = new MemoryStream()) { - PngEncoder encoder = new PngEncoder() { Quantizer = new OctreeQuantizer(), Quality = 256 }; + PngEncoder encoder = new PngEncoder() { Quantizer = new OctreeQuantizer(), PaletteSize = 256 }; this.bmpCore.SaveAsPng(memoryStream, encoder); } @@ -64,7 +64,7 @@ namespace ImageSharp.Benchmarks.Image { using (MemoryStream memoryStream = new MemoryStream()) { - PngEncoder options = new PngEncoder { Quantizer = new OctreeQuantizer { Dither = false }, Quality = 256 }; + PngEncoder options = new PngEncoder { Quantizer = new OctreeQuantizer { Dither = false }, PaletteSize = 256 }; this.bmpCore.SaveAsPng(memoryStream, options); } @@ -75,7 +75,7 @@ namespace ImageSharp.Benchmarks.Image { using (MemoryStream memoryStream = new MemoryStream()) { - PngEncoder options = new PngEncoder { Quantizer = new PaletteQuantizer(), Quality = 256 }; + PngEncoder options = new PngEncoder { Quantizer = new PaletteQuantizer(), PaletteSize = 256 }; this.bmpCore.SaveAsPng(memoryStream, options); } @@ -86,7 +86,7 @@ namespace ImageSharp.Benchmarks.Image { using (MemoryStream memoryStream = new MemoryStream()) { - PngEncoder options = new PngEncoder { Quantizer = new PaletteQuantizer { Dither = false }, Quality = 256 }; + PngEncoder options = new PngEncoder { Quantizer = new PaletteQuantizer { Dither = false }, PaletteSize = 256 }; this.bmpCore.SaveAsPng(memoryStream, options); } @@ -97,7 +97,7 @@ namespace ImageSharp.Benchmarks.Image { using (MemoryStream memoryStream = new MemoryStream()) { - PngEncoder options = new PngEncoder() { Quantizer = new WuQuantizer(), Quality = 256 }; + PngEncoder options = new PngEncoder() { Quantizer = new WuQuantizer(), PaletteSize = 256 }; this.bmpCore.SaveAsPng(memoryStream, options); } diff --git a/tests/ImageSharp.Tests/ConfigurationTests.cs b/tests/ImageSharp.Tests/ConfigurationTests.cs index e8927c75c..64b96168a 100644 --- a/tests/ImageSharp.Tests/ConfigurationTests.cs +++ b/tests/ImageSharp.Tests/ConfigurationTests.cs @@ -40,8 +40,8 @@ namespace ImageSharp.Tests [Fact] public void IfAutoloadWellknwonFormatesIsTrueAllFormateAreLoaded() { - Assert.Equal(4, DefaultConfiguration.AllMimeImageDecoders.Count()); - Assert.Equal(4, DefaultConfiguration.AllMimeImageDecoders.Count()); + Assert.Equal(6, DefaultConfiguration.ImageEncoders.Count()); + Assert.Equal(6, DefaultConfiguration.ImageDecoders.Count()); } /// @@ -103,15 +103,15 @@ namespace ImageSharp.Tests { Assert.Throws(() => { - DefaultConfiguration.SetFileExtensionEncoder(null, new Mock().Object); + DefaultConfiguration.SetFileExtensionToMimeTypeMapping(null, "str"); }); Assert.Throws(() => { - DefaultConfiguration.SetFileExtensionEncoder("sdsdsd", null); + DefaultConfiguration.SetFileExtensionToMimeTypeMapping("sdsdsd", null); }); Assert.Throws(() => { - DefaultConfiguration.SetFileExtensionEncoder(null, null); + DefaultConfiguration.SetFileExtensionToMimeTypeMapping(null, null); }); } @@ -150,14 +150,14 @@ namespace ImageSharp.Tests [Fact] public void RegisterFileExtEnecoderReplacesLast() { - var encoder1 = new Mock().Object; - ConfigurationEmpty.SetFileExtensionEncoder("TEST", encoder1); - var found = ConfigurationEmpty.FindFileExtensionsEncoder("test"); + var encoder1 = "mime1"; + ConfigurationEmpty.SetFileExtensionToMimeTypeMapping("TEST", encoder1); + var found = ConfigurationEmpty.FindFileExtensionsMimeType("test"); Assert.Equal(encoder1, found); - var encoder2 = new Mock().Object; - ConfigurationEmpty.SetFileExtensionEncoder("test", encoder2); - var found2 = ConfigurationEmpty.FindFileExtensionsEncoder("TEST"); + var encoder2 = "mime2"; + ConfigurationEmpty.SetFileExtensionToMimeTypeMapping("test", encoder2); + var found2 = ConfigurationEmpty.FindFileExtensionsMimeType("TEST"); Assert.Equal(encoder2, found2); Assert.NotEqual(found, found2); } diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs index 06bfd8990..cc7935fbf 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs @@ -18,6 +18,19 @@ namespace ImageSharp.Tests public static readonly string[] TestFiles = { TestImages.Gif.Giphy, TestImages.Gif.Rings, TestImages.Gif.Trans }; + [Fact] + public void SkipDecodingFrames() + { + var file = TestFile.GetPath(TestImages.Gif.Giphy); + + using (Image image = Image.Load(file, new GifDecoder() { IgnoreFrames = true })) + using (Image imageWithFrames = Image.Load(file, new GifDecoder() { IgnoreFrames = false })) + { + Assert.NotEmpty(imageWithFrames.Frames); + Assert.Empty(image.Frames); + } + } + [Theory] [WithFileCollection(nameof(TestFiles), PixelTypes)] public void DecodeAndReSave(TestImageProvider imageProvider) diff --git a/tests/ImageSharp.Tests/Formats/Png/PngSmokeTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngSmokeTests.cs index bb7824914..bac340a71 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngSmokeTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngSmokeTests.cs @@ -50,7 +50,7 @@ namespace ImageSharp.Tests.Formats.Png using (MemoryStream ms = new MemoryStream()) { // image.Save(provider.Utility.GetTestOutputFileName("bmp")); - image.Save(ms, new PngEncoder() { Quality = 256 }); + image.Save(ms, new PngEncoder() { PaletteSize = 256 }); ms.Position = 0; using (Image img2 = Image.Load(ms, new PngDecoder())) { diff --git a/tests/ImageSharp.Tests/Image/ImageSaveTests.cs b/tests/ImageSharp.Tests/Image/ImageSaveTests.cs index e2e0b1364..72461cfc7 100644 --- a/tests/ImageSharp.Tests/Image/ImageSaveTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageSaveTests.cs @@ -43,7 +43,7 @@ namespace ImageSharp.Tests }; config.AddMimeTypeDetector(this.localMimeTypeDetector.Object); config.SetMimeTypeEncoder("img/test", this.encoder.Object); - config.SetFileExtensionEncoder("png", this.encoder.Object); + config.SetFileExtensionToMimeTypeMapping("png", "img/test"); this.Image = new Image(config, 1, 1); } diff --git a/tests/ImageSharp.Tests/TestFormat.cs b/tests/ImageSharp.Tests/TestFormat.cs index 701b02c09..85e11ee87 100644 --- a/tests/ImageSharp.Tests/TestFormat.cs +++ b/tests/ImageSharp.Tests/TestFormat.cs @@ -114,7 +114,7 @@ namespace ImageSharp.Tests host.AddMimeTypeDetector(new TestHeader(this)); foreach (var ext in this.SupportedExtensions) { - host.SetFileExtensionEncoder(ext, new TestEncoder(this)); + host.SetFileExtensionToMimeTypeMapping(ext, this.MimeType); } host.SetMimeTypeEncoder(this.MimeType, new TestEncoder(this)); From 8cd195cb34d6eddac22daa9d3c508fee25ea2692 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sat, 24 Jun 2017 12:15:42 +0100 Subject: [PATCH 04/13] discover types tests --- .../Image/ImageDiscoverMimeType.cs | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 tests/ImageSharp.Tests/Image/ImageDiscoverMimeType.cs diff --git a/tests/ImageSharp.Tests/Image/ImageDiscoverMimeType.cs b/tests/ImageSharp.Tests/Image/ImageDiscoverMimeType.cs new file mode 100644 index 000000000..80414662b --- /dev/null +++ b/tests/ImageSharp.Tests/Image/ImageDiscoverMimeType.cs @@ -0,0 +1,107 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Tests +{ + using System; + using System.IO; + + using ImageSharp.Formats; + using ImageSharp.IO; + using ImageSharp.PixelFormats; + using Moq; + using Xunit; + + /// + /// Tests the class. + /// + public class DiscoverMimeTypeTests + { + private readonly Mock fileSystem; + private readonly string FilePath; + private readonly Mock localMimeTypeDetector; + + public Configuration LocalConfiguration { get; private set; } + public byte[] Marker { get; private set; } + public MemoryStream DataStream { get; private set; } + public byte[] DecodedData { get; private set; } + private const string localMimeType = "image/local"; + + public DiscoverMimeTypeTests() + { + this.localMimeTypeDetector = new Mock(); + this.localMimeTypeDetector.Setup(x => x.HeaderSize).Returns(1); + this.localMimeTypeDetector.Setup(x => x.DetectMimeType(It.IsAny>())).Returns(localMimeType); + + this.fileSystem = new Mock(); + + this.LocalConfiguration = new Configuration() + { + FileSystem = this.fileSystem.Object + }; + this.LocalConfiguration.AddMimeTypeDetector(this.localMimeTypeDetector.Object); + + TestFormat.RegisterGloablTestFormat(); + this.Marker = Guid.NewGuid().ToByteArray(); + this.DataStream = TestFormat.GlobalTestFormat.CreateStream(this.Marker); + + this.FilePath = Guid.NewGuid().ToString(); + this.fileSystem.Setup(x => x.OpenRead(this.FilePath)).Returns(this.DataStream); + + TestFileSystem.RegisterGloablTestFormat(); + TestFileSystem.Global.AddFile(this.FilePath, this.DataStream); + } + + [Fact] + public void DiscoverMimeTypeByteArray() + { + var type = Image.DiscoverMimeType(DataStream.ToArray()); + Assert.Equal(TestFormat.GlobalTestFormat.MimeType, type); + } + + [Fact] + public void DiscoverMimeTypeByteArray_WithConfig() + { + var type = Image.DiscoverMimeType(this.LocalConfiguration, DataStream.ToArray()); + Assert.Equal(localMimeType, type); + } + + [Fact] + public void DiscoverMimeTypeFile() + { + var type = Image.DiscoverMimeType(this.FilePath); + Assert.Equal(TestFormat.GlobalTestFormat.MimeType, type); + } + + [Fact] + public void DiscoverMimeTypeFilePath_WithConfig() + { + var type = Image.DiscoverMimeType(this.LocalConfiguration, FilePath); + Assert.Equal(localMimeType, type); + } + + + [Fact] + public void DiscoverMimeTypeStream() + { + var type = Image.DiscoverMimeType(this.DataStream); + Assert.Equal(TestFormat.GlobalTestFormat.MimeType, type); + } + + [Fact] + public void DiscoverMimeTypeFileStream_WithConfig() + { + var type = Image.DiscoverMimeType(this.LocalConfiguration, DataStream); + Assert.Equal(localMimeType, type); + } + + [Fact] + public void DiscoverMimeTypeNoDetectorsRegisterdShouldReturnNull() + { + var type = Image.DiscoverMimeType(new Configuration(), DataStream); + Assert.Null(type); + } + } +} From fbed11bb78ac6b235023fc4d93dbdda59d617a09 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sat, 24 Jun 2017 13:47:17 +0100 Subject: [PATCH 05/13] fix comments --- src/ImageSharp/Formats/Bmp/BmpConstants.cs | 2 +- src/ImageSharp/Formats/Gif/GifConstants.cs | 2 +- src/ImageSharp/Formats/Jpeg/JpegConstants.cs | 2 +- src/ImageSharp/Formats/Png/PngConstants.cs | 2 +- tests/ImageSharp.Tests/ConfigurationTests.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpConstants.cs b/src/ImageSharp/Formats/Bmp/BmpConstants.cs index f2454f24d..43b6dd900 100644 --- a/src/ImageSharp/Formats/Bmp/BmpConstants.cs +++ b/src/ImageSharp/Formats/Bmp/BmpConstants.cs @@ -18,7 +18,7 @@ namespace ImageSharp.Formats public static readonly IEnumerable MimeTypes = new[] { "image/bmp", "image/x-windows-bmp" }; /// - /// The list of mimetypes that equate to a bmp + /// The list of file extensions that equate to a bmp /// public static readonly IEnumerable FileExtensions = new[] { "bm", "bmp", "dip" }; } diff --git a/src/ImageSharp/Formats/Gif/GifConstants.cs b/src/ImageSharp/Formats/Gif/GifConstants.cs index 5c4d806d7..e4d3be3d6 100644 --- a/src/ImageSharp/Formats/Gif/GifConstants.cs +++ b/src/ImageSharp/Formats/Gif/GifConstants.cs @@ -99,7 +99,7 @@ namespace ImageSharp.Formats public static readonly IEnumerable MimeTypes = new[] { "image/gif" }; /// - /// The list of mimetypes that equate to a bmp + /// The list of file extensions that equate to a bmp /// public static readonly IEnumerable FileExtensions = new[] { "gif" }; } diff --git a/src/ImageSharp/Formats/Jpeg/JpegConstants.cs b/src/ImageSharp/Formats/Jpeg/JpegConstants.cs index 959813611..27ba4190e 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegConstants.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegConstants.cs @@ -23,7 +23,7 @@ namespace ImageSharp.Formats public static readonly IEnumerable MimeTypes = new[] { "image/jpeg", "image/pjpeg" }; /// - /// The list of mimetypes that equate to a jpeg + /// The list of file extensions that equate to a jpeg /// public static readonly IEnumerable FileExtensions = new[] { "jpg", "jpeg", "jfif" }; diff --git a/src/ImageSharp/Formats/Png/PngConstants.cs b/src/ImageSharp/Formats/Png/PngConstants.cs index b44ab7663..8528e93ee 100644 --- a/src/ImageSharp/Formats/Png/PngConstants.cs +++ b/src/ImageSharp/Formats/Png/PngConstants.cs @@ -23,7 +23,7 @@ namespace ImageSharp.Formats public static readonly IEnumerable MimeTypes = new[] { "image/png" }; /// - /// The list of mimetypes that equate to a jpeg + /// The list of file extensions that equate to a jpeg /// public static readonly IEnumerable FileExtensions = new[] { "png" }; } diff --git a/tests/ImageSharp.Tests/ConfigurationTests.cs b/tests/ImageSharp.Tests/ConfigurationTests.cs index 64b96168a..aa09cf816 100644 --- a/tests/ImageSharp.Tests/ConfigurationTests.cs +++ b/tests/ImageSharp.Tests/ConfigurationTests.cs @@ -27,7 +27,7 @@ namespace ImageSharp.Tests public ConfigurationTests() { this.DefaultConfiguration = Configuration.CreateDefaultInstance(); - this.ConfigurationEmpty = Configuration.CreateDefaultInstance(); + this.ConfigurationEmpty = new Configuration(); } [Fact] From f8f1305076a14da3dbd6cd0dc3aea3b97efb34ce Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sat, 24 Jun 2017 14:01:27 +0100 Subject: [PATCH 06/13] update comment --- src/ImageSharp/Formats/IImageFormatProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/IImageFormatProvider.cs b/src/ImageSharp/Formats/IImageFormatProvider.cs index 81f78729b..34e90e2f6 100644 --- a/src/ImageSharp/Formats/IImageFormatProvider.cs +++ b/src/ImageSharp/Formats/IImageFormatProvider.cs @@ -34,7 +34,7 @@ namespace ImageSharp.Formats void SetMimeTypeEncoder(string mimeType, IImageEncoder encoder); // could/should this be an Action??? /// - /// Sets a specific image encoder as the encoder for a specific mimetype + /// Sets a mapping value between a file extension and a mimetype /// /// the target mimetype /// the mimetype this extenion equates to From 6d4e4f2f23e5b67653eb2cf6f774aeefd9ef56b0 Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Sun, 25 Jun 2017 12:08:40 +0200 Subject: [PATCH 07/13] Various comment fixes and some variable renames. --- src/ImageSharp/Configuration.cs | 72 ++++++++++--------- src/ImageSharp/Formats/Bmp/BmpConstants.cs | 4 +- src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs | 2 +- .../Formats/Bmp/BmpImageFormatProvider.cs | 2 +- src/ImageSharp/Formats/Gif/GifConstants.cs | 4 +- src/ImageSharp/Formats/Gif/GifEncoder.cs | 2 +- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 4 +- .../Formats/Gif/GifImageFormatProvider.cs | 2 +- .../Formats/IImageFormatProvider.cs | 24 +++---- src/ImageSharp/Formats/Jpeg/JpegConstants.cs | 4 +- .../Formats/Jpeg/JpegImageFormatProvider.cs | 2 +- src/ImageSharp/Formats/Png/PngConstants.cs | 6 +- src/ImageSharp/Formats/Png/PngEncoder.cs | 20 +++--- .../Formats/Png/PngImageFormatProvider.cs | 2 +- src/ImageSharp/Image/Image.Decode.cs | 2 +- src/ImageSharp/Image/Image.FromBytes.cs | 36 +++++----- src/ImageSharp/Image/Image.FromFile.cs | 28 ++++---- src/ImageSharp/Image/Image.FromStream.cs | 16 ++--- src/ImageSharp/Image/Image{TPixel}.cs | 4 +- 19 files changed, 120 insertions(+), 116 deletions(-) diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs index 890a0cbf9..f48aefbcd 100644 --- a/src/ImageSharp/Configuration.cs +++ b/src/ImageSharp/Configuration.cs @@ -31,17 +31,17 @@ namespace ImageSharp private readonly object syncRoot = new object(); /// - /// The list of supported keyed to mimestypes. + /// The list of supported keyed to mime types. /// private readonly ConcurrentDictionary mimeTypeEncoders = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); /// - /// The list of supported keyed to fiel extensions. + /// The list of supported mime types keyed to file extensions. /// private readonly ConcurrentDictionary extensionsMap = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); /// - /// The list of supported keyed to mimestypes. + /// The list of supported keyed to mime types. /// private readonly ConcurrentDictionary mimeTypeDecoders = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); @@ -83,27 +83,27 @@ namespace ImageSharp public ParallelOptions ParallelOptions { get; } = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }; /// - /// Gets the maximum header size of all formats. + /// Gets the maximum header size of all the formats. /// internal int MaxHeaderSize { get; private set; } /// - /// Gets the currently registerd s. + /// Gets the currently registered s. /// internal IEnumerable MimeTypeDetectors => this.mimeTypeDetectors; /// - /// Gets the typeof of all the current image decoders + /// Gets the currently registered s. /// internal IEnumerable> ImageDecoders => this.mimeTypeDecoders; /// - /// Gets the typeof of all the current image decoders + /// Gets the currently registered s. /// internal IEnumerable> ImageEncoders => this.mimeTypeEncoders; /// - /// Gets the typeof of all the current image decoders + /// Gets the currently registered file extensions. /// internal IEnumerable> ImageExtensionToMimeTypeMapping => this.extensionsMap; @@ -133,11 +133,11 @@ namespace ImageSharp } /// - public void SetFileExtensionToMimeTypeMapping(string extension, string mimetype) + public void SetFileExtensionToMimeTypeMapping(string extension, string mimeType) { Guard.NotNullOrEmpty(extension, nameof(extension)); - Guard.NotNullOrEmpty(mimetype, nameof(mimetype)); - this.extensionsMap.AddOrUpdate(extension?.Trim(), mimetype, (s, e) => mimetype); + Guard.NotNullOrEmpty(mimeType, nameof(mimeType)); + this.extensionsMap.AddOrUpdate(extension?.Trim(), mimeType, (s, e) => mimeType); } /// @@ -149,7 +149,7 @@ namespace ImageSharp } /// - /// Removes all the registerd detectors + /// Removes all the registered mime type detectors. /// public void ClearMimeTypeDetectors() { @@ -165,9 +165,13 @@ namespace ImageSharp } /// - /// Creates the default instance, with Png, Jpeg, Gif and Bmp preregisterd (if they have been referenced) + /// Creates the default instance with the following s preregistered: + /// + /// + /// + /// /// - /// The default configuration of + /// The default configuration of internal static Configuration CreateDefaultInstance() { return new Configuration( @@ -178,73 +182,73 @@ namespace ImageSharp } /// - /// For the specified mimetype find the decoder. + /// For the specified mime type find the decoder. /// - /// the mimetype to discover - /// the IImageDecoder if found othersize null + /// The mime type to discover + /// The if found otherwise null internal IImageDecoder FindMimeTypeDecoder(string mimeType) { Guard.NotNullOrEmpty(mimeType, nameof(mimeType)); - if (this.mimeTypeDecoders.TryGetValue(mimeType, out IImageDecoder dec)) + if (this.mimeTypeDecoders.TryGetValue(mimeType, out IImageDecoder decoder)) { - return dec; + return decoder; } return null; } /// - /// For the specified mimetype find the encoder. + /// For the specified mime type find the encoder. /// - /// the mimetype to discover - /// the IImageEncoder if found othersize null + /// The mime type to discover + /// The if found otherwise null internal IImageEncoder FindMimeTypeEncoder(string mimeType) { Guard.NotNullOrEmpty(mimeType, nameof(mimeType)); - if (this.mimeTypeEncoders.TryGetValue(mimeType, out IImageEncoder dec)) + if (this.mimeTypeEncoders.TryGetValue(mimeType, out IImageEncoder encoder)) { - return dec; + return encoder; } return null; } /// - /// For the specified mimetype find the encoder. + /// For the specified mime type find the encoder. /// - /// the extensions to discover - /// the IImageEncoder if found othersize null + /// The extensions to discover + /// The if found otherwise null internal IImageEncoder FindFileExtensionsEncoder(string extensions) { extensions = extensions?.TrimStart('.'); Guard.NotNullOrEmpty(extensions, nameof(extensions)); - if (this.extensionsMap.TryGetValue(extensions, out string mime)) + if (this.extensionsMap.TryGetValue(extensions, out string mimeType)) { - return this.FindMimeTypeEncoder(mime); + return this.FindMimeTypeEncoder(mimeType); } return null; } /// - /// For the specified mimetype find the encoder. + /// For the specified extension find the mime type. /// /// the extensions to discover - /// the IImageEncoder if found othersize null + /// The mime type if found otherwise null internal string FindFileExtensionsMimeType(string extensions) { extensions = extensions?.TrimStart('.'); Guard.NotNullOrEmpty(extensions, nameof(extensions)); - if (this.extensionsMap.TryGetValue(extensions, out string mime)) + if (this.extensionsMap.TryGetValue(extensions, out string mimeType)) { - return mime; + return mimeType; } return null; } /// - /// Sets max header size. + /// Sets the max header size. /// private void SetMaxHeaderSize() { diff --git a/src/ImageSharp/Formats/Bmp/BmpConstants.cs b/src/ImageSharp/Formats/Bmp/BmpConstants.cs index 43b6dd900..d394b61f6 100644 --- a/src/ImageSharp/Formats/Bmp/BmpConstants.cs +++ b/src/ImageSharp/Formats/Bmp/BmpConstants.cs @@ -13,12 +13,12 @@ namespace ImageSharp.Formats internal static class BmpConstants { /// - /// The list of mimetypes that equate to a bmp + /// The list of mimetypes that equate to a bmp. /// public static readonly IEnumerable MimeTypes = new[] { "image/bmp", "image/x-windows-bmp" }; /// - /// The list of file extensions that equate to a bmp + /// The list of file extensions that equate to a bmp. /// public static readonly IEnumerable FileExtensions = new[] { "bm", "bmp", "dip" }; } diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index 615ff23ee..daff65cbc 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -30,7 +30,7 @@ namespace ImageSharp.Formats } /// - /// Gets or sets the BitsPerPixel + /// Gets or sets the number of bits per pixel. /// public BmpBitsPerPixel BitsPerPixel { get; internal set; } = BmpBitsPerPixel.Pixel24; diff --git a/src/ImageSharp/Formats/Bmp/BmpImageFormatProvider.cs b/src/ImageSharp/Formats/Bmp/BmpImageFormatProvider.cs index 1c4cada76..b532ccfb5 100644 --- a/src/ImageSharp/Formats/Bmp/BmpImageFormatProvider.cs +++ b/src/ImageSharp/Formats/Bmp/BmpImageFormatProvider.cs @@ -12,7 +12,7 @@ namespace ImageSharp.Formats using ImageSharp.PixelFormats; /// - /// Detects gif file headers + /// Registers the image encoders, decoders and mime type detectors for the bmp format. /// public class BmpImageFormatProvider : IImageFormatProvider { diff --git a/src/ImageSharp/Formats/Gif/GifConstants.cs b/src/ImageSharp/Formats/Gif/GifConstants.cs index e4d3be3d6..7b215b773 100644 --- a/src/ImageSharp/Formats/Gif/GifConstants.cs +++ b/src/ImageSharp/Formats/Gif/GifConstants.cs @@ -94,12 +94,12 @@ namespace ImageSharp.Formats public static readonly Encoding DefaultEncoding = Encoding.GetEncoding("ASCII"); /// - /// The list of mimetypes that equate to a bmp + /// The list of mimetypes that equate to a gif. /// public static readonly IEnumerable MimeTypes = new[] { "image/gif" }; /// - /// The list of file extensions that equate to a bmp + /// The list of file extensions that equate to a gif. /// public static readonly IEnumerable FileExtensions = new[] { "gif" }; } diff --git a/src/ImageSharp/Formats/Gif/GifEncoder.cs b/src/ImageSharp/Formats/Gif/GifEncoder.cs index eb87000a8..ee78c3266 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoder.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoder.cs @@ -33,7 +33,7 @@ namespace ImageSharp.Formats public Encoding TextEncoding { get; set; } = GifConstants.DefaultEncoding; /// - /// Gets or sets the size of the color palette to use. For gifs the value ranges from 1 to 256. Leave as zero for default size. + /// Gets or sets the size of the color palette to use. For gifs the value ranges from 1 to 256. Leave as zero for default size. /// public int PaletteSize { get; set; } = 0; diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index ccaa9a019..3191aafc9 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -60,7 +60,7 @@ namespace ImageSharp.Formats public byte Threshold { get; internal set; } /// - /// Gets or sets the quality of output for images. + /// Gets or sets the size of the color palette to use. /// public int PaletteSize { get; internal set; } @@ -91,7 +91,7 @@ namespace ImageSharp.Formats // Do not use IDisposable pattern here as we want to preserve the stream. var writer = new EndianBinaryWriter(Endianness.LittleEndian, stream); - // Ensure that quality can be set but has a fallback. + // Ensure that pallete size can be set but has a fallback. int paletteSize = this.PaletteSize; paletteSize = paletteSize > 0 ? paletteSize.Clamp(1, 256) : 256; diff --git a/src/ImageSharp/Formats/Gif/GifImageFormatProvider.cs b/src/ImageSharp/Formats/Gif/GifImageFormatProvider.cs index 54dd29411..7e16bff72 100644 --- a/src/ImageSharp/Formats/Gif/GifImageFormatProvider.cs +++ b/src/ImageSharp/Formats/Gif/GifImageFormatProvider.cs @@ -12,7 +12,7 @@ namespace ImageSharp.Formats using ImageSharp.PixelFormats; /// - /// Detects gif file headers + /// Registers the image encoders, decoders and mime type detectors for the gif format. /// public class GifImageFormatProvider : IImageFormatProvider { diff --git a/src/ImageSharp/Formats/IImageFormatProvider.cs b/src/ImageSharp/Formats/IImageFormatProvider.cs index 34e90e2f6..1e5ea7f93 100644 --- a/src/ImageSharp/Formats/IImageFormatProvider.cs +++ b/src/ImageSharp/Formats/IImageFormatProvider.cs @@ -10,47 +10,47 @@ namespace ImageSharp.Formats using System.Text; /// - /// Represents an abstract class that can register image encoders, decoders and mime type detectors + /// Represents an interface that can register image encoders, decoders and mime type detectors. /// public interface IImageFormatProvider { /// - /// Called when loaded so the provider and register its encoders, decodes and mime type detectors into an IImageFormatHost. + /// Called when loaded so the provider and register its encoders, decoders and mime type detectors into an IImageFormatHost. /// /// The host that will retain the encoders, decodes and mime type detectors. void Configure(IImageFormatHost host); } /// - /// Represents an abstract class that can have encoders decoders and mimetype detecotrs loaded into. + /// Represents an interface that can have encoders, decoders and mime type detectors loaded into. /// public interface IImageFormatHost { /// - /// Sets a specific image encoder as the encoder for a specific mimetype + /// Sets a specific image encoder as the encoder for a specific mime type. /// /// the target mimetype /// the encoder to use void SetMimeTypeEncoder(string mimeType, IImageEncoder encoder); // could/should this be an Action??? /// - /// Sets a mapping value between a file extension and a mimetype + /// Sets a mapping value between a file extension and a mime type. /// - /// the target mimetype - /// the mimetype this extenion equates to + /// The target mime type + /// The mime type this extension equates to void SetFileExtensionToMimeTypeMapping(string extension, string mimetype); /// - /// Sets a specific image decoder as the decoder for a specific mimetype + /// Sets a specific image decoder as the decoder for a specific mime type. /// - /// the target mimetype - /// the decoder to use + /// The target mime type + /// The decoder to use void SetMimeTypeDecoder(string mimeType, IImageDecoder decoder); /// - /// Adds a new detector for detecting in mime types + /// Adds a new detector for detecting mime types. /// - /// The detector + /// The detector to add void AddMimeTypeDetector(IMimeTypeDetector detector); } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegConstants.cs b/src/ImageSharp/Formats/Jpeg/JpegConstants.cs index 27ba4190e..99c0399dc 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegConstants.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegConstants.cs @@ -18,12 +18,12 @@ namespace ImageSharp.Formats public const ushort MaxLength = 65535; /// - /// The list of mimetypes that equate to a jpeg + /// The list of mimetypes that equate to a jpeg. /// public static readonly IEnumerable MimeTypes = new[] { "image/jpeg", "image/pjpeg" }; /// - /// The list of file extensions that equate to a jpeg + /// The list of file extensions that equate to a jpeg. /// public static readonly IEnumerable FileExtensions = new[] { "jpg", "jpeg", "jfif" }; diff --git a/src/ImageSharp/Formats/Jpeg/JpegImageFormatProvider.cs b/src/ImageSharp/Formats/Jpeg/JpegImageFormatProvider.cs index ca2d019fe..5eefa5db1 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegImageFormatProvider.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegImageFormatProvider.cs @@ -12,7 +12,7 @@ namespace ImageSharp.Formats using ImageSharp.PixelFormats; /// - /// Detects png file headers + /// Registers the image encoders, decoders and mime type detectors for the jpeg format. /// public class JpegImageFormatProvider : IImageFormatProvider { diff --git a/src/ImageSharp/Formats/Png/PngConstants.cs b/src/ImageSharp/Formats/Png/PngConstants.cs index 8528e93ee..8c10ad960 100644 --- a/src/ImageSharp/Formats/Png/PngConstants.cs +++ b/src/ImageSharp/Formats/Png/PngConstants.cs @@ -13,17 +13,17 @@ namespace ImageSharp.Formats internal static class PngConstants { /// - /// The default encoding for text metadata + /// The default encoding for text metadata. /// public static readonly Encoding DefaultEncoding = Encoding.GetEncoding("ASCII"); /// - /// The list of mimetypes that equate to a jpeg + /// The list of mimetypes that equate to a png. /// public static readonly IEnumerable MimeTypes = new[] { "image/png" }; /// - /// The list of file extensions that equate to a jpeg + /// The list of file extensions that equate to a png. /// public static readonly IEnumerable FileExtensions = new[] { "png" }; } diff --git a/src/ImageSharp/Formats/Png/PngEncoder.cs b/src/ImageSharp/Formats/Png/PngEncoder.cs index 954150e8e..8d5b09d0c 100644 --- a/src/ImageSharp/Formats/Png/PngEncoder.cs +++ b/src/ImageSharp/Formats/Png/PngEncoder.cs @@ -70,19 +70,19 @@ namespace ImageSharp.Formats public void Encode(Image image, Stream stream) where TPixel : struct, IPixel { - using (var encode = new PngEncoderCore()) + using (var encoder = new PngEncoderCore()) { - encode.IgnoreMetadata = this.IgnoreMetadata; + encoder.IgnoreMetadata = this.IgnoreMetadata; - encode.PaletteSize = this.PaletteSize > 0 ? this.PaletteSize.Clamp(1, int.MaxValue) : int.MaxValue; - encode.PngColorType = this.PngColorType; - encode.CompressionLevel = this.CompressionLevel; - encode.Gamma = this.Gamma; - encode.Quantizer = this.Quantizer; - encode.Threshold = this.Threshold; - encode.WriteGamma = this.WriteGamma; + encoder.PaletteSize = this.PaletteSize > 0 ? this.PaletteSize.Clamp(1, int.MaxValue) : int.MaxValue; + encoder.PngColorType = this.PngColorType; + encoder.CompressionLevel = this.CompressionLevel; + encoder.Gamma = this.Gamma; + encoder.Quantizer = this.Quantizer; + encoder.Threshold = this.Threshold; + encoder.WriteGamma = this.WriteGamma; - encode.Encode(image, stream); + encoder.Encode(image, stream); } } } diff --git a/src/ImageSharp/Formats/Png/PngImageFormatProvider.cs b/src/ImageSharp/Formats/Png/PngImageFormatProvider.cs index fc5ac4450..abbbaa6d5 100644 --- a/src/ImageSharp/Formats/Png/PngImageFormatProvider.cs +++ b/src/ImageSharp/Formats/Png/PngImageFormatProvider.cs @@ -12,7 +12,7 @@ namespace ImageSharp.Formats using ImageSharp.PixelFormats; /// - /// Detects png file headers + /// Registers the image encoders, decoders and mime type detectors for the png format. /// public class PngImageFormatProvider : IImageFormatProvider { diff --git a/src/ImageSharp/Image/Image.Decode.cs b/src/ImageSharp/Image/Image.Decode.cs index 00725d72b..436cde466 100644 --- a/src/ImageSharp/Image/Image.Decode.cs +++ b/src/ImageSharp/Image/Image.Decode.cs @@ -22,7 +22,7 @@ namespace ImageSharp /// /// The image stream to read the header from. /// The configuration. - /// The mimetype or null if none found. + /// The mime type or null if none found. private static string InternalDiscoverMimeType(Stream stream, Configuration config) { // This is probably a candidate for making into a public API in the future! diff --git a/src/ImageSharp/Image/Image.FromBytes.cs b/src/ImageSharp/Image/Image.FromBytes.cs index 5fb460a48..3b9521102 100644 --- a/src/ImageSharp/Image/Image.FromBytes.cs +++ b/src/ImageSharp/Image/Image.FromBytes.cs @@ -16,21 +16,21 @@ namespace ImageSharp public static partial class Image { /// - /// By reading the header on the provided byte array this calculates the images mimetype. + /// By reading the header on the provided byte array this calculates the images mime type. /// /// The byte array containing image data to read the header from. - /// The mimetype or null if none found. + /// The mime type or null if none found. public static string DiscoverMimeType(byte[] data) { return DiscoverMimeType(null, data); } /// - /// By reading the header on the provided byte array this calculates the images mimetype. + /// By reading the header on the provided byte array this calculates the images mime type. /// /// The configuration. /// The byte array containing image data to read the header from. - /// The mimetype or null if none found. + /// The mime type or null if none found. public static string DiscoverMimeType(Configuration config, byte[] data) { using (Stream stream = new MemoryStream(data)) @@ -50,12 +50,12 @@ namespace ImageSharp /// Create a new instance of the class from the given byte array. /// /// The byte array containing image data. - /// the mime type of the decoded image. + /// The mime type of the decoded image. /// A new . public static Image Load(byte[] data, out string mimeType) => Load(null, data, out mimeType); /// - /// Create a new instance of the class from the given byte array. + /// Create a new instance of the class from the given byte array. /// /// The config for the decoder. /// The byte array containing image data. @@ -63,11 +63,11 @@ namespace ImageSharp public static Image Load(Configuration config, byte[] data) => Load(config, data); /// - /// Create a new instance of the class from the given byte array. + /// Create a new instance of the class from the given byte array. /// /// The config for the decoder. /// The byte array containing image data. - /// the mime type of the decoded image. + /// The mime type of the decoded image. /// A new . public static Image Load(Configuration config, byte[] data, out string mimeType) => Load(config, data, out mimeType); @@ -104,7 +104,7 @@ namespace ImageSharp /// Create a new instance of the class from the given byte array. /// /// The byte array containing image data. - /// the mime type of the decoded image. + /// The mime type of the decoded image. /// The pixel format. /// A new . public static Image Load(byte[] data, out string mimeType) @@ -123,9 +123,9 @@ namespace ImageSharp public static Image Load(Configuration config, byte[] data) where TPixel : struct, IPixel { - using (MemoryStream ms = new MemoryStream(data)) + using (var memoryStream = new MemoryStream(data)) { - return Load(config, ms); + return Load(config, memoryStream); } } @@ -134,15 +134,15 @@ namespace ImageSharp /// /// The configuration options. /// The byte array containing image data. - /// the mime type of the decoded image. + /// The mime type of the decoded image. /// The pixel format. /// A new . public static Image Load(Configuration config, byte[] data, out string mimeType) where TPixel : struct, IPixel { - using (MemoryStream ms = new MemoryStream(data)) + using (var memoryStream = new MemoryStream(data)) { - return Load(config, ms, out mimeType); + return Load(config, memoryStream, out mimeType); } } @@ -156,9 +156,9 @@ namespace ImageSharp public static Image Load(byte[] data, IImageDecoder decoder) where TPixel : struct, IPixel { - using (var ms = new MemoryStream(data)) + using (var memoryStream = new MemoryStream(data)) { - return Load(ms, decoder); + return Load(memoryStream, decoder); } } @@ -173,9 +173,9 @@ namespace ImageSharp public static Image Load(Configuration config, byte[] data, IImageDecoder decoder) where TPixel : struct, IPixel { - using (var ms = new MemoryStream(data)) + using (var memoryStream = new MemoryStream(data)) { - return Load(config, ms, decoder); + return Load(config, memoryStream, decoder); } } } diff --git a/src/ImageSharp/Image/Image.FromFile.cs b/src/ImageSharp/Image/Image.FromFile.cs index 96d509752..c44a5da5e 100644 --- a/src/ImageSharp/Image/Image.FromFile.cs +++ b/src/ImageSharp/Image/Image.FromFile.cs @@ -17,21 +17,21 @@ namespace ImageSharp public static partial class Image { /// - /// By reading the header on the provided file this calculates the images mimetype. + /// By reading the header on the provided file this calculates the images mime type. /// /// The image file to open and to read the header from. - /// The mimetype or null if none found. + /// The mime type or null if none found. public static string DiscoverMimeType(string filePath) { return DiscoverMimeType(null, filePath); } /// - /// By reading the header on the provided file this calculates the images mimetype. + /// By reading the header on the provided file this calculates the images mime type. /// /// The configuration. /// The image file to open and to read the header from. - /// The mimetype or null if none found. + /// The mime type or null if none found. public static string DiscoverMimeType(Configuration config, string filePath) { config = config ?? Configuration.Default; @@ -55,7 +55,7 @@ namespace ImageSharp /// Create a new instance of the class from the given file. /// /// The file path to the image. - /// the mime type of the decoded image. + /// The mime type of the decoded image. /// /// Thrown if the stream is not readable nor seekable. /// @@ -78,7 +78,7 @@ namespace ImageSharp /// /// The config for the decoder. /// The file path to the image. - /// the mime type of the decoded image. + /// The mime type of the decoded image. /// /// Thrown if the stream is not readable nor seekable. /// @@ -127,7 +127,7 @@ namespace ImageSharp /// Create a new instance of the class from the given file. /// /// The file path to the image. - /// the mime type of the decoded image. + /// The mime type of the decoded image. /// /// Thrown if the stream is not readable nor seekable. /// @@ -153,9 +153,9 @@ namespace ImageSharp where TPixel : struct, IPixel { config = config ?? Configuration.Default; - using (Stream s = config.FileSystem.OpenRead(path)) + using (Stream stream = config.FileSystem.OpenRead(path)) { - return Load(config, s); + return Load(config, stream); } } @@ -164,7 +164,7 @@ namespace ImageSharp /// /// The configuration options. /// The file path to the image. - /// the mime type of the decoded image. + /// The mime type of the decoded image. /// /// Thrown if the stream is not readable nor seekable. /// @@ -174,9 +174,9 @@ namespace ImageSharp where TPixel : struct, IPixel { config = config ?? Configuration.Default; - using (Stream s = config.FileSystem.OpenRead(path)) + using (Stream stream = config.FileSystem.OpenRead(path)) { - return Load(config, s, out mimeType); + return Load(config, stream, out mimeType); } } @@ -211,9 +211,9 @@ namespace ImageSharp where TPixel : struct, IPixel { config = config ?? Configuration.Default; - using (Stream s = config.FileSystem.OpenRead(path)) + using (Stream stream = config.FileSystem.OpenRead(path)) { - return Load(config, s, decoder); + return Load(config, stream, decoder); } } } diff --git a/src/ImageSharp/Image/Image.FromStream.cs b/src/ImageSharp/Image/Image.FromStream.cs index 5bd87b145..19f930493 100644 --- a/src/ImageSharp/Image/Image.FromStream.cs +++ b/src/ImageSharp/Image/Image.FromStream.cs @@ -20,21 +20,21 @@ namespace ImageSharp public static partial class Image { /// - /// By reading the header on the provided stream this calculates the images mimetype. + /// By reading the header on the provided stream this calculates the images mime type. /// /// The image stream to read the header from. - /// The mimetype or null if none found. + /// The mime type or null if none found. public static string DiscoverMimeType(Stream stream) { return DiscoverMimeType(null, stream); } /// - /// By reading the header on the provided stream this calculates the images mimetype. + /// By reading the header on the provided stream this calculates the images mime type. /// /// The configuration. /// The image stream to read the header from. - /// The mimetype or null if none found. + /// The mime type or null if none found. public static string DiscoverMimeType(Configuration config, Stream stream) { return WithSeekableStream(stream, s => InternalDiscoverMimeType(s, config ?? Configuration.Default)); @@ -224,12 +224,12 @@ namespace ImageSharp } // We want to be able to load images from things like HttpContext.Request.Body - using (var ms = new MemoryStream()) + using (var memoryStream = new MemoryStream()) { - stream.CopyTo(ms); - ms.Position = 0; + stream.CopyTo(memoryStream); + memoryStream.Position = 0; - return action(ms); + return action(memoryStream); } } } diff --git a/src/ImageSharp/Image/Image{TPixel}.cs b/src/ImageSharp/Image/Image{TPixel}.cs index d8aff5041..5165bc857 100644 --- a/src/ImageSharp/Image/Image{TPixel}.cs +++ b/src/ImageSharp/Image/Image{TPixel}.cs @@ -214,7 +214,7 @@ namespace ImageSharp string mime = this.Configuration.FindFileExtensionsMimeType(ext); if (mime == null) { - stringBuilder.AppendLine($"Can't find a mime type for the file extention '{ext}'. Registerd File extension maps include:"); + stringBuilder.AppendLine($"Can't find a mime type for the file extention '{ext}'. Registered file extension maps include:"); foreach (KeyValuePair map in this.Configuration.ImageExtensionToMimeTypeMapping) { stringBuilder.AppendLine($" - {map.Key} : {map.Value}"); @@ -222,7 +222,7 @@ namespace ImageSharp } else { - stringBuilder.AppendLine($"Can't find encoder for file extention '{ext}' using mime type '{mime}'. Registerd encoders include:"); + stringBuilder.AppendLine($"Can't find encoder for file extention '{ext}' using mime type '{mime}'. Registered encoders include:"); foreach (KeyValuePair enc in this.Configuration.ImageEncoders) { stringBuilder.AppendLine($" - {enc.Key} : {enc.Value.GetType().Name}"); From babd2bc642b4f2bc84938b3dab1442163e037ca9 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 25 Jun 2017 13:04:25 +0100 Subject: [PATCH 08/13] add internal IXXOptions to provider cleaner passing of params to core encoders/decoders --- .../ChangeDefaultEncoderOptions/Program.cs | 17 +---- src/ImageSharp/Formats/Bmp/BmpDecoder.cs | 4 +- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 3 +- src/ImageSharp/Formats/Bmp/BmpEncoder.cs | 5 +- src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs | 20 +++--- .../Formats/Bmp/IBmpDecoderOptions.cs | 21 ++++++ .../Formats/Bmp/IBmpEncoderOptions.cs | 25 +++++++ src/ImageSharp/Formats/Gif/GifDecoder.cs | 11 +-- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 19 ++---- src/ImageSharp/Formats/Gif/GifEncoder.cs | 14 +--- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 44 ++++++------ .../Formats/Gif/IGifDecoderOptions.cs | 29 ++++++++ .../Formats/Gif/IGifEncoderOptions.cs | 45 ++++++++++++ .../Formats/Jpeg/IJpegDecoderOptions.cs | 24 +++++++ .../Formats/Jpeg/IJpegEncoderOptions.cs | 37 ++++++++++ src/ImageSharp/Formats/Jpeg/JpegDecoder.cs | 5 +- .../Formats/Jpeg/JpegDecoderCore.cs | 8 ++- src/ImageSharp/Formats/Jpeg/JpegEncoder.cs | 16 +---- .../Formats/Jpeg/JpegEncoderCore.cs | 41 +++++++---- .../Formats/Png/IPngDecoderOptions.cs | 29 ++++++++ .../Formats/Png/IPngEncoderOptions.cs | 64 +++++++++++++++++ src/ImageSharp/Formats/Png/PngDecoder.cs | 5 +- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 31 +++++---- src/ImageSharp/Formats/Png/PngEncoder.cs | 14 +--- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 68 +++++++++---------- .../Formats/Gif/GifDecoderTests.cs | 13 ---- .../Formats/Jpg/JpegDecoderTests.cs | 2 +- 27 files changed, 410 insertions(+), 204 deletions(-) create mode 100644 src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs create mode 100644 src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs create mode 100644 src/ImageSharp/Formats/Gif/IGifDecoderOptions.cs create mode 100644 src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs create mode 100644 src/ImageSharp/Formats/Jpeg/IJpegDecoderOptions.cs create mode 100644 src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs create mode 100644 src/ImageSharp/Formats/Png/IPngDecoderOptions.cs create mode 100644 src/ImageSharp/Formats/Png/IPngEncoderOptions.cs diff --git a/samples/ChangeDefaultEncoderOptions/Program.cs b/samples/ChangeDefaultEncoderOptions/Program.cs index 5ba6f52b5..b085e468a 100644 --- a/samples/ChangeDefaultEncoderOptions/Program.cs +++ b/samples/ChangeDefaultEncoderOptions/Program.cs @@ -1,5 +1,6 @@ using System; using ImageSharp; +using ImageSharp.Formats; namespace ChangeDefaultEncoderOptions { @@ -14,22 +15,6 @@ namespace ChangeDefaultEncoderOptions Quality = 90, IgnoreMetadata = true }); - - // now lets say we don't want animated gifs, lets skip decoding the alternative frames - Configuration.Default.SetMimeTypeDecoder("image/gif", new ImageSharp.Formats.GifDecoder() - { - IgnoreFrames = true, - IgnoreMetadata = true - }); - - // and just to be douple sure we don't want animations lets disable them on encode too. - Configuration.Default.SetMimeTypeEncoder("image/gif", new ImageSharp.Formats.GifEncoder() - { - IgnoreFrames = true, - IgnoreMetadata = true - }); - - } } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs index e1dc489f4..66af2fa75 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs @@ -26,7 +26,7 @@ namespace ImageSharp.Formats /// Formats will be supported in a later releases. We advise always /// to use only 24 Bit Windows bitmaps. /// - public class BmpDecoder : IImageDecoder + public class BmpDecoder : IImageDecoder, IBmpDecoderOptions { /// public Image Decode(Configuration configuration, Stream stream) @@ -35,7 +35,7 @@ namespace ImageSharp.Formats { Guard.NotNull(stream, "stream"); - return new BmpDecoderCore(configuration).Decode(stream); + return new BmpDecoderCore(configuration, this).Decode(stream); } } } diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index 997a77d6c..817d00f7e 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -52,7 +52,8 @@ namespace ImageSharp.Formats /// Initializes a new instance of the class. /// /// The configuration. - public BmpDecoderCore(Configuration configuration) + /// The options + public BmpDecoderCore(Configuration configuration, IBmpDecoderOptions options) { this.configuration = configuration; } diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoder.cs b/src/ImageSharp/Formats/Bmp/BmpEncoder.cs index f47bedb81..b0064a508 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoder.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoder.cs @@ -15,7 +15,7 @@ namespace ImageSharp.Formats /// Image encoder for writing an image to a stream as a Windows bitmap. /// /// The encoder can currently only write 24-bit rgb images to streams. - public class BmpEncoder : IImageEncoder + public class BmpEncoder : IImageEncoder, IBmpEncoderOptions { /// /// Gets or sets the number of bits per pixel. @@ -26,8 +26,7 @@ namespace ImageSharp.Formats public void Encode(Image image, Stream stream) where TPixel : struct, IPixel { - BmpEncoderCore encoder = new BmpEncoderCore(); - encoder.BitsPerPixel = this.BitsPerPixel; + var encoder = new BmpEncoderCore(this); encoder.Encode(image, stream); } } diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index daff65cbc..e41c29501 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -23,16 +23,18 @@ namespace ImageSharp.Formats private int padding; /// - /// Initializes a new instance of the class. + /// Gets or sets the number of bits per pixel. /// - public BmpEncoderCore() - { - } + private BmpBitsPerPixel bitsPerPixel; /// - /// Gets or sets the number of bits per pixel. + /// Initializes a new instance of the class. /// - public BmpBitsPerPixel BitsPerPixel { get; internal set; } = BmpBitsPerPixel.Pixel24; + /// The encoder options + public BmpEncoderCore(IBmpEncoderOptions options) + { + this.bitsPerPixel = options.BitsPerPixel; + } /// /// Encodes the image to the specified stream from the . @@ -47,9 +49,9 @@ namespace ImageSharp.Formats Guard.NotNull(stream, nameof(stream)); // Cast to int will get the bytes per pixel - short bpp = (short)(8 * (int)this.BitsPerPixel); + short bpp = (short)(8 * (int)this.bitsPerPixel); int bytesPerLine = 4 * (((image.Width * bpp) + 31) / 32); - this.padding = bytesPerLine - (image.Width * (int)this.BitsPerPixel); + this.padding = bytesPerLine - (image.Width * (int)this.bitsPerPixel); // Do not use IDisposable pattern here as we want to preserve the stream. EndianBinaryWriter writer = new EndianBinaryWriter(Endianness.LittleEndian, stream); @@ -134,7 +136,7 @@ namespace ImageSharp.Formats { using (PixelAccessor pixels = image.Lock()) { - switch (this.BitsPerPixel) + switch (this.bitsPerPixel) { case BmpBitsPerPixel.Pixel32: this.Write32Bit(writer, pixels); diff --git a/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs b/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs new file mode 100644 index 000000000..9285b9cf7 --- /dev/null +++ b/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs @@ -0,0 +1,21 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + using System.Collections.Generic; + using System.IO; + + using ImageSharp.PixelFormats; + + /// + /// Image decoder options for decoding Windows bitmap streams. + /// + internal interface IBmpDecoderOptions + { + // added this for consistancy so we can add stuff as required, no options currently availible + } +} diff --git a/src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs b/src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs new file mode 100644 index 000000000..dd17043fa --- /dev/null +++ b/src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs @@ -0,0 +1,25 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + using System.Collections.Generic; + using System.IO; + + using ImageSharp.PixelFormats; + + /// + /// Configuration options for use during bmp encoding + /// + /// The encoder can currently only write 24-bit rgb images to streams. + internal interface IBmpEncoderOptions + { + /// + /// Gets the number of bits per pixel. + /// + BmpBitsPerPixel BitsPerPixel { get; } + } +} diff --git a/src/ImageSharp/Formats/Gif/GifDecoder.cs b/src/ImageSharp/Formats/Gif/GifDecoder.cs index caf39c2e1..e026cc29b 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoder.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoder.cs @@ -14,18 +14,13 @@ namespace ImageSharp.Formats /// /// Decoder for generating an image out of a gif encoded stream. /// - public class GifDecoder : IImageDecoder + public class GifDecoder : IImageDecoder, IGifDecoderOptions { /// /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. /// public bool IgnoreMetadata { get; set; } = false; - /// - /// Gets or sets a value indicating whether the additional frames should be ignored when the image is being decoded. - /// - public bool IgnoreFrames { get; set; } = false; - /// /// Gets or sets the encoding that should be used when reading comments. /// @@ -35,9 +30,7 @@ namespace ImageSharp.Formats public Image Decode(Configuration configuration, Stream stream) where TPixel : struct, IPixel { - var decoder = new GifDecoderCore(this.TextEncoding, configuration); - decoder.IgnoreMetadata = this.IgnoreMetadata; - decoder.IgnoreFrames = this.IgnoreFrames; + var decoder = new GifDecoderCore(configuration, this); return decoder.Decode(stream); } } diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index ad34009b6..bbecf32dd 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -78,11 +78,12 @@ namespace ImageSharp.Formats /// /// Initializes a new instance of the class. /// - /// The decoder encoding. /// The configuration. - public GifDecoderCore(Encoding encoding, Configuration configuration) + /// The decoder options. + public GifDecoderCore(Configuration configuration, IGifDecoderOptions options) { - this.TextEncoding = encoding ?? GifConstants.DefaultEncoding; + this.TextEncoding = options.TextEncoding ?? GifConstants.DefaultEncoding; + this.IgnoreMetadata = options.IgnoreMetadata; this.configuration = configuration ?? Configuration.Default; } @@ -96,11 +97,6 @@ namespace ImageSharp.Formats /// public Encoding TextEncoding { get; private set; } - /// - /// Gets or sets a value indicating whether the additional frames should be ignored when the image is being decoded. - /// - public bool IgnoreFrames { get; internal set; } - /// /// Decodes the stream to the image. /// @@ -362,13 +358,6 @@ namespace ImageSharp.Formats /// The private unsafe void ReadFrameColors(byte[] indices, byte[] colorTable, int colorTableLength, GifImageDescriptor descriptor) { - if (this.IgnoreFrames && this.image != null) - { - // we already have our images skip this - // TODO move this higher up the stack to prevent some of the data loading higher up. - return; - } - int imageWidth = this.logicalScreenDescriptor.Width; int imageHeight = this.logicalScreenDescriptor.Height; diff --git a/src/ImageSharp/Formats/Gif/GifEncoder.cs b/src/ImageSharp/Formats/Gif/GifEncoder.cs index ee78c3266..b725f1260 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoder.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoder.cs @@ -15,18 +15,13 @@ namespace ImageSharp.Formats /// /// Image encoder for writing image data to a stream in gif format. /// - public class GifEncoder : IImageEncoder + public class GifEncoder : IImageEncoder, IGifEncoderOptions { /// /// Gets or sets a value indicating whether the metadata should be ignored when the image is being encoded. /// public bool IgnoreMetadata { get; set; } = false; - /// - /// Gets or sets a value indicating whether the additional frames should be ignored when the image is being encoded. - /// - public bool IgnoreFrames { get; set; } = false; - /// /// Gets or sets the encoding that should be used when writing comments. /// @@ -51,12 +46,7 @@ namespace ImageSharp.Formats public void Encode(Image image, Stream stream) where TPixel : struct, IPixel { - GifEncoderCore encoder = new GifEncoderCore(this.TextEncoding); - encoder.Quantizer = this.Quantizer; - encoder.Threshold = this.Threshold; - encoder.PaletteSize = this.PaletteSize; - encoder.IgnoreMetadata = this.IgnoreMetadata; - encoder.IgnoreFrames = this.IgnoreFrames; + GifEncoderCore encoder = new GifEncoderCore(this); encoder.Encode(image, stream); } } diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 3191aafc9..81b3cfba4 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -35,44 +35,44 @@ namespace ImageSharp.Formats /// private bool hasFrames; - /// - /// Initializes a new instance of the class. - /// - /// The encoding for the encoder. - public GifEncoderCore(Encoding encoding) - { - this.TextEncoding = encoding ?? GifConstants.DefaultEncoding; - } - /// /// Gets the TextEncoding /// - public Encoding TextEncoding { get; private set; } + private Encoding textEncoding; /// /// Gets or sets the quantizer for reducing the color count. /// - public IQuantizer Quantizer { get; set; } + private IQuantizer quantizer; /// /// Gets or sets the threshold. /// - public byte Threshold { get; internal set; } + private byte threshold; /// /// Gets or sets the size of the color palette to use. /// - public int PaletteSize { get; internal set; } + private int paletteSize; /// /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. /// - public bool IgnoreMetadata { get; internal set; } + private bool ignoreMetadata; /// - /// Gets or sets a value indicating whether the additional frames should be ignored when the image is being encoded. + /// Initializes a new instance of the class. /// - public bool IgnoreFrames { get; internal set; } + /// The options for the encoder. + public GifEncoderCore(IGifEncoderOptions options) + { + this.textEncoding = options.TextEncoding ?? GifConstants.DefaultEncoding; + + this.quantizer = options.Quantizer; + this.threshold = options.Threshold; + this.paletteSize = options.PaletteSize; + this.ignoreMetadata = options.IgnoreMetadata; + } /// /// Encodes the image to the specified stream from the . @@ -86,22 +86,22 @@ namespace ImageSharp.Formats Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); - this.Quantizer = this.Quantizer ?? new OctreeQuantizer(); + this.quantizer = this.quantizer ?? new OctreeQuantizer(); // Do not use IDisposable pattern here as we want to preserve the stream. var writer = new EndianBinaryWriter(Endianness.LittleEndian, stream); // Ensure that pallete size can be set but has a fallback. - int paletteSize = this.PaletteSize; + int paletteSize = this.paletteSize; paletteSize = paletteSize > 0 ? paletteSize.Clamp(1, 256) : 256; // Get the number of bits. this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(paletteSize); - this.hasFrames = !this.IgnoreFrames && image.Frames.Any(); + this.hasFrames = image.Frames.Any(); // Dithering when animating gifs is a bad idea as we introduce pixel tearing across frames. - var ditheredQuantizer = (IQuantizer)this.Quantizer; + var ditheredQuantizer = (IQuantizer)this.quantizer; ditheredQuantizer.Dither = !this.hasFrames; // Quantize the image returning a palette. @@ -260,7 +260,7 @@ namespace ImageSharp.Formats private void WriteComments(Image image, EndianBinaryWriter writer) where TPixel : struct, IPixel { - if (this.IgnoreMetadata) + if (this.ignoreMetadata) { return; } @@ -271,7 +271,7 @@ namespace ImageSharp.Formats return; } - byte[] comments = this.TextEncoding.GetBytes(property.Value); + byte[] comments = this.textEncoding.GetBytes(property.Value); int count = Math.Min(comments.Length, 255); diff --git a/src/ImageSharp/Formats/Gif/IGifDecoderOptions.cs b/src/ImageSharp/Formats/Gif/IGifDecoderOptions.cs new file mode 100644 index 000000000..caaa8932b --- /dev/null +++ b/src/ImageSharp/Formats/Gif/IGifDecoderOptions.cs @@ -0,0 +1,29 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Text; + using ImageSharp.PixelFormats; + + /// + /// Decoder for generating an image out of a gif encoded stream. + /// + internal interface IGifDecoderOptions + { + /// + /// Gets a value indicating whether the metadata should be ignored when the image is being decoded. + /// + bool IgnoreMetadata { get; } + + /// + /// Gets the encoding that should be used when reading comments. + /// + Encoding TextEncoding { get; } + } +} diff --git a/src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs b/src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs new file mode 100644 index 000000000..c38ec7e45 --- /dev/null +++ b/src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs @@ -0,0 +1,45 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Text; + using ImageSharp.PixelFormats; + using ImageSharp.Quantizers; + + /// + /// The configuration options used for encoding gifs + /// + internal interface IGifEncoderOptions + { + /// + /// Gets a value indicating whether the metadata should be ignored when the image is being encoded. + /// + bool IgnoreMetadata { get; } + + /// + /// Gets the encoding that should be used when writing comments. + /// + Encoding TextEncoding { get; } + + /// + /// Gets the size of the color palette to use. For gifs the value ranges from 1 to 256. Leave as zero for default size. + /// + int PaletteSize { get; } + + /// + /// Gets the transparency threshold. + /// + byte Threshold { get; } + + /// + /// Gets the quantizer for reducing the color count. + /// + IQuantizer Quantizer { get; } + } +} diff --git a/src/ImageSharp/Formats/Jpeg/IJpegDecoderOptions.cs b/src/ImageSharp/Formats/Jpeg/IJpegDecoderOptions.cs new file mode 100644 index 000000000..6830e2e4a --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/IJpegDecoderOptions.cs @@ -0,0 +1,24 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + using System.Collections.Generic; + using System.IO; + + using ImageSharp.PixelFormats; + + /// + /// Image decoder for generating an image out of a jpg stream. + /// + internal interface IJpegDecoderOptions + { + /// + /// Gets a value indicating whether the metadata should be ignored when the image is being decoded. + /// + bool IgnoreMetadata { get; } + } +} diff --git a/src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs b/src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs new file mode 100644 index 000000000..947c98ee2 --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs @@ -0,0 +1,37 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + using System.Collections.Generic; + using System.IO; + + using ImageSharp.PixelFormats; + + /// + /// Encoder for writing the data image to a stream in jpeg format. + /// + internal interface IJpegEncoderOptions + { + /// + /// Gets a value indicating whether the metadata should be ignored when the image is being decoded. + /// + bool IgnoreMetadata { get; } + + /// + /// Gets the quality, that will be used to encode the image. Quality + /// index must be between 0 and 100 (compression from max to min). + /// + /// The quality of the jpg image from 0 to 100. + int Quality { get; } + + /// + /// Gets the subsample ration, that will be used to encode the image. + /// + /// The subsample ratio of the jpg image. + JpegSubsample? Subsample { get; } + } +} diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs index b809908e9..0dc186697 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs @@ -14,7 +14,7 @@ namespace ImageSharp.Formats /// /// Image decoder for generating an image out of a jpg stream. /// - public class JpegDecoder : IImageDecoder + public class JpegDecoder : IImageDecoder, IJpegDecoderOptions { /// /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. @@ -27,9 +27,8 @@ namespace ImageSharp.Formats { Guard.NotNull(stream, "stream"); - using (JpegDecoderCore decoder = new JpegDecoderCore(configuration)) + using (JpegDecoderCore decoder = new JpegDecoderCore(configuration, this)) { - decoder.IgnoreMetadata = this.IgnoreMetadata; return decoder.Decode(stream); } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index f6456620e..1ce78a8b1 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -99,8 +99,10 @@ namespace ImageSharp.Formats /// Initializes a new instance of the class. /// /// The configuration. - public JpegDecoderCore(Configuration configuration) + /// The options. + public JpegDecoderCore(Configuration configuration, IJpegDecoderOptions options) { + this.IgnoreMetadata = options.IgnoreMetadata; this.configuration = configuration ?? Configuration.Default; this.HuffmanTrees = HuffmanTree.CreateHuffmanTrees(); this.QuantizationTables = new Block8x8F[MaxTq + 1]; @@ -184,9 +186,9 @@ namespace ImageSharp.Formats public int TotalMCUCount => this.MCUCountX * this.MCUCountY; /// - /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. + /// Gets a value indicating whether the metadata should be ignored when the image is being decoded. /// - public bool IgnoreMetadata { get; internal set; } + public bool IgnoreMetadata { get; private set; } /// /// Decodes the image from the specified and sets diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs index d0be9eaf8..350856471 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs @@ -14,7 +14,7 @@ namespace ImageSharp.Formats /// /// Encoder for writing the data image to a stream in jpeg format. /// - public class JpegEncoder : IImageEncoder + public class JpegEncoder : IImageEncoder, IJpegEncoderOptions { /// /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. @@ -43,19 +43,7 @@ namespace ImageSharp.Formats public void Encode(Image image, Stream stream) where TPixel : struct, IPixel { - JpegEncoderCore encoder = new JpegEncoderCore(); - - var quality = this.Quality; - if (quality == 0) - { - quality = 75; - } - - encoder.Quality = quality; - encoder.Subsample = this.Subsample ?? (quality >= 91 ? JpegSubsample.Ratio444 : JpegSubsample.Ratio420); - - encoder.IgnoreMetadata = this.IgnoreMetadata; - + var encoder = new JpegEncoderCore(this); encoder.Encode(image, stream); } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 168e47311..2d67f6735 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -149,29 +149,40 @@ namespace ImageSharp.Formats /// private Stream outputStream; - /// - /// Initializes a new instance of the class. - /// - public JpegEncoderCore() - { - } - /// /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. /// - public bool IgnoreMetadata { get; internal set; } = false; + private bool ignoreMetadata = false; /// /// Gets or sets the quality, that will be used to encode the image. Quality /// index must be between 0 and 100 (compression from max to min). /// /// The quality of the jpg image from 0 to 100. - public int Quality { get; internal set; } + private int quality = 0; /// /// Gets or sets the subsampling method to use. /// - public JpegSubsample? Subsample { get; internal set; } + private JpegSubsample? subsample; + + /// + /// Initializes a new instance of the class. + /// + /// The options + public JpegEncoderCore(IJpegEncoderOptions options) + { + int quality = options.Quality; + if (quality == 0) + { + quality = 75; + } + + this.quality = quality; + this.subsample = options.Subsample ?? (quality >= 91 ? JpegSubsample.Ratio444 : JpegSubsample.Ratio420); + + this.ignoreMetadata = options.IgnoreMetadata; + } /// /// Encode writes the image to the jpeg baseline format with the given options. @@ -193,11 +204,11 @@ namespace ImageSharp.Formats this.outputStream = stream; - int quality = this.Quality.Clamp(1, 100); + int quality = this.quality.Clamp(1, 100); // Convert from a quality rating to a scaling factor. int scale; - if (this.Quality < 50) + if (this.quality < 50) { scale = 5000 / quality; } @@ -785,7 +796,7 @@ namespace ImageSharp.Formats private void WriteProfiles(Image image) where TPixel : struct, IPixel { - if (this.IgnoreMetadata) + if (this.ignoreMetadata) { return; } @@ -807,7 +818,7 @@ namespace ImageSharp.Formats byte[] subsamples = { 0x22, 0x11, 0x11 }; byte[] chroma = { 0x00, 0x01, 0x01 }; - switch (this.Subsample) + switch (this.subsample) { case JpegSubsample.Ratio444: subsamples = new byte[] { 0x11, 0x11, 0x11 }; @@ -863,7 +874,7 @@ namespace ImageSharp.Formats // TODO: We should allow grayscale writing. this.outputStream.Write(SosHeaderYCbCr, 0, SosHeaderYCbCr.Length); - switch (this.Subsample) + switch (this.subsample) { case JpegSubsample.Ratio444: this.Encode444(pixels); diff --git a/src/ImageSharp/Formats/Png/IPngDecoderOptions.cs b/src/ImageSharp/Formats/Png/IPngDecoderOptions.cs new file mode 100644 index 000000000..de163ba7e --- /dev/null +++ b/src/ImageSharp/Formats/Png/IPngDecoderOptions.cs @@ -0,0 +1,29 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Text; + using ImageSharp.PixelFormats; + + /// + /// The optioas for decoding png images + /// + internal interface IPngDecoderOptions + { + /// + /// Gets a value indicating whether the metadata should be ignored when the image is being decoded. + /// + bool IgnoreMetadata { get; } + + /// + /// Gets the encoding that should be used when reading text chunks. + /// + Encoding TextEncoding { get; } + } +} diff --git a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs new file mode 100644 index 000000000..8f0a4cd82 --- /dev/null +++ b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs @@ -0,0 +1,64 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System.Collections.Generic; + using System.IO; + + using ImageSharp.PixelFormats; + using ImageSharp.Quantizers; + + /// + /// The options availible for manipulating the encoder pipeline + /// + internal interface IPngEncoderOptions + { + /// + /// Gets a value indicating whether the metadata should be ignored when the image is being encoded. + /// + bool IgnoreMetadata { get; } + + /// + /// Gets the size of the color palette to use. Set to zero to leav png encoding to use pixel data. + /// + int PaletteSize { get; } + + /// + /// Gets the png color type + /// + PngColorType PngColorType { get; } + + /// + /// Gets the compression level 1-9. + /// Defaults to 6. + /// + int CompressionLevel { get; } + + /// + /// Gets the gamma value, that will be written + /// the the stream, when the property + /// is set to true. The default value is 2.2F. + /// + /// The gamma value of the image. + float Gamma { get; } + + /// + /// Gets quantizer for reducing the color count. + /// + IQuantizer Quantizer { get; } + + /// + /// Gets the transparency threshold. + /// + byte Threshold { get; } + + /// + /// Gets a value indicating whether this instance should write + /// gamma information to the stream. The default value is false. + /// + bool WriteGamma { get; } + } +} diff --git a/src/ImageSharp/Formats/Png/PngDecoder.cs b/src/ImageSharp/Formats/Png/PngDecoder.cs index c9fab8e3f..2e177bc21 100644 --- a/src/ImageSharp/Formats/Png/PngDecoder.cs +++ b/src/ImageSharp/Formats/Png/PngDecoder.cs @@ -31,7 +31,7 @@ namespace ImageSharp.Formats /// /// /// - public class PngDecoder : IImageDecoder + public class PngDecoder : IImageDecoder, IPngDecoderOptions { /// /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. @@ -53,8 +53,7 @@ namespace ImageSharp.Formats public Image Decode(Configuration configuration, Stream stream) where TPixel : struct, IPixel { - var decoder = new PngDecoderCore(configuration, this.TextEncoding); - decoder.IgnoreMetadata = this.IgnoreMetadata; + var decoder = new PngDecoderCore(configuration, this); return decoder.Decode(stream); } } diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index b1b98eca5..aef588f25 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -155,25 +155,26 @@ namespace ImageSharp.Formats private PngColorType pngColorType; /// - /// Initializes a new instance of the class. + /// Gets the encoding to use /// - /// The configuration. - /// The text encoding. - public PngDecoderCore(Configuration configuration, Encoding encoding) - { - this.configuration = configuration ?? Configuration.Default; - this.TextEncoding = encoding ?? PngConstants.DefaultEncoding; - } + private Encoding textEncoding; /// - /// Gets the encoding to use + /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. /// - public Encoding TextEncoding { get; private set; } + private bool ignoreMetadata; /// - /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. + /// Initializes a new instance of the class. /// - public bool IgnoreMetadata { get; internal set; } + /// The configuration. + /// The decoder options. + public PngDecoderCore(Configuration configuration, IPngDecoderOptions options) + { + this.configuration = configuration ?? Configuration.Default; + this.textEncoding = options.TextEncoding ?? PngConstants.DefaultEncoding; + this.ignoreMetadata = options.IgnoreMetadata; + } /// /// Decodes the stream to the image. @@ -900,7 +901,7 @@ namespace ImageSharp.Formats /// The maximum length to read. private void ReadTextChunk(ImageMetaData metadata, byte[] data, int length) { - if (this.IgnoreMetadata) + if (this.ignoreMetadata) { return; } @@ -916,8 +917,8 @@ namespace ImageSharp.Formats } } - string name = this.TextEncoding.GetString(data, 0, zeroIndex); - string value = this.TextEncoding.GetString(data, zeroIndex + 1, length - zeroIndex - 1); + string name = this.textEncoding.GetString(data, 0, zeroIndex); + string value = this.textEncoding.GetString(data, zeroIndex + 1, length - zeroIndex - 1); metadata.Properties.Add(new ImageProperty(name, value)); } diff --git a/src/ImageSharp/Formats/Png/PngEncoder.cs b/src/ImageSharp/Formats/Png/PngEncoder.cs index 8d5b09d0c..f0d332fc4 100644 --- a/src/ImageSharp/Formats/Png/PngEncoder.cs +++ b/src/ImageSharp/Formats/Png/PngEncoder.cs @@ -14,7 +14,7 @@ namespace ImageSharp.Formats /// /// Image encoder for writing image data to a stream in png format. /// - public class PngEncoder : IImageEncoder + public class PngEncoder : IImageEncoder, IPngEncoderOptions { /// /// Gets or sets a value indicating whether the metadata should be ignored when the image is being encoded. @@ -70,18 +70,8 @@ namespace ImageSharp.Formats public void Encode(Image image, Stream stream) where TPixel : struct, IPixel { - using (var encoder = new PngEncoderCore()) + using (var encoder = new PngEncoderCore(this)) { - encoder.IgnoreMetadata = this.IgnoreMetadata; - - encoder.PaletteSize = this.PaletteSize > 0 ? this.PaletteSize.Clamp(1, int.MaxValue) : int.MaxValue; - encoder.PngColorType = this.PngColorType; - encoder.CompressionLevel = this.CompressionLevel; - encoder.Gamma = this.Gamma; - encoder.Quantizer = this.Quantizer; - encoder.Threshold = this.Threshold; - encoder.WriteGamma = this.WriteGamma; - encoder.Encode(image, stream); } } diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index c0cd0ffaf..cfbd0c449 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -118,52 +118,51 @@ namespace ImageSharp.Formats /// private IQuantizer quantizer; - /// - /// Initializes a new instance of the class. - /// - public PngEncoderCore() - { - } - /// /// Gets or sets a value indicating whether to ignore metadata /// - public bool IgnoreMetadata { get; internal set; } - - /// - /// Gets or sets the Quality value - /// - public int PaletteSize { get; internal set; } + private bool ignoreMetadata; /// /// Gets or sets the Quality value /// - public PngColorType PngColorType { get; internal set; } + private int paletteSize; /// /// Gets or sets the CompressionLevel value /// - public int CompressionLevel { get; internal set; } + private int compressionLevel; /// /// Gets or sets the Gamma value /// - public float Gamma { get; internal set; } + private float gamma; /// - /// Gets or sets the Quantizer value + /// Gets or sets the Threshold value /// - public IQuantizer Quantizer { get; internal set; } + private byte threshold; /// - /// Gets or sets the Threshold value + /// Gets or sets a value indicating whether to Write Gamma /// - public byte Threshold { get; internal set; } + private bool writeGamma; /// - /// Gets or sets a value indicating whether to Write Gamma + /// Initializes a new instance of the class. /// - public bool WriteGamma { get; internal set; } + /// The options for influancing the encoder + public PngEncoderCore(IPngEncoderOptions options) + { + this.ignoreMetadata = options.IgnoreMetadata; + this.paletteSize = options.PaletteSize > 0 ? options.PaletteSize.Clamp(1, int.MaxValue) : int.MaxValue; + this.pngColorType = options.PngColorType; + this.compressionLevel = options.CompressionLevel; + this.gamma = options.Gamma; + this.quantizer = options.Quantizer; + this.threshold = options.Threshold; + this.writeGamma = options.WriteGamma; + } /// /// Encodes the image to the specified stream from the . @@ -192,23 +191,20 @@ namespace ImageSharp.Formats stream.Write(this.chunkDataBuffer, 0, 8); - this.pngColorType = this.PngColorType; - this.quantizer = this.Quantizer; - // Set correct color type if the color count is 256 or less. - if (this.PaletteSize <= 256) + if (this.paletteSize <= 256) { this.pngColorType = PngColorType.Palette; } - if (this.pngColorType == PngColorType.Palette && this.PaletteSize > 256) + if (this.pngColorType == PngColorType.Palette && this.paletteSize > 256) { - this.PaletteSize = 256; + this.paletteSize = 256; } // Set correct bit depth. - this.bitDepth = this.PaletteSize <= 256 - ? (byte)ImageMaths.GetBitsNeededForColorDepth(this.PaletteSize).Clamp(1, 8) + this.bitDepth = this.paletteSize <= 256 + ? (byte)ImageMaths.GetBitsNeededForColorDepth(this.paletteSize).Clamp(1, 8) : (byte)8; // Png only supports in four pixel depths: 1, 2, 4, and 8 bits when using the PLTE chunk @@ -538,7 +534,7 @@ namespace ImageSharp.Formats private QuantizedImage WritePaletteChunk(Stream stream, PngHeader header, ImageBase image) where TPixel : struct, IPixel { - if (this.PaletteSize > 256) + if (this.paletteSize > 256) { return null; } @@ -549,7 +545,7 @@ namespace ImageSharp.Formats } // Quantize the image returning a palette. This boxing is icky. - QuantizedImage quantized = ((IQuantizer)this.quantizer).Quantize(image, this.PaletteSize); + QuantizedImage quantized = ((IQuantizer)this.quantizer).Quantize(image, this.paletteSize); // Grab the palette and write it to the stream. TPixel[] palette = quantized.Palette; @@ -576,7 +572,7 @@ namespace ImageSharp.Formats colorTable[offset + 1] = bytes[1]; colorTable[offset + 2] = bytes[2]; - if (alpha > this.Threshold) + if (alpha > this.threshold) { alpha = 255; } @@ -634,9 +630,9 @@ namespace ImageSharp.Formats /// The containing image data. private void WriteGammaChunk(Stream stream) { - if (this.WriteGamma) + if (this.writeGamma) { - int gammaValue = (int)(this.Gamma * 100000F); + int gammaValue = (int)(this.gamma * 100000F); byte[] size = BitConverter.GetBytes(gammaValue); @@ -679,7 +675,7 @@ namespace ImageSharp.Formats try { memoryStream = new MemoryStream(); - using (var deflateStream = new ZlibDeflateStream(memoryStream, this.CompressionLevel)) + using (var deflateStream = new ZlibDeflateStream(memoryStream, this.compressionLevel)) { for (int y = 0; y < this.height; y++) { diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs index cc7935fbf..06bfd8990 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs @@ -18,19 +18,6 @@ namespace ImageSharp.Tests public static readonly string[] TestFiles = { TestImages.Gif.Giphy, TestImages.Gif.Rings, TestImages.Gif.Trans }; - [Fact] - public void SkipDecodingFrames() - { - var file = TestFile.GetPath(TestImages.Gif.Giphy); - - using (Image image = Image.Load(file, new GifDecoder() { IgnoreFrames = true })) - using (Image imageWithFrames = Image.Load(file, new GifDecoder() { IgnoreFrames = false })) - { - Assert.NotEmpty(imageWithFrames.Frames); - Assert.Empty(image.Frames); - } - } - [Theory] [WithFileCollection(nameof(TestFiles), PixelTypes)] public void DecodeAndReSave(TestImageProvider imageProvider) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index ab4850ecf..9401d098d 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -90,7 +90,7 @@ namespace ImageSharp.Tests image.Save(ms, new JpegEncoder()); ms.Seek(0, SeekOrigin.Begin); - using (JpegDecoderCore decoder = new JpegDecoderCore(null)) + using (JpegDecoderCore decoder = new JpegDecoderCore(null, new JpegDecoder())) { Image mirror = decoder.Decode(ms); From 8bd785af5070776412baee6b680a86c072ff4344 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 25 Jun 2017 18:03:59 +0100 Subject: [PATCH 09/13] switch from mimetype strings to IImageFormats --- .../ChangeDefaultEncoderOptions/Program.cs | 2 +- src/ImageSharp/Configuration.cs | 183 +++++++++--------- .../Formats/Bmp/BmpConfigurationModule.cs | 27 +++ src/ImageSharp/Formats/Bmp/BmpFormat.cs | 31 +++ ...eDetector.cs => BmpImageFormatDetector.cs} | 8 +- .../Formats/Bmp/BmpImageFormatProvider.cs | 45 ----- .../Formats/Gif/GifConfigurationModule.cs | 28 +++ src/ImageSharp/Formats/Gif/GifFormat.cs | 31 +++ ...eDetector.cs => GifImageFormatDetector.cs} | 8 +- .../Formats/Gif/GifImageFormatProvider.cs | 45 ----- src/ImageSharp/Formats/IImageFormat.cs | 39 ++++ ...ypeDetector.cs => IImageFormatDetector.cs} | 6 +- .../Formats/IImageFormatProvider.cs | 56 ------ .../Formats/Jpeg/JpegConfigurationModule.cs | 28 +++ src/ImageSharp/Formats/Jpeg/JpegFormat.cs | 31 +++ ...Detector.cs => JpegImageFormatDetector.cs} | 14 +- .../Formats/Jpeg/JpegImageFormatProvider.cs | 45 ----- .../Formats/Png/PngConfigurationModule.cs | 27 +++ src/ImageSharp/Formats/Png/PngFormat.cs | 31 +++ ...eDetector.cs => PngImageFormatDetector.cs} | 10 +- .../Formats/Png/PngImageFormatProvider.cs | 45 ----- src/ImageSharp/IConfigurationModule.cs | 23 +++ src/ImageSharp/Image/Image.Decode.cs | 31 ++- src/ImageSharp/Image/Image.FromBytes.cs | 34 ++-- src/ImageSharp/Image/Image.FromFile.cs | 28 +-- src/ImageSharp/Image/Image.FromStream.cs | 36 ++-- src/ImageSharp/Image/Image{TPixel}.cs | 52 ++--- src/ImageSharp/ImageFormats.cs | 39 ++++ src/ImageSharp/Memory/Buffer.cs | 10 + tests/ImageSharp.Tests/ConfigurationTests.cs | 76 +++----- .../Formats/GeneralFormatTests.cs | 6 +- .../Image/ImageDiscoverMimeType.cs | 56 +++--- .../ImageSharp.Tests/Image/ImageLoadTests.cs | 14 +- .../ImageSharp.Tests/Image/ImageSaveTests.cs | 19 +- tests/ImageSharp.Tests/Image/ImageTests.cs | 4 +- tests/ImageSharp.Tests/TestFormat.cs | 33 ++-- .../TestUtilities/ImagingTestCaseUtility.cs | 4 +- 37 files changed, 647 insertions(+), 558 deletions(-) create mode 100644 src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs create mode 100644 src/ImageSharp/Formats/Bmp/BmpFormat.cs rename src/ImageSharp/Formats/Bmp/{BmpMimeTypeDetector.cs => BmpImageFormatDetector.cs} (77%) delete mode 100644 src/ImageSharp/Formats/Bmp/BmpImageFormatProvider.cs create mode 100644 src/ImageSharp/Formats/Gif/GifConfigurationModule.cs create mode 100644 src/ImageSharp/Formats/Gif/GifFormat.cs rename src/ImageSharp/Formats/Gif/{GifMimeTypeDetector.cs => GifImageFormatDetector.cs} (81%) delete mode 100644 src/ImageSharp/Formats/Gif/GifImageFormatProvider.cs create mode 100644 src/ImageSharp/Formats/IImageFormat.cs rename src/ImageSharp/Formats/{IMimeTypeDetector.cs => IImageFormatDetector.cs} (81%) delete mode 100644 src/ImageSharp/Formats/IImageFormatProvider.cs create mode 100644 src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs create mode 100644 src/ImageSharp/Formats/Jpeg/JpegFormat.cs rename src/ImageSharp/Formats/Jpeg/{JpegMimeTypeDetector.cs => JpegImageFormatDetector.cs} (85%) delete mode 100644 src/ImageSharp/Formats/Jpeg/JpegImageFormatProvider.cs create mode 100644 src/ImageSharp/Formats/Png/PngConfigurationModule.cs create mode 100644 src/ImageSharp/Formats/Png/PngFormat.cs rename src/ImageSharp/Formats/Png/{PngMimeTypeDetector.cs => PngImageFormatDetector.cs} (76%) delete mode 100644 src/ImageSharp/Formats/Png/PngImageFormatProvider.cs create mode 100644 src/ImageSharp/IConfigurationModule.cs create mode 100644 src/ImageSharp/ImageFormats.cs diff --git a/samples/ChangeDefaultEncoderOptions/Program.cs b/samples/ChangeDefaultEncoderOptions/Program.cs index b085e468a..dab8d445c 100644 --- a/samples/ChangeDefaultEncoderOptions/Program.cs +++ b/samples/ChangeDefaultEncoderOptions/Program.cs @@ -10,7 +10,7 @@ namespace ChangeDefaultEncoderOptions { // lets switch out the default encoder for jpeg to one // 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, IgnoreMetadata = true diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs index f48aefbcd..90fd3a0e6 100644 --- a/src/ImageSharp/Configuration.cs +++ b/src/ImageSharp/Configuration.cs @@ -18,7 +18,7 @@ namespace ImageSharp /// /// Provides initialization code which allows extending the library. /// - public class Configuration : IImageFormatHost + public class Configuration { /// /// A lazily initialized configuration default instance. @@ -33,22 +33,22 @@ namespace ImageSharp /// /// The list of supported keyed to mime types. /// - private readonly ConcurrentDictionary mimeTypeEncoders = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private readonly ConcurrentDictionary mimeTypeEncoders = new ConcurrentDictionary(); /// - /// The list of supported mime types keyed to file extensions. + /// The list of supported keyed to mime types. /// - private readonly ConcurrentDictionary extensionsMap = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private readonly ConcurrentDictionary mimeTypeDecoders = new ConcurrentDictionary(); /// - /// The list of supported keyed to mime types. + /// The list of supported s. /// - private readonly ConcurrentDictionary mimeTypeDecoders = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private readonly List imageFormatDetectors = new List(); /// - /// The list of supported s. + /// The list of supported s. /// - private readonly List mimeTypeDetectors = new List(); + private readonly HashSet imageFormats = new HashSet(); /// /// Initializes a new instance of the class. @@ -61,11 +61,11 @@ namespace ImageSharp /// Initializes a new instance of the class. /// /// A collection of providers to configure - public Configuration(params IImageFormatProvider[] providers) + public Configuration(params IConfigurationModule[] providers) { if (providers != null) { - foreach (IImageFormatProvider p in providers) + foreach (IConfigurationModule p in providers) { p.Configure(this); } @@ -88,24 +88,24 @@ namespace ImageSharp internal int MaxHeaderSize { get; private set; } /// - /// Gets the currently registered s. + /// Gets the currently registered s. /// - internal IEnumerable MimeTypeDetectors => this.mimeTypeDetectors; + internal IEnumerable FormatDetectors => this.imageFormatDetectors; /// /// Gets the currently registered s. /// - internal IEnumerable> ImageDecoders => this.mimeTypeDecoders; + internal IEnumerable> ImageDecoders => this.mimeTypeDecoders; /// /// Gets the currently registered s. /// - internal IEnumerable> ImageEncoders => this.mimeTypeEncoders; + internal IEnumerable> ImageEncoders => this.mimeTypeEncoders; /// - /// Gets the currently registered file extensions. + /// Gets the currently registered s. /// - internal IEnumerable> ImageExtensionToMimeTypeMapping => this.extensionsMap; + internal IEnumerable ImageFormats => this.imageFormats; #if !NETSTANDARD1_1 /// @@ -117,35 +117,69 @@ namespace ImageSharp /// /// Registers a new format provider. /// - /// The format providers to call configure on. - public void AddImageFormat(IImageFormatProvider formatProvider) + /// The configuration provider to call configure on. + public void Configure(IConfigurationModule configuration) { - Guard.NotNull(formatProvider, nameof(formatProvider)); - formatProvider.Configure(this); + Guard.NotNull(configuration, nameof(configuration)); + configuration.Configure(this); } - /// - public void SetMimeTypeEncoder(string mimeType, IImageEncoder encoder) + /// + /// Registers a new format provider. + /// + /// The format to register as a well know format. + public void AddImageFormat(IImageFormat format) { - Guard.NotNullOrEmpty(mimeType, nameof(mimeType)); - Guard.NotNull(encoder, nameof(encoder)); - this.mimeTypeEncoders.AddOrUpdate(mimeType?.Trim(), encoder, (s, e) => encoder); + Guard.NotNull(format, nameof(format)); + Guard.NotNull(format.MimeTypes, nameof(format.MimeTypes)); + Guard.NotNull(format.FileExtensions, nameof(format.FileExtensions)); + this.imageFormats.Add(format); + } + + /// + /// For the specified file extensions type find the e . + /// + /// The extension to discover + /// The if found otherwise null + public IImageFormat FindFormatByFileExtensions(string extension) + { + return this.imageFormats.FirstOrDefault(x => x.FileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase)); } - /// - public void SetFileExtensionToMimeTypeMapping(string extension, string mimeType) + /// + /// For the specified mime type find the . + /// + /// The mime-type to discover + /// The if found otherwise null + public IImageFormat FindFormatByMimeType(string mimeType) { - Guard.NotNullOrEmpty(extension, nameof(extension)); - Guard.NotNullOrEmpty(mimeType, nameof(mimeType)); - this.extensionsMap.AddOrUpdate(extension?.Trim(), mimeType, (s, e) => mimeType); + return this.imageFormats.FirstOrDefault(x => x.MimeTypes.Contains(mimeType, StringComparer.OrdinalIgnoreCase)); } - /// - public void SetMimeTypeDecoder(string mimeType, IImageDecoder decoder) + /// + /// Sets a specific image encoder as the encoder for a specific image format. + /// + /// The image format to register the encoder for. + /// The encoder to use, + 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); + } + + /// + /// Sets a specific image decoder as the decoder for a specific image format. + /// + /// The image format to register the encoder for. + /// The decoder to use, + public void SetDecoder(IImageFormat imageFormat, IImageDecoder decoder) + { + Guard.NotNull(imageFormat, nameof(imageFormat)); Guard.NotNull(decoder, nameof(decoder)); - this.mimeTypeDecoders.AddOrUpdate(mimeType, decoder, (s, e) => decoder); + this.AddImageFormat(imageFormat); + this.mimeTypeDecoders.AddOrUpdate(imageFormat, decoder, (s, e) => decoder); } /// @@ -153,43 +187,46 @@ namespace ImageSharp /// public void ClearMimeTypeDetectors() { - this.mimeTypeDetectors.Clear(); + this.imageFormatDetectors.Clear(); } - /// - public void AddMimeTypeDetector(IMimeTypeDetector detector) + /// + /// Adds a new detector for detecting mime types. + /// + /// The detector to add + public void AddImageFormatDetector(IImageFormatDetector detector) { Guard.NotNull(detector, nameof(detector)); - this.mimeTypeDetectors.Add(detector); + this.imageFormatDetectors.Add(detector); this.SetMaxHeaderSize(); } /// - /// Creates the default instance with the following s preregistered: - /// - /// - /// - /// + /// Creates the default instance with the following s preregistered: + /// + /// + /// + /// /// /// The default configuration of internal static Configuration CreateDefaultInstance() { return new Configuration( - new PngImageFormatProvider(), - new JpegImageFormatProvider(), - new GifImageFormatProvider(), - new BmpImageFormatProvider()); + new PngConfigurationModule(), + new JpegConfigurationModule(), + new GifConfigurationModule(), + new BmpConfigurationModule()); } /// /// For the specified mime type find the decoder. /// - /// The mime type to discover + /// The format to discover /// The if found otherwise null - internal IImageDecoder FindMimeTypeDecoder(string mimeType) + internal IImageDecoder FindDecoder(IImageFormat format) { - Guard.NotNullOrEmpty(mimeType, nameof(mimeType)); - if (this.mimeTypeDecoders.TryGetValue(mimeType, out IImageDecoder decoder)) + Guard.NotNull(format, nameof(format)); + if (this.mimeTypeDecoders.TryGetValue(format, out IImageDecoder decoder)) { return decoder; } @@ -200,12 +237,12 @@ namespace ImageSharp /// /// For the specified mime type find the encoder. /// - /// The mime type to discover + /// The format to discover /// The if found otherwise null - internal IImageEncoder FindMimeTypeEncoder(string mimeType) + internal IImageEncoder FindEncoder(IImageFormat format) { - Guard.NotNullOrEmpty(mimeType, nameof(mimeType)); - if (this.mimeTypeEncoders.TryGetValue(mimeType, out IImageEncoder encoder)) + Guard.NotNull(format, nameof(format)); + if (this.mimeTypeEncoders.TryGetValue(format, out IImageEncoder encoder)) { return encoder; } @@ -213,46 +250,12 @@ namespace ImageSharp return null; } - /// - /// For the specified mime type find the encoder. - /// - /// The extensions to discover - /// The if found otherwise null - 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; - } - - /// - /// For the specified extension find the mime type. - /// - /// the extensions to discover - /// The mime type if found otherwise null - 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; - } - /// /// Sets the max header size. /// private void SetMaxHeaderSize() { - this.MaxHeaderSize = this.mimeTypeDetectors.Max(x => x.HeaderSize); + this.MaxHeaderSize = this.imageFormatDetectors.Max(x => x.HeaderSize); } } } diff --git a/src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs b/src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs new file mode 100644 index 000000000..2553f1454 --- /dev/null +++ b/src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs @@ -0,0 +1,27 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Text; + using ImageSharp.PixelFormats; + + /// + /// Registers the image encoders, decoders and mime type detectors for the bmp format. + /// + public class BmpConfigurationModule : IConfigurationModule + { + /// + public void Configure(Configuration config) + { + config.SetEncoder(ImageFormats.Bitmap, new BmpEncoder()); + config.SetDecoder(ImageFormats.Bitmap, new BmpDecoder()); + config.AddImageFormatDetector(new BmpImageFormatDetector()); + } + } +} diff --git a/src/ImageSharp/Formats/Bmp/BmpFormat.cs b/src/ImageSharp/Formats/Bmp/BmpFormat.cs new file mode 100644 index 000000000..4f32e2875 --- /dev/null +++ b/src/ImageSharp/Formats/Bmp/BmpFormat.cs @@ -0,0 +1,31 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Text; + using ImageSharp.PixelFormats; + + /// + /// Registers the image encoders, decoders and mime type detectors for the jpeg format. + /// + internal sealed class BmpFormat : IImageFormat + { + /// + public string Name => "BMP"; + + /// + public string DefaultMimeType => "image/bmp"; + + /// + public IEnumerable MimeTypes => BmpConstants.MimeTypes; + + /// + public IEnumerable FileExtensions => BmpConstants.FileExtensions; + } +} diff --git a/src/ImageSharp/Formats/Bmp/BmpMimeTypeDetector.cs b/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs similarity index 77% rename from src/ImageSharp/Formats/Bmp/BmpMimeTypeDetector.cs rename to src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs index c13181d6a..4f1054b09 100644 --- a/src/ImageSharp/Formats/Bmp/BmpMimeTypeDetector.cs +++ b/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs @@ -14,23 +14,23 @@ namespace ImageSharp.Formats /// /// Detects bmp file headers /// - internal class BmpMimeTypeDetector : IMimeTypeDetector + internal class BmpImageFormatDetector : IImageFormatDetector { /// public int HeaderSize => 2; /// - public string DetectMimeType(Span header) + public IImageFormat DetectFormat(ReadOnlySpan header) { if (this.IsSupportedFileFormat(header)) { - return "image/bmp"; + return ImageFormats.Bitmap; } return null; } - private bool IsSupportedFileFormat(Span header) + private bool IsSupportedFileFormat(ReadOnlySpan header) { return header.Length >= this.HeaderSize && header[0] == 0x42 && // B diff --git a/src/ImageSharp/Formats/Bmp/BmpImageFormatProvider.cs b/src/ImageSharp/Formats/Bmp/BmpImageFormatProvider.cs deleted file mode 100644 index b532ccfb5..000000000 --- a/src/ImageSharp/Formats/Bmp/BmpImageFormatProvider.cs +++ /dev/null @@ -1,45 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Formats -{ - using System; - using System.Collections.Generic; - using System.IO; - using System.Text; - using ImageSharp.PixelFormats; - - /// - /// Registers the image encoders, decoders and mime type detectors for the bmp format. - /// - public class BmpImageFormatProvider : IImageFormatProvider - { - /// - public void Configure(IImageFormatHost host) - { - var encoder = new BmpEncoder(); - foreach (string mimeType in BmpConstants.MimeTypes) - { - host.SetMimeTypeEncoder(mimeType, encoder); - } - - foreach (string 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()); - } - } -} diff --git a/src/ImageSharp/Formats/Gif/GifConfigurationModule.cs b/src/ImageSharp/Formats/Gif/GifConfigurationModule.cs new file mode 100644 index 000000000..0640cb234 --- /dev/null +++ b/src/ImageSharp/Formats/Gif/GifConfigurationModule.cs @@ -0,0 +1,28 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Text; + using ImageSharp.PixelFormats; + + /// + /// Registers the image encoders, decoders and mime type detectors for the gif format. + /// + public class GifConfigurationModule : IConfigurationModule + { + /// + public void Configure(Configuration config) + { + config.SetEncoder(ImageFormats.Gif, new GifEncoder()); + config.SetDecoder(ImageFormats.Gif, new GifDecoder()); + + config.AddImageFormatDetector(new GifImageFormatDetector()); + } + } +} diff --git a/src/ImageSharp/Formats/Gif/GifFormat.cs b/src/ImageSharp/Formats/Gif/GifFormat.cs new file mode 100644 index 000000000..5aa667ea9 --- /dev/null +++ b/src/ImageSharp/Formats/Gif/GifFormat.cs @@ -0,0 +1,31 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Text; + using ImageSharp.PixelFormats; + + /// + /// Registers the image encoders, decoders and mime type detectors for the jpeg format. + /// + internal sealed class GifFormat : IImageFormat + { + /// + public string Name => "GIF"; + + /// + public string DefaultMimeType => "image/gif"; + + /// + public IEnumerable MimeTypes => GifConstants.MimeTypes; + + /// + public IEnumerable FileExtensions => GifConstants.FileExtensions; + } +} diff --git a/src/ImageSharp/Formats/Gif/GifMimeTypeDetector.cs b/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs similarity index 81% rename from src/ImageSharp/Formats/Gif/GifMimeTypeDetector.cs rename to src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs index f4ad8fa8e..2aee86795 100644 --- a/src/ImageSharp/Formats/Gif/GifMimeTypeDetector.cs +++ b/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs @@ -14,23 +14,23 @@ namespace ImageSharp.Formats /// /// Detects gif file headers /// - public class GifMimeTypeDetector : IMimeTypeDetector + public class GifImageFormatDetector : IImageFormatDetector { /// public int HeaderSize => 6; /// - public string DetectMimeType(Span header) + public IImageFormat DetectFormat(ReadOnlySpan header) { if (this.IsSupportedFileFormat(header)) { - return "image/gif"; + return ImageFormats.Gif; } return null; } - private bool IsSupportedFileFormat(Span header) + private bool IsSupportedFileFormat(ReadOnlySpan header) { return header.Length >= this.HeaderSize && header[0] == 0x47 && // G diff --git a/src/ImageSharp/Formats/Gif/GifImageFormatProvider.cs b/src/ImageSharp/Formats/Gif/GifImageFormatProvider.cs deleted file mode 100644 index 7e16bff72..000000000 --- a/src/ImageSharp/Formats/Gif/GifImageFormatProvider.cs +++ /dev/null @@ -1,45 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Formats -{ - using System; - using System.Collections.Generic; - using System.IO; - using System.Text; - using ImageSharp.PixelFormats; - - /// - /// Registers the image encoders, decoders and mime type detectors for the gif format. - /// - public class GifImageFormatProvider : IImageFormatProvider - { - /// - public void Configure(IImageFormatHost host) - { - var encoder = new GifEncoder(); - foreach (string mimeType in GifConstants.MimeTypes) - { - host.SetMimeTypeEncoder(mimeType, encoder); - } - - foreach (string 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()); - } - } -} diff --git a/src/ImageSharp/Formats/IImageFormat.cs b/src/ImageSharp/Formats/IImageFormat.cs new file mode 100644 index 000000000..8643e2f4c --- /dev/null +++ b/src/ImageSharp/Formats/IImageFormat.cs @@ -0,0 +1,39 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + using System.Collections.Generic; + using System.IO; + + using ImageSharp.PixelFormats; + + /// + /// Describes an image format. + /// + public interface IImageFormat + { + /// + /// Gets the name that describes this image format. + /// + string Name { get; } + + /// + /// Gets the default mimetype that the image foramt uses + /// + string DefaultMimeType { get; } + + /// + /// Gets all the mimetypes that have been used by this image foramt. + /// + IEnumerable MimeTypes { get; } + + /// + /// Gets the file extensions this image format commonly uses. + /// + IEnumerable FileExtensions { get; } + } +} diff --git a/src/ImageSharp/Formats/IMimeTypeDetector.cs b/src/ImageSharp/Formats/IImageFormatDetector.cs similarity index 81% rename from src/ImageSharp/Formats/IMimeTypeDetector.cs rename to src/ImageSharp/Formats/IImageFormatDetector.cs index f55be7151..a53da07e8 100644 --- a/src/ImageSharp/Formats/IMimeTypeDetector.cs +++ b/src/ImageSharp/Formats/IImageFormatDetector.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // @@ -12,7 +12,7 @@ namespace ImageSharp.Formats /// /// Used for detecting mime types from a file header /// - public interface IMimeTypeDetector + public interface IImageFormatDetector { /// /// Gets the size of the header for this image type. @@ -25,6 +25,6 @@ namespace ImageSharp.Formats /// /// The containing the file header. /// returns the mime type of detected othersie returns null - string DetectMimeType(Span header); + IImageFormat DetectFormat(ReadOnlySpan header); } } diff --git a/src/ImageSharp/Formats/IImageFormatProvider.cs b/src/ImageSharp/Formats/IImageFormatProvider.cs deleted file mode 100644 index 1e5ea7f93..000000000 --- a/src/ImageSharp/Formats/IImageFormatProvider.cs +++ /dev/null @@ -1,56 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Formats -{ - using System; - using System.Collections.Generic; - using System.Text; - - /// - /// Represents an interface that can register image encoders, decoders and mime type detectors. - /// - public interface IImageFormatProvider - { - /// - /// Called when loaded so the provider and register its encoders, decoders and mime type detectors into an IImageFormatHost. - /// - /// The host that will retain the encoders, decodes and mime type detectors. - void Configure(IImageFormatHost host); - } - - /// - /// Represents an interface that can have encoders, decoders and mime type detectors loaded into. - /// - public interface IImageFormatHost - { - /// - /// Sets a specific image encoder as the encoder for a specific mime type. - /// - /// the target mimetype - /// the encoder to use - void SetMimeTypeEncoder(string mimeType, IImageEncoder encoder); // could/should this be an Action??? - - /// - /// Sets a mapping value between a file extension and a mime type. - /// - /// The target mime type - /// The mime type this extension equates to - void SetFileExtensionToMimeTypeMapping(string extension, string mimetype); - - /// - /// Sets a specific image decoder as the decoder for a specific mime type. - /// - /// The target mime type - /// The decoder to use - void SetMimeTypeDecoder(string mimeType, IImageDecoder decoder); - - /// - /// Adds a new detector for detecting mime types. - /// - /// The detector to add - void AddMimeTypeDetector(IMimeTypeDetector detector); - } -} diff --git a/src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs b/src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs new file mode 100644 index 000000000..64c7af357 --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs @@ -0,0 +1,28 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Text; + using ImageSharp.PixelFormats; + + /// + /// Registers the image encoders, decoders and mime type detectors for the jpeg format. + /// + public class JpegConfigurationModule : IConfigurationModule + { + /// + public void Configure(Configuration config) + { + config.SetEncoder(ImageFormats.Jpeg, new JpegEncoder()); + config.SetDecoder(ImageFormats.Jpeg, new JpegDecoder()); + + config.AddImageFormatDetector(new JpegImageFormatDetector()); + } + } +} diff --git a/src/ImageSharp/Formats/Jpeg/JpegFormat.cs b/src/ImageSharp/Formats/Jpeg/JpegFormat.cs new file mode 100644 index 000000000..86b624fc8 --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/JpegFormat.cs @@ -0,0 +1,31 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Text; + using ImageSharp.PixelFormats; + + /// + /// Registers the image encoders, decoders and mime type detectors for the jpeg format. + /// + internal sealed class JpegFormat : IImageFormat + { + /// + public string Name => "JPEG"; + + /// + public string DefaultMimeType => "image/jpeg"; + + /// + public IEnumerable MimeTypes => JpegConstants.MimeTypes; + + /// + public IEnumerable FileExtensions => JpegConstants.FileExtensions; + } +} diff --git a/src/ImageSharp/Formats/Jpeg/JpegMimeTypeDetector.cs b/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs similarity index 85% rename from src/ImageSharp/Formats/Jpeg/JpegMimeTypeDetector.cs rename to src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs index f84a91f70..82f810625 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegMimeTypeDetector.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs @@ -14,23 +14,23 @@ namespace ImageSharp.Formats /// /// Detects Jpeg file headers /// - public class JpegMimeTypeDetector : IMimeTypeDetector + public class JpegImageFormatDetector : IImageFormatDetector { /// public int HeaderSize => 11; /// - public string DetectMimeType(Span header) + public IImageFormat DetectFormat(ReadOnlySpan header) { if (this.IsSupportedFileFormat(header)) { - return "image/jpeg"; + return ImageFormats.Jpeg; } return null; } - private bool IsSupportedFileFormat(Span header) + private bool IsSupportedFileFormat(ReadOnlySpan header) { return header.Length >= this.HeaderSize && (this.IsJfif(header) || this.IsExif(header) || this.IsJpeg(header)); @@ -41,7 +41,7 @@ namespace ImageSharp.Formats /// /// The bytes representing the file header. /// The - private bool IsJfif(Span header) + private bool IsJfif(ReadOnlySpan header) { bool isJfif = header[6] == 0x4A && // J @@ -58,7 +58,7 @@ namespace ImageSharp.Formats /// /// The bytes representing the file header. /// The - private bool IsExif(Span header) + private bool IsExif(ReadOnlySpan header) { bool isExif = header[6] == 0x45 && // E @@ -76,7 +76,7 @@ namespace ImageSharp.Formats /// /// The bytes representing the file header. /// The - private bool IsJpeg(Span header) + private bool IsJpeg(ReadOnlySpan header) { bool isJpg = header[0] == 0xFF && // 255 diff --git a/src/ImageSharp/Formats/Jpeg/JpegImageFormatProvider.cs b/src/ImageSharp/Formats/Jpeg/JpegImageFormatProvider.cs deleted file mode 100644 index 5eefa5db1..000000000 --- a/src/ImageSharp/Formats/Jpeg/JpegImageFormatProvider.cs +++ /dev/null @@ -1,45 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Formats -{ - using System; - using System.Collections.Generic; - using System.IO; - using System.Text; - using ImageSharp.PixelFormats; - - /// - /// Registers the image encoders, decoders and mime type detectors for the jpeg format. - /// - public class JpegImageFormatProvider : IImageFormatProvider - { - /// - public void Configure(IImageFormatHost host) - { - var pngEncoder = new JpegEncoder(); - foreach (string mimeType in JpegConstants.MimeTypes) - { - host.SetMimeTypeEncoder(mimeType, pngEncoder); - } - - foreach (string 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()); - } - } -} diff --git a/src/ImageSharp/Formats/Png/PngConfigurationModule.cs b/src/ImageSharp/Formats/Png/PngConfigurationModule.cs new file mode 100644 index 000000000..47fe8b136 --- /dev/null +++ b/src/ImageSharp/Formats/Png/PngConfigurationModule.cs @@ -0,0 +1,27 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Text; + using ImageSharp.PixelFormats; + + /// + /// Registers the image encoders, decoders and mime type detectors for the png format. + /// + public class PngConfigurationModule : IConfigurationModule + { + /// + public void Configure(Configuration host) + { + host.SetEncoder(ImageFormats.Png, new PngEncoder()); + host.SetDecoder(ImageFormats.Png, new PngDecoder()); + host.AddImageFormatDetector(new PngImageFormatDetector()); + } + } +} diff --git a/src/ImageSharp/Formats/Png/PngFormat.cs b/src/ImageSharp/Formats/Png/PngFormat.cs new file mode 100644 index 000000000..60ba30605 --- /dev/null +++ b/src/ImageSharp/Formats/Png/PngFormat.cs @@ -0,0 +1,31 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Text; + using ImageSharp.PixelFormats; + + /// + /// Registers the image encoders, decoders and mime type detectors for the jpeg format. + /// + internal sealed class PngFormat : IImageFormat + { + /// + public string Name => "PNG"; + + /// + public string DefaultMimeType => "image/png"; + + /// + public IEnumerable MimeTypes => PngConstants.MimeTypes; + + /// + public IEnumerable FileExtensions => PngConstants.FileExtensions; + } +} diff --git a/src/ImageSharp/Formats/Png/PngMimeTypeDetector.cs b/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs similarity index 76% rename from src/ImageSharp/Formats/Png/PngMimeTypeDetector.cs rename to src/ImageSharp/Formats/Png/PngImageFormatDetector.cs index 6b5d43fbd..6183ef449 100644 --- a/src/ImageSharp/Formats/Png/PngMimeTypeDetector.cs +++ b/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // @@ -14,23 +14,23 @@ namespace ImageSharp.Formats /// /// Detects png file headers /// - public class PngMimeTypeDetector : IMimeTypeDetector + public class PngImageFormatDetector : IImageFormatDetector { /// public int HeaderSize => 8; /// - public string DetectMimeType(Span header) + public IImageFormat DetectFormat(ReadOnlySpan header) { if (this.IsSupportedFileFormat(header)) { - return "image/png"; + return ImageFormats.Png; } return null; } - private bool IsSupportedFileFormat(Span header) + private bool IsSupportedFileFormat(ReadOnlySpan header) { return header.Length >= this.HeaderSize && header[0] == 0x89 && diff --git a/src/ImageSharp/Formats/Png/PngImageFormatProvider.cs b/src/ImageSharp/Formats/Png/PngImageFormatProvider.cs deleted file mode 100644 index abbbaa6d5..000000000 --- a/src/ImageSharp/Formats/Png/PngImageFormatProvider.cs +++ /dev/null @@ -1,45 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Formats -{ - using System; - using System.Collections.Generic; - using System.IO; - using System.Text; - using ImageSharp.PixelFormats; - - /// - /// Registers the image encoders, decoders and mime type detectors for the png format. - /// - public class PngImageFormatProvider : IImageFormatProvider - { - /// - public void Configure(IImageFormatHost host) - { - var pngEncoder = new PngEncoder(); - foreach (string mimeType in PngConstants.MimeTypes) - { - host.SetMimeTypeEncoder(mimeType, pngEncoder); - } - - foreach (string 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()); - } - } -} diff --git a/src/ImageSharp/IConfigurationModule.cs b/src/ImageSharp/IConfigurationModule.cs new file mode 100644 index 000000000..d37e0042b --- /dev/null +++ b/src/ImageSharp/IConfigurationModule.cs @@ -0,0 +1,23 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + using System; + using System.Collections.Generic; + using System.Text; + + /// + /// Represents an interface that can register image encoders, decoders and image format detectors. + /// + public interface IConfigurationModule + { + /// + /// Called when loaded into a configuration object so the module can register items into the configuration. + /// + /// The configuration that will retain the encoders, decodes and mime type detectors. + void Configure(Configuration configuration); + } +} diff --git a/src/ImageSharp/Image/Image.Decode.cs b/src/ImageSharp/Image/Image.Decode.cs index 436cde466..2408ec3aa 100644 --- a/src/ImageSharp/Image/Image.Decode.cs +++ b/src/ImageSharp/Image/Image.Decode.cs @@ -9,7 +9,7 @@ namespace ImageSharp using System.IO; using System.Linq; using Formats; - + using ImageSharp.Memory; using ImageSharp.PixelFormats; /// @@ -23,7 +23,7 @@ namespace ImageSharp /// The image stream to read the header from. /// The configuration. /// The mime type or null if none found. - 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! int maxHeaderSize = config.MaxHeaderSize; @@ -32,17 +32,12 @@ namespace ImageSharp return null; } - byte[] header = ArrayPool.Shared.Rent(maxHeaderSize); - try + using (var buffer = new Buffer(maxHeaderSize)) { long startPosition = stream.Position; - stream.Read(header, 0, maxHeaderSize); + stream.Read(buffer.Array, 0, maxHeaderSize); stream.Position = startPosition; - return config.MimeTypeDetectors.Select(x => x.DetectMimeType(header)).LastOrDefault(x => x != null); - } - finally - { - ArrayPool.Shared.Return(header); + return config.FormatDetectors.Select(x => x.DetectFormat(buffer)).LastOrDefault(x => x != null); } } @@ -51,14 +46,14 @@ namespace ImageSharp /// /// The image stream to read the header from. /// The configuration. - /// The mimeType. + /// The IImageFormat. /// The image format or null if none found. - 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); - if (mimeType != null) + format = InternalDetectFormat(stream, config); + if (format != null) { - return config.FindMimeTypeDecoder(mimeType); + return config.FindDecoder(format); } return null; @@ -74,18 +69,18 @@ namespace ImageSharp /// /// A new . /// - private static (Image img, string mimeType) Decode(Stream stream, Configuration config) + private static (Image img, IImageFormat format) Decode(Stream stream, Configuration config) #pragma warning restore SA1008 // Opening parenthesis must be spaced correctly where TPixel : struct, IPixel { - IImageDecoder decoder = DiscoverDecoder(stream, config, out string mimeType); + IImageDecoder decoder = DiscoverDecoder(stream, config, out IImageFormat format); if (decoder == null) { return (null, null); } Image img = decoder.Decode(config, stream); - return (img, mimeType); + return (img, format); } } } \ No newline at end of file diff --git a/src/ImageSharp/Image/Image.FromBytes.cs b/src/ImageSharp/Image/Image.FromBytes.cs index 3b9521102..c7023b860 100644 --- a/src/ImageSharp/Image/Image.FromBytes.cs +++ b/src/ImageSharp/Image/Image.FromBytes.cs @@ -16,26 +16,26 @@ namespace ImageSharp public static partial class Image { /// - /// 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. /// /// The byte array containing image data to read the header from. - /// The mime type or null if none found. - public static string DiscoverMimeType(byte[] data) + /// The format or null if none found. + public static IImageFormat DetectFormat(byte[] data) { - return DiscoverMimeType(null, data); + return DetectFormat(null, data); } /// - /// 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. /// /// The configuration. /// The byte array containing image data to read the header from. /// The mime type or null if none found. - public static string DiscoverMimeType(Configuration config, byte[] data) + public static IImageFormat DetectFormat(Configuration config, byte[] 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 class from the given byte array. /// /// The byte array containing image data. - /// The mime type of the decoded image. + /// The mime type of the decoded image. /// A new . - public static Image Load(byte[] data, out string mimeType) => Load(null, data, out mimeType); + public static Image Load(byte[] data, out IImageFormat format) => Load(null, data, out format); /// /// Create a new instance of the class from the given byte array. @@ -67,9 +67,9 @@ namespace ImageSharp /// /// The config for the decoder. /// The byte array containing image data. - /// The mime type of the decoded image. + /// The mime type of the decoded image. /// A new . - public static Image Load(Configuration config, byte[] data, out string mimeType) => Load(config, data, out mimeType); + public static Image Load(Configuration config, byte[] data, out IImageFormat format) => Load(config, data, out format); /// /// Create a new instance of the class from the given byte array. @@ -104,13 +104,13 @@ namespace ImageSharp /// Create a new instance of the class from the given byte array. /// /// The byte array containing image data. - /// The mime type of the decoded image. + /// The mime type of the decoded image. /// The pixel format. /// A new . - public static Image Load(byte[] data, out string mimeType) + public static Image Load(byte[] data, out IImageFormat format) where TPixel : struct, IPixel { - return Load(null, data, out mimeType); + return Load(null, data, out format); } /// @@ -134,15 +134,15 @@ namespace ImageSharp /// /// The configuration options. /// The byte array containing image data. - /// The mime type of the decoded image. + /// The mime type of the decoded image. /// The pixel format. /// A new . - public static Image Load(Configuration config, byte[] data, out string mimeType) + public static Image Load(Configuration config, byte[] data, out IImageFormat format) where TPixel : struct, IPixel { using (var memoryStream = new MemoryStream(data)) { - return Load(config, memoryStream, out mimeType); + return Load(config, memoryStream, out format); } } diff --git a/src/ImageSharp/Image/Image.FromFile.cs b/src/ImageSharp/Image/Image.FromFile.cs index c44a5da5e..ca395ce08 100644 --- a/src/ImageSharp/Image/Image.FromFile.cs +++ b/src/ImageSharp/Image/Image.FromFile.cs @@ -21,9 +21,9 @@ namespace ImageSharp /// /// The image file to open and to read the header from. /// The mime type or null if none found. - public static string DiscoverMimeType(string filePath) + public static IImageFormat DetectFormat(string filePath) { - return DiscoverMimeType(null, filePath); + return DetectFormat(null, filePath); } /// @@ -32,12 +32,12 @@ namespace ImageSharp /// The configuration. /// The image file to open and to read the header from. /// The mime type or null if none found. - public static string DiscoverMimeType(Configuration config, string filePath) + public static IImageFormat DetectFormat(Configuration config, string filePath) { config = config ?? Configuration.Default; 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 class from the given file. /// /// The file path to the image. - /// The mime type of the decoded image. + /// The mime type of the decoded image. /// /// Thrown if the stream is not readable nor seekable. /// /// A new . - public static Image Load(string path, out string mimeType) => Load(path, out mimeType); + public static Image Load(string path, out IImageFormat format) => Load(path, out format); /// /// Create a new instance of the class from the given file. @@ -78,12 +78,12 @@ namespace ImageSharp /// /// The config for the decoder. /// The file path to the image. - /// The mime type of the decoded image. + /// The mime type of the decoded image. /// /// Thrown if the stream is not readable nor seekable. /// /// A new . - public static Image Load(Configuration config, string path, out string mimeType) => Load(config, path, out mimeType); + public static Image Load(Configuration config, string path, out IImageFormat format) => Load(config, path, out format); /// /// Create a new instance of the class from the given file. @@ -127,16 +127,16 @@ namespace ImageSharp /// Create a new instance of the class from the given file. /// /// The file path to the image. - /// The mime type of the decoded image. + /// The mime type of the decoded image. /// /// Thrown if the stream is not readable nor seekable. /// /// The pixel format. /// A new . - public static Image Load(string path, out string mimeType) + public static Image Load(string path, out IImageFormat format) where TPixel : struct, IPixel { - return Load(null, path, out mimeType); + return Load(null, path, out format); } /// @@ -164,19 +164,19 @@ namespace ImageSharp /// /// The configuration options. /// The file path to the image. - /// The mime type of the decoded image. + /// The mime type of the decoded image. /// /// Thrown if the stream is not readable nor seekable. /// /// The pixel format. /// A new . - public static Image Load(Configuration config, string path, out string mimeType) + public static Image Load(Configuration config, string path, out IImageFormat format) where TPixel : struct, IPixel { config = config ?? Configuration.Default; using (Stream stream = config.FileSystem.OpenRead(path)) { - return Load(config, stream, out mimeType); + return Load(config, stream, out format); } } diff --git a/src/ImageSharp/Image/Image.FromStream.cs b/src/ImageSharp/Image/Image.FromStream.cs index 19f930493..7493d66fc 100644 --- a/src/ImageSharp/Image/Image.FromStream.cs +++ b/src/ImageSharp/Image/Image.FromStream.cs @@ -24,9 +24,9 @@ namespace ImageSharp /// /// The image stream to read the header from. /// The mime type or null if none found. - public static string DiscoverMimeType(Stream stream) + public static IImageFormat DetectFormat(Stream stream) { - return DiscoverMimeType(null, stream); + return DetectFormat(null, stream); } /// @@ -35,21 +35,21 @@ namespace ImageSharp /// The configuration. /// The image stream to read the header from. /// The mime type or null if none found. - 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)); } /// /// Create a new instance of the class from the given stream. /// /// The stream containing image information. - /// the mime type of the decoded image. + /// the mime type of the decoded image. /// /// Thrown if the stream is not readable nor seekable. /// /// A new .> - public static Image Load(Stream stream, out string mimeType) => Load(stream, out mimeType); + public static Image Load(Stream stream, out IImageFormat format) => Load(stream, out format); /// /// Create a new instance of the class from the given stream. @@ -88,12 +88,12 @@ namespace ImageSharp /// /// The config for the decoder. /// The stream containing image information. - /// the mime type of the decoded image. + /// the mime type of the decoded image. /// /// Thrown if the stream is not readable nor seekable. /// /// A new .> - public static Image Load(Configuration config, Stream stream, out string mimeType) => Load(config, stream, out mimeType); + public static Image Load(Configuration config, Stream stream, out IImageFormat format) => Load(config, stream, out format); /// /// Create a new instance of the class from the given stream. @@ -114,16 +114,16 @@ namespace ImageSharp /// Create a new instance of the class from the given stream. /// /// The stream containing image information. - /// the mime type of the decoded image. + /// the mime type of the decoded image. /// /// Thrown if the stream is not readable nor seekable. /// /// The pixel format. /// A new .> - public static Image Load(Stream stream, out string mimeType) + public static Image Load(Stream stream, out IImageFormat format) where TPixel : struct, IPixel { - return Load(null, stream, out mimeType); + return Load(null, stream, out format); } /// @@ -180,20 +180,20 @@ namespace ImageSharp /// /// The configuration options. /// The stream containing image information. - /// the mime type of the decoded image. + /// the mime type of the decoded image. /// /// Thrown if the stream is not readable nor seekable. /// /// The pixel format. /// A new .> - public static Image Load(Configuration config, Stream stream, out string mimeType) + public static Image Load(Configuration config, Stream stream, out IImageFormat format) where TPixel : struct, IPixel { config = config ?? Configuration.Default; - mimeType = null; - (Image img, string mimeType) data = WithSeekableStream(stream, s => Decode(s, config)); + format = null; + (Image img, IImageFormat format) data = WithSeekableStream(stream, s => Decode(s, config)); - mimeType = data.mimeType; + format = data.format; if (data.img != null) { @@ -203,9 +203,9 @@ namespace ImageSharp var stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Image cannot be loaded. Available decoders:"); - foreach (KeyValuePair val in config.ImageDecoders) + foreach (KeyValuePair 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()); diff --git a/src/ImageSharp/Image/Image{TPixel}.cs b/src/ImageSharp/Image/Image{TPixel}.cs index 5165bc857..11fea5145 100644 --- a/src/ImageSharp/Image/Image{TPixel}.cs +++ b/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. /// /// The stream to save the image to. - /// The mime type to save the image to. + /// The format to save the image to. /// Thrown if the stream is null. /// The - public Image Save(Stream stream, string mimeType) + public Image Save(Stream stream, IImageFormat format) { - Guard.NotNullOrEmpty(mimeType, nameof(mimeType)); - IImageEncoder encoder = this.Configuration.FindMimeTypeEncoder(mimeType); + Guard.NotNull(format, nameof(format)); + IImageEncoder encoder = this.Configuration.FindEncoder(format); if (encoder == null) { var stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Can't find encoder for provided mime type. Available encoded:"); - foreach (KeyValuePair val in this.Configuration.ImageEncoders) + foreach (KeyValuePair 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()); @@ -207,26 +207,28 @@ namespace ImageSharp Guard.NotNullOrEmpty(filePath, nameof(filePath)); string ext = Path.GetExtension(filePath).Trim('.'); - IImageEncoder encoder = this.Configuration.FindFileExtensionsEncoder(ext); - if (encoder == null) + var format = this.Configuration.FindFormatByFileExtensions(ext); + if (format == null) { var stringBuilder = new StringBuilder(); - string mime = this.Configuration.FindFileExtensionsMimeType(ext); - if (mime == null) + stringBuilder.AppendLine($"Can't find a format that is associated with the file extention '{ext}'. Registered formats with there extensions include:"); + 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:"); - foreach (KeyValuePair map in this.Configuration.ImageExtensionToMimeTypeMapping) - { - stringBuilder.AppendLine($" - {map.Key} : {map.Value}"); - } + stringBuilder.AppendLine($" - {fmt.Name} : {string.Join(", ", fmt.FileExtensions)}"); } - 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 enc in this.Configuration.ImageEncoders) { - stringBuilder.AppendLine($"Can't find encoder for file extention '{ext}' using mime type '{mime}'. Registered encoders include:"); - foreach (KeyValuePair enc in this.Configuration.ImageEncoders) - { - stringBuilder.AppendLine($" - {enc.Key} : {enc.Value.GetType().Name}"); - } + stringBuilder.AppendLine($" - {enc.Key} : {enc.Value.GetType().Name}"); } throw new NotSupportedException(stringBuilder.ToString()); @@ -262,15 +264,15 @@ namespace ImageSharp /// Returns a Base64 encoded string from the given image. /// /// - /// The mimeType. + /// The format. /// The - public string ToBase64String(string mimeType) + public string ToBase64String(IImageFormat format) { using (var stream = new MemoryStream()) { - this.Save(stream, mimeType); + this.Save(stream, format); stream.Flush(); - return $"data:{mimeType};base64,{Convert.ToBase64String(stream.ToArray())}"; + return $"data:{format.DefaultMimeType};base64,{Convert.ToBase64String(stream.ToArray())}"; } } diff --git a/src/ImageSharp/ImageFormats.cs b/src/ImageSharp/ImageFormats.cs new file mode 100644 index 000000000..fb67fb714 --- /dev/null +++ b/src/ImageSharp/ImageFormats.cs @@ -0,0 +1,39 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + using System; + using System.Collections.Generic; + using System.IO; + using ImageSharp.Formats; + using ImageSharp.PixelFormats; + + /// + /// 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 Bitmap = new BmpFormat(); + } +} diff --git a/src/ImageSharp/Memory/Buffer.cs b/src/ImageSharp/Memory/Buffer.cs index a894ea53a..4b3681c74 100644 --- a/src/ImageSharp/Memory/Buffer.cs +++ b/src/ImageSharp/Memory/Buffer.cs @@ -115,6 +115,16 @@ namespace ImageSharp.Memory } } + /// + /// Converts to an . + /// + /// The to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ReadOnlySpan(Buffer buffer) + { + return new ReadOnlySpan(buffer.Array, 0, buffer.Length); + } + /// /// Converts to an . /// diff --git a/tests/ImageSharp.Tests/ConfigurationTests.cs b/tests/ImageSharp.Tests/ConfigurationTests.cs index aa09cf816..417588180 100644 --- a/tests/ImageSharp.Tests/ConfigurationTests.cs +++ b/tests/ImageSharp.Tests/ConfigurationTests.cs @@ -40,8 +40,8 @@ namespace ImageSharp.Tests [Fact] public void IfAutoloadWellknwonFormatesIsTrueAllFormateAreLoaded() { - Assert.Equal(6, DefaultConfiguration.ImageEncoders.Count()); - Assert.Equal(6, DefaultConfiguration.ImageDecoders.Count()); + Assert.Equal(4, DefaultConfiguration.ImageEncoders.Count()); + Assert.Equal(4, DefaultConfiguration.ImageDecoders.Count()); } /// @@ -73,11 +73,11 @@ namespace ImageSharp.Tests } [Fact] - public void AddMimeTypeDetectorNullthrows() + public void AddImageFormatDetectorNullthrows() { Assert.Throws(() => { - DefaultConfiguration.AddMimeTypeDetector(null); + DefaultConfiguration.AddImageFormatDetector(null); }); } @@ -86,49 +86,32 @@ namespace ImageSharp.Tests { Assert.Throws(() => { - DefaultConfiguration.SetMimeTypeEncoder(null, new Mock().Object); + DefaultConfiguration.SetEncoder(null, new Mock().Object); }); Assert.Throws(() => { - DefaultConfiguration.SetMimeTypeEncoder("sdsdsd", null); + DefaultConfiguration.SetEncoder(ImageFormats.Bitmap, null); }); Assert.Throws(() => { - DefaultConfiguration.SetMimeTypeEncoder(null, null); + DefaultConfiguration.SetEncoder(null, null); }); } [Fact] - public void RegisterNullFileExtEncoder() + public void RegisterNullSetDecoder() { Assert.Throws(() => { - DefaultConfiguration.SetFileExtensionToMimeTypeMapping(null, "str"); + DefaultConfiguration.SetDecoder(null, new Mock().Object); }); Assert.Throws(() => { - DefaultConfiguration.SetFileExtensionToMimeTypeMapping("sdsdsd", null); + DefaultConfiguration.SetDecoder(ImageFormats.Bitmap, null); }); Assert.Throws(() => { - DefaultConfiguration.SetFileExtensionToMimeTypeMapping(null, null); - }); - } - - [Fact] - public void RegisterNullMimeTypeDecoder() - { - Assert.Throws(() => - { - DefaultConfiguration.SetMimeTypeDecoder(null, new Mock().Object); - }); - Assert.Throws(() => - { - DefaultConfiguration.SetMimeTypeDecoder("sdsdsd", null); - }); - Assert.Throws(() => - { - DefaultConfiguration.SetMimeTypeDecoder(null, null); + DefaultConfiguration.SetDecoder(null, null); }); } @@ -136,28 +119,13 @@ namespace ImageSharp.Tests public void RegisterMimeTypeEncoderReplacesLast() { var encoder1 = new Mock().Object; - ConfigurationEmpty.SetMimeTypeEncoder("test", encoder1); - var found = ConfigurationEmpty.FindMimeTypeEncoder("TEST"); + ConfigurationEmpty.SetEncoder(TestFormat.GlobalTestFormat, encoder1); + var found = ConfigurationEmpty.FindEncoder(TestFormat.GlobalTestFormat); Assert.Equal(encoder1, found); var encoder2 = new Mock().Object; - ConfigurationEmpty.SetMimeTypeEncoder("TEST", encoder2); - var found2 = ConfigurationEmpty.FindMimeTypeEncoder("test"); - Assert.Equal(encoder2, found2); - Assert.NotEqual(found, found2); - } - - [Fact] - public void RegisterFileExtEnecoderReplacesLast() - { - var encoder1 = "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"); + ConfigurationEmpty.SetEncoder(TestFormat.GlobalTestFormat, encoder2); + var found2 = ConfigurationEmpty.FindEncoder(TestFormat.GlobalTestFormat); Assert.Equal(encoder2, found2); Assert.NotEqual(found, found2); } @@ -166,13 +134,13 @@ namespace ImageSharp.Tests public void RegisterMimeTypeDecoderReplacesLast() { var decoder1 = new Mock().Object; - ConfigurationEmpty.SetMimeTypeDecoder("test", decoder1); - var found = ConfigurationEmpty.FindMimeTypeDecoder("TEST"); + ConfigurationEmpty.SetDecoder(TestFormat.GlobalTestFormat, decoder1); + var found = ConfigurationEmpty.FindDecoder(TestFormat.GlobalTestFormat); Assert.Equal(decoder1, found); var decoder2 = new Mock().Object; - ConfigurationEmpty.SetMimeTypeDecoder("TEST", decoder2); - var found2 = ConfigurationEmpty.FindMimeTypeDecoder("test"); + ConfigurationEmpty.SetDecoder(TestFormat.GlobalTestFormat, decoder2); + var found2 = ConfigurationEmpty.FindDecoder(TestFormat.GlobalTestFormat); Assert.Equal(decoder2, found2); Assert.NotEqual(found, found2); } @@ -181,7 +149,7 @@ namespace ImageSharp.Tests [Fact] public void ConstructorCallConfigureOnFormatProvider() { - var provider = new Mock(); + var provider = new Mock(); var config = new Configuration(provider.Object); provider.Verify(x => x.Configure(config)); @@ -190,9 +158,9 @@ namespace ImageSharp.Tests [Fact] public void AddFormatCallsConfig() { - var provider = new Mock(); + var provider = new Mock(); var config = new Configuration(); - config.AddImageFormat(provider.Object); + config.Configure(provider.Object); provider.Verify(x => x.Configure(config)); } diff --git a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs index 659aa317b..4ef8fe061 100644 --- a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs +++ b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs @@ -6,7 +6,7 @@ namespace ImageSharp.Tests { using System.IO; - + using ImageSharp.Formats; using ImageSharp.PixelFormats; using Xunit; @@ -36,7 +36,7 @@ namespace ImageSharp.Tests using (Image image = file.CreateImage()) { 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) { byte[] serialized; - using (Image image = Image.Load(file.Bytes, out string mimeType)) + using (Image image = Image.Load(file.Bytes, out IImageFormat mimeType)) using (MemoryStream memoryStream = new MemoryStream()) { image.Save(memoryStream, mimeType); diff --git a/tests/ImageSharp.Tests/Image/ImageDiscoverMimeType.cs b/tests/ImageSharp.Tests/Image/ImageDiscoverMimeType.cs index 80414662b..59a39c454 100644 --- a/tests/ImageSharp.Tests/Image/ImageDiscoverMimeType.cs +++ b/tests/ImageSharp.Tests/Image/ImageDiscoverMimeType.cs @@ -17,23 +17,27 @@ namespace ImageSharp.Tests /// /// Tests the class. /// - public class DiscoverMimeTypeTests + public class DiscoverImageFormatTests { private readonly Mock fileSystem; private readonly string FilePath; - private readonly Mock localMimeTypeDetector; + private readonly Mock localMimeTypeDetector; + private readonly Mock localImageFormatMock; + public IImageFormat localImageFormat => localImageFormatMock.Object; public Configuration LocalConfiguration { get; private set; } public byte[] Marker { get; private set; } public MemoryStream DataStream { get; private set; } public byte[] DecodedData { get; private set; } private const string localMimeType = "image/local"; - public DiscoverMimeTypeTests() + public DiscoverImageFormatTests() { - this.localMimeTypeDetector = new Mock(); + this.localImageFormatMock = new Mock(); + + this.localMimeTypeDetector = new Mock(); this.localMimeTypeDetector.Setup(x => x.HeaderSize).Returns(1); - this.localMimeTypeDetector.Setup(x => x.DetectMimeType(It.IsAny>())).Returns(localMimeType); + this.localMimeTypeDetector.Setup(x => x.DetectFormat(It.IsAny>())).Returns(localImageFormatMock.Object); this.fileSystem = new Mock(); @@ -41,7 +45,7 @@ namespace ImageSharp.Tests { FileSystem = this.fileSystem.Object }; - this.LocalConfiguration.AddMimeTypeDetector(this.localMimeTypeDetector.Object); + this.LocalConfiguration.AddImageFormatDetector(this.localMimeTypeDetector.Object); TestFormat.RegisterGloablTestFormat(); this.Marker = Guid.NewGuid().ToByteArray(); @@ -55,52 +59,52 @@ namespace ImageSharp.Tests } [Fact] - public void DiscoverMimeTypeByteArray() + public void DiscoverImageFormatByteArray() { - var type = Image.DiscoverMimeType(DataStream.ToArray()); - Assert.Equal(TestFormat.GlobalTestFormat.MimeType, type); + var type = Image.DetectFormat(DataStream.ToArray()); + Assert.Equal(TestFormat.GlobalTestFormat, type); } [Fact] - public void DiscoverMimeTypeByteArray_WithConfig() + public void DiscoverImageFormatByteArray_WithConfig() { - var type = Image.DiscoverMimeType(this.LocalConfiguration, DataStream.ToArray()); - Assert.Equal(localMimeType, type); + var type = Image.DetectFormat(this.LocalConfiguration, DataStream.ToArray()); + Assert.Equal(localImageFormat, type); } [Fact] - public void DiscoverMimeTypeFile() + public void DiscoverImageFormatFile() { - var type = Image.DiscoverMimeType(this.FilePath); - Assert.Equal(TestFormat.GlobalTestFormat.MimeType, type); + var type = Image.DetectFormat(this.FilePath); + Assert.Equal(TestFormat.GlobalTestFormat, type); } [Fact] - public void DiscoverMimeTypeFilePath_WithConfig() + public void DiscoverImageFormatFilePath_WithConfig() { - var type = Image.DiscoverMimeType(this.LocalConfiguration, FilePath); - Assert.Equal(localMimeType, type); + var type = Image.DetectFormat(this.LocalConfiguration, FilePath); + Assert.Equal(localImageFormat, type); } [Fact] - public void DiscoverMimeTypeStream() + public void DiscoverImageFormatStream() { - var type = Image.DiscoverMimeType(this.DataStream); - Assert.Equal(TestFormat.GlobalTestFormat.MimeType, type); + var type = Image.DetectFormat(this.DataStream); + Assert.Equal(TestFormat.GlobalTestFormat, type); } [Fact] - public void DiscoverMimeTypeFileStream_WithConfig() + public void DiscoverImageFormatFileStream_WithConfig() { - var type = Image.DiscoverMimeType(this.LocalConfiguration, DataStream); - Assert.Equal(localMimeType, type); + var type = Image.DetectFormat(this.LocalConfiguration, DataStream); + Assert.Equal(localImageFormat, type); } [Fact] - public void DiscoverMimeTypeNoDetectorsRegisterdShouldReturnNull() + public void DiscoverImageFormatNoDetectorsRegisterdShouldReturnNull() { - var type = Image.DiscoverMimeType(new Configuration(), DataStream); + var type = Image.DetectFormat(new Configuration(), DataStream); Assert.Null(type); } } diff --git a/tests/ImageSharp.Tests/Image/ImageLoadTests.cs b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs index efd7b6935..bb64ceda3 100644 --- a/tests/ImageSharp.Tests/Image/ImageLoadTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs @@ -23,7 +23,8 @@ namespace ImageSharp.Tests private Image returnImage; private Mock localDecoder; private readonly string FilePath; - private readonly Mock localMimeTypeDetector; + private readonly Mock localMimeTypeDetector; + private readonly Mock localImageFormatMock; public Configuration LocalConfiguration { get; private set; } public byte[] Marker { get; private set; } @@ -34,10 +35,12 @@ namespace ImageSharp.Tests { this.returnImage = new Image(1, 1); + this.localImageFormatMock = new Mock(); + this.localDecoder = new Mock(); - this.localMimeTypeDetector = new Mock(); + this.localMimeTypeDetector = new Mock(); this.localMimeTypeDetector.Setup(x => x.HeaderSize).Returns(1); - this.localMimeTypeDetector.Setup(x => x.DetectMimeType(It.IsAny>())).Returns("test"); + this.localMimeTypeDetector.Setup(x => x.DetectFormat(It.IsAny>())).Returns(localImageFormatMock.Object); this.localDecoder.Setup(x => x.Decode(It.IsAny(), It.IsAny())) @@ -56,8 +59,8 @@ namespace ImageSharp.Tests { FileSystem = this.fileSystem.Object }; - this.LocalConfiguration.AddMimeTypeDetector(this.localMimeTypeDetector.Object); - this.LocalConfiguration.SetMimeTypeDecoder("test", this.localDecoder.Object); + this.LocalConfiguration.AddImageFormatDetector(this.localMimeTypeDetector.Object); + this.LocalConfiguration.SetDecoder(localImageFormatMock.Object, this.localDecoder.Object); TestFormat.RegisterGloablTestFormat(); this.Marker = Guid.NewGuid().ToByteArray(); @@ -78,7 +81,6 @@ namespace ImageSharp.Tests Assert.NotNull(img); TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default); - } [Fact] diff --git a/tests/ImageSharp.Tests/Image/ImageSaveTests.cs b/tests/ImageSharp.Tests/Image/ImageSaveTests.cs index 72461cfc7..eecb98380 100644 --- a/tests/ImageSharp.Tests/Image/ImageSaveTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageSaveTests.cs @@ -24,13 +24,17 @@ namespace ImageSharp.Tests private readonly Mock fileSystem; private readonly Mock encoder; private readonly Mock encoderNotInFormat; - private Mock localMimeTypeDetector; + private Mock localMimeTypeDetector; + private Mock localImageFormat; public ImageSaveTests() { - this.localMimeTypeDetector = new Mock(); + this.localImageFormat = new Mock(); + this.localImageFormat.Setup(x => x.FileExtensions).Returns(new[] { "png" }); + + this.localMimeTypeDetector = new Mock(); this.localMimeTypeDetector.Setup(x => x.HeaderSize).Returns(1); - this.localMimeTypeDetector.Setup(x => x.DetectMimeType(It.IsAny>())).Returns("img/test"); + this.localMimeTypeDetector.Setup(x => x.DetectFormat(It.IsAny>())).Returns(localImageFormat.Object); this.encoder = new Mock(); @@ -41,9 +45,8 @@ namespace ImageSharp.Tests { FileSystem = this.fileSystem.Object }; - config.AddMimeTypeDetector(this.localMimeTypeDetector.Object); - config.SetMimeTypeEncoder("img/test", this.encoder.Object); - config.SetFileExtensionToMimeTypeMapping("png", "img/test"); + config.AddImageFormatDetector(this.localMimeTypeDetector.Object); + config.SetEncoder(localImageFormat.Object, this.encoder.Object); this.Image = new Image(config, 1, 1); } @@ -72,7 +75,7 @@ namespace ImageSharp.Tests [Fact] public void ToBase64String() { - var str = this.Image.ToBase64String("img/test"); + var str = this.Image.ToBase64String(localImageFormat.Object); this.encoder.Verify(x => x.Encode(this.Image, It.IsAny())); } @@ -81,7 +84,7 @@ namespace ImageSharp.Tests public void SaveStreamWithMime() { Stream stream = new MemoryStream(); - this.Image.Save(stream, "img/test"); + this.Image.Save(stream, localImageFormat.Object); this.encoder.Verify(x => x.Encode(this.Image, stream)); } diff --git a/tests/ImageSharp.Tests/Image/ImageTests.cs b/tests/ImageSharp.Tests/Image/ImageTests.cs index cb8607c09..3157c27d8 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.cs @@ -76,7 +76,7 @@ namespace ImageSharp.Tests using (Image 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 img = Image.Load(file, out var mime)) { - Assert.Equal("image/png", mime); + Assert.Equal("image/png", mime.DefaultMimeType); } } } diff --git a/tests/ImageSharp.Tests/TestFormat.cs b/tests/ImageSharp.Tests/TestFormat.cs index 85e11ee87..5a3cd102e 100644 --- a/tests/ImageSharp.Tests/TestFormat.cs +++ b/tests/ImageSharp.Tests/TestFormat.cs @@ -19,13 +19,13 @@ namespace ImageSharp.Tests /// /// A test image file. /// - public class TestFormat : IImageFormatProvider + public class TestFormat : IConfigurationModule, IImageFormat { public static TestFormat GlobalTestFormat { get; } = new TestFormat(); public static void RegisterGloablTestFormat() { - Configuration.Default.AddImageFormat(GlobalTestFormat); + Configuration.Default.Configure(GlobalTestFormat); } public TestFormat() @@ -93,7 +93,15 @@ namespace ImageSharp.Tests public int HeaderSize => this.header.Length; - public bool IsSupportedFileFormat(Span header) + public string Name => this.Extension; + + public string DefaultMimeType => this.MimeType; + + public IEnumerable MimeTypes => new[] { this.MimeType }; + + public IEnumerable FileExtensions => this.SupportedExtensions; + + public bool IsSupportedFileFormat(ReadOnlySpan header) { if (header.Length < this.header.Length) { @@ -109,16 +117,11 @@ namespace ImageSharp.Tests return true; } - public void Configure(IImageFormatHost host) + public void Configure(Configuration host) { - host.AddMimeTypeDetector(new TestHeader(this)); - foreach (var ext in this.SupportedExtensions) - { - host.SetFileExtensionToMimeTypeMapping(ext, this.MimeType); - } - - host.SetMimeTypeEncoder(this.MimeType, new TestEncoder(this)); - host.SetMimeTypeDecoder(this.MimeType, new TestDecoder(this)); + host.AddImageFormatDetector(new TestHeader(this)); + host.SetEncoder(this, new TestEncoder(this)); + host.SetDecoder(this, new TestDecoder(this)); } public struct DecodeOperation @@ -150,17 +153,17 @@ namespace ImageSharp.Tests } } - public class TestHeader : IMimeTypeDetector + public class TestHeader : IImageFormatDetector { private TestFormat testFormat; public int HeaderSize => testFormat.HeaderSize; - public string DetectMimeType(Span header) + public IImageFormat DetectFormat(ReadOnlySpan header) { if (testFormat.IsSupportedFileFormat(header)) - return testFormat.MimeType; + return testFormat; return null; } diff --git a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs index 21b167ca2..47085cf5f 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs @@ -124,13 +124,13 @@ namespace ImageSharp.Tests private static IImageEncoder GetImageFormatByExtension(string extension) { extension = extension?.TrimStart('.'); - return Configuration.Default.FindFileExtensionsEncoder(extension); + var format = Configuration.Default.FindFormatByFileExtensions(extension); + return Configuration.Default.FindEncoder(format); } private string GetTestOutputDir() { string testGroupName = Path.GetFileNameWithoutExtension(this.TestGroupName); - return CreateOutputDirectory(testGroupName); } } From b61cae24d6281eec68e871877b4d77a871adb5ec Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Tue, 27 Jun 2017 08:12:26 +0100 Subject: [PATCH 10/13] fix paramater names --- src/ImageSharp/Configuration.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs index 90fd3a0e6..4c9ba6a41 100644 --- a/src/ImageSharp/Configuration.cs +++ b/src/ImageSharp/Configuration.cs @@ -18,7 +18,7 @@ namespace ImageSharp /// /// Provides initialization code which allows extending the library. /// - public class Configuration + public sealed partial class Configuration { /// /// A lazily initialized configuration default instance. @@ -60,12 +60,12 @@ namespace ImageSharp /// /// Initializes a new instance of the class. /// - /// A collection of providers to configure - public Configuration(params IConfigurationModule[] providers) + /// A collection of configuration modules to register + public Configuration(params IConfigurationModule[] configurationModules) { - if (providers != null) + if (configurationModules != null) { - foreach (IConfigurationModule p in providers) + foreach (IConfigurationModule p in configurationModules) { p.Configure(this); } @@ -183,9 +183,9 @@ namespace ImageSharp } /// - /// Removes all the registered mime type detectors. + /// Removes all the registered image format detectors. /// - public void ClearMimeTypeDetectors() + public void ClearImageFormatDetectors() { this.imageFormatDetectors.Clear(); } From fe346134feae82fe2531529c87f0dff8e990ffef Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 28 Jun 2017 10:14:09 +1000 Subject: [PATCH 11/13] Minor cleanup --- src/ImageSharp/Configuration.cs | 10 ++-------- src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs | 10 ++-------- src/ImageSharp/Formats/Bmp/BmpFormat.cs | 6 +----- src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs | 9 +++------ src/ImageSharp/Formats/Gif/GifConfigurationModule.cs | 10 ++-------- src/ImageSharp/Formats/Gif/GifConstants.cs | 2 +- src/ImageSharp/Formats/Gif/GifFormat.cs | 6 +----- src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs | 9 +++------ src/ImageSharp/Formats/IImageFormat.cs | 6 +----- .../Formats/Jpeg/JpegConfigurationModule.cs | 8 +------- src/ImageSharp/Formats/Jpeg/JpegFormat.cs | 6 +----- .../Formats/Jpeg/JpegImageFormatDetector.cs | 11 +++++------ src/ImageSharp/Formats/Png/PngConfigurationModule.cs | 8 +------- src/ImageSharp/Formats/Png/PngConstants.cs | 3 ++- src/ImageSharp/Formats/Png/PngFormat.cs | 6 +----- src/ImageSharp/Formats/Png/PngImageFormatDetector.cs | 7 ++----- src/ImageSharp/IConfigurationModule.cs | 4 ---- src/ImageSharp/Image/Image.Decode.cs | 1 - src/ImageSharp/Image/Image.FromStream.cs | 2 -- src/ImageSharp/Image/Image{TPixel}.cs | 1 - src/ImageSharp/ImageFormats.cs | 6 +----- 21 files changed, 30 insertions(+), 101 deletions(-) diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs index 4c9ba6a41..226d45132 100644 --- a/src/ImageSharp/Configuration.cs +++ b/src/ImageSharp/Configuration.cs @@ -8,7 +8,6 @@ namespace ImageSharp using System; using System.Collections.Concurrent; using System.Collections.Generic; - using System.Collections.ObjectModel; using System.Linq; using System.Threading.Tasks; @@ -18,17 +17,12 @@ namespace ImageSharp /// /// Provides initialization code which allows extending the library. /// - public sealed partial class Configuration + public sealed class Configuration { /// /// A lazily initialized configuration default instance. /// - private static readonly Lazy Lazy = new Lazy(() => CreateDefaultInstance()); - - /// - /// An object that can be used to synchronize access to the . - /// - private readonly object syncRoot = new object(); + private static readonly Lazy Lazy = new Lazy(CreateDefaultInstance); /// /// The list of supported keyed to mime types. diff --git a/src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs b/src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs index 2553f1454..4534f2636 100644 --- a/src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs +++ b/src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs @@ -1,16 +1,10 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // namespace ImageSharp.Formats { - using System; - using System.Collections.Generic; - using System.IO; - using System.Text; - using ImageSharp.PixelFormats; - /// /// Registers the image encoders, decoders and mime type detectors for the bmp format. /// @@ -24,4 +18,4 @@ namespace ImageSharp.Formats config.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 4f32e2875..fb65f34d7 100644 --- a/src/ImageSharp/Formats/Bmp/BmpFormat.cs +++ b/src/ImageSharp/Formats/Bmp/BmpFormat.cs @@ -5,11 +5,7 @@ namespace ImageSharp.Formats { - using System; using System.Collections.Generic; - using System.IO; - using System.Text; - using ImageSharp.PixelFormats; /// /// Registers the image encoders, decoders and mime type detectors for the jpeg format. @@ -28,4 +24,4 @@ namespace ImageSharp.Formats /// public 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 4f1054b09..96ab92f25 100644 --- a/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // @@ -6,10 +6,6 @@ namespace ImageSharp.Formats { using System; - using System.Collections.Generic; - using System.IO; - using System.Text; - using ImageSharp.PixelFormats; /// /// Detects bmp file headers @@ -32,9 +28,10 @@ namespace ImageSharp.Formats private bool IsSupportedFileFormat(ReadOnlySpan header) { + // TODO: This should be in constants return header.Length >= this.HeaderSize && header[0] == 0x42 && // B header[1] == 0x4D; // M } } -} +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/GifConfigurationModule.cs b/src/ImageSharp/Formats/Gif/GifConfigurationModule.cs index 0640cb234..4e810ffad 100644 --- a/src/ImageSharp/Formats/Gif/GifConfigurationModule.cs +++ b/src/ImageSharp/Formats/Gif/GifConfigurationModule.cs @@ -1,16 +1,10 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // namespace ImageSharp.Formats { - using System; - using System.Collections.Generic; - using System.IO; - using System.Text; - using ImageSharp.PixelFormats; - /// /// Registers the image encoders, decoders and mime type detectors for the gif format. /// @@ -25,4 +19,4 @@ namespace ImageSharp.Formats config.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 7b215b773..9bec6c48f 100644 --- a/src/ImageSharp/Formats/Gif/GifConstants.cs +++ b/src/ImageSharp/Formats/Gif/GifConstants.cs @@ -103,4 +103,4 @@ namespace ImageSharp.Formats /// public static readonly IEnumerable FileExtensions = new[] { "gif" }; } -} +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/GifFormat.cs b/src/ImageSharp/Formats/Gif/GifFormat.cs index 5aa667ea9..ea7b72d32 100644 --- a/src/ImageSharp/Formats/Gif/GifFormat.cs +++ b/src/ImageSharp/Formats/Gif/GifFormat.cs @@ -5,11 +5,7 @@ namespace ImageSharp.Formats { - using System; using System.Collections.Generic; - using System.IO; - using System.Text; - using ImageSharp.PixelFormats; /// /// Registers the image encoders, decoders and mime type detectors for the jpeg format. @@ -28,4 +24,4 @@ namespace ImageSharp.Formats /// public IEnumerable FileExtensions => GifConstants.FileExtensions; } -} +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs b/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs index 2aee86795..5a6dfe198 100644 --- a/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // @@ -6,10 +6,6 @@ namespace ImageSharp.Formats { using System; - using System.Collections.Generic; - using System.IO; - using System.Text; - using ImageSharp.PixelFormats; /// /// Detects gif file headers @@ -32,6 +28,7 @@ namespace ImageSharp.Formats private bool IsSupportedFileFormat(ReadOnlySpan header) { + // TODO: This should be in constants return header.Length >= this.HeaderSize && header[0] == 0x47 && // G header[1] == 0x49 && // I @@ -41,4 +38,4 @@ namespace ImageSharp.Formats header[5] == 0x61; // a } } -} +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/IImageFormat.cs b/src/ImageSharp/Formats/IImageFormat.cs index 8643e2f4c..d6ddc0b0b 100644 --- a/src/ImageSharp/Formats/IImageFormat.cs +++ b/src/ImageSharp/Formats/IImageFormat.cs @@ -5,11 +5,7 @@ namespace ImageSharp.Formats { - using System; using System.Collections.Generic; - using System.IO; - - using ImageSharp.PixelFormats; /// /// Describes an image format. @@ -36,4 +32,4 @@ namespace ImageSharp.Formats /// IEnumerable FileExtensions { get; } } -} +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs b/src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs index 64c7af357..8fe4a35a0 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs @@ -1,16 +1,10 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // namespace ImageSharp.Formats { - using System; - using System.Collections.Generic; - using System.IO; - using System.Text; - using ImageSharp.PixelFormats; - /// /// Registers the image encoders, decoders and mime type detectors for the jpeg format. /// diff --git a/src/ImageSharp/Formats/Jpeg/JpegFormat.cs b/src/ImageSharp/Formats/Jpeg/JpegFormat.cs index 86b624fc8..23cd5d875 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegFormat.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegFormat.cs @@ -5,11 +5,7 @@ namespace ImageSharp.Formats { - using System; using System.Collections.Generic; - using System.IO; - using System.Text; - using ImageSharp.PixelFormats; /// /// Registers the image encoders, decoders and mime type detectors for the jpeg format. @@ -28,4 +24,4 @@ namespace ImageSharp.Formats /// public 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 82f810625..8d6923c8d 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // @@ -6,10 +6,6 @@ namespace ImageSharp.Formats { using System; - using System.Collections.Generic; - using System.IO; - using System.Text; - using ImageSharp.PixelFormats; /// /// Detects Jpeg file headers @@ -43,6 +39,7 @@ namespace ImageSharp.Formats /// The private bool IsJfif(ReadOnlySpan header) { + // TODO: This should be in constants bool isJfif = header[6] == 0x4A && // J header[7] == 0x46 && // F @@ -60,6 +57,7 @@ namespace ImageSharp.Formats /// The private bool IsExif(ReadOnlySpan header) { + // TODO: This should be in constants bool isExif = header[6] == 0x45 && // E header[7] == 0x78 && // X @@ -78,6 +76,7 @@ namespace ImageSharp.Formats /// The private bool IsJpeg(ReadOnlySpan header) { + // TODO: This should be in constants bool isJpg = header[0] == 0xFF && // 255 header[1] == 0xD8; // 216 @@ -85,4 +84,4 @@ namespace ImageSharp.Formats return isJpg; } } -} +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Png/PngConfigurationModule.cs b/src/ImageSharp/Formats/Png/PngConfigurationModule.cs index 47fe8b136..a3813c500 100644 --- a/src/ImageSharp/Formats/Png/PngConfigurationModule.cs +++ b/src/ImageSharp/Formats/Png/PngConfigurationModule.cs @@ -5,12 +5,6 @@ namespace ImageSharp.Formats { - using System; - using System.Collections.Generic; - using System.IO; - using System.Text; - using ImageSharp.PixelFormats; - /// /// Registers the image encoders, decoders and mime type detectors for the png format. /// @@ -24,4 +18,4 @@ namespace ImageSharp.Formats host.AddImageFormatDetector(new PngImageFormatDetector()); } } -} +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Png/PngConstants.cs b/src/ImageSharp/Formats/Png/PngConstants.cs index 8c10ad960..84e76a341 100644 --- a/src/ImageSharp/Formats/Png/PngConstants.cs +++ b/src/ImageSharp/Formats/Png/PngConstants.cs @@ -2,6 +2,7 @@ // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // + namespace ImageSharp.Formats { using System.Collections.Generic; @@ -27,4 +28,4 @@ namespace ImageSharp.Formats /// public static readonly IEnumerable FileExtensions = new[] { "png" }; } -} +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Png/PngFormat.cs b/src/ImageSharp/Formats/Png/PngFormat.cs index 60ba30605..551b4a8c7 100644 --- a/src/ImageSharp/Formats/Png/PngFormat.cs +++ b/src/ImageSharp/Formats/Png/PngFormat.cs @@ -5,11 +5,7 @@ namespace ImageSharp.Formats { - using System; using System.Collections.Generic; - using System.IO; - using System.Text; - using ImageSharp.PixelFormats; /// /// Registers the image encoders, decoders and mime type detectors for the jpeg format. @@ -28,4 +24,4 @@ namespace ImageSharp.Formats /// public 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 6183ef449..a9327983b 100644 --- a/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs @@ -6,10 +6,6 @@ namespace ImageSharp.Formats { using System; - using System.Collections.Generic; - using System.IO; - using System.Text; - using ImageSharp.PixelFormats; /// /// Detects png file headers @@ -32,6 +28,7 @@ namespace ImageSharp.Formats private bool IsSupportedFileFormat(ReadOnlySpan header) { + // TODO: This should be in constants return header.Length >= this.HeaderSize && header[0] == 0x89 && header[1] == 0x50 && // P @@ -43,4 +40,4 @@ namespace ImageSharp.Formats header[7] == 0x0A; // LF } } -} +} \ No newline at end of file diff --git a/src/ImageSharp/IConfigurationModule.cs b/src/ImageSharp/IConfigurationModule.cs index d37e0042b..95b92ed05 100644 --- a/src/ImageSharp/IConfigurationModule.cs +++ b/src/ImageSharp/IConfigurationModule.cs @@ -5,10 +5,6 @@ namespace ImageSharp { - using System; - using System.Collections.Generic; - using System.Text; - /// /// Represents an interface that can register image encoders, decoders and image format detectors. /// diff --git a/src/ImageSharp/Image/Image.Decode.cs b/src/ImageSharp/Image/Image.Decode.cs index 2408ec3aa..101310706 100644 --- a/src/ImageSharp/Image/Image.Decode.cs +++ b/src/ImageSharp/Image/Image.Decode.cs @@ -5,7 +5,6 @@ namespace ImageSharp { - using System.Buffers; using System.IO; using System.Linq; using Formats; diff --git a/src/ImageSharp/Image/Image.FromStream.cs b/src/ImageSharp/Image/Image.FromStream.cs index 7493d66fc..29d93ae85 100644 --- a/src/ImageSharp/Image/Image.FromStream.cs +++ b/src/ImageSharp/Image/Image.FromStream.cs @@ -8,7 +8,6 @@ namespace ImageSharp using System; using System.Collections.Generic; using System.IO; - using System.Linq; using System.Text; using Formats; @@ -190,7 +189,6 @@ namespace ImageSharp where TPixel : struct, IPixel { config = config ?? Configuration.Default; - format = null; (Image img, IImageFormat format) data = WithSeekableStream(stream, s => Decode(s, config)); format = data.format; diff --git a/src/ImageSharp/Image/Image{TPixel}.cs b/src/ImageSharp/Image/Image{TPixel}.cs index 9af788327..5e8bcab31 100644 --- a/src/ImageSharp/Image/Image{TPixel}.cs +++ b/src/ImageSharp/Image/Image{TPixel}.cs @@ -9,7 +9,6 @@ namespace ImageSharp using System.Collections.Generic; using System.Diagnostics; using System.IO; - using System.Linq; using System.Numerics; using System.Text; using System.Threading.Tasks; diff --git a/src/ImageSharp/ImageFormats.cs b/src/ImageSharp/ImageFormats.cs index fb67fb714..f79191eae 100644 --- a/src/ImageSharp/ImageFormats.cs +++ b/src/ImageSharp/ImageFormats.cs @@ -5,11 +5,7 @@ namespace ImageSharp { - using System; - using System.Collections.Generic; - using System.IO; using ImageSharp.Formats; - using ImageSharp.PixelFormats; /// /// The static collection of all the default image formats @@ -36,4 +32,4 @@ namespace ImageSharp /// public static readonly IImageFormat Bitmap = new BmpFormat(); } -} +} \ No newline at end of file From 465c7368411112ac59aec48cc0114158ba517d7b Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Sat, 1 Jul 2017 14:30:34 +0200 Subject: [PATCH 12/13] Made the default IImageFormatDetectors public and sealed. --- src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs | 2 +- src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs | 2 +- src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs | 2 +- src/ImageSharp/Formats/Png/PngImageFormatDetector.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs b/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs index 96ab92f25..697ee0f98 100644 --- a/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs @@ -10,7 +10,7 @@ namespace ImageSharp.Formats /// /// Detects bmp file headers /// - internal class BmpImageFormatDetector : IImageFormatDetector + public sealed class BmpImageFormatDetector : IImageFormatDetector { /// public int HeaderSize => 2; diff --git a/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs b/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs index 5a6dfe198..04fcfc516 100644 --- a/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs @@ -10,7 +10,7 @@ namespace ImageSharp.Formats /// /// Detects gif file headers /// - public class GifImageFormatDetector : IImageFormatDetector + public sealed class GifImageFormatDetector : IImageFormatDetector { /// public int HeaderSize => 6; diff --git a/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs b/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs index 8d6923c8d..b72b290c0 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs @@ -10,7 +10,7 @@ namespace ImageSharp.Formats /// /// Detects Jpeg file headers /// - public class JpegImageFormatDetector : IImageFormatDetector + public sealed class JpegImageFormatDetector : IImageFormatDetector { /// public int HeaderSize => 11; diff --git a/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs b/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs index a9327983b..fdea3eb8a 100644 --- a/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs @@ -10,7 +10,7 @@ namespace ImageSharp.Formats /// /// Detects png file headers /// - public class PngImageFormatDetector : IImageFormatDetector + public sealed class PngImageFormatDetector : IImageFormatDetector { /// public int HeaderSize => 8; From 5ce77d127c6302da62b08362b57e325429f12624 Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Sat, 1 Jul 2017 14:56:21 +0200 Subject: [PATCH 13/13] Sealed some classes and made some classes internal. --- src/ImageSharp/Common/Exceptions/ImageFormatException.cs | 2 +- src/ImageSharp/Common/Exceptions/ImageProcessingException.cs | 2 +- src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs | 2 +- src/ImageSharp/Formats/Bmp/BmpDecoder.cs | 2 +- src/ImageSharp/Formats/Bmp/BmpEncoder.cs | 2 +- src/ImageSharp/Formats/Bmp/BmpFileHeader.cs | 2 +- src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs | 2 +- src/ImageSharp/Formats/Gif/GifConfigurationModule.cs | 2 +- src/ImageSharp/Formats/Gif/GifDecoder.cs | 2 +- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 2 +- src/ImageSharp/Formats/Gif/GifEncoder.cs | 2 +- src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs | 2 +- src/ImageSharp/Formats/Jpeg/JpegDecoder.cs | 2 +- src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs | 2 +- src/ImageSharp/Formats/Jpeg/JpegEncoder.cs | 2 +- src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs | 2 +- src/ImageSharp/Formats/Png/PngConfigurationModule.cs | 2 +- src/ImageSharp/Formats/Png/PngDecoder.cs | 2 +- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 2 +- src/ImageSharp/Formats/Png/PngEncoder.cs | 2 +- src/ImageSharp/Formats/Png/PngHeader.cs | 2 +- src/ImageSharp/Formats/Png/PngInterlaceMode.cs | 2 +- src/ImageSharp/Formats/Png/Zlib/IChecksum.cs | 2 +- src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs | 2 +- 24 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/ImageSharp/Common/Exceptions/ImageFormatException.cs b/src/ImageSharp/Common/Exceptions/ImageFormatException.cs index 70491ba22..32a085435 100644 --- a/src/ImageSharp/Common/Exceptions/ImageFormatException.cs +++ b/src/ImageSharp/Common/Exceptions/ImageFormatException.cs @@ -11,7 +11,7 @@ namespace ImageSharp /// The exception that is thrown when the library tries to load /// an image, which has an invalid format. /// - public class ImageFormatException : Exception + public sealed class ImageFormatException : Exception { /// /// Initializes a new instance of the class. diff --git a/src/ImageSharp/Common/Exceptions/ImageProcessingException.cs b/src/ImageSharp/Common/Exceptions/ImageProcessingException.cs index a59be9ca8..ef84a1e39 100644 --- a/src/ImageSharp/Common/Exceptions/ImageProcessingException.cs +++ b/src/ImageSharp/Common/Exceptions/ImageProcessingException.cs @@ -10,7 +10,7 @@ namespace ImageSharp /// /// The exception that is thrown when an error occurs when applying a process to an image. /// - public class ImageProcessingException : Exception + public sealed class ImageProcessingException : Exception { /// /// Initializes a new instance of the class. diff --git a/src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs b/src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs index 4534f2636..f70ff1a56 100644 --- a/src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs +++ b/src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs @@ -8,7 +8,7 @@ namespace ImageSharp.Formats /// /// Registers the image encoders, decoders and mime type detectors for the bmp format. /// - public class BmpConfigurationModule : IConfigurationModule + public sealed class BmpConfigurationModule : IConfigurationModule { /// public void Configure(Configuration config) diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs index 66af2fa75..5baf1b1a5 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs @@ -26,7 +26,7 @@ namespace ImageSharp.Formats /// Formats will be supported in a later releases. We advise always /// to use only 24 Bit Windows bitmaps. /// - public class BmpDecoder : IImageDecoder, IBmpDecoderOptions + public sealed class BmpDecoder : IImageDecoder, IBmpDecoderOptions { /// public Image Decode(Configuration configuration, Stream stream) diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoder.cs b/src/ImageSharp/Formats/Bmp/BmpEncoder.cs index b0064a508..dfba0b41c 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoder.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoder.cs @@ -15,7 +15,7 @@ namespace ImageSharp.Formats /// Image encoder for writing an image to a stream as a Windows bitmap. /// /// The encoder can currently only write 24-bit rgb images to streams. - public class BmpEncoder : IImageEncoder, IBmpEncoderOptions + public sealed class BmpEncoder : IImageEncoder, IBmpEncoderOptions { /// /// Gets or sets the number of bits per pixel. diff --git a/src/ImageSharp/Formats/Bmp/BmpFileHeader.cs b/src/ImageSharp/Formats/Bmp/BmpFileHeader.cs index 4be602f4b..f9b20a48f 100644 --- a/src/ImageSharp/Formats/Bmp/BmpFileHeader.cs +++ b/src/ImageSharp/Formats/Bmp/BmpFileHeader.cs @@ -15,7 +15,7 @@ namespace ImageSharp.Formats /// All of the other integer values are stored in little-endian format /// (i.e. least-significant byte first). /// - internal class BmpFileHeader + internal sealed class BmpFileHeader { /// /// Defines of the data structure in the bitmap file. diff --git a/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs b/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs index e652cb504..dc6a489d3 100644 --- a/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs +++ b/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs @@ -10,7 +10,7 @@ namespace ImageSharp.Formats /// the screen. /// /// - internal class BmpInfoHeader + internal sealed class BmpInfoHeader { /// /// Defines of the data structure in the bitmap file. diff --git a/src/ImageSharp/Formats/Gif/GifConfigurationModule.cs b/src/ImageSharp/Formats/Gif/GifConfigurationModule.cs index 4e810ffad..ee134d66c 100644 --- a/src/ImageSharp/Formats/Gif/GifConfigurationModule.cs +++ b/src/ImageSharp/Formats/Gif/GifConfigurationModule.cs @@ -8,7 +8,7 @@ namespace ImageSharp.Formats /// /// Registers the image encoders, decoders and mime type detectors for the gif format. /// - public class GifConfigurationModule : IConfigurationModule + public sealed class GifConfigurationModule : IConfigurationModule { /// public void Configure(Configuration config) diff --git a/src/ImageSharp/Formats/Gif/GifDecoder.cs b/src/ImageSharp/Formats/Gif/GifDecoder.cs index e026cc29b..927289094 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoder.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoder.cs @@ -14,7 +14,7 @@ namespace ImageSharp.Formats /// /// Decoder for generating an image out of a gif encoded stream. /// - public class GifDecoder : IImageDecoder, IGifDecoderOptions + public sealed class GifDecoder : IImageDecoder, IGifDecoderOptions { /// /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index 22e5e475b..bb230beac 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -18,7 +18,7 @@ namespace ImageSharp.Formats /// Performs the gif decoding operation. /// /// The pixel format. - internal class GifDecoderCore + internal sealed class GifDecoderCore where TPixel : struct, IPixel { /// diff --git a/src/ImageSharp/Formats/Gif/GifEncoder.cs b/src/ImageSharp/Formats/Gif/GifEncoder.cs index b725f1260..b48db5635 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoder.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoder.cs @@ -15,7 +15,7 @@ namespace ImageSharp.Formats /// /// Image encoder for writing image data to a stream in gif format. /// - public class GifEncoder : IImageEncoder, IGifEncoderOptions + public sealed class GifEncoder : IImageEncoder, IGifEncoderOptions { /// /// Gets or sets a value indicating whether the metadata should be ignored when the image is being encoded. diff --git a/src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs b/src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs index 8fe4a35a0..bb8c4e83f 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs @@ -8,7 +8,7 @@ namespace ImageSharp.Formats /// /// Registers the image encoders, decoders and mime type detectors for the jpeg format. /// - public class JpegConfigurationModule : IConfigurationModule + public sealed class JpegConfigurationModule : IConfigurationModule { /// public void Configure(Configuration config) diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs index 0dc186697..b3caddeca 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs @@ -14,7 +14,7 @@ namespace ImageSharp.Formats /// /// Image decoder for generating an image out of a jpg stream. /// - public class JpegDecoder : IImageDecoder, IJpegDecoderOptions + public sealed class JpegDecoder : IImageDecoder, IJpegDecoderOptions { /// /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 1ce78a8b1..0ce927e51 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -18,7 +18,7 @@ namespace ImageSharp.Formats /// /// Performs the jpeg decoding operation. /// - internal unsafe class JpegDecoderCore : IDisposable + internal sealed unsafe class JpegDecoderCore : IDisposable { /// /// The maximum number of color components diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs index 350856471..6c6561468 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs @@ -14,7 +14,7 @@ namespace ImageSharp.Formats /// /// Encoder for writing the data image to a stream in jpeg format. /// - public class JpegEncoder : IImageEncoder, IJpegEncoderOptions + public sealed class JpegEncoder : IImageEncoder, IJpegEncoderOptions { /// /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 2d67f6735..d2b7d2d7c 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -17,7 +17,7 @@ namespace ImageSharp.Formats /// /// Image encoder for writing an image to a stream as a jpeg. /// - internal unsafe class JpegEncoderCore + internal sealed unsafe class JpegEncoderCore { /// /// The number of quantization tables. diff --git a/src/ImageSharp/Formats/Png/PngConfigurationModule.cs b/src/ImageSharp/Formats/Png/PngConfigurationModule.cs index a3813c500..bb1c2086c 100644 --- a/src/ImageSharp/Formats/Png/PngConfigurationModule.cs +++ b/src/ImageSharp/Formats/Png/PngConfigurationModule.cs @@ -8,7 +8,7 @@ namespace ImageSharp.Formats /// /// Registers the image encoders, decoders and mime type detectors for the png format. /// - public class PngConfigurationModule : IConfigurationModule + public sealed class PngConfigurationModule : IConfigurationModule { /// public void Configure(Configuration host) diff --git a/src/ImageSharp/Formats/Png/PngDecoder.cs b/src/ImageSharp/Formats/Png/PngDecoder.cs index 2e177bc21..61a8cb212 100644 --- a/src/ImageSharp/Formats/Png/PngDecoder.cs +++ b/src/ImageSharp/Formats/Png/PngDecoder.cs @@ -31,7 +31,7 @@ namespace ImageSharp.Formats /// /// /// - public class PngDecoder : IImageDecoder, IPngDecoderOptions + public sealed class PngDecoder : IImageDecoder, IPngDecoderOptions { /// /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index aef588f25..e6f19b915 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -20,7 +20,7 @@ namespace ImageSharp.Formats /// /// Performs the png decoding operation. /// - internal class PngDecoderCore + internal sealed class PngDecoderCore { /// /// The dictionary of available color types. diff --git a/src/ImageSharp/Formats/Png/PngEncoder.cs b/src/ImageSharp/Formats/Png/PngEncoder.cs index f0d332fc4..bfd82a074 100644 --- a/src/ImageSharp/Formats/Png/PngEncoder.cs +++ b/src/ImageSharp/Formats/Png/PngEncoder.cs @@ -14,7 +14,7 @@ namespace ImageSharp.Formats /// /// Image encoder for writing image data to a stream in png format. /// - public class PngEncoder : IImageEncoder, IPngEncoderOptions + public sealed class PngEncoder : IImageEncoder, IPngEncoderOptions { /// /// Gets or sets a value indicating whether the metadata should be ignored when the image is being encoded. diff --git a/src/ImageSharp/Formats/Png/PngHeader.cs b/src/ImageSharp/Formats/Png/PngHeader.cs index 50d6cc9ec..9cf823fa1 100644 --- a/src/ImageSharp/Formats/Png/PngHeader.cs +++ b/src/ImageSharp/Formats/Png/PngHeader.cs @@ -8,7 +8,7 @@ namespace ImageSharp.Formats /// /// Represents the png header chunk. /// - public sealed class PngHeader + internal sealed class PngHeader { /// /// Gets or sets the dimension in x-direction of the image in pixels. diff --git a/src/ImageSharp/Formats/Png/PngInterlaceMode.cs b/src/ImageSharp/Formats/Png/PngInterlaceMode.cs index ec3b8ebe7..b43aff0b7 100644 --- a/src/ImageSharp/Formats/Png/PngInterlaceMode.cs +++ b/src/ImageSharp/Formats/Png/PngInterlaceMode.cs @@ -8,7 +8,7 @@ namespace ImageSharp.Formats /// /// Provides enumeration of available PNG interlace modes. /// - public enum PngInterlaceMode : byte + internal enum PngInterlaceMode : byte { /// /// Non interlaced diff --git a/src/ImageSharp/Formats/Png/Zlib/IChecksum.cs b/src/ImageSharp/Formats/Png/Zlib/IChecksum.cs index 935cdf953..cbd292dc4 100644 --- a/src/ImageSharp/Formats/Png/Zlib/IChecksum.cs +++ b/src/ImageSharp/Formats/Png/Zlib/IChecksum.cs @@ -12,7 +12,7 @@ namespace ImageSharp.Formats /// Value. The complete checksum object can also be reset /// so it can be used again with new data. /// - public interface IChecksum + internal interface IChecksum { /// /// Gets the data checksum computed so far. diff --git a/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs b/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs index 0743d8ded..136f919da 100644 --- a/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs +++ b/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs @@ -9,7 +9,7 @@ /// /// Provides methods and properties for deframing streams from PNGs. /// - internal class ZlibInflateStream : Stream + internal sealed class ZlibInflateStream : Stream { /// /// The inner raw memory stream