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 System;
using ImageSharp; using ImageSharp;
using ImageSharp.Formats;
namespace ChangeDefaultEncoderOptions namespace ChangeDefaultEncoderOptions
{ {
@ -14,22 +15,6 @@ namespace ChangeDefaultEncoderOptions
Quality = 90, Quality = 90,
IgnoreMetadata = true 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 /// Formats will be supported in a later releases. We advise always
/// to use only 24 Bit Windows bitmaps. /// to use only 24 Bit Windows bitmaps.
/// </remarks> /// </remarks>
public class BmpDecoder : IImageDecoder public class BmpDecoder : IImageDecoder, IBmpDecoderOptions
{ {
/// <inheritdoc/> /// <inheritdoc/>
public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream) public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)
@ -35,7 +35,7 @@ namespace ImageSharp.Formats
{ {
Guard.NotNull(stream, "stream"); 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. /// Initializes a new instance of the <see cref="BmpDecoderCore"/> class.
/// </summary> /// </summary>
/// <param name="configuration">The configuration.</param> /// <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; 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. /// Image encoder for writing an image to a stream as a Windows bitmap.
/// </summary> /// </summary>
/// <remarks>The encoder can currently only write 24-bit rgb images to streams.</remarks> /// <remarks>The encoder can currently only write 24-bit rgb images to streams.</remarks>
public class BmpEncoder : IImageEncoder public class BmpEncoder : IImageEncoder, IBmpEncoderOptions
{ {
/// <summary> /// <summary>
/// Gets or sets the number of bits per pixel. /// 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) public void Encode<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
BmpEncoderCore encoder = new BmpEncoderCore(); var encoder = new BmpEncoderCore(this);
encoder.BitsPerPixel = this.BitsPerPixel;
encoder.Encode(image, stream); encoder.Encode(image, stream);
} }
} }

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

@ -23,16 +23,18 @@ namespace ImageSharp.Formats
private int padding; private int padding;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="BmpEncoderCore"/> class. /// Gets or sets the number of bits per pixel.
/// </summary> /// </summary>
public BmpEncoderCore() private BmpBitsPerPixel bitsPerPixel;
{
}
/// <summary> /// <summary>
/// Gets or sets the number of bits per pixel. /// Initializes a new instance of the <see cref="BmpEncoderCore"/> class.
/// </summary> /// </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> /// <summary>
/// Encodes the image to the specified stream from the <see cref="ImageBase{TPixel}"/>. /// 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)); Guard.NotNull(stream, nameof(stream));
// Cast to int will get the bytes per pixel // 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); 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. // Do not use IDisposable pattern here as we want to preserve the stream.
EndianBinaryWriter writer = new EndianBinaryWriter(Endianness.LittleEndian, stream); EndianBinaryWriter writer = new EndianBinaryWriter(Endianness.LittleEndian, stream);
@ -134,7 +136,7 @@ namespace ImageSharp.Formats
{ {
using (PixelAccessor<TPixel> pixels = image.Lock()) using (PixelAccessor<TPixel> pixels = image.Lock())
{ {
switch (this.BitsPerPixel) switch (this.bitsPerPixel)
{ {
case BmpBitsPerPixel.Pixel32: case BmpBitsPerPixel.Pixel32:
this.Write32Bit(writer, pixels); 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> /// <summary>
/// Decoder for generating an image out of a gif encoded stream. /// Decoder for generating an image out of a gif encoded stream.
/// </summary> /// </summary>
public class GifDecoder : IImageDecoder public class GifDecoder : IImageDecoder, IGifDecoderOptions
{ {
/// <summary> /// <summary>
/// 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 decoded.
/// </summary> /// </summary>
public bool IgnoreMetadata { get; set; } = false; 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> /// <summary>
/// Gets or sets the encoding that should be used when reading comments. /// Gets or sets the encoding that should be used when reading comments.
/// </summary> /// </summary>
@ -35,9 +30,7 @@ namespace ImageSharp.Formats
public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream) public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
var decoder = new GifDecoderCore<TPixel>(this.TextEncoding, configuration); var decoder = new GifDecoderCore<TPixel>(configuration, this);
decoder.IgnoreMetadata = this.IgnoreMetadata;
decoder.IgnoreFrames = this.IgnoreFrames;
return decoder.Decode(stream); return decoder.Decode(stream);
} }
} }

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

@ -78,11 +78,12 @@ namespace ImageSharp.Formats
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="GifDecoderCore{TPixel}"/> class. /// Initializes a new instance of the <see cref="GifDecoderCore{TPixel}"/> class.
/// </summary> /// </summary>
/// <param name="encoding">The decoder encoding.</param>
/// <param name="configuration">The configuration.</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; this.configuration = configuration ?? Configuration.Default;
} }
@ -96,11 +97,6 @@ namespace ImageSharp.Formats
/// </summary> /// </summary>
public Encoding TextEncoding { get; private set; } 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> /// <summary>
/// Decodes the stream to the image. /// Decodes the stream to the image.
/// </summary> /// </summary>
@ -362,13 +358,6 @@ namespace ImageSharp.Formats
/// <param name="descriptor">The <see cref="GifImageDescriptor"/></param> /// <param name="descriptor">The <see cref="GifImageDescriptor"/></param>
private unsafe void ReadFrameColors(byte[] indices, byte[] colorTable, int colorTableLength, GifImageDescriptor descriptor) 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 imageWidth = this.logicalScreenDescriptor.Width;
int imageHeight = this.logicalScreenDescriptor.Height; int imageHeight = this.logicalScreenDescriptor.Height;

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

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

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

@ -35,44 +35,44 @@ namespace ImageSharp.Formats
/// </summary> /// </summary>
private bool hasFrames; 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> /// <summary>
/// Gets the TextEncoding /// Gets the TextEncoding
/// </summary> /// </summary>
public Encoding TextEncoding { get; private set; } private Encoding textEncoding;
/// <summary> /// <summary>
/// Gets or sets the quantizer for reducing the color count. /// Gets or sets the quantizer for reducing the color count.
/// </summary> /// </summary>
public IQuantizer Quantizer { get; set; } private IQuantizer quantizer;
/// <summary> /// <summary>
/// Gets or sets the threshold. /// Gets or sets the threshold.
/// </summary> /// </summary>
public byte Threshold { get; internal set; } private byte threshold;
/// <summary> /// <summary>
/// Gets or sets the size of the color palette to use. /// Gets or sets the size of the color palette to use.
/// </summary> /// </summary>
public int PaletteSize { get; internal set; } private int paletteSize;
/// <summary> /// <summary>
/// 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 decoded.
/// </summary> /// </summary>
public bool IgnoreMetadata { get; internal set; } private bool ignoreMetadata;
/// <summary> /// <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> /// </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> /// <summary>
/// Encodes the image to the specified stream from the <see cref="Image{TPixel}"/>. /// 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(image, nameof(image));
Guard.NotNull(stream, nameof(stream)); 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. // Do not use IDisposable pattern here as we want to preserve the stream.
var writer = new EndianBinaryWriter(Endianness.LittleEndian, stream); var writer = new EndianBinaryWriter(Endianness.LittleEndian, stream);
// Ensure that pallete size can be set but has a fallback. // 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; paletteSize = paletteSize > 0 ? paletteSize.Clamp(1, 256) : 256;
// Get the number of bits. // Get the number of bits.
this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(paletteSize); 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. // 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; ditheredQuantizer.Dither = !this.hasFrames;
// Quantize the image returning a palette. // Quantize the image returning a palette.
@ -260,7 +260,7 @@ namespace ImageSharp.Formats
private void WriteComments<TPixel>(Image<TPixel> image, EndianBinaryWriter writer) private void WriteComments<TPixel>(Image<TPixel> image, EndianBinaryWriter writer)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
if (this.IgnoreMetadata) if (this.ignoreMetadata)
{ {
return; return;
} }
@ -271,7 +271,7 @@ namespace ImageSharp.Formats
return; return;
} }
byte[] comments = this.TextEncoding.GetBytes(property.Value); byte[] comments = this.textEncoding.GetBytes(property.Value);
int count = Math.Min(comments.Length, 255); 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> /// <summary>
/// Image decoder for generating an image out of a jpg stream. /// Image decoder for generating an image out of a jpg stream.
/// </summary> /// </summary>
public class JpegDecoder : IImageDecoder public class JpegDecoder : IImageDecoder, IJpegDecoderOptions
{ {
/// <summary> /// <summary>
/// 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 decoded.
@ -27,9 +27,8 @@ namespace ImageSharp.Formats
{ {
Guard.NotNull(stream, "stream"); 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); 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. /// Initializes a new instance of the <see cref="JpegDecoderCore" /> class.
/// </summary> /// </summary>
/// <param name="configuration">The configuration.</param> /// <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.configuration = configuration ?? Configuration.Default;
this.HuffmanTrees = HuffmanTree.CreateHuffmanTrees(); this.HuffmanTrees = HuffmanTree.CreateHuffmanTrees();
this.QuantizationTables = new Block8x8F[MaxTq + 1]; this.QuantizationTables = new Block8x8F[MaxTq + 1];
@ -184,9 +186,9 @@ namespace ImageSharp.Formats
public int TotalMCUCount => this.MCUCountX * this.MCUCountY; public int TotalMCUCount => this.MCUCountX * this.MCUCountY;
/// <summary> /// <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> /// </summary>
public bool IgnoreMetadata { get; internal set; } public bool IgnoreMetadata { get; private set; }
/// <summary> /// <summary>
/// Decodes the image from the specified <see cref="Stream"/> and sets /// 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> /// <summary>
/// Encoder for writing the data image to a stream in jpeg format. /// Encoder for writing the data image to a stream in jpeg format.
/// </summary> /// </summary>
public class JpegEncoder : IImageEncoder public class JpegEncoder : IImageEncoder, IJpegEncoderOptions
{ {
/// <summary> /// <summary>
/// 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 decoded.
@ -43,19 +43,7 @@ namespace ImageSharp.Formats
public void Encode<TPixel>(Image<TPixel> image, Stream stream) public void Encode<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
JpegEncoderCore encoder = new JpegEncoderCore(); var encoder = new JpegEncoderCore(this);
var quality = this.Quality;
if (quality == 0)
{
quality = 75;
}
encoder.Quality = quality;
encoder.Subsample = this.Subsample ?? (quality >= 91 ? JpegSubsample.Ratio444 : JpegSubsample.Ratio420);
encoder.IgnoreMetadata = this.IgnoreMetadata;
encoder.Encode(image, stream); encoder.Encode(image, stream);
} }
} }

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

@ -149,29 +149,40 @@ namespace ImageSharp.Formats
/// </summary> /// </summary>
private Stream outputStream; private Stream outputStream;
/// <summary>
/// Initializes a new instance of the <see cref="JpegEncoderCore"/> class.
/// </summary>
public JpegEncoderCore()
{
}
/// <summary> /// <summary>
/// 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 decoded.
/// </summary> /// </summary>
public bool IgnoreMetadata { get; internal set; } = false; private bool ignoreMetadata = false;
/// <summary> /// <summary>
/// Gets or sets the quality, that will be used to encode the image. Quality /// 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). /// index must be between 0 and 100 (compression from max to min).
/// </summary> /// </summary>
/// <value>The quality of the jpg image from 0 to 100.</value> /// <value>The quality of the jpg image from 0 to 100.</value>
public int Quality { get; internal set; } private int quality = 0;
/// <summary> /// <summary>
/// Gets or sets the subsampling method to use. /// Gets or sets the subsampling method to use.
/// </summary> /// </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> /// <summary>
/// Encode writes the image to the jpeg baseline format with the given options. /// Encode writes the image to the jpeg baseline format with the given options.
@ -193,11 +204,11 @@ namespace ImageSharp.Formats
this.outputStream = stream; 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. // Convert from a quality rating to a scaling factor.
int scale; int scale;
if (this.Quality < 50) if (this.quality < 50)
{ {
scale = 5000 / quality; scale = 5000 / quality;
} }
@ -785,7 +796,7 @@ namespace ImageSharp.Formats
private void WriteProfiles<TPixel>(Image<TPixel> image) private void WriteProfiles<TPixel>(Image<TPixel> image)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
if (this.IgnoreMetadata) if (this.ignoreMetadata)
{ {
return; return;
} }
@ -807,7 +818,7 @@ namespace ImageSharp.Formats
byte[] subsamples = { 0x22, 0x11, 0x11 }; byte[] subsamples = { 0x22, 0x11, 0x11 };
byte[] chroma = { 0x00, 0x01, 0x01 }; byte[] chroma = { 0x00, 0x01, 0x01 };
switch (this.Subsample) switch (this.subsample)
{ {
case JpegSubsample.Ratio444: case JpegSubsample.Ratio444:
subsamples = new byte[] { 0x11, 0x11, 0x11 }; subsamples = new byte[] { 0x11, 0x11, 0x11 };
@ -863,7 +874,7 @@ namespace ImageSharp.Formats
// TODO: We should allow grayscale writing. // TODO: We should allow grayscale writing.
this.outputStream.Write(SosHeaderYCbCr, 0, SosHeaderYCbCr.Length); this.outputStream.Write(SosHeaderYCbCr, 0, SosHeaderYCbCr.Length);
switch (this.Subsample) switch (this.subsample)
{ {
case JpegSubsample.Ratio444: case JpegSubsample.Ratio444:
this.Encode444(pixels); 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> /// </list>
/// </para> /// </para>
/// </remarks> /// </remarks>
public class PngDecoder : IImageDecoder public class PngDecoder : IImageDecoder, IPngDecoderOptions
{ {
/// <summary> /// <summary>
/// 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 decoded.
@ -53,8 +53,7 @@ namespace ImageSharp.Formats
public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream) public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
var decoder = new PngDecoderCore(configuration, this.TextEncoding); var decoder = new PngDecoderCore(configuration, this);
decoder.IgnoreMetadata = this.IgnoreMetadata;
return decoder.Decode<TPixel>(stream); return decoder.Decode<TPixel>(stream);
} }
} }

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

@ -155,25 +155,26 @@ namespace ImageSharp.Formats
private PngColorType pngColorType; private PngColorType pngColorType;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="PngDecoderCore"/> class. /// Gets the encoding to use
/// </summary> /// </summary>
/// <param name="configuration">The configuration.</param> private Encoding textEncoding;
/// <param name="encoding">The text encoding.</param>
public PngDecoderCore(Configuration configuration, Encoding encoding)
{
this.configuration = configuration ?? Configuration.Default;
this.TextEncoding = encoding ?? PngConstants.DefaultEncoding;
}
/// <summary> /// <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> /// </summary>
public Encoding TextEncoding { get; private set; } private bool ignoreMetadata;
/// <summary> /// <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> /// </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> /// <summary>
/// Decodes the stream to the image. /// Decodes the stream to the image.
@ -900,7 +901,7 @@ namespace ImageSharp.Formats
/// <param name="length">The maximum length to read.</param> /// <param name="length">The maximum length to read.</param>
private void ReadTextChunk(ImageMetaData metadata, byte[] data, int length) private void ReadTextChunk(ImageMetaData metadata, byte[] data, int length)
{ {
if (this.IgnoreMetadata) if (this.ignoreMetadata)
{ {
return; return;
} }
@ -916,8 +917,8 @@ namespace ImageSharp.Formats
} }
} }
string name = this.TextEncoding.GetString(data, 0, zeroIndex); string name = this.textEncoding.GetString(data, 0, zeroIndex);
string value = this.TextEncoding.GetString(data, zeroIndex + 1, length - zeroIndex - 1); string value = this.textEncoding.GetString(data, zeroIndex + 1, length - zeroIndex - 1);
metadata.Properties.Add(new ImageProperty(name, value)); metadata.Properties.Add(new ImageProperty(name, value));
} }

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

@ -14,7 +14,7 @@ namespace ImageSharp.Formats
/// <summary> /// <summary>
/// Image encoder for writing image data to a stream in png format. /// Image encoder for writing image data to a stream in png format.
/// </summary> /// </summary>
public class PngEncoder : IImageEncoder public class PngEncoder : IImageEncoder, IPngEncoderOptions
{ {
/// <summary> /// <summary>
/// Gets or sets a value indicating whether the metadata should be ignored when the image is being encoded. /// 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) public void Encode<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : struct, IPixel<TPixel> 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); encoder.Encode(image, stream);
} }
} }

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

@ -118,52 +118,51 @@ namespace ImageSharp.Formats
/// </summary> /// </summary>
private IQuantizer quantizer; private IQuantizer quantizer;
/// <summary>
/// Initializes a new instance of the <see cref="PngEncoderCore"/> class.
/// </summary>
public PngEncoderCore()
{
}
/// <summary> /// <summary>
/// Gets or sets a value indicating whether to ignore metadata /// Gets or sets a value indicating whether to ignore metadata
/// </summary> /// </summary>
public bool IgnoreMetadata { get; internal set; } private bool ignoreMetadata;
/// <summary>
/// Gets or sets the Quality value
/// </summary>
public int PaletteSize { get; internal set; }
/// <summary> /// <summary>
/// Gets or sets the Quality value /// Gets or sets the Quality value
/// </summary> /// </summary>
public PngColorType PngColorType { get; internal set; } private int paletteSize;
/// <summary> /// <summary>
/// Gets or sets the CompressionLevel value /// Gets or sets the CompressionLevel value
/// </summary> /// </summary>
public int CompressionLevel { get; internal set; } private int compressionLevel;
/// <summary> /// <summary>
/// Gets or sets the Gamma value /// Gets or sets the Gamma value
/// </summary> /// </summary>
public float Gamma { get; internal set; } private float gamma;
/// <summary> /// <summary>
/// Gets or sets the Quantizer value /// Gets or sets the Threshold value
/// </summary> /// </summary>
public IQuantizer Quantizer { get; internal set; } private byte threshold;
/// <summary> /// <summary>
/// Gets or sets the Threshold value /// Gets or sets a value indicating whether to Write Gamma
/// </summary> /// </summary>
public byte Threshold { get; internal set; } private bool writeGamma;
/// <summary> /// <summary>
/// Gets or sets a value indicating whether to Write Gamma /// Initializes a new instance of the <see cref="PngEncoderCore"/> class.
/// </summary> /// </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> /// <summary>
/// Encodes the image to the specified stream from the <see cref="Image{TPixel}"/>. /// 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); 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. // Set correct color type if the color count is 256 or less.
if (this.PaletteSize <= 256) if (this.paletteSize <= 256)
{ {
this.pngColorType = PngColorType.Palette; 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. // Set correct bit depth.
this.bitDepth = this.PaletteSize <= 256 this.bitDepth = this.paletteSize <= 256
? (byte)ImageMaths.GetBitsNeededForColorDepth(this.PaletteSize).Clamp(1, 8) ? (byte)ImageMaths.GetBitsNeededForColorDepth(this.paletteSize).Clamp(1, 8)
: (byte)8; : (byte)8;
// Png only supports in four pixel depths: 1, 2, 4, and 8 bits when using the PLTE chunk // 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) private QuantizedImage<TPixel> WritePaletteChunk<TPixel>(Stream stream, PngHeader header, ImageBase<TPixel> image)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
if (this.PaletteSize > 256) if (this.paletteSize > 256)
{ {
return null; return null;
} }
@ -549,7 +545,7 @@ namespace ImageSharp.Formats
} }
// Quantize the image returning a palette. This boxing is icky. // 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. // Grab the palette and write it to the stream.
TPixel[] palette = quantized.Palette; TPixel[] palette = quantized.Palette;
@ -576,7 +572,7 @@ namespace ImageSharp.Formats
colorTable[offset + 1] = bytes[1]; colorTable[offset + 1] = bytes[1];
colorTable[offset + 2] = bytes[2]; colorTable[offset + 2] = bytes[2];
if (alpha > this.Threshold) if (alpha > this.threshold)
{ {
alpha = 255; alpha = 255;
} }
@ -634,9 +630,9 @@ namespace ImageSharp.Formats
/// <param name="stream">The <see cref="Stream"/> containing image data.</param> /// <param name="stream">The <see cref="Stream"/> containing image data.</param>
private void WriteGammaChunk(Stream stream) 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); byte[] size = BitConverter.GetBytes(gammaValue);
@ -679,7 +675,7 @@ namespace ImageSharp.Formats
try try
{ {
memoryStream = new MemoryStream(); 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++) 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 }; 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] [Theory]
[WithFileCollection(nameof(TestFiles), PixelTypes)] [WithFileCollection(nameof(TestFiles), PixelTypes)]
public void DecodeAndReSave<TPixel>(TestImageProvider<TPixel> imageProvider) 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()); image.Save(ms, new JpegEncoder());
ms.Seek(0, SeekOrigin.Begin); 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); Image<TPixel> mirror = decoder.Decode<TPixel>(ms);

Loading…
Cancel
Save