Browse Source

refactor PngDecoder to SpecializedImageDecoder<PngDecoderOptions>

pull/2589/head
Sven Claesson 3 years ago
parent
commit
72b8013241
  1. 17
      src/ImageSharp/Formats/Png/PngDecoder.cs
  2. 32
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  3. 19
      src/ImageSharp/Formats/Png/PngDecoderOptions.cs
  4. 11
      tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs
  5. 5
      tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs

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

@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Formats.Png;
/// <summary>
/// Decoder for generating an image out of a png encoded stream.
/// </summary>
public sealed class PngDecoder : ImageDecoder
public sealed class PngDecoder : SpecializedImageDecoder<PngDecoderOptions>
{
private PngDecoder()
{
@ -25,31 +25,31 @@ public sealed class PngDecoder : ImageDecoder
Guard.NotNull(options, nameof(options));
Guard.NotNull(stream, nameof(stream));
return new PngDecoderCore(options).Identify(options.Configuration, stream, cancellationToken);
return new PngDecoderCore(new PngDecoderOptions() { GeneralOptions = options }).Identify(options.Configuration, stream, cancellationToken);
}
/// <inheritdoc/>
protected override Image<TPixel> Decode<TPixel>(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
protected override Image<TPixel> Decode<TPixel>(PngDecoderOptions options, Stream stream, CancellationToken cancellationToken)
{
Guard.NotNull(options, nameof(options));
Guard.NotNull(stream, nameof(stream));
PngDecoderCore decoder = new(options);
Image<TPixel> image = decoder.Decode<TPixel>(options.Configuration, stream, cancellationToken);
Image<TPixel> image = decoder.Decode<TPixel>(options.GeneralOptions.Configuration, stream, cancellationToken);
ScaleToTargetSize(options, image);
ScaleToTargetSize(options.GeneralOptions, image);
return image;
}
/// <inheritdoc/>
protected override Image Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
protected override Image Decode(PngDecoderOptions options, Stream stream, CancellationToken cancellationToken)
{
Guard.NotNull(options, nameof(options));
Guard.NotNull(stream, nameof(stream));
PngDecoderCore decoder = new(options, true);
ImageInfo info = decoder.Identify(options.Configuration, stream, cancellationToken);
ImageInfo info = decoder.Identify(options.GeneralOptions.Configuration, stream, cancellationToken);
stream.Position = 0;
PngMetadata meta = info.Metadata.GetPngMetadata();
@ -99,4 +99,7 @@ public sealed class PngDecoder : ImageDecoder
return this.Decode<Rgba32>(options, stream, cancellationToken);
}
}
/// <inheritdoc/>
protected override PngDecoderOptions CreateDefaultSpecializedOptions(DecoderOptions options) => new PngDecoderOptions() { GeneralOptions = options };
}

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

@ -113,27 +113,34 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
/// </summary>
private PngChunk? nextChunk;
/// <summary>
/// If true, ADLER32 checksum in the IDAT chunk as well as the chunk CRCs will be ignored.
/// </summary>
private bool ignoreCrcErrors;
/// <summary>
/// Initializes a new instance of the <see cref="PngDecoderCore"/> class.
/// </summary>
/// <param name="options">The decoder options.</param>
public PngDecoderCore(DecoderOptions options)
public PngDecoderCore(PngDecoderOptions options)
{
this.Options = options;
this.configuration = options.Configuration;
this.maxFrames = options.MaxFrames;
this.skipMetadata = options.SkipMetadata;
this.Options = options.GeneralOptions;
this.configuration = options.GeneralOptions.Configuration;
this.maxFrames = options.GeneralOptions.MaxFrames;
this.skipMetadata = options.GeneralOptions.SkipMetadata;
this.memoryAllocator = this.configuration.MemoryAllocator;
this.ignoreCrcErrors = options.IgnoreCrcCheck;
}
internal PngDecoderCore(DecoderOptions options, bool colorMetadataOnly)
internal PngDecoderCore(PngDecoderOptions options, bool colorMetadataOnly)
{
this.Options = options;
this.Options = options.GeneralOptions;
this.colorMetadataOnly = colorMetadataOnly;
this.maxFrames = options.MaxFrames;
this.maxFrames = options.GeneralOptions.MaxFrames;
this.skipMetadata = true;
this.configuration = options.Configuration;
this.configuration = options.GeneralOptions.Configuration;
this.memoryAllocator = this.configuration.MemoryAllocator;
this.ignoreCrcErrors = options.IgnoreCrcCheck;
}
/// <inheritdoc/>
@ -1789,8 +1796,11 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
type: type,
data: this.ReadChunkData(length));
this.ValidateChunk(chunk, buffer);
if (!this.ignoreCrcErrors)
{
this.ValidateChunk(chunk, buffer);
}
// Restore the stream position for IDAT and fdAT chunks, because it will be decoded later and
// was only read to verifying the CRC is correct.
if (type is PngChunkType.Data or PngChunkType.FrameData)

19
src/ImageSharp/Formats/Png/PngDecoderOptions.cs

@ -0,0 +1,19 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Png;
/// <summary>
/// Configuration options for decoding png images.
/// </summary>
public sealed class PngDecoderOptions : ISpecializedDecoderOptions
{
/// <inheritdoc/>
public DecoderOptions GeneralOptions { get; init; } = new DecoderOptions();
/// <summary>
/// If true, ADLER32 checksum in the IDAT chunk as well as the chunk CRCs will be ignored.
/// Similar to PNG_CRC_QUIET_USE in libpng.
/// </summary>
public bool IgnoreCrcCheck { get; init; }
}

11
tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs

@ -470,6 +470,17 @@ public partial class PngDecoderTests
Assert.Contains("CRC Error. PNG IDAT chunk is corrupt!", ex.Message);
}
[Theory]
[WithFile(TestImages.Png.Bad.WrongCrcDataChunk, PixelTypes.Rgba32)]
public void Decode_InvalidDataChunkCrc_IgnoreCrcErrors<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> image = provider.GetImage(PngDecoder.Instance, new PngDecoderOptions() { IgnoreCrcCheck = true });
image.DebugSave(provider);
image.CompareToOriginal(provider, new MagickReferenceDecoder(false));
}
// https://github.com/SixLabors/ImageSharp/issues/1014
[Theory]
[WithFileCollection(nameof(TestImagesIssue1014), PixelTypes.Rgba32)]

5
tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs

@ -31,12 +31,17 @@ public class MagickReferenceDecoder : ImageDecoder
{
IgnoreFileSize = !this.validate
};
PngReadDefines pngReadDefines = new()
{
IgnoreCrc = !this.validate
};
MagickReadSettings settings = new()
{
FrameCount = (int)options.MaxFrames
};
settings.SetDefines(bmpReadDefines);
settings.SetDefines(pngReadDefines);
using MagickImageCollection magickImageCollection = new(stream, settings);
List<ImageFrame<TPixel>> framesList = new();

Loading…
Cancel
Save