From a1908fb909bb0c6f631089b809e76230cdb48ff3 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 25 Jun 2017 13:04:25 +0100 Subject: [PATCH] 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);