Browse Source

Fix handling of case where default image isn't animated

pull/2713/head
SpaceCheetah 2 years ago
parent
commit
9b8ef108d4
No known key found for this signature in database GPG Key ID: A60F20D29141DFF9
  1. 22
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  2. 5
      src/ImageSharp/Formats/Png/PngMetadata.cs

22
src/ImageSharp/Formats/Png/PngDecoderCore.cs

@ -228,8 +228,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
PngThrowHelper.ThrowMissingFrameControl(); PngThrowHelper.ThrowMissingFrameControl();
} }
previousFrameControl ??= new((uint)this.header.Width, (uint)this.header.Height); this.InitializeFrame(previousFrameControl, currentFrameControl.Value, image, previousFrame, out currentFrame);
this.InitializeFrame(previousFrameControl.Value, currentFrameControl.Value, image, previousFrame, out currentFrame);
this.currentStream.Position += 4; this.currentStream.Position += 4;
this.ReadScanlines( this.ReadScanlines(
@ -249,7 +248,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
break; break;
case PngChunkType.Data: case PngChunkType.Data:
pngMetadata.DefaultImageAnimated = currentFrameControl != null;
currentFrameControl ??= new((uint)this.header.Width, (uint)this.header.Height); currentFrameControl ??= new((uint)this.header.Width, (uint)this.header.Height);
if (image is null) if (image is null)
{ {
@ -266,9 +265,12 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
this.ReadNextDataChunk, this.ReadNextDataChunk,
currentFrameControl.Value, currentFrameControl.Value,
cancellationToken); cancellationToken);
if (pngMetadata.DefaultImageAnimated)
{
previousFrame = currentFrame;
previousFrameControl = currentFrameControl;
}
previousFrame = currentFrame;
previousFrameControl = currentFrameControl;
break; break;
case PngChunkType.Palette: case PngChunkType.Palette:
this.palette = chunk.Data.GetSpan().ToArray(); this.palette = chunk.Data.GetSpan().ToArray();
@ -637,7 +639,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
/// <param name="previousFrame">The previous frame.</param> /// <param name="previousFrame">The previous frame.</param>
/// <param name="frame">The created frame</param> /// <param name="frame">The created frame</param>
private void InitializeFrame<TPixel>( private void InitializeFrame<TPixel>(
FrameControl previousFrameControl, FrameControl? previousFrameControl,
FrameControl currentFrameControl, FrameControl currentFrameControl,
Image<TPixel> image, Image<TPixel> image,
ImageFrame<TPixel>? previousFrame, ImageFrame<TPixel>? previousFrame,
@ -646,15 +648,15 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
{ {
frame = image.Frames.AddFrame(previousFrame ?? image.Frames.RootFrame); frame = image.Frames.AddFrame(previousFrame ?? image.Frames.RootFrame);
// if restoring to before first frame, restore to background // If restoring to before first frame, restore to background. Same if first frame (previousFrameControl null).
if (previousFrame is null && previousFrameControl.DisposeOperation == PngDisposalMethod.RestoreToPrevious) if (previousFrameControl == null || (previousFrame is null && previousFrameControl.Value.DisposeOperation == PngDisposalMethod.RestoreToPrevious))
{ {
Buffer2DRegion<TPixel> pixelRegion = frame.PixelBuffer.GetRegion(); Buffer2DRegion<TPixel> pixelRegion = frame.PixelBuffer.GetRegion();
pixelRegion.Clear(); pixelRegion.Clear();
} }
else if (previousFrameControl.DisposeOperation == PngDisposalMethod.RestoreToBackground) else if (previousFrameControl.Value.DisposeOperation == PngDisposalMethod.RestoreToBackground)
{ {
Rectangle restoreArea = previousFrameControl.Bounds; Rectangle restoreArea = previousFrameControl.Value.Bounds;
Buffer2DRegion<TPixel> pixelRegion = frame.PixelBuffer.GetRegion(restoreArea); Buffer2DRegion<TPixel> pixelRegion = frame.PixelBuffer.GetRegion(restoreArea);
pixelRegion.Clear(); pixelRegion.Clear();
} }

5
src/ImageSharp/Formats/Png/PngMetadata.cs

@ -83,6 +83,11 @@ public class PngMetadata : IDeepCloneable
/// </summary> /// </summary>
public uint RepeatCount { get; set; } = 1; public uint RepeatCount { get; set; } = 1;
/// <summary>
/// Gets or sets a value indicating whether the default image is shown as part of the animated sequence
/// </summary>
public bool DefaultImageAnimated { get; set; }
/// <inheritdoc/> /// <inheritdoc/>
public IDeepCloneable DeepClone() => new PngMetadata(this); public IDeepCloneable DeepClone() => new PngMetadata(this);

Loading…
Cancel
Save