From 66f444d200985720a9ff3e27a7a52d4722836b43 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 30 Oct 2023 23:52:41 +1000 Subject: [PATCH] Fix alpha blending and add tests --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 174 +++++++++++------- .../ImageFrameCollection{TPixel}.cs | 1 - .../Formats/Png/PngDecoderTests.cs | 26 ++- tests/ImageSharp.Tests/TestImages.cs | 12 +- .../TestUtilities/ImagingTestCaseUtility.cs | 28 +-- .../TestUtilities/TestImageExtensions.cs | 7 +- .../Tests/TestImageProviderTests.cs | 8 +- .../00.png | 3 + .../01.png | 3 + .../00.png | 3 + .../01.png | 3 + .../00.png | 3 + .../01.png | 3 + .../02.png | 3 + .../00.png | 3 + .../01.png | 3 + .../02.png | 3 + .../03.png | 3 + .../04.png | 3 + .../05.png | 3 + .../06.png | 3 + .../07.png | 3 + .../08.png | 3 + .../104.png | 3 + .../112.png | 3 + .../120.png | 3 + .../128.png | 3 + .../16.png | 3 + .../24.png | 3 + .../32.png | 3 + .../40.png | 3 + .../48.png | 3 + .../56.png | 3 + .../64.png | 3 + .../72.png | 3 + .../80.png | 3 + .../88.png | 3 + .../96.png | 3 + .../00.png | 3 + .../00.png | 3 + .../01.png | 3 + .../02.png | 3 + .../00.png | 3 + .../01.png | 3 + .../02.png | 3 + .../00.png | 3 + .../01.png | 3 + .../02.png | 3 + .../03.png | 3 + .../04.png | 3 + .../Png/animated/12-dispose-prev-first.png | 3 + .../14-dispose-background-before-region.png | 3 + .../animated/15-dispose-background-region.png | 3 + .../Png/animated/21-blend-over-multiple.png | 3 + .../Png/animated/4-split-idat-zero-length.png | 3 + .../Input/Png/animated/7-dispose-none.png | 3 + .../Png/animated/8-dispose-background.png | 3 + .../Images/Input/Png/{ => animated}/apng.png | 0 58 files changed, 302 insertions(+), 104 deletions(-) create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_12-dispose-prev-first.png/00.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_12-dispose-prev-first.png/01.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_14-dispose-background-before-region.png/00.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_14-dispose-background-before-region.png/01.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_15-dispose-background-region.png/00.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_15-dispose-background-region.png/01.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_15-dispose-background-region.png/02.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/00.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/01.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/02.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/03.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/04.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/05.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/06.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/07.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/08.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/104.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/112.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/120.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/128.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/16.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/24.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/32.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/40.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/48.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/56.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/64.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/72.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/80.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/88.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/96.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_4-split-idat-zero-length.png/00.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_7-dispose-none.png/00.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_7-dispose-none.png/01.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_7-dispose-none.png/02.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_8-dispose-background.png/00.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_8-dispose-background.png/01.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_8-dispose-background.png/02.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_apng.png/00.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_apng.png/01.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_apng.png/02.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_apng.png/03.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_apng.png/04.png create mode 100644 tests/Images/Input/Png/animated/12-dispose-prev-first.png create mode 100644 tests/Images/Input/Png/animated/14-dispose-background-before-region.png create mode 100644 tests/Images/Input/Png/animated/15-dispose-background-region.png create mode 100644 tests/Images/Input/Png/animated/21-blend-over-multiple.png create mode 100644 tests/Images/Input/Png/animated/4-split-idat-zero-length.png create mode 100644 tests/Images/Input/Png/animated/7-dispose-none.png create mode 100644 tests/Images/Input/Png/animated/8-dispose-background.png rename tests/Images/Input/Png/{ => animated}/apng.png (100%) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 8c7c7c30d7..08f9865490 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -153,6 +153,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals this.currentStream.Skip(8); Image? image = null; FrameControl? previousFrameControl = null; + FrameControl? currentFrameControl = null; ImageFrame? previousFrame = null; ImageFrame? currentFrame = null; Span buffer = stackalloc byte[20]; @@ -190,7 +191,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals } currentFrame = null; - previousFrameControl = this.ReadFrameControlChunk(chunk.Data.GetSpan()); + currentFrameControl = this.ReadFrameControlChunk(chunk.Data.GetSpan()); break; case PngChunkType.FrameData: if (frameCount == this.maxFrames) @@ -203,15 +204,13 @@ internal sealed class PngDecoderCore : IImageDecoderInternals PngThrowHelper.ThrowMissingDefaultData(); } - if (previousFrameControl is null) + if (currentFrameControl is null) { PngThrowHelper.ThrowMissingFrameControl(); } - if (currentFrame is null) - { - this.InitializeFrame(previousFrameControl.Value, image, previousFrame, out currentFrame); - } + previousFrameControl ??= new((uint)this.header.Width, (uint)this.header.Height); + this.InitializeFrame(previousFrameControl.Value, currentFrameControl.Value, image, previousFrame, out currentFrame); this.currentStream.Position += 4; this.ReadScanlines( @@ -219,37 +218,33 @@ internal sealed class PngDecoderCore : IImageDecoderInternals currentFrame, pngMetadata, this.ReadNextDataChunkAndSkipSeq, - previousFrameControl.Value, + currentFrameControl.Value, cancellationToken); - PngFrameMetadata pngFrameMetadata = currentFrame.Metadata.GetPngFrameMetadata(); - if (previousFrame != null && pngFrameMetadata.BlendMethod == PngBlendMethod.Over) - { - this.AlphaBlend(previousFrame, currentFrame, previousFrameControl.Value.Bounds); - } - previousFrame = currentFrame; - previousFrameControl = null; + previousFrameControl = currentFrameControl; break; case PngChunkType.Data: + + currentFrameControl ??= new((uint)this.header.Width, (uint)this.header.Height); if (image is null) { - this.InitializeImage(metadata, previousFrameControl, out image); + this.InitializeImage(metadata, currentFrameControl.Value, out image); // Both PLTE and tRNS chunks, if present, have been read at this point as per spec. AssignColorPalette(this.palette, this.paletteAlpha, pngMetadata); } - FrameControl frameControl = previousFrameControl ?? new((uint)this.header.Width, (uint)this.header.Height); this.ReadScanlines( chunk.Length, image.Frames.RootFrame, pngMetadata, this.ReadNextDataChunk, - in frameControl, + currentFrameControl.Value, cancellationToken); - previousFrameControl = null; + previousFrame = currentFrame; + previousFrameControl = currentFrameControl; break; case PngChunkType.Palette: this.palette = chunk.Data.GetSpan().ToArray(); @@ -577,7 +572,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals /// The metadata information for the image /// The frame control information for the frame /// The image that we will populate - private void InitializeImage(ImageMetadata metadata, FrameControl? frameControl, out Image image) + private void InitializeImage(ImageMetadata metadata, FrameControl frameControl, out Image image) where TPixel : unmanaged, IPixel { image = Image.CreateUninitialized( @@ -586,11 +581,8 @@ internal sealed class PngDecoderCore : IImageDecoderInternals this.header.Height, metadata); - if (frameControl is { } control) - { - PngFrameMetadata frameMetadata = image.Frames.RootFrame.Metadata.GetPngFrameMetadata(); - frameMetadata.FromChunk(in control); - } + PngFrameMetadata frameMetadata = image.Frames.RootFrame.Metadata.GetPngFrameMetadata(); + frameMetadata.FromChunk(in frameControl); this.bytesPerPixel = this.CalculateBytesPerPixel(); this.bytesPerScanline = this.CalculateScanlineLength(this.header.Width) + 1; @@ -610,12 +602,14 @@ internal sealed class PngDecoderCore : IImageDecoderInternals /// Initializes the image and various buffers needed for processing /// /// The type the pixels will be - /// The frame control information for the frame + /// The frame control information for the previous frame. + /// The frame control information for the current frame. /// The image that we will populate /// The previous frame. /// The created frame private void InitializeFrame( - FrameControl frameControl, + FrameControl previousFrameControl, + FrameControl currentFrameControl, Image image, ImageFrame? previousFrame, out ImageFrame frame) @@ -627,17 +621,17 @@ internal sealed class PngDecoderCore : IImageDecoderInternals frame = image.Frames.AddFrame(previousFrame ?? image.Frames.RootFrame); // If the first `fcTL` chunk uses a `dispose_op` of APNG_DISPOSE_OP_PREVIOUS it should be treated as APNG_DISPOSE_OP_BACKGROUND. - if (frameControl.DisposeOperation == PngDisposalMethod.Background - || (previousFrame is null && frameControl.DisposeOperation == PngDisposalMethod.Previous)) + if (previousFrameControl.DisposeOperation == PngDisposalMethod.Background + || (previousFrame is null && previousFrameControl.DisposeOperation == PngDisposalMethod.Previous)) { - Rectangle restoreArea = frameControl.Bounds; + Rectangle restoreArea = previousFrameControl.Bounds; Rectangle interest = Rectangle.Intersect(frame.Bounds(), restoreArea); Buffer2DRegion pixelRegion = frame.PixelBuffer.GetRegion(interest); pixelRegion.Clear(); } PngFrameMetadata frameMetadata = frame.Metadata.GetPngFrameMetadata(); - frameMetadata.FromChunk(frameControl); + frameMetadata.FromChunk(currentFrameControl); this.previousScanline?.Dispose(); this.scanline?.Dispose(); @@ -714,12 +708,18 @@ internal sealed class PngDecoderCore : IImageDecoderInternals /// A delegate to get more data from the inner stream for . /// The frame control /// The cancellation token. - private void ReadScanlines(int chunkLength, ImageFrame image, PngMetadata pngMetadata, Func getData, in FrameControl frameControl, CancellationToken cancellationToken) + private void ReadScanlines( + int chunkLength, + ImageFrame image, + PngMetadata pngMetadata, + Func getData, + in FrameControl frameControl, + CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { - using ZlibInflateStream deframeStream = new(this.currentStream, getData); - deframeStream.AllocateNewBytes(chunkLength, true); - DeflateStream dataStream = deframeStream.CompressedStream!; + using ZlibInflateStream inflateStream = new(this.currentStream, getData); + inflateStream.AllocateNewBytes(chunkLength, true); + DeflateStream dataStream = inflateStream.CompressedStream!; if (this.header.InterlaceMethod is PngInterlaceMode.Adam7) { @@ -751,13 +751,23 @@ internal sealed class PngDecoderCore : IImageDecoderInternals int currentRow = (int)frameControl.YOffset; int currentRowBytesRead = 0; int height = (int)frameControl.YMax; + + IMemoryOwner? blendMemory = null; + Span blendRowBuffer = Span.Empty; + if (frameControl.BlendOperation == PngBlendMethod.Over) + { + blendMemory = this.memoryAllocator.Allocate(imageFrame.Width, AllocationOptions.Clean); + blendRowBuffer = blendMemory.Memory.Span; + } + while (currentRow < height) { cancellationToken.ThrowIfCancellationRequested(); - Span scanlineSpan = this.scanline.GetSpan(); - while (currentRowBytesRead < this.bytesPerScanline) + int bytesPerFrameScanline = this.CalculateScanlineLength((int)frameControl.Width) + 1; + Span scanlineSpan = this.scanline.GetSpan()[..bytesPerFrameScanline]; + while (currentRowBytesRead < bytesPerFrameScanline) { - int bytesRead = compressedStream.Read(scanlineSpan, currentRowBytesRead, this.bytesPerScanline - currentRowBytesRead); + int bytesRead = compressedStream.Read(scanlineSpan, currentRowBytesRead, bytesPerFrameScanline - currentRowBytesRead); if (bytesRead <= 0) { return; @@ -794,10 +804,12 @@ internal sealed class PngDecoderCore : IImageDecoderInternals break; } - this.ProcessDefilteredScanline(frameControl, currentRow, scanlineSpan, imageFrame, pngMetadata); + this.ProcessDefilteredScanline(frameControl, currentRow, scanlineSpan, imageFrame, pngMetadata, blendRowBuffer); this.SwapScanlineBuffers(); currentRow++; } + + blendMemory?.Dispose(); } /// @@ -806,13 +818,13 @@ internal sealed class PngDecoderCore : IImageDecoderInternals /// The pixel format. /// The frame control /// The compressed pixel data stream. - /// The current image. + /// The current image frame. /// The png metadata. /// The cancellation token. private void DecodeInterlacedPixelData( in FrameControl frameControl, DeflateStream compressedStream, - ImageFrame image, + ImageFrame imageFrame, PngMetadata pngMetadata, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel @@ -823,7 +835,16 @@ internal sealed class PngDecoderCore : IImageDecoderInternals int width = (int)frameControl.Width; int endRow = (int)frameControl.YMax; - Buffer2D imageBuffer = image.PixelBuffer; + Buffer2D imageBuffer = imageFrame.PixelBuffer; + + IMemoryOwner? blendMemory = null; + Span blendRowBuffer = Span.Empty; + if (frameControl.BlendOperation == PngBlendMethod.Over) + { + blendMemory = this.memoryAllocator.Allocate(imageFrame.Width, AllocationOptions.Clean); + blendRowBuffer = blendMemory.Memory.Span; + } + while (true) { int numColumns = Adam7.ComputeColumns(width, pass); @@ -889,10 +910,11 @@ internal sealed class PngDecoderCore : IImageDecoderInternals this.scanline.GetSpan(), rowSpan, pngMetadata, + blendRowBuffer, pixelOffset: Adam7.FirstColumn[pass], increment: Adam7.ColumnIncrement[pass]); - // TODO: Alpha blending. + blendRowBuffer.Clear(); this.SwapScanlineBuffers(); currentRow += Adam7.RowIncrement[pass]; @@ -911,6 +933,8 @@ internal sealed class PngDecoderCore : IImageDecoderInternals break; } } + + blendMemory?.Dispose(); } /// @@ -919,26 +943,34 @@ internal sealed class PngDecoderCore : IImageDecoderInternals /// The pixel format. /// The frame control /// The index of the current scanline being processed. - /// The de-filtered scanline + /// The de-filtered scanline /// The image /// The png metadata. + /// A span used to temporarily hold the decoded row pixel data for alpha blending. private void ProcessDefilteredScanline( in FrameControl frameControl, int currentRow, - ReadOnlySpan defilteredScanline, + ReadOnlySpan scanline, ImageFrame pixels, - PngMetadata pngMetadata) + PngMetadata pngMetadata, + Span blendRowBuffer) where TPixel : unmanaged, IPixel { - Span rowSpan = pixels.PixelBuffer.DangerousGetRowSpan(currentRow); + Span destination = pixels.PixelBuffer.DangerousGetRowSpan(currentRow); + + bool blend = frameControl.BlendOperation == PngBlendMethod.Over; + Span rowSpan = blend + ? blendRowBuffer + : destination; // Trim the first marker byte from the buffer - ReadOnlySpan trimmed = defilteredScanline[1..]; + ReadOnlySpan trimmed = scanline[1..]; // Convert 1, 2, and 4 bit pixel data into the 8 bit equivalent. IMemoryOwner? buffer = null; try { + // TODO: The allocation here could be per frame, not per scanline. ReadOnlySpan scanlineSpan = this.TryScaleUpTo8BitArray( trimmed, this.bytesPerScanline - 1, @@ -1004,6 +1036,13 @@ internal sealed class PngDecoderCore : IImageDecoderInternals break; } + + if (blend) + { + PixelBlender blender = + PixelOperations.Instance.GetPixelBlender(PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.SrcOver); + blender.Blend(this.configuration, destination, destination, rowSpan, 1f); + } } finally { @@ -1016,22 +1055,29 @@ internal sealed class PngDecoderCore : IImageDecoderInternals /// /// The pixel format. /// The frame control - /// The de-filtered scanline - /// The current image row. + /// The de-filtered scanline + /// The current image row. /// The png metadata. + /// A span used to temporarily hold the decoded row pixel data for alpha blending. /// The column start index. Always 0 for none interlaced images. /// The column increment. Always 1 for none interlaced images. private void ProcessInterlacedDefilteredScanline( in FrameControl frameControl, - ReadOnlySpan defilteredScanline, - Span rowSpan, + ReadOnlySpan scanline, + Span destination, PngMetadata pngMetadata, + Span blendRowBuffer, int pixelOffset = 0, int increment = 1) where TPixel : unmanaged, IPixel { + bool blend = frameControl.BlendOperation == PngBlendMethod.Over; + Span rowSpan = blend + ? blendRowBuffer + : destination; + // Trim the first marker byte from the buffer - ReadOnlySpan trimmed = defilteredScanline[1..]; + ReadOnlySpan trimmed = scanline[1..]; // Convert 1, 2, and 4 bit pixel data into the 8 bit equivalent. IMemoryOwner? buffer = null; @@ -1112,6 +1158,13 @@ internal sealed class PngDecoderCore : IImageDecoderInternals break; } + + if (blend) + { + PixelBlender blender = + PixelOperations.Instance.GetPixelBlender(PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.SrcOver); + blender.Blend(this.configuration, destination, destination, rowSpan, 1f); + } } finally { @@ -1894,21 +1947,4 @@ internal sealed class PngDecoderCore : IImageDecoderInternals private void SwapScanlineBuffers() => (this.scanline, this.previousScanline) = (this.previousScanline, this.scanline); - - private void AlphaBlend(ImageFrame src, ImageFrame dst, Rectangle restoreArea) - where TPixel : unmanaged, IPixel - { - Buffer2DRegion srcPixels = src.PixelBuffer.GetRegion(restoreArea); - Buffer2DRegion dstPixels = dst.PixelBuffer.GetRegion(restoreArea); - PixelBlender blender = - PixelOperations.Instance.GetPixelBlender(PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.SrcOver); - - for (int y = 0; y < srcPixels.Height; y++) - { - Span srcPixelRow = srcPixels.DangerousGetRowSpan(y); - Span dstPixelRow = dstPixels.DangerousGetRowSpan(y); - - blender.Blend(this.configuration, dstPixelRow, srcPixelRow, dstPixelRow, 1f); - } - } } diff --git a/src/ImageSharp/ImageFrameCollection{TPixel}.cs b/src/ImageSharp/ImageFrameCollection{TPixel}.cs index b32711ebf2..e927fb0fac 100644 --- a/src/ImageSharp/ImageFrameCollection{TPixel}.cs +++ b/src/ImageSharp/ImageFrameCollection{TPixel}.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Collections; -using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index 9f11bf6507..9345681149 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -78,6 +78,18 @@ public partial class PngDecoderTests { TestImages.Png.Rgba64Bpp, typeof(Image) }, }; + public static readonly string[] MultiFrameTestFiles = + { + //TestImages.Png.APng, + //TestImages.Png.SplitIDatZeroLength, + //TestImages.Png.DisposeNone, + //TestImages.Png.DisposeBackground, + //TestImages.Png.DisposeBackgroundRegion, + //TestImages.Png.DisposePreviousFirst, + //TestImages.Png.DisposeBackgroundBeforeRegion, + TestImages.Png.BlendOverMultiple + }; + [Theory] [MemberData(nameof(PixelFormatRange))] public void Decode_NonGeneric_CreatesCorrectImageType(string path, Type type) @@ -107,16 +119,16 @@ public partial class PngDecoderTests } [Theory] - [WithFile(TestImages.Png.APng, PixelTypes.Rgba32)] - public void Decode_APng(TestImageProvider provider) - where TPixel : unmanaged, IPixel + [WithFileCollection(nameof(MultiFrameTestFiles), PixelTypes.Rgba32)] + public void Decode_VerifyAllFrames(TestImageProvider provider) + where TPixel : unmanaged, IPixel { using Image image = provider.GetImage(PngDecoder.Instance); - Assert.Equal(5, image.Frames.Count); - - // TODO: Assertations. - // MagickReferenceDecoder cannot decode APNGs (Though ImageMagick can, we likely need to update our mapping implementation) + // Some images have many frames, only compare a selection of them. + static bool Predicate(int i, int _) => i <= 8 || i % 8 == 0; + image.DebugSaveMultiFrame(provider, predicate: Predicate); + image.CompareToReferenceOutputMultiFrame(provider, ImageComparer.Exact, predicate: Predicate); } [Theory] diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 4b7badfdc2..048b19dc5b 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -61,7 +61,17 @@ public static class TestImages public const string TestPattern31x31 = "Png/testpattern31x31.png"; public const string TestPattern31x31HalfTransparent = "Png/testpattern31x31-halftransparent.png"; public const string XmpColorPalette = "Png/xmp-colorpalette.png"; - public const string APng = "Png/apng.png"; + + // Animated + // https://philip.html5.org/tests/apng/tests.html + public const string APng = "Png/animated/apng.png"; + public const string SplitIDatZeroLength = "Png/animated/4-split-idat-zero-length.png"; + public const string DisposeNone = "Png/animated/7-dispose-none.png"; + public const string DisposeBackground = "Png/animated/8-dispose-background.png"; + public const string DisposeBackgroundBeforeRegion = "Png/animated/14-dispose-background-before-region.png"; + public const string DisposeBackgroundRegion = "Png/animated/15-dispose-background-region.png"; + public const string DisposePreviousFirst = "Png/animated/12-dispose-prev-first.png"; + public const string BlendOverMultiple = "Png/animated/21-blend-over-multiple.png"; // Filtered test images from http://www.schaik.com/pngsuite/pngsuite_fil_png.html public const string Filter0 = "Png/filter0.png"; diff --git a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs index 3601344ee3..9b100047f0 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs @@ -179,7 +179,7 @@ public class ImagingTestCaseUtility return path; } - public IEnumerable GetTestOutputFileNamesMultiFrame( + public IEnumerable<(int Index, string FileName)> GetTestOutputFileNamesMultiFrame( int frameCount, string extension = null, object testOutputDetails = null, @@ -201,11 +201,11 @@ public class ImagingTestCaseUtility continue; } - yield return $"{baseDir}/{i:D2}.{extension}"; + yield return (i, $"{baseDir}/{i:D2}.{extension}"); } } - public string[] SaveTestOutputFileMultiFrame( + public (int Index, string FileName)[] SaveTestOutputFileMultiFrame( Image image, string extension = "png", IImageEncoder encoder = null, @@ -216,27 +216,17 @@ public class ImagingTestCaseUtility { encoder ??= TestEnvironment.GetReferenceEncoder($"foo.{extension}"); - string[] files = this.GetTestOutputFileNamesMultiFrame( + (int Index, string FileName)[] files = this.GetTestOutputFileNamesMultiFrame( image.Frames.Count, extension, testOutputDetails, appendPixelTypeToFileName, predicate: predicate).ToArray(); - for (int i = 0; i < image.Frames.Count; i++) + foreach ((int Index, string FileName) file in files) { - if (predicate != null && !predicate(i, image.Frames.Count)) - { - continue; - } - - if (i >= files.Length) - { - break; - } - - using Image frameImage = image.Frames.CloneFrame(i); - string filePath = files[i]; + using Image frameImage = image.Frames.CloneFrame(file.Index); + string filePath = file.FileName; using FileStream stream = File.OpenWrite(filePath); frameImage.Save(stream, encoder); } @@ -252,14 +242,14 @@ public class ImagingTestCaseUtility => TestEnvironment.GetReferenceOutputFileName( this.GetTestOutputFileName(extension, testOutputDetails, appendPixelTypeToFileName, appendSourceFileOrDescription)); - public string[] GetReferenceOutputFileNamesMultiFrame( + public (int Index, string FileName)[] GetReferenceOutputFileNamesMultiFrame( int frameCount, string extension, object testOutputDetails, bool appendPixelTypeToFileName = true, Func predicate = null) => this.GetTestOutputFileNamesMultiFrame(frameCount, extension, testOutputDetails, appendPixelTypeToFileName, predicate: predicate) - .Select(TestEnvironment.GetReferenceOutputFileName).ToArray(); + .Select(x => (x.Index, TestEnvironment.GetReferenceOutputFileName(x.FileName))).ToArray(); internal void Init(string typeName, string methodName, string outputSubfolderName) { diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs index 6417d6691c..3c74b48938 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -336,7 +336,7 @@ public static class TestImageExtensions Func predicate = null) where TPixel : unmanaged, IPixel { - string[] frameFiles = provider.Utility.GetReferenceOutputFileNamesMultiFrame( + (int Index, string FileName)[] frameFiles = provider.Utility.GetReferenceOutputFileNamesMultiFrame( frameCount, extension, testOutputDetails, @@ -345,10 +345,11 @@ public static class TestImageExtensions List> temporaryFrameImages = new(); - IImageDecoder decoder = TestEnvironment.GetReferenceDecoder(frameFiles[0]); + IImageDecoder decoder = TestEnvironment.GetReferenceDecoder(frameFiles[0].FileName); - foreach (string path in frameFiles) + for (int i = 0; i < frameFiles.Length; i++) { + string path = frameFiles[i].FileName; if (!File.Exists(path)) { throw new FileNotFoundException("Reference output file missing: " + path); diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs index 974e951f6f..3dceaf2524 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs @@ -200,13 +200,13 @@ public class TestImageProviderTests where TPixel : unmanaged, IPixel { using Image image = provider.GetImage(); - string[] files = provider.Utility.SaveTestOutputFileMultiFrame(image); + (int Index, string FileName)[] files = provider.Utility.SaveTestOutputFileMultiFrame(image); Assert.True(files.Length > 2); - foreach (string path in files) + foreach ((int Index, string FileName) file in files) { - this.Output.WriteLine(path); - Assert.True(File.Exists(path)); + this.Output.WriteLine(file.FileName); + Assert.True(File.Exists(file.FileName)); } } diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_12-dispose-prev-first.png/00.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_12-dispose-prev-first.png/00.png new file mode 100644 index 0000000000..8fcbcb492a --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_12-dispose-prev-first.png/00.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cb2d35aad4996610f754a166ae30906b49f98979c14a71143f99911e465755a8 +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_12-dispose-prev-first.png/01.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_12-dispose-prev-first.png/01.png new file mode 100644 index 0000000000..a695681b0f --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_12-dispose-prev-first.png/01.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ea3f66d081c07c2eeefccae69084dbd0eabb824ace03280cb58a39b818de556 +size 102 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_14-dispose-background-before-region.png/00.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_14-dispose-background-before-region.png/00.png new file mode 100644 index 0000000000..8fcbcb492a --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_14-dispose-background-before-region.png/00.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cb2d35aad4996610f754a166ae30906b49f98979c14a71143f99911e465755a8 +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_14-dispose-background-before-region.png/01.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_14-dispose-background-before-region.png/01.png new file mode 100644 index 0000000000..a695681b0f --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_14-dispose-background-before-region.png/01.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ea3f66d081c07c2eeefccae69084dbd0eabb824ace03280cb58a39b818de556 +size 102 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_15-dispose-background-region.png/00.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_15-dispose-background-region.png/00.png new file mode 100644 index 0000000000..7f10ed9664 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_15-dispose-background-region.png/00.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:02c81691db45508be3fe8c6051e8b09937eaa347f332f1097026e00a0e084b38 +size 99 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_15-dispose-background-region.png/01.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_15-dispose-background-region.png/01.png new file mode 100644 index 0000000000..7f10ed9664 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_15-dispose-background-region.png/01.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:02c81691db45508be3fe8c6051e8b09937eaa347f332f1097026e00a0e084b38 +size 99 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_15-dispose-background-region.png/02.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_15-dispose-background-region.png/02.png new file mode 100644 index 0000000000..de47c015c9 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_15-dispose-background-region.png/02.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e1322aa335ad845cacfa20266bc0ffc31db117376373c15bcdb222abcf4b8f83 +size 113 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/00.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/00.png new file mode 100644 index 0000000000..8fcbcb492a --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/00.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cb2d35aad4996610f754a166ae30906b49f98979c14a71143f99911e465755a8 +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/01.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/01.png new file mode 100644 index 0000000000..e544ca74e4 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/01.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11558f68c1a1c3ad32832c7fc91ae093b7351bef68222e4d28ea44f6f2d6511a +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/02.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/02.png new file mode 100644 index 0000000000..e544ca74e4 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/02.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11558f68c1a1c3ad32832c7fc91ae093b7351bef68222e4d28ea44f6f2d6511a +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/03.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/03.png new file mode 100644 index 0000000000..e544ca74e4 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/03.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11558f68c1a1c3ad32832c7fc91ae093b7351bef68222e4d28ea44f6f2d6511a +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/04.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/04.png new file mode 100644 index 0000000000..e544ca74e4 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/04.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11558f68c1a1c3ad32832c7fc91ae093b7351bef68222e4d28ea44f6f2d6511a +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/05.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/05.png new file mode 100644 index 0000000000..e544ca74e4 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/05.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11558f68c1a1c3ad32832c7fc91ae093b7351bef68222e4d28ea44f6f2d6511a +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/06.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/06.png new file mode 100644 index 0000000000..e544ca74e4 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/06.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11558f68c1a1c3ad32832c7fc91ae093b7351bef68222e4d28ea44f6f2d6511a +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/07.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/07.png new file mode 100644 index 0000000000..e544ca74e4 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/07.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11558f68c1a1c3ad32832c7fc91ae093b7351bef68222e4d28ea44f6f2d6511a +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/08.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/08.png new file mode 100644 index 0000000000..e544ca74e4 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/08.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11558f68c1a1c3ad32832c7fc91ae093b7351bef68222e4d28ea44f6f2d6511a +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/104.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/104.png new file mode 100644 index 0000000000..e544ca74e4 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/104.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11558f68c1a1c3ad32832c7fc91ae093b7351bef68222e4d28ea44f6f2d6511a +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/112.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/112.png new file mode 100644 index 0000000000..e544ca74e4 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/112.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11558f68c1a1c3ad32832c7fc91ae093b7351bef68222e4d28ea44f6f2d6511a +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/120.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/120.png new file mode 100644 index 0000000000..e544ca74e4 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/120.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11558f68c1a1c3ad32832c7fc91ae093b7351bef68222e4d28ea44f6f2d6511a +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/128.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/128.png new file mode 100644 index 0000000000..e544ca74e4 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/128.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11558f68c1a1c3ad32832c7fc91ae093b7351bef68222e4d28ea44f6f2d6511a +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/16.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/16.png new file mode 100644 index 0000000000..e544ca74e4 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/16.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11558f68c1a1c3ad32832c7fc91ae093b7351bef68222e4d28ea44f6f2d6511a +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/24.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/24.png new file mode 100644 index 0000000000..e544ca74e4 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/24.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11558f68c1a1c3ad32832c7fc91ae093b7351bef68222e4d28ea44f6f2d6511a +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/32.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/32.png new file mode 100644 index 0000000000..e544ca74e4 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/32.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11558f68c1a1c3ad32832c7fc91ae093b7351bef68222e4d28ea44f6f2d6511a +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/40.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/40.png new file mode 100644 index 0000000000..e544ca74e4 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/40.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11558f68c1a1c3ad32832c7fc91ae093b7351bef68222e4d28ea44f6f2d6511a +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/48.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/48.png new file mode 100644 index 0000000000..e544ca74e4 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/48.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11558f68c1a1c3ad32832c7fc91ae093b7351bef68222e4d28ea44f6f2d6511a +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/56.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/56.png new file mode 100644 index 0000000000..e544ca74e4 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/56.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11558f68c1a1c3ad32832c7fc91ae093b7351bef68222e4d28ea44f6f2d6511a +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/64.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/64.png new file mode 100644 index 0000000000..e544ca74e4 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/64.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11558f68c1a1c3ad32832c7fc91ae093b7351bef68222e4d28ea44f6f2d6511a +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/72.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/72.png new file mode 100644 index 0000000000..e544ca74e4 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/72.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11558f68c1a1c3ad32832c7fc91ae093b7351bef68222e4d28ea44f6f2d6511a +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/80.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/80.png new file mode 100644 index 0000000000..e544ca74e4 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/80.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11558f68c1a1c3ad32832c7fc91ae093b7351bef68222e4d28ea44f6f2d6511a +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/88.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/88.png new file mode 100644 index 0000000000..e544ca74e4 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/88.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11558f68c1a1c3ad32832c7fc91ae093b7351bef68222e4d28ea44f6f2d6511a +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/96.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/96.png new file mode 100644 index 0000000000..e544ca74e4 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_21-blend-over-multiple.png/96.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11558f68c1a1c3ad32832c7fc91ae093b7351bef68222e4d28ea44f6f2d6511a +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_4-split-idat-zero-length.png/00.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_4-split-idat-zero-length.png/00.png new file mode 100644 index 0000000000..e544ca74e4 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_4-split-idat-zero-length.png/00.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11558f68c1a1c3ad32832c7fc91ae093b7351bef68222e4d28ea44f6f2d6511a +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_7-dispose-none.png/00.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_7-dispose-none.png/00.png new file mode 100644 index 0000000000..8fcbcb492a --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_7-dispose-none.png/00.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cb2d35aad4996610f754a166ae30906b49f98979c14a71143f99911e465755a8 +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_7-dispose-none.png/01.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_7-dispose-none.png/01.png new file mode 100644 index 0000000000..e544ca74e4 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_7-dispose-none.png/01.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11558f68c1a1c3ad32832c7fc91ae093b7351bef68222e4d28ea44f6f2d6511a +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_7-dispose-none.png/02.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_7-dispose-none.png/02.png new file mode 100644 index 0000000000..e544ca74e4 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_7-dispose-none.png/02.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11558f68c1a1c3ad32832c7fc91ae093b7351bef68222e4d28ea44f6f2d6511a +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_8-dispose-background.png/00.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_8-dispose-background.png/00.png new file mode 100644 index 0000000000..8fcbcb492a --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_8-dispose-background.png/00.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cb2d35aad4996610f754a166ae30906b49f98979c14a71143f99911e465755a8 +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_8-dispose-background.png/01.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_8-dispose-background.png/01.png new file mode 100644 index 0000000000..8fcbcb492a --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_8-dispose-background.png/01.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cb2d35aad4996610f754a166ae30906b49f98979c14a71143f99911e465755a8 +size 89 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_8-dispose-background.png/02.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_8-dispose-background.png/02.png new file mode 100644 index 0000000000..a695681b0f --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_8-dispose-background.png/02.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ea3f66d081c07c2eeefccae69084dbd0eabb824ace03280cb58a39b818de556 +size 102 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_apng.png/00.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_apng.png/00.png new file mode 100644 index 0000000000..7b8766bdc5 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_apng.png/00.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6118abf41302696bfe4a62baa32a7798b3833ca49fc3854dcde4a810905fc457 +size 1012 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_apng.png/01.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_apng.png/01.png new file mode 100644 index 0000000000..097c9b76f9 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_apng.png/01.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e8d11d84cab8580efc7397870116ff3ddde4c3a5da9c2c2baa473eb463326072 +size 915 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_apng.png/02.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_apng.png/02.png new file mode 100644 index 0000000000..47148a78e6 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_apng.png/02.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f36ea3ed9e652fe005c2767d758da268feb444e90833e02ab3fb15d1155037fd +size 971 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_apng.png/03.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_apng.png/03.png new file mode 100644 index 0000000000..ff550fcfbb --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_apng.png/03.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eb61715535a98977f4a3cb89ac85bc56826a54b4bdd4393d89ca445f50865d22 +size 990 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_apng.png/04.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_apng.png/04.png new file mode 100644 index 0000000000..12233f3015 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_apng.png/04.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0648a06346a6ccca69503da187bc5901c7275ade03834030a8f3895ad03ff58a +size 941 diff --git a/tests/Images/Input/Png/animated/12-dispose-prev-first.png b/tests/Images/Input/Png/animated/12-dispose-prev-first.png new file mode 100644 index 0000000000..7d6c9db25d --- /dev/null +++ b/tests/Images/Input/Png/animated/12-dispose-prev-first.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:28138dd4a4ad56f86c18216b051b96a1bb353b69ebd85ce272928b085bb84400 +size 371 diff --git a/tests/Images/Input/Png/animated/14-dispose-background-before-region.png b/tests/Images/Input/Png/animated/14-dispose-background-before-region.png new file mode 100644 index 0000000000..3411044e6d --- /dev/null +++ b/tests/Images/Input/Png/animated/14-dispose-background-before-region.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e3d4ba499c333a600dd1e42f374a9a68fb783b0f3274091ab34f5b395462eae8 +size 327 diff --git a/tests/Images/Input/Png/animated/15-dispose-background-region.png b/tests/Images/Input/Png/animated/15-dispose-background-region.png new file mode 100644 index 0000000000..8e684686c9 --- /dev/null +++ b/tests/Images/Input/Png/animated/15-dispose-background-region.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6db2a90911b40067b7f35b01869115f081858ee15b28374e57c51c7e5c0cb524 +size 492 diff --git a/tests/Images/Input/Png/animated/21-blend-over-multiple.png b/tests/Images/Input/Png/animated/21-blend-over-multiple.png new file mode 100644 index 0000000000..4c088bacc4 --- /dev/null +++ b/tests/Images/Input/Png/animated/21-blend-over-multiple.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b571f7034ef1fb355182cf00fa6ccd7d784720709f229e3bcc5948abf2f81ee +size 28791 diff --git a/tests/Images/Input/Png/animated/4-split-idat-zero-length.png b/tests/Images/Input/Png/animated/4-split-idat-zero-length.png new file mode 100644 index 0000000000..d2d6567462 --- /dev/null +++ b/tests/Images/Input/Png/animated/4-split-idat-zero-length.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3e0ffdbe7dc6dad05dfc4cacd712b76c1121cd7378671212ae000d76c07b1a4e +size 273 diff --git a/tests/Images/Input/Png/animated/7-dispose-none.png b/tests/Images/Input/Png/animated/7-dispose-none.png new file mode 100644 index 0000000000..d0ef09b852 --- /dev/null +++ b/tests/Images/Input/Png/animated/7-dispose-none.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1abab0c7de5252a16da34777ff34c4a29c6000493d23ac1777cd17415e6aab33 +size 617 diff --git a/tests/Images/Input/Png/animated/8-dispose-background.png b/tests/Images/Input/Png/animated/8-dispose-background.png new file mode 100644 index 0000000000..89052b655d --- /dev/null +++ b/tests/Images/Input/Png/animated/8-dispose-background.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8f26f544d5f7f0c8d4448ca020c93f79b64e1d607c7c561082bc989ca2e91fad +size 572 diff --git a/tests/Images/Input/Png/apng.png b/tests/Images/Input/Png/animated/apng.png similarity index 100% rename from tests/Images/Input/Png/apng.png rename to tests/Images/Input/Png/animated/apng.png