diff --git a/src/ImageSharp/Formats/Png/Chunks/FrameControl.cs b/src/ImageSharp/Formats/Png/Chunks/FrameControl.cs index b912e9b09a..fb2ca473c2 100644 --- a/src/ImageSharp/Formats/Png/Chunks/FrameControl.cs +++ b/src/ImageSharp/Formats/Png/Chunks/FrameControl.cs @@ -91,6 +91,8 @@ internal readonly struct FrameControl /// public PngBlendMethod BlendOperation { get; } + public Rectangle Bounds => new((int)this.XOffset, (int)this.YOffset, (int)this.Width, (int)this.Height); + /// /// Validates the APng fcTL. /// diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 317207da0f..8c7c7c30d7 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -225,7 +225,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals PngFrameMetadata pngFrameMetadata = currentFrame.Metadata.GetPngFrameMetadata(); if (previousFrame != null && pngFrameMetadata.BlendMethod == PngBlendMethod.Over) { - this.AlphaBlend(previousFrame, currentFrame); + this.AlphaBlend(previousFrame, currentFrame, previousFrameControl.Value.Bounds); } previousFrame = currentFrame; @@ -630,7 +630,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals if (frameControl.DisposeOperation == PngDisposalMethod.Background || (previousFrame is null && frameControl.DisposeOperation == PngDisposalMethod.Previous)) { - Rectangle restoreArea = new((int)frameControl.XOffset, (int)frameControl.YOffset, (int)frameControl.Width, (int)frameControl.Height); + Rectangle restoreArea = frameControl.Bounds; Rectangle interest = Rectangle.Intersect(frame.Bounds(), restoreArea); Buffer2DRegion pixelRegion = frame.PixelBuffer.GetRegion(interest); pixelRegion.Clear(); @@ -1895,15 +1895,15 @@ internal sealed class PngDecoderCore : IImageDecoderInternals private void SwapScanlineBuffers() => (this.scanline, this.previousScanline) = (this.previousScanline, this.scanline); - private void AlphaBlend(ImageFrame src, ImageFrame dst) + private void AlphaBlend(ImageFrame src, ImageFrame dst, Rectangle restoreArea) where TPixel : unmanaged, IPixel { - Buffer2D srcPixels = src.PixelBuffer; - Buffer2D dstPixels = dst.PixelBuffer; + 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 < src.Height; y++) + for (int y = 0; y < srcPixels.Height; y++) { Span srcPixelRow = srcPixels.DangerousGetRowSpan(y); Span dstPixelRow = dstPixels.DangerousGetRowSpan(y);