Browse Source

Fix handling of case where default image isn't animated

pull/2710/head
SpaceCheetah 2 years ago
parent
commit
5cd98723dc
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

@ -234,8 +234,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(
@ -255,7 +254,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)
{ {
@ -272,9 +271,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();
@ -643,7 +645,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,
@ -652,15 +654,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