Browse Source

Create fine-grained options for CRC handling.

pull/2589/head
James Jackson-South 2 years ago
parent
commit
c99c83ae61
  1. 14
      src/ImageSharp/Formats/Png/PngChunk.cs
  2. 30
      src/ImageSharp/Formats/Png/PngCrcChunkHandling.cs
  3. 18
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  4. 5
      src/ImageSharp/Formats/Png/PngDecoderOptions.cs
  5. 2
      tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs

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

@ -41,9 +41,13 @@ internal readonly struct PngChunk
/// <summary>
/// Gets a value indicating whether the given chunk is critical to decoding
/// </summary>
public bool IsCritical =>
this.Type is PngChunkType.Header or
PngChunkType.Palette or
PngChunkType.Data or
PngChunkType.FrameData;
/// <param name="handling">The chunk CRC handling behavior.</param>
public bool IsCritical(PngCrcChunkHandling handling)
=> handling switch
{
PngCrcChunkHandling.IgnoreNone => true,
PngCrcChunkHandling.IgnoreNonCritical => this.Type is PngChunkType.Header or PngChunkType.Palette or PngChunkType.Data or PngChunkType.FrameData,
PngCrcChunkHandling.IgnoreData => this.Type is PngChunkType.Header or PngChunkType.Palette,
_ => false,
};
}

30
src/ImageSharp/Formats/Png/PngCrcChunkHandling.cs

@ -0,0 +1,30 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Png;
/// <summary>
/// Specifies how to handle validation of any CRC (Cyclic Redundancy Check) data within the encoded PNG.
/// </summary>
public enum PngCrcChunkHandling
{
/// <summary>
/// Do not ignore any CRC chunk errors.
/// </summary>
IgnoreNone,
/// <summary>
/// Ignore CRC errors in non critical chunks.
/// </summary>
IgnoreNonCritical,
/// <summary>
/// Ignore CRC errors in data chunks.
/// </summary>
IgnoreData,
/// <summary>
/// Ignore CRC errors in all chunks.
/// </summary>
IgnoreAll
}

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

@ -115,9 +115,9 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
private PngChunk? nextChunk;
/// <summary>
/// If true, ADLER32 checksum in the IDAT chunk as well as the chunk CRCs will be ignored.
/// How to handle CRC errors.
/// </summary>
private bool ignoreCrcErrors;
private readonly PngCrcChunkHandling pngCrcChunkHandling;
/// <summary>
/// Initializes a new instance of the <see cref="PngDecoderCore"/> class.
@ -130,7 +130,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
this.maxFrames = options.GeneralOptions.MaxFrames;
this.skipMetadata = options.GeneralOptions.SkipMetadata;
this.memoryAllocator = this.configuration.MemoryAllocator;
this.ignoreCrcErrors = options.IgnoreCrcCheck;
this.pngCrcChunkHandling = options.PngCrcChunkHandling;
}
internal PngDecoderCore(PngDecoderOptions options, bool colorMetadataOnly)
@ -141,7 +141,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
this.skipMetadata = true;
this.configuration = options.GeneralOptions.Configuration;
this.memoryAllocator = this.configuration.MemoryAllocator;
this.ignoreCrcErrors = options.IgnoreCrcCheck;
this.pngCrcChunkHandling = options.PngCrcChunkHandling;
}
/// <inheritdoc/>
@ -1797,11 +1797,8 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
type: type,
data: this.ReadChunkData(length));
if (!this.ignoreCrcErrors)
{
this.ValidateChunk(chunk, buffer);
}
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)
@ -1820,8 +1817,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
private void ValidateChunk(in PngChunk chunk, Span<byte> buffer)
{
uint inputCrc = this.ReadChunkCrc(buffer);
if (chunk.IsCritical)
if (chunk.IsCritical(this.pngCrcChunkHandling))
{
Span<byte> chunkType = stackalloc byte[4];
BinaryPrimitives.WriteUInt32BigEndian(chunkType, (uint)chunk.Type);

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

@ -12,8 +12,7 @@ public sealed class PngDecoderOptions : ISpecializedDecoderOptions
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.
/// Gets a value indicating how to handle validation of any CRC (Cyclic Redundancy Check) data within the encoded PNG.
/// </summary>
public bool IgnoreCrcCheck { get; init; }
public PngCrcChunkHandling PngCrcChunkHandling { get; init; } = PngCrcChunkHandling.IgnoreNonCritical;
}

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

@ -475,7 +475,7 @@ public partial class PngDecoderTests
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 });
using Image<TPixel> image = provider.GetImage(PngDecoder.Instance, new PngDecoderOptions() { PngCrcChunkHandling = PngCrcChunkHandling.IgnoreData });
image.DebugSave(provider);
image.CompareToOriginal(provider, new MagickReferenceDecoder(false));

Loading…
Cancel
Save