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));