diff --git a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs
index e5d0b09cf..770afa3c5 100644
--- a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs
+++ b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs
@@ -59,7 +59,13 @@ namespace SixLabors.ImageSharp.Formats.Png
PngInterlaceMode? InterlaceMethod { get; }
///
- /// Gets chunk filter method.
+ /// Gets a value indicating whether the metadata should be ignored when the image is being encoded.
+ /// When set to true, all ancillary chunks will be skipped.
+ ///
+ bool IgnoreMetadata { get; }
+
+ ///
+ /// Gets the chunk filter method. This allows to filter ancillary chunks.
///
PngChunkFilter? ChunkFilter { get; }
diff --git a/src/ImageSharp/Formats/Png/PngChunkFilter.cs b/src/ImageSharp/Formats/Png/PngChunkFilter.cs
index 04f27fb73..31d3012a6 100644
--- a/src/ImageSharp/Formats/Png/PngChunkFilter.cs
+++ b/src/ImageSharp/Formats/Png/PngChunkFilter.cs
@@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Formats.Png
ExcludeTextChunks = 1 << 3,
///
- /// All possible optimizations.
+ /// All ancillary chunks will be excluded.
///
ExcludeAll = ~None
}
diff --git a/src/ImageSharp/Formats/Png/PngEncoder.cs b/src/ImageSharp/Formats/Png/PngEncoder.cs
index 53cec6e4e..062e56c1d 100644
--- a/src/ImageSharp/Formats/Png/PngEncoder.cs
+++ b/src/ImageSharp/Formats/Png/PngEncoder.cs
@@ -34,22 +34,19 @@ namespace SixLabors.ImageSharp.Formats.Png
///
public IQuantizer Quantizer { get; set; }
- ///
- /// Gets or sets the transparency threshold.
- ///
+ ///
public byte Threshold { get; set; } = byte.MaxValue;
///
public PngInterlaceMode? InterlaceMethod { get; set; }
- ///
- /// Gets or sets the chunk filter. This can be used to exclude some ancillary chunks from being written.
- ///
+ ///
public PngChunkFilter? ChunkFilter { get; set; }
- ///
- /// Gets or sets a value indicating whether fully transparent pixels should be converted to black pixels.
- ///
+ ///
+ public bool IgnoreMetadata { get; set; }
+
+ ///
public bool MakeTransparentBlack { get; set; }
///
diff --git a/src/ImageSharp/Formats/Png/PngEncoderOptions.cs b/src/ImageSharp/Formats/Png/PngEncoderOptions.cs
index 2b43edd12..d0eb1a843 100644
--- a/src/ImageSharp/Formats/Png/PngEncoderOptions.cs
+++ b/src/ImageSharp/Formats/Png/PngEncoderOptions.cs
@@ -30,6 +30,7 @@ namespace SixLabors.ImageSharp.Formats.Png
this.Threshold = source.Threshold;
this.InterlaceMethod = source.InterlaceMethod;
this.ChunkFilter = source.ChunkFilter;
+ this.IgnoreMetadata = source.IgnoreMetadata;
this.MakeTransparentBlack = source.MakeTransparentBlack;
}
@@ -60,11 +61,12 @@ namespace SixLabors.ImageSharp.Formats.Png
///
public PngInterlaceMode? InterlaceMethod { get; set; }
- ///
- /// Gets or sets a the optimize method.
- ///
+ ///
public PngChunkFilter? ChunkFilter { get; set; }
+ ///
+ public bool IgnoreMetadata { get; set; }
+
///
public bool MakeTransparentBlack { get; set; }
}
diff --git a/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs b/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs
index 3a8e528cc..52d7fe6d0 100644
--- a/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs
+++ b/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs
@@ -40,6 +40,11 @@ namespace SixLabors.ImageSharp.Formats.Png
use16Bit = options.BitDepth == PngBitDepth.Bit16;
bytesPerPixel = CalculateBytesPerPixel(options.ColorType, use16Bit);
+ if (options.IgnoreMetadata)
+ {
+ options.ChunkFilter = PngChunkFilter.ExcludeAll;
+ }
+
// Ensure we are not allowing impossible combinations.
if (!PngConstants.ColorTypes.ContainsKey(options.ColorType.Value))
{
diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs
index fa1544816..0418b36c8 100644
--- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs
+++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs
@@ -144,6 +144,58 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
}
}
+ [Fact]
+ public void IgnoreMetadata_WillExcludeAllAncillaryChunks()
+ {
+ // arrange
+ var testFile = TestFile.Create(TestImages.Png.PngWithMetadata);
+ using Image input = testFile.CreateRgba32Image();
+ using var memStream = new MemoryStream();
+ var encoder = new PngEncoder() { IgnoreMetadata = true, TextCompressionThreshold = 8 };
+ var expectedChunkTypes = new Dictionary()
+ {
+ { PngChunkType.Header, false },
+ { PngChunkType.Palette, false },
+ { PngChunkType.Data, false },
+ { PngChunkType.End, false }
+ };
+ var excludedChunkTypes = new List()
+ {
+ PngChunkType.Gamma,
+ PngChunkType.Exif,
+ PngChunkType.Physical,
+ PngChunkType.Text,
+ PngChunkType.InternationalText,
+ PngChunkType.CompressedText,
+ };
+
+ // act
+ input.Save(memStream, encoder);
+
+ // assert
+ Assert.True(excludedChunkTypes.Count > 0);
+ memStream.Position = 0;
+ Span bytesSpan = memStream.ToArray().AsSpan(8); // Skip header.
+ while (bytesSpan.Length > 0)
+ {
+ int length = BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(0, 4));
+ var chunkType = (PngChunkType)BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(4, 4));
+ Assert.False(excludedChunkTypes.Contains(chunkType), $"{chunkType} chunk should have been excluded");
+ if (expectedChunkTypes.ContainsKey(chunkType))
+ {
+ expectedChunkTypes[chunkType] = true;
+ }
+
+ bytesSpan = bytesSpan.Slice(4 + 4 + length + 4);
+ }
+
+ // all expected chunk types should have been seen at least once.
+ foreach (PngChunkType chunkType in expectedChunkTypes.Keys)
+ {
+ Assert.True(expectedChunkTypes[chunkType], $"We expect {chunkType} chunk to be present at least once");
+ }
+ }
+
[Theory]
[InlineData(PngChunkFilter.ExcludeGammaChunk)]
[InlineData(PngChunkFilter.ExcludeExifChunk)]