diff --git a/src/ImageSharp/Formats/Png/PngChunkType.cs b/src/ImageSharp/Formats/Png/PngChunkType.cs
index 866bf28af..a008bf8ea 100644
--- a/src/ImageSharp/Formats/Png/PngChunkType.cs
+++ b/src/ImageSharp/Formats/Png/PngChunkType.cs
@@ -9,22 +9,7 @@ namespace SixLabors.ImageSharp.Formats.Png;
internal enum PngChunkType : uint
{
///
- ///
- /// acTL (Single)
- AnimationControl = 0x6163544cU,
-
- ///
- ///
- /// fcTL (Multiple)
- FrameControl = 0x6663544cU,
-
- ///
- ///
- /// fdAT (Multiple)
- FrameData = 0x66644154U,
-
- ///
- /// The IDAT chunk contains the actual image data. The image can contains more
+ /// This chunk contains the actual image data. The image can contains more
/// than one chunk of this type. All chunks together are the whole image.
///
/// IDAT (Multiple)
@@ -155,6 +140,27 @@ internal enum PngChunkType : uint
/// cHRM (Single)
Chroma = 0x6348524d,
+ ///
+ /// This chunk is an ancillary chunk as defined in the PNG Specification.
+ /// It must appear before the first IDAT chunk within a valid PNG stream.
+ ///
+ /// acTL (Single, APNG)
+ AnimationControl = 0x6163544cU,
+
+ ///
+ /// This chunk is an ancillary chunk as defined in the PNG Specification.
+ /// It must appear before the IDAT or fdAT chunks of the frame to which it applies.
+ ///
+ /// fcTL (Multiple, APNG)
+ FrameControl = 0x6663544cU,
+
+ ///
+ /// This chunk has the same purpose as an IDAT chunk.
+ /// It has the same structure as an IDAT chunk, except preceded by a sequence number.
+ ///
+ /// fdAT (Multiple, APNG)
+ FrameData = 0x66644154U,
+
///
/// Malformed chunk named CgBI produced by apple, which is not conform to the specification.
/// Related issue is here https://github.com/SixLabors/ImageSharp/issues/410
diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
index 2cbc86f42..155041789 100644
--- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
@@ -168,7 +168,8 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
this.WriteXmpChunk(stream, metadata);
this.WriteTextChunks(stream, pngMetadata);
- if (this.encoder.IsSimplePng is not true && targetImage.Frames.Count > 1)
+ if ((this.encoder.IsSimplePng is null && targetImage.Frames.Count > 1)
+ || this.encoder.IsSimplePng is false)
{
this.WriteAnimationControlChunk(stream, targetImage.Frames.Count, pngMetadata.NumberPlays);
@@ -642,7 +643,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
ref Rgba32 rgbaPaletteRef = ref MemoryMarshal.GetReference(rgbaPaletteSpan);
// Loop, assign, and extract alpha values from the palette.
- for (int i = 0; i < paletteLength; i++)
+ for (int i = 0; i < paletteLength; ++i)
{
Rgba32 rgba = Unsafe.Add(ref rgbaPaletteRef, (uint)i);
byte alpha = rgba.A;
@@ -674,7 +675,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
/// The image metadata.
private void WritePhysicalChunk(Stream stream, ImageMetadata meta)
{
- if ((this.chunkFilter & PngChunkFilter.ExcludePhysicalChunk) == PngChunkFilter.ExcludePhysicalChunk)
+ if (this.chunkFilter.HasFlag(PngChunkFilter.ExcludePhysicalChunk))
{
return;
}
diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs
index 2fc0dc0c0..19283ebf8 100644
--- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs
@@ -111,20 +111,7 @@ public partial class PngDecoderTests
public void Decode_APng(TestImageProvider provider)
where TPixel : unmanaged, IPixel
{
- using Image image = provider.GetImage(PngDecoder.Instance);
- image.SaveAsPng("C:\\WorkSpace\\1.png");
- image.DebugSave(provider);
- image.CompareToOriginal(provider, ImageComparer.Exact);
- // TODO test
- }
-
- [Theory]
- [WithFile("C:\\WorkSpace\\Fuck.png", PixelTypes.Rgba32)]
- public void Decode_APng2(TestImageProvider provider)
- where TPixel : unmanaged, IPixel
- {
- using Image image = provider.GetImage(PngDecoder.Instance);
- image.SaveAsPng("C:\\WorkSpace\\1.png");
+ using Image image = provider.GetImage(PngDecoder.Instance); // MagickReferenceDecoder cannot decode APNGs
}
[Theory]
diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs
index b4fda5d32..74885283d 100644
--- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs
@@ -439,6 +439,19 @@ public partial class PngEncoderTests
});
}
+ [Theory]
+ [WithFile(TestImages.Png.APng, PixelTypes.Rgba32)]
+ public void Encode_APng(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ using Image image = provider.GetImage(PngDecoder.Instance);
+ using MemoryStream memStream = new();
+ image.Save(memStream, PngEncoder);
+ memStream.Position = 0;
+ using Image output = Image.Load(memStream);
+ ImageComparer.Exact.VerifySimilarity(output, image);
+ }
+
[Theory]
[MemberData(nameof(PngTrnsFiles))]
public void Encode_PreserveTrns(string imagePath, PngBitDepth pngBitDepth, PngColorType pngColorType)
diff --git a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs
index 460ecac85..42be46645 100644
--- a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs
+++ b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs
@@ -208,7 +208,7 @@ public class ImagingTestCaseUtility
bool appendPixelTypeToFileName = true)
where TPixel : unmanaged, IPixel
{
- encoder = encoder ?? TestEnvironment.GetReferenceEncoder($"foo.{extension}");
+ encoder ??= TestEnvironment.GetReferenceEncoder($"foo.{extension}");
string[] files = this.GetTestOutputFileNamesMultiFrame(
image.Frames.Count,
@@ -218,14 +218,10 @@ public class ImagingTestCaseUtility
for (int i = 0; i < image.Frames.Count; i++)
{
- using (Image frameImage = image.Frames.CloneFrame(i))
- {
- string filePath = files[i];
- using (FileStream stream = File.OpenWrite(filePath))
- {
- frameImage.Save(stream, encoder);
- }
- }
+ using Image frameImage = image.Frames.CloneFrame(i);
+ string filePath = files[i];
+ using FileStream stream = File.OpenWrite(filePath);
+ frameImage.Save(stream, encoder);
}
return files;
diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs
index 31c9f541e..7cdf66e3a 100644
--- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs
+++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs
@@ -534,10 +534,8 @@ public static class TestImageExtensions
referenceDecoder ??= TestEnvironment.GetReferenceDecoder(path);
using MemoryStream stream = new(testFile.Bytes);
- using (Image original = referenceDecoder.Decode(referenceDecoderOptions ?? DecoderOptions.Default, stream))
- {
- comparer.VerifySimilarity(original, image);
- }
+ using Image original = referenceDecoder.Decode(referenceDecoderOptions ?? DecoderOptions.Default, stream);
+ comparer.VerifySimilarity(original, image);
return image;
}
@@ -560,10 +558,8 @@ public static class TestImageExtensions
referenceDecoder ??= TestEnvironment.GetReferenceDecoder(path);
using MemoryStream stream = new(testFile.Bytes);
- using (Image original = referenceDecoder.Decode(DecoderOptions.Default, stream))
- {
- comparer.VerifySimilarity(original, image);
- }
+ using Image original = referenceDecoder.Decode(DecoderOptions.Default, stream);
+ comparer.VerifySimilarity(original, image);
return image;
}
diff --git a/tests/Images/Input/Png/apng.png b/tests/Images/Input/Png/apng.png
index c5b2adf8e..7def301ae 100644
--- a/tests/Images/Input/Png/apng.png
+++ b/tests/Images/Input/Png/apng.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f6b0e5a904e269a9108b32c0f5cc98cda4240a60db421f560f45d2e36ead32a9
-size 212
+oid sha256:7c15e4670da1826d1cc25555bd6cbe287ecc70327cd029a7613334a39a283021
+size 2508