@@ -210,7 +210,7 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
210
210
211
211
if ( currentFrame is null )
212
212
{
213
- this . InitializeFrame ( previousFrameControl . Value , image , out currentFrame ) ;
213
+ this . InitializeFrame ( previousFrameControl . Value , image , previousFrame , out currentFrame ) ;
214
214
}
215
215
216
216
this . currentStream . Position += 4 ;
@@ -612,14 +612,31 @@ private void InitializeImage<TPixel>(ImageMetadata metadata, FrameControl? frame
612
612
/// <typeparam name="TPixel">The type the pixels will be</typeparam>
613
613
/// <param name="frameControl">The frame control information for the frame</param>
614
614
/// <param name="image">The image that we will populate</param>
615
+ /// <param name="previousFrame">The previous frame.</param>
615
616
/// <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 )
617
622
where TPixel : unmanaged, IPixel < TPixel >
618
623
{
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 ) ;
620
628
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
+ }
622
638
639
+ PngFrameMetadata frameMetadata = frame . Metadata . GetPngFrameMetadata ( ) ;
623
640
frameMetadata . FromChunk ( frameControl ) ;
624
641
625
642
this . previousScanline ? . Dispose ( ) ;
0 commit comments