Skip to content

Commit 8455275

Browse files
Handle disposal methods.
1 parent bc5b6c5 commit 8455275

File tree

1 file changed

+21
-4
lines changed

1 file changed

+21
-4
lines changed

src/ImageSharp/Formats/Png/PngDecoderCore.cs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
210210

211211
if (currentFrame is null)
212212
{
213-
this.InitializeFrame(previousFrameControl.Value, image, out currentFrame);
213+
this.InitializeFrame(previousFrameControl.Value, image, previousFrame, out currentFrame);
214214
}
215215

216216
this.currentStream.Position += 4;
@@ -612,14 +612,31 @@ private void InitializeImage<TPixel>(ImageMetadata metadata, FrameControl? frame
612612
/// <typeparam name="TPixel">The type the pixels will be</typeparam>
613613
/// <param name="frameControl">The frame control information for the frame</param>
614614
/// <param name="image">The image that we will populate</param>
615+
/// <param name="previousFrame">The previous frame.</param>
615616
/// <param name="frame">The created frame</param>
616-
private void InitializeFrame<TPixel>(FrameControl frameControl, Image<TPixel> image, out ImageFrame<TPixel> frame)
617+
private void InitializeFrame<TPixel>(
618+
FrameControl frameControl,
619+
Image<TPixel> image,
620+
ImageFrame<TPixel>? previousFrame,
621+
out ImageFrame<TPixel> frame)
617622
where TPixel : unmanaged, IPixel<TPixel>
618623
{
619-
frame = image.Frames.CreateFrame();
624+
// We create a clone of the previous frame and add it.
625+
// We will overpaint the difference of pixels on the current frame to create a complete image.
626+
// This ensures that we have enough pixel data to process without distortion. #2450
627+
frame = image.Frames.AddFrame(previousFrame ?? image.Frames.RootFrame);
620628

621-
PngFrameMetadata frameMetadata = frame.Metadata.GetPngFrameMetadata();
629+
// If the first `fcTL` chunk uses a `dispose_op` of APNG_DISPOSE_OP_PREVIOUS it should be treated as APNG_DISPOSE_OP_BACKGROUND.
630+
if (frameControl.DisposeOperation == PngDisposalMethod.Background
631+
|| (previousFrame is null && frameControl.DisposeOperation == PngDisposalMethod.Previous))
632+
{
633+
Rectangle restoreArea = new((int)frameControl.XOffset, (int)frameControl.YOffset, (int)frameControl.Width, (int)frameControl.Height);
634+
Rectangle interest = Rectangle.Intersect(frame.Bounds(), restoreArea);
635+
Buffer2DRegion<TPixel> pixelRegion = frame.PixelBuffer.GetRegion(interest);
636+
pixelRegion.Clear();
637+
}
622638

639+
PngFrameMetadata frameMetadata = frame.Metadata.GetPngFrameMetadata();
623640
frameMetadata.FromChunk(frameControl);
624641

625642
this.previousScanline?.Dispose();

0 commit comments

Comments
 (0)