Skip to content

Commit c99c83a

Browse files
Create fine-grained options for CRC handling.
1 parent 53dc3e3 commit c99c83a

File tree

5 files changed

+49
-20
lines changed

5 files changed

+49
-20
lines changed

src/ImageSharp/Formats/Png/PngChunk.cs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,13 @@ public PngChunk(int length, PngChunkType type, IMemoryOwner<byte> data = null)
4141
/// <summary>
4242
/// Gets a value indicating whether the given chunk is critical to decoding
4343
/// </summary>
44-
public bool IsCritical =>
45-
this.Type is PngChunkType.Header or
46-
PngChunkType.Palette or
47-
PngChunkType.Data or
48-
PngChunkType.FrameData;
44+
/// <param name="handling">The chunk CRC handling behavior.</param>
45+
public bool IsCritical(PngCrcChunkHandling handling)
46+
=> handling switch
47+
{
48+
PngCrcChunkHandling.IgnoreNone => true,
49+
PngCrcChunkHandling.IgnoreNonCritical => this.Type is PngChunkType.Header or PngChunkType.Palette or PngChunkType.Data or PngChunkType.FrameData,
50+
PngCrcChunkHandling.IgnoreData => this.Type is PngChunkType.Header or PngChunkType.Palette,
51+
_ => false,
52+
};
4953
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Six Labors Split License.
3+
4+
namespace SixLabors.ImageSharp.Formats.Png;
5+
6+
/// <summary>
7+
/// Specifies how to handle validation of any CRC (Cyclic Redundancy Check) data within the encoded PNG.
8+
/// </summary>
9+
public enum PngCrcChunkHandling
10+
{
11+
/// <summary>
12+
/// Do not ignore any CRC chunk errors.
13+
/// </summary>
14+
IgnoreNone,
15+
16+
/// <summary>
17+
/// Ignore CRC errors in non critical chunks.
18+
/// </summary>
19+
IgnoreNonCritical,
20+
21+
/// <summary>
22+
/// Ignore CRC errors in data chunks.
23+
/// </summary>
24+
IgnoreData,
25+
26+
/// <summary>
27+
/// Ignore CRC errors in all chunks.
28+
/// </summary>
29+
IgnoreAll
30+
}

src/ImageSharp/Formats/Png/PngDecoderCore.cs

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,9 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
115115
private PngChunk? nextChunk;
116116

117117
/// <summary>
118-
/// If true, ADLER32 checksum in the IDAT chunk as well as the chunk CRCs will be ignored.
118+
/// How to handle CRC errors.
119119
/// </summary>
120-
private bool ignoreCrcErrors;
120+
private readonly PngCrcChunkHandling pngCrcChunkHandling;
121121

122122
/// <summary>
123123
/// Initializes a new instance of the <see cref="PngDecoderCore"/> class.
@@ -130,7 +130,7 @@ public PngDecoderCore(PngDecoderOptions options)
130130
this.maxFrames = options.GeneralOptions.MaxFrames;
131131
this.skipMetadata = options.GeneralOptions.SkipMetadata;
132132
this.memoryAllocator = this.configuration.MemoryAllocator;
133-
this.ignoreCrcErrors = options.IgnoreCrcCheck;
133+
this.pngCrcChunkHandling = options.PngCrcChunkHandling;
134134
}
135135

136136
internal PngDecoderCore(PngDecoderOptions options, bool colorMetadataOnly)
@@ -141,7 +141,7 @@ internal PngDecoderCore(PngDecoderOptions options, bool colorMetadataOnly)
141141
this.skipMetadata = true;
142142
this.configuration = options.GeneralOptions.Configuration;
143143
this.memoryAllocator = this.configuration.MemoryAllocator;
144-
this.ignoreCrcErrors = options.IgnoreCrcCheck;
144+
this.pngCrcChunkHandling = options.PngCrcChunkHandling;
145145
}
146146

147147
/// <inheritdoc/>
@@ -1797,11 +1797,8 @@ private bool TryReadChunk(Span<byte> buffer, out PngChunk chunk)
17971797
type: type,
17981798
data: this.ReadChunkData(length));
17991799

1800-
if (!this.ignoreCrcErrors)
1801-
{
1802-
this.ValidateChunk(chunk, buffer);
1803-
}
1804-
1800+
this.ValidateChunk(chunk, buffer);
1801+
18051802
// Restore the stream position for IDAT and fdAT chunks, because it will be decoded later and
18061803
// was only read to verifying the CRC is correct.
18071804
if (type is PngChunkType.Data or PngChunkType.FrameData)
@@ -1820,8 +1817,7 @@ private bool TryReadChunk(Span<byte> buffer, out PngChunk chunk)
18201817
private void ValidateChunk(in PngChunk chunk, Span<byte> buffer)
18211818
{
18221819
uint inputCrc = this.ReadChunkCrc(buffer);
1823-
1824-
if (chunk.IsCritical)
1820+
if (chunk.IsCritical(this.pngCrcChunkHandling))
18251821
{
18261822
Span<byte> chunkType = stackalloc byte[4];
18271823
BinaryPrimitives.WriteUInt32BigEndian(chunkType, (uint)chunk.Type);

src/ImageSharp/Formats/Png/PngDecoderOptions.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ public sealed class PngDecoderOptions : ISpecializedDecoderOptions
1212
public DecoderOptions GeneralOptions { get; init; } = new DecoderOptions();
1313

1414
/// <summary>
15-
/// If true, ADLER32 checksum in the IDAT chunk as well as the chunk CRCs will be ignored.
16-
/// Similar to PNG_CRC_QUIET_USE in libpng.
15+
/// Gets a value indicating how to handle validation of any CRC (Cyclic Redundancy Check) data within the encoded PNG.
1716
/// </summary>
18-
public bool IgnoreCrcCheck { get; init; }
17+
public PngCrcChunkHandling PngCrcChunkHandling { get; init; } = PngCrcChunkHandling.IgnoreNonCritical;
1918
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@ public void Decode_InvalidDataChunkCrc_ThrowsException<TPixel>(TestImageProvider
475475
public void Decode_InvalidDataChunkCrc_IgnoreCrcErrors<TPixel>(TestImageProvider<TPixel> provider)
476476
where TPixel : unmanaged, IPixel<TPixel>
477477
{
478-
using Image<TPixel> image = provider.GetImage(PngDecoder.Instance, new PngDecoderOptions() { IgnoreCrcCheck = true });
478+
using Image<TPixel> image = provider.GetImage(PngDecoder.Instance, new PngDecoderOptions() { PngCrcChunkHandling = PngCrcChunkHandling.IgnoreData });
479479

480480
image.DebugSave(provider);
481481
image.CompareToOriginal(provider, new MagickReferenceDecoder(false));

0 commit comments

Comments
 (0)