From ceb0d51fa90d0503b4a74515eb081bb4057f4932 Mon Sep 17 00:00:00 2001 From: Poker Date: Tue, 8 Apr 2025 17:47:06 +0800 Subject: [PATCH] apply new metadata layout --- src/ImageSharp/Formats/Ani/AniDecoderCore.cs | 126 ++++++++++-------- .../Formats/Ani/AniFrameMetadata.cs | 29 +++- src/ImageSharp/Formats/Ani/AniMetadata.cs | 5 - 3 files changed, 93 insertions(+), 67 deletions(-) diff --git a/src/ImageSharp/Formats/Ani/AniDecoderCore.cs b/src/ImageSharp/Formats/Ani/AniDecoderCore.cs index 7ce8292a7..539c3db2d 100644 --- a/src/ImageSharp/Formats/Ani/AniDecoderCore.cs +++ b/src/ImageSharp/Formats/Ani/AniDecoderCore.cs @@ -59,12 +59,17 @@ internal class AniDecoderCore : ImageDecoderCore List> list = []; - foreach (int i in sequence) + for (int i = 0; i < sequence.Length; i++) { - (ListIconChunkType type, Image? img) = frames[i]; - byte? encodingWidth = null; - byte? encodingHeight = null; - bool isRootFrame = true; + int sequenceIndex = sequence[i]; + (ListIconChunkType type, Image? img) = frames[sequenceIndex]; + + AniFrameMetadata aniFrameMetadata = new() + { + FrameDelay = rate.IsEmpty ? aniMetadata.DisplayRate : rate[sequenceIndex], + SequenceNumber = i + }; + list.AddRange(img.Frames.Select(source => { ImageFrame target = new(this.Options.Configuration, this.Dimensions); @@ -73,53 +78,34 @@ internal class AniDecoderCore : ImageDecoderCore source.PixelBuffer.DangerousGetRowSpan(y).CopyTo(target.PixelBuffer.DangerousGetRowSpan(y)); } + AniFrameMetadata clonedMetadata = aniFrameMetadata.DeepClone(); + source.Metadata.SetFormatMetadata(AniFormat.Instance, clonedMetadata); switch (type) { case ListIconChunkType.Ico: IcoFrameMetadata icoFrameMetadata = source.Metadata.GetIcoMetadata(); - target.Metadata.SetFormatMetadata(IcoFormat.Instance, icoFrameMetadata); - if (isRootFrame) - { - encodingWidth ??= icoFrameMetadata.EncodingWidth; - encodingHeight ??= icoFrameMetadata.EncodingHeight; - } - + // TODO source.Metadata.SetFormatMetadata(IcoFormat.Instance, null); + clonedMetadata.IcoFrameMetadata = icoFrameMetadata; + clonedMetadata.EncodingWidth = icoFrameMetadata.EncodingWidth; + clonedMetadata.EncodingHeight = icoFrameMetadata.EncodingHeight; break; case ListIconChunkType.Cur: CurFrameMetadata curFrameMetadata = source.Metadata.GetCurMetadata(); - target.Metadata.SetFormatMetadata(CurFormat.Instance, curFrameMetadata); - if (isRootFrame) - { - encodingWidth ??= curFrameMetadata.EncodingWidth; - encodingHeight ??= curFrameMetadata.EncodingHeight; - } - + // TODO source.Metadata.SetFormatMetadata(CurFormat.Instance, null); + clonedMetadata.CurFrameMetadata = curFrameMetadata; + clonedMetadata.EncodingWidth = curFrameMetadata.EncodingWidth; + clonedMetadata.EncodingHeight = curFrameMetadata.EncodingHeight; break; case ListIconChunkType.Bmp: - if (isRootFrame) - { - encodingWidth = Narrow(source.Width); - encodingHeight = Narrow(source.Height); - } - + clonedMetadata.EncodingWidth = Narrow(source.Width); + clonedMetadata.EncodingHeight = Narrow(source.Height); break; default: break; } - isRootFrame = false; - return target; })); - - ImageFrameMetadata rootFrameMetadata = img.Frames.RootFrame.Metadata; - AniFrameMetadata aniFrameMetadata = rootFrameMetadata.GetAniMetadata(); - aniFrameMetadata.FrameDelay = rate.IsEmpty ? aniMetadata.DisplayRate : rate[i]; - aniFrameMetadata.FrameCount = img.Frames.Count; - aniFrameMetadata.EncodingWidth = encodingWidth; - aniFrameMetadata.EncodingHeight = encodingHeight; - aniFrameMetadata.SubImageMetadata = img.Metadata; - aniMetadata.IconFrames.Add(rootFrameMetadata); } foreach ((ListIconChunkType _, Image img) in frames) @@ -193,34 +179,62 @@ internal class AniDecoderCore : ImageDecoderCore List<(ListIconChunkType Type, ImageInfo Info)> infoList = []; this.HandleRiffChunk(out Span sequence, out Span rate, dataStartPosition, dataSize, aniMetadata, infoList, IdentifyFrameChunk); - ImageInfo imageInfo = new(this.Dimensions, metadata, (IReadOnlyList)aniMetadata.IconFrames); + List frameMetadataCollection = new(sequence.Length); - foreach (int i in sequence) + for (int i = 0; i < sequence.Length; i++) { - (ListIconChunkType type, ImageInfo info) = infoList[i]; + int sequenceIndex = sequence[i]; + (ListIconChunkType type, ImageInfo info) = infoList[sequenceIndex]; - ImageFrameMetadata rootFrameMetadata = imageInfo.FrameMetadataCollection is [var first, ..] ? first : new(); - AniFrameMetadata aniFrameMetadata = rootFrameMetadata.GetAniMetadata(); - aniFrameMetadata.FrameDelay = rate.IsEmpty ? aniMetadata.DisplayRate : rate[i]; - aniFrameMetadata.FrameCount = info.FrameMetadataCollection.Count; - aniFrameMetadata.EncodingWidth = type switch + AniFrameMetadata aniFrameMetadata = new() { - ListIconChunkType.Bmp => Narrow(info.Width), - ListIconChunkType.Cur => rootFrameMetadata.GetCurMetadata().EncodingWidth, - ListIconChunkType.Ico => rootFrameMetadata.GetIcoMetadata().EncodingWidth, - _ => null + FrameDelay = rate.IsEmpty ? aniMetadata.DisplayRate : rate[sequenceIndex], + SequenceNumber = i }; - aniFrameMetadata.EncodingHeight = type switch + + if (info.FrameMetadataCollection.Count is not 0) { - ListIconChunkType.Bmp => Narrow(info.Height), - ListIconChunkType.Cur => rootFrameMetadata.GetCurMetadata().EncodingHeight, - ListIconChunkType.Ico => rootFrameMetadata.GetIcoMetadata().EncodingHeight, - _ => null - }; - aniFrameMetadata.SubImageMetadata = info.Metadata; - aniMetadata.IconFrames.Add(rootFrameMetadata); + frameMetadataCollection.AddRange( + info.FrameMetadataCollection.Select(frameMetadata => + { + AniFrameMetadata clonedMetadata = aniFrameMetadata.DeepClone(); + frameMetadata.SetFormatMetadata(AniFormat.Instance, clonedMetadata); + switch (type) + { + case ListIconChunkType.Ico: + IcoFrameMetadata icoFrameMetadata = frameMetadata.GetIcoMetadata(); + // TODO source.Metadata.SetFormatMetadata(IcoFormat.Instance, null); + clonedMetadata.IcoFrameMetadata = icoFrameMetadata; + clonedMetadata.EncodingWidth = icoFrameMetadata.EncodingWidth; + clonedMetadata.EncodingHeight = icoFrameMetadata.EncodingHeight; + break; + case ListIconChunkType.Cur: + CurFrameMetadata curFrameMetadata = frameMetadata.GetCurMetadata(); + // TODO source.Metadata.SetFormatMetadata(CurFormat.Instance, null); + clonedMetadata.CurFrameMetadata = curFrameMetadata; + clonedMetadata.EncodingWidth = curFrameMetadata.EncodingWidth; + clonedMetadata.EncodingHeight = curFrameMetadata.EncodingHeight; + break; + default: + ThrowHelper.ThrowArgumentOutOfRangeException(nameof(type), "FrameMetadata must be ICO or CUR"); + break; + } + + return frameMetadata; + })); + } + else // BMP + { + aniFrameMetadata.EncodingWidth = Narrow(info.Width); + aniFrameMetadata.EncodingHeight = Narrow(info.Height); + ImageFrameMetadata frameMetadata = new(); + frameMetadata.SetFormatMetadata(AniFormat.Instance, aniFrameMetadata); + frameMetadataCollection.Add(frameMetadata); + } } + ImageInfo imageInfo = new(this.Dimensions, metadata, frameMetadataCollection); + return imageInfo; void IdentifyFrameChunk() diff --git a/src/ImageSharp/Formats/Ani/AniFrameMetadata.cs b/src/ImageSharp/Formats/Ani/AniFrameMetadata.cs index 928899476..6e7f220bd 100644 --- a/src/ImageSharp/Formats/Ani/AniFrameMetadata.cs +++ b/src/ImageSharp/Formats/Ani/AniFrameMetadata.cs @@ -1,7 +1,9 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Metadata; +using System.Diagnostics.CodeAnalysis; +using SixLabors.ImageSharp.Formats.Cur; +using SixLabors.ImageSharp.Formats.Ico; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Formats.Ani; @@ -24,9 +26,9 @@ public class AniFrameMetadata : IFormatFrameMetadata public uint FrameDelay { get; set; } /// - /// Gets or sets the frames count of **one** "icon" chunk. + /// Gets or sets the sequence number of current frame. /// - public int FrameCount { get; set; } = 1; + public int SequenceNumber { get; set; } = 1; /// /// Gets or sets the encoding width.
@@ -41,9 +43,21 @@ public class AniFrameMetadata : IFormatFrameMetadata public byte? EncodingHeight { get; set; } /// - /// Gets or sets the of one "icon" chunk. + /// Gets or sets a value indicating whether the frame will be encoded as an ICO or CUR file. /// - public ImageMetadata? SubImageMetadata { get; set; } + [MemberNotNullWhen(true, nameof(IcoFrameMetadata))] + [MemberNotNullWhen(false, nameof(CurFrameMetadata))] + public bool IsIco { get; set; } + + /// + /// Gets or sets the of one "icon" chunk. + /// + public IcoFrameMetadata? IcoFrameMetadata { get; set; } + + /// + /// Gets or sets the of one "icon" chunk. + /// + public CurFrameMetadata? CurFrameMetadata { get; set; } /// public static AniFrameMetadata FromFormatConnectingFrameMetadata(FormatConnectingFrameMetadata metadata) => @@ -70,7 +84,10 @@ public class AniFrameMetadata : IFormatFrameMetadata FrameDelay = this.FrameDelay, EncodingHeight = this.EncodingHeight, EncodingWidth = this.EncodingWidth, - FrameCount = this.FrameCount + SequenceNumber = this.SequenceNumber, + IsIco = this.IsIco, + IcoFrameMetadata = this.IcoFrameMetadata?.DeepClone(), + CurFrameMetadata = this.CurFrameMetadata?.DeepClone(), // TODO SubImageMetadata }; diff --git a/src/ImageSharp/Formats/Ani/AniMetadata.cs b/src/ImageSharp/Formats/Ani/AniMetadata.cs index 9b30bedb6..1660b8a76 100644 --- a/src/ImageSharp/Formats/Ani/AniMetadata.cs +++ b/src/ImageSharp/Formats/Ani/AniMetadata.cs @@ -70,11 +70,6 @@ public class AniMetadata : IFormatMetadata ///
public string? Artist { get; set; } - /// - /// Gets or sets the each "icon" chunk in ANI file. - /// - public IList IconFrames { get; set; } = []; - /// public static AniMetadata FromFormatConnectingMetadata(FormatConnectingMetadata metadata) => throw new NotImplementedException();