Browse Source

add internal IXXOptions to provider cleaner passing of params to core encoders/decoders

af/merge-core
Scott Williams 9 years ago
parent
commit
a1908fb909
  1. 17
      samples/ChangeDefaultEncoderOptions/Program.cs
  2. 4
      src/ImageSharp/Formats/Bmp/BmpDecoder.cs
  3. 3
      src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
  4. 5
      src/ImageSharp/Formats/Bmp/BmpEncoder.cs
  5. 20
      src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
  6. 21
      src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs
  7. 25
      src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs
  8. 11
      src/ImageSharp/Formats/Gif/GifDecoder.cs
  9. 19
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs
  10. 14
      src/ImageSharp/Formats/Gif/GifEncoder.cs
  11. 44
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  12. 29
      src/ImageSharp/Formats/Gif/IGifDecoderOptions.cs
  13. 45
      src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs
  14. 24
      src/ImageSharp/Formats/Jpeg/IJpegDecoderOptions.cs
  15. 37
      src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs
  16. 5
      src/ImageSharp/Formats/Jpeg/JpegDecoder.cs
  17. 8
      src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
  18. 16
      src/ImageSharp/Formats/Jpeg/JpegEncoder.cs
  19. 41
      src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
  20. 29
      src/ImageSharp/Formats/Png/IPngDecoderOptions.cs
  21. 64
      src/ImageSharp/Formats/Png/IPngEncoderOptions.cs
  22. 5
      src/ImageSharp/Formats/Png/PngDecoder.cs
  23. 31
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  24. 14
      src/ImageSharp/Formats/Png/PngEncoder.cs
  25. 68
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  26. 13
      tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs
  27. 2
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs

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

4
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.
/// </remarks>
public class BmpDecoder : IImageDecoder
public class BmpDecoder : IImageDecoder, IBmpDecoderOptions
{
/// <inheritdoc/>
public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)
@ -35,7 +35,7 @@ namespace ImageSharp.Formats
{
Guard.NotNull(stream, "stream");
return new BmpDecoderCore(configuration).Decode<TPixel>(stream);
return new BmpDecoderCore(configuration, this).Decode<TPixel>(stream);
}
}
}

3
src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs

@ -52,7 +52,8 @@ namespace ImageSharp.Formats
/// Initializes a new instance of the <see cref="BmpDecoderCore"/> class.
/// </summary>
/// <param name="configuration">The configuration.</param>
public BmpDecoderCore(Configuration configuration)
/// <param name="options">The options</param>
public BmpDecoderCore(Configuration configuration, IBmpDecoderOptions options)
{
this.configuration = configuration;
}

5
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.
/// </summary>
/// <remarks>The encoder can currently only write 24-bit rgb images to streams.</remarks>
public class BmpEncoder : IImageEncoder
public class BmpEncoder : IImageEncoder, IBmpEncoderOptions
{
/// <summary>
/// Gets or sets the number of bits per pixel.
@ -26,8 +26,7 @@ namespace ImageSharp.Formats
public void Encode<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : struct, IPixel<TPixel>
{
BmpEncoderCore encoder = new BmpEncoderCore();
encoder.BitsPerPixel = this.BitsPerPixel;
var encoder = new BmpEncoderCore(this);
encoder.Encode(image, stream);
}
}

20
src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs

@ -23,16 +23,18 @@ namespace ImageSharp.Formats
private int padding;
/// <summary>
/// Initializes a new instance of the <see cref="BmpEncoderCore"/> class.
/// Gets or sets the number of bits per pixel.
/// </summary>
public BmpEncoderCore()
{
}
private BmpBitsPerPixel bitsPerPixel;
/// <summary>
/// Gets or sets the number of bits per pixel.
/// Initializes a new instance of the <see cref="BmpEncoderCore"/> class.
/// </summary>
public BmpBitsPerPixel BitsPerPixel { get; internal set; } = BmpBitsPerPixel.Pixel24;
/// <param name="options">The encoder options</param>
public BmpEncoderCore(IBmpEncoderOptions options)
{
this.bitsPerPixel = options.BitsPerPixel;
}
/// <summary>
/// Encodes the image to the specified stream from the <see cref="ImageBase{TPixel}"/>.
@ -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<TPixel> pixels = image.Lock())
{
switch (this.BitsPerPixel)
switch (this.bitsPerPixel)
{
case BmpBitsPerPixel.Pixel32:
this.Write32Bit(writer, pixels);

21
src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs

@ -0,0 +1,21 @@
// <copyright file="BmpDecoder.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats
{
using System;
using System.Collections.Generic;
using System.IO;
using ImageSharp.PixelFormats;
/// <summary>
/// Image decoder options for decoding Windows bitmap streams.
/// </summary>
internal interface IBmpDecoderOptions
{
// added this for consistancy so we can add stuff as required, no options currently availible
}
}

25
src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs

@ -0,0 +1,25 @@
// <copyright file="BmpEncoder.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats
{
using System;
using System.Collections.Generic;
using System.IO;
using ImageSharp.PixelFormats;
/// <summary>
/// Configuration options for use during bmp encoding
/// </summary>
/// <remarks>The encoder can currently only write 24-bit rgb images to streams.</remarks>
internal interface IBmpEncoderOptions
{
/// <summary>
/// Gets the number of bits per pixel.
/// </summary>
BmpBitsPerPixel BitsPerPixel { get; }
}
}

11
src/ImageSharp/Formats/Gif/GifDecoder.cs

@ -14,18 +14,13 @@ namespace ImageSharp.Formats
/// <summary>
/// Decoder for generating an image out of a gif encoded stream.
/// </summary>
public class GifDecoder : IImageDecoder
public class GifDecoder : IImageDecoder, IGifDecoderOptions
{
/// <summary>
/// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded.
/// </summary>
public bool IgnoreMetadata { get; set; } = false;
/// <summary>
/// Gets or sets a value indicating whether the additional frames should be ignored when the image is being decoded.
/// </summary>
public bool IgnoreFrames { get; set; } = false;
/// <summary>
/// Gets or sets the encoding that should be used when reading comments.
/// </summary>
@ -35,9 +30,7 @@ namespace ImageSharp.Formats
public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)
where TPixel : struct, IPixel<TPixel>
{
var decoder = new GifDecoderCore<TPixel>(this.TextEncoding, configuration);
decoder.IgnoreMetadata = this.IgnoreMetadata;
decoder.IgnoreFrames = this.IgnoreFrames;
var decoder = new GifDecoderCore<TPixel>(configuration, this);
return decoder.Decode(stream);
}
}

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

@ -78,11 +78,12 @@ namespace ImageSharp.Formats
/// <summary>
/// Initializes a new instance of the <see cref="GifDecoderCore{TPixel}"/> class.
/// </summary>
/// <param name="encoding">The decoder encoding.</param>
/// <param name="configuration">The configuration.</param>
public GifDecoderCore(Encoding encoding, Configuration configuration)
/// <param name="options">The decoder options.</param>
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
/// </summary>
public Encoding TextEncoding { get; private set; }
/// <summary>
/// Gets or sets a value indicating whether the additional frames should be ignored when the image is being decoded.
/// </summary>
public bool IgnoreFrames { get; internal set; }
/// <summary>
/// Decodes the stream to the image.
/// </summary>
@ -362,13 +358,6 @@ namespace ImageSharp.Formats
/// <param name="descriptor">The <see cref="GifImageDescriptor"/></param>
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;

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

@ -15,18 +15,13 @@ namespace ImageSharp.Formats
/// <summary>
/// Image encoder for writing image data to a stream in gif format.
/// </summary>
public class GifEncoder : IImageEncoder
public class GifEncoder : IImageEncoder, IGifEncoderOptions
{
/// <summary>
/// Gets or sets a value indicating whether the metadata should be ignored when the image is being encoded.
/// </summary>
public bool IgnoreMetadata { get; set; } = false;
/// <summary>
/// Gets or sets a value indicating whether the additional frames should be ignored when the image is being encoded.
/// </summary>
public bool IgnoreFrames { get; set; } = false;
/// <summary>
/// Gets or sets the encoding that should be used when writing comments.
/// </summary>
@ -51,12 +46,7 @@ namespace ImageSharp.Formats
public void Encode<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : struct, IPixel<TPixel>
{
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);
}
}

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

@ -35,44 +35,44 @@ namespace ImageSharp.Formats
/// </summary>
private bool hasFrames;
/// <summary>
/// Initializes a new instance of the <see cref="GifEncoderCore"/> class.
/// </summary>
/// <param name="encoding">The encoding for the encoder.</param>
public GifEncoderCore(Encoding encoding)
{
this.TextEncoding = encoding ?? GifConstants.DefaultEncoding;
}
/// <summary>
/// Gets the TextEncoding
/// </summary>
public Encoding TextEncoding { get; private set; }
private Encoding textEncoding;
/// <summary>
/// Gets or sets the quantizer for reducing the color count.
/// </summary>
public IQuantizer Quantizer { get; set; }
private IQuantizer quantizer;
/// <summary>
/// Gets or sets the threshold.
/// </summary>
public byte Threshold { get; internal set; }
private byte threshold;
/// <summary>
/// Gets or sets the size of the color palette to use.
/// </summary>
public int PaletteSize { get; internal set; }
private int paletteSize;
/// <summary>
/// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded.
/// </summary>
public bool IgnoreMetadata { get; internal set; }
private bool ignoreMetadata;
/// <summary>
/// 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 <see cref="GifEncoderCore"/> class.
/// </summary>
public bool IgnoreFrames { get; internal set; }
/// <param name="options">The options for the encoder.</param>
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;
}
/// <summary>
/// Encodes the image to the specified stream from the <see cref="Image{TPixel}"/>.
@ -86,22 +86,22 @@ namespace ImageSharp.Formats
Guard.NotNull(image, nameof(image));
Guard.NotNull(stream, nameof(stream));
this.Quantizer = this.Quantizer ?? new OctreeQuantizer<TPixel>();
this.quantizer = this.quantizer ?? new OctreeQuantizer<TPixel>();
// 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<TPixel>)this.Quantizer;
var ditheredQuantizer = (IQuantizer<TPixel>)this.quantizer;
ditheredQuantizer.Dither = !this.hasFrames;
// Quantize the image returning a palette.
@ -260,7 +260,7 @@ namespace ImageSharp.Formats
private void WriteComments<TPixel>(Image<TPixel> image, EndianBinaryWriter writer)
where TPixel : struct, IPixel<TPixel>
{
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);

29
src/ImageSharp/Formats/Gif/IGifDecoderOptions.cs

@ -0,0 +1,29 @@
// <copyright file="GifDecoder.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using ImageSharp.PixelFormats;
/// <summary>
/// Decoder for generating an image out of a gif encoded stream.
/// </summary>
internal interface IGifDecoderOptions
{
/// <summary>
/// Gets a value indicating whether the metadata should be ignored when the image is being decoded.
/// </summary>
bool IgnoreMetadata { get; }
/// <summary>
/// Gets the encoding that should be used when reading comments.
/// </summary>
Encoding TextEncoding { get; }
}
}

45
src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs

@ -0,0 +1,45 @@
// <copyright file="GifEncoder.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using ImageSharp.PixelFormats;
using ImageSharp.Quantizers;
/// <summary>
/// The configuration options used for encoding gifs
/// </summary>
internal interface IGifEncoderOptions
{
/// <summary>
/// Gets a value indicating whether the metadata should be ignored when the image is being encoded.
/// </summary>
bool IgnoreMetadata { get; }
/// <summary>
/// Gets the encoding that should be used when writing comments.
/// </summary>
Encoding TextEncoding { get; }
/// <summary>
/// Gets the size of the color palette to use. For gifs the value ranges from 1 to 256. Leave as zero for default size.
/// </summary>
int PaletteSize { get; }
/// <summary>
/// Gets the transparency threshold.
/// </summary>
byte Threshold { get; }
/// <summary>
/// Gets the quantizer for reducing the color count.
/// </summary>
IQuantizer Quantizer { get; }
}
}

24
src/ImageSharp/Formats/Jpeg/IJpegDecoderOptions.cs

@ -0,0 +1,24 @@
// <copyright file="JpegDecoder.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats
{
using System;
using System.Collections.Generic;
using System.IO;
using ImageSharp.PixelFormats;
/// <summary>
/// Image decoder for generating an image out of a jpg stream.
/// </summary>
internal interface IJpegDecoderOptions
{
/// <summary>
/// Gets a value indicating whether the metadata should be ignored when the image is being decoded.
/// </summary>
bool IgnoreMetadata { get; }
}
}

37
src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs

@ -0,0 +1,37 @@
// <copyright file="JpegEncoder.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats
{
using System;
using System.Collections.Generic;
using System.IO;
using ImageSharp.PixelFormats;
/// <summary>
/// Encoder for writing the data image to a stream in jpeg format.
/// </summary>
internal interface IJpegEncoderOptions
{
/// <summary>
/// Gets a value indicating whether the metadata should be ignored when the image is being decoded.
/// </summary>
bool IgnoreMetadata { get; }
/// <summary>
/// Gets the quality, that will be used to encode the image. Quality
/// index must be between 0 and 100 (compression from max to min).
/// </summary>
/// <value>The quality of the jpg image from 0 to 100.</value>
int Quality { get; }
/// <summary>
/// Gets the subsample ration, that will be used to encode the image.
/// </summary>
/// <value>The subsample ratio of the jpg image.</value>
JpegSubsample? Subsample { get; }
}
}

5
src/ImageSharp/Formats/Jpeg/JpegDecoder.cs

@ -14,7 +14,7 @@ namespace ImageSharp.Formats
/// <summary>
/// Image decoder for generating an image out of a jpg stream.
/// </summary>
public class JpegDecoder : IImageDecoder
public class JpegDecoder : IImageDecoder, IJpegDecoderOptions
{
/// <summary>
/// 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<TPixel>(stream);
}
}

8
src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs

@ -99,8 +99,10 @@ namespace ImageSharp.Formats
/// Initializes a new instance of the <see cref="JpegDecoderCore" /> class.
/// </summary>
/// <param name="configuration">The configuration.</param>
public JpegDecoderCore(Configuration configuration)
/// <param name="options">The options.</param>
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;
/// <summary>
/// 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.
/// </summary>
public bool IgnoreMetadata { get; internal set; }
public bool IgnoreMetadata { get; private set; }
/// <summary>
/// Decodes the image from the specified <see cref="Stream"/> and sets

16
src/ImageSharp/Formats/Jpeg/JpegEncoder.cs

@ -14,7 +14,7 @@ namespace ImageSharp.Formats
/// <summary>
/// Encoder for writing the data image to a stream in jpeg format.
/// </summary>
public class JpegEncoder : IImageEncoder
public class JpegEncoder : IImageEncoder, IJpegEncoderOptions
{
/// <summary>
/// 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<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : struct, IPixel<TPixel>
{
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);
}
}

41
src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs

@ -149,29 +149,40 @@ namespace ImageSharp.Formats
/// </summary>
private Stream outputStream;
/// <summary>
/// Initializes a new instance of the <see cref="JpegEncoderCore"/> class.
/// </summary>
public JpegEncoderCore()
{
}
/// <summary>
/// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded.
/// </summary>
public bool IgnoreMetadata { get; internal set; } = false;
private bool ignoreMetadata = false;
/// <summary>
/// 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).
/// </summary>
/// <value>The quality of the jpg image from 0 to 100.</value>
public int Quality { get; internal set; }
private int quality = 0;
/// <summary>
/// Gets or sets the subsampling method to use.
/// </summary>
public JpegSubsample? Subsample { get; internal set; }
private JpegSubsample? subsample;
/// <summary>
/// Initializes a new instance of the <see cref="JpegEncoderCore"/> class.
/// </summary>
/// <param name="options">The options</param>
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;
}
/// <summary>
/// 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<TPixel>(Image<TPixel> image)
where TPixel : struct, IPixel<TPixel>
{
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);

29
src/ImageSharp/Formats/Png/IPngDecoderOptions.cs

@ -0,0 +1,29 @@
// <copyright file="PngDecoder.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using ImageSharp.PixelFormats;
/// <summary>
/// The optioas for decoding png images
/// </summary>
internal interface IPngDecoderOptions
{
/// <summary>
/// Gets a value indicating whether the metadata should be ignored when the image is being decoded.
/// </summary>
bool IgnoreMetadata { get; }
/// <summary>
/// Gets the encoding that should be used when reading text chunks.
/// </summary>
Encoding TextEncoding { get; }
}
}

64
src/ImageSharp/Formats/Png/IPngEncoderOptions.cs

@ -0,0 +1,64 @@
// <copyright file="PngEncoder.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats
{
using System.Collections.Generic;
using System.IO;
using ImageSharp.PixelFormats;
using ImageSharp.Quantizers;
/// <summary>
/// The options availible for manipulating the encoder pipeline
/// </summary>
internal interface IPngEncoderOptions
{
/// <summary>
/// Gets a value indicating whether the metadata should be ignored when the image is being encoded.
/// </summary>
bool IgnoreMetadata { get; }
/// <summary>
/// Gets the size of the color palette to use. Set to zero to leav png encoding to use pixel data.
/// </summary>
int PaletteSize { get; }
/// <summary>
/// Gets the png color type
/// </summary>
PngColorType PngColorType { get; }
/// <summary>
/// Gets the compression level 1-9.
/// <remarks>Defaults to 6.</remarks>
/// </summary>
int CompressionLevel { get; }
/// <summary>
/// Gets the gamma value, that will be written
/// the the stream, when the <see cref="WriteGamma"/> property
/// is set to true. The default value is 2.2F.
/// </summary>
/// <value>The gamma value of the image.</value>
float Gamma { get; }
/// <summary>
/// Gets quantizer for reducing the color count.
/// </summary>
IQuantizer Quantizer { get; }
/// <summary>
/// Gets the transparency threshold.
/// </summary>
byte Threshold { get; }
/// <summary>
/// Gets a value indicating whether this instance should write
/// gamma information to the stream. The default value is false.
/// </summary>
bool WriteGamma { get; }
}
}

5
src/ImageSharp/Formats/Png/PngDecoder.cs

@ -31,7 +31,7 @@ namespace ImageSharp.Formats
/// </list>
/// </para>
/// </remarks>
public class PngDecoder : IImageDecoder
public class PngDecoder : IImageDecoder, IPngDecoderOptions
{
/// <summary>
/// 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<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)
where TPixel : struct, IPixel<TPixel>
{
var decoder = new PngDecoderCore(configuration, this.TextEncoding);
decoder.IgnoreMetadata = this.IgnoreMetadata;
var decoder = new PngDecoderCore(configuration, this);
return decoder.Decode<TPixel>(stream);
}
}

31
src/ImageSharp/Formats/Png/PngDecoderCore.cs

@ -155,25 +155,26 @@ namespace ImageSharp.Formats
private PngColorType pngColorType;
/// <summary>
/// Initializes a new instance of the <see cref="PngDecoderCore"/> class.
/// Gets the encoding to use
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="encoding">The text encoding.</param>
public PngDecoderCore(Configuration configuration, Encoding encoding)
{
this.configuration = configuration ?? Configuration.Default;
this.TextEncoding = encoding ?? PngConstants.DefaultEncoding;
}
private Encoding textEncoding;
/// <summary>
/// Gets the encoding to use
/// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded.
/// </summary>
public Encoding TextEncoding { get; private set; }
private bool ignoreMetadata;
/// <summary>
/// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded.
/// Initializes a new instance of the <see cref="PngDecoderCore"/> class.
/// </summary>
public bool IgnoreMetadata { get; internal set; }
/// <param name="configuration">The configuration.</param>
/// <param name="options">The decoder options.</param>
public PngDecoderCore(Configuration configuration, IPngDecoderOptions options)
{
this.configuration = configuration ?? Configuration.Default;
this.textEncoding = options.TextEncoding ?? PngConstants.DefaultEncoding;
this.ignoreMetadata = options.IgnoreMetadata;
}
/// <summary>
/// Decodes the stream to the image.
@ -900,7 +901,7 @@ namespace ImageSharp.Formats
/// <param name="length">The maximum length to read.</param>
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));
}

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

@ -14,7 +14,7 @@ namespace ImageSharp.Formats
/// <summary>
/// Image encoder for writing image data to a stream in png format.
/// </summary>
public class PngEncoder : IImageEncoder
public class PngEncoder : IImageEncoder, IPngEncoderOptions
{
/// <summary>
/// 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<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : struct, IPixel<TPixel>
{
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);
}
}

68
src/ImageSharp/Formats/Png/PngEncoderCore.cs

@ -118,52 +118,51 @@ namespace ImageSharp.Formats
/// </summary>
private IQuantizer quantizer;
/// <summary>
/// Initializes a new instance of the <see cref="PngEncoderCore"/> class.
/// </summary>
public PngEncoderCore()
{
}
/// <summary>
/// Gets or sets a value indicating whether to ignore metadata
/// </summary>
public bool IgnoreMetadata { get; internal set; }
/// <summary>
/// Gets or sets the Quality value
/// </summary>
public int PaletteSize { get; internal set; }
private bool ignoreMetadata;
/// <summary>
/// Gets or sets the Quality value
/// </summary>
public PngColorType PngColorType { get; internal set; }
private int paletteSize;
/// <summary>
/// Gets or sets the CompressionLevel value
/// </summary>
public int CompressionLevel { get; internal set; }
private int compressionLevel;
/// <summary>
/// Gets or sets the Gamma value
/// </summary>
public float Gamma { get; internal set; }
private float gamma;
/// <summary>
/// Gets or sets the Quantizer value
/// Gets or sets the Threshold value
/// </summary>
public IQuantizer Quantizer { get; internal set; }
private byte threshold;
/// <summary>
/// Gets or sets the Threshold value
/// Gets or sets a value indicating whether to Write Gamma
/// </summary>
public byte Threshold { get; internal set; }
private bool writeGamma;
/// <summary>
/// Gets or sets a value indicating whether to Write Gamma
/// Initializes a new instance of the <see cref="PngEncoderCore"/> class.
/// </summary>
public bool WriteGamma { get; internal set; }
/// <param name="options">The options for influancing the encoder</param>
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;
}
/// <summary>
/// Encodes the image to the specified stream from the <see cref="Image{TPixel}"/>.
@ -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<TPixel> WritePaletteChunk<TPixel>(Stream stream, PngHeader header, ImageBase<TPixel> image)
where TPixel : struct, IPixel<TPixel>
{
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<TPixel> quantized = ((IQuantizer<TPixel>)this.quantizer).Quantize(image, this.PaletteSize);
QuantizedImage<TPixel> quantized = ((IQuantizer<TPixel>)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
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
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++)
{

13
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<Rgba32> image = Image.Load(file, new GifDecoder() { IgnoreFrames = true }))
using (Image<Rgba32> imageWithFrames = Image.Load(file, new GifDecoder() { IgnoreFrames = false }))
{
Assert.NotEmpty(imageWithFrames.Frames);
Assert.Empty(image.Frames);
}
}
[Theory]
[WithFileCollection(nameof(TestFiles), PixelTypes)]
public void DecodeAndReSave<TPixel>(TestImageProvider<TPixel> imageProvider)

2
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<TPixel> mirror = decoder.Decode<TPixel>(ms);

Loading…
Cancel
Save