mirror of https://github.com/SixLabors/ImageSharp
9 changed files with 229 additions and 20 deletions
@ -0,0 +1,71 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Numerics; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif; |
|||
|
|||
/// <summary>
|
|||
/// Provides HEIF-specific metadata for an image frame.
|
|||
/// </summary>
|
|||
public class HeifFrameMetadata : IFormatFrameMetadata<HeifFrameMetadata> |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="HeifFrameMetadata"/> class.
|
|||
/// </summary>
|
|||
public HeifFrameMetadata() |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="HeifFrameMetadata"/> class by copying another instance.
|
|||
/// </summary>
|
|||
/// <param name="other">The metadata to copy.</param>
|
|||
private HeifFrameMetadata(HeifFrameMetadata other) => this.FrameDelay = other.FrameDelay; |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the frame display duration in seconds. The numerator contains duration units and the denominator
|
|||
/// contains units per second. Zero indicates that no explicit duration is available.
|
|||
/// </summary>
|
|||
public Rational FrameDelay { get; set; } = new(0); |
|||
|
|||
/// <inheritdoc/>
|
|||
public static HeifFrameMetadata FromFormatConnectingFrameMetadata(FormatConnectingFrameMetadata metadata) |
|||
=> new() |
|||
{ |
|||
FrameDelay = new Rational(metadata.Duration.TotalSeconds) |
|||
}; |
|||
|
|||
/// <inheritdoc/>
|
|||
public FormatConnectingFrameMetadata ToFormatConnectingFrameMetadata() |
|||
{ |
|||
double seconds = this.FrameDelay.ToDouble(); |
|||
|
|||
// Rational permits a zero denominator for metadata roundtripping. ImageSharp's connecting metadata cannot
|
|||
// represent an infinite duration, so preserve it as the same unspecified zero duration used by other formats.
|
|||
if (!double.IsFinite(seconds)) |
|||
{ |
|||
seconds = 0; |
|||
} |
|||
|
|||
return new FormatConnectingFrameMetadata |
|||
{ |
|||
BlendMode = FrameBlendMode.Source, |
|||
DisposalMode = FrameDisposalMode.DoNotDispose, |
|||
Duration = TimeSpan.FromSeconds(seconds) |
|||
}; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public void AfterFrameApply<TPixel>(ImageFrame<TPixel> source, ImageFrame<TPixel> destination, Matrix4x4 matrix) |
|||
where TPixel : unmanaged, IPixel<TPixel> |
|||
{ |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone(); |
|||
|
|||
/// <inheritdoc/>
|
|||
public HeifFrameMetadata DeepClone() => new(this); |
|||
} |
|||
@ -0,0 +1,69 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using SixLabors.ImageSharp.Formats; |
|||
using SixLabors.ImageSharp.Formats.Heif; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Tests.Formats.Heif; |
|||
|
|||
[Trait("Format", "Heif")] |
|||
public class HeifFrameMetadataTests |
|||
{ |
|||
[Fact] |
|||
public void FormatCreatesFrameMetadata() |
|||
{ |
|||
HeifFrameMetadata metadata = HeifFormat.Instance.CreateDefaultFormatFrameMetadata(); |
|||
|
|||
Assert.Equal(new Rational(0), metadata.FrameDelay); |
|||
} |
|||
|
|||
[Fact] |
|||
public void DeepCloneCopiesFrameDelay() |
|||
{ |
|||
HeifFrameMetadata metadata = new() { FrameDelay = new Rational(1, 4) }; |
|||
|
|||
HeifFrameMetadata clone = metadata.DeepClone(); |
|||
clone.FrameDelay = new Rational(1, 2); |
|||
|
|||
Assert.Equal(new Rational(1, 4), metadata.FrameDelay); |
|||
Assert.Equal(new Rational(1, 2), clone.FrameDelay); |
|||
} |
|||
|
|||
[Fact] |
|||
public void DurationRoundTripsFormatConnectingMetadata() |
|||
{ |
|||
FormatConnectingFrameMetadata connectingMetadata = new() { Duration = TimeSpan.FromMilliseconds(250) }; |
|||
|
|||
HeifFrameMetadata metadata = HeifFrameMetadata.FromFormatConnectingFrameMetadata(connectingMetadata); |
|||
FormatConnectingFrameMetadata result = metadata.ToFormatConnectingFrameMetadata(); |
|||
|
|||
Assert.Equal(0.25, metadata.FrameDelay.ToDouble(), 10); |
|||
Assert.Equal(TimeSpan.FromMilliseconds(250), result.Duration); |
|||
Assert.Equal(FrameBlendMode.Source, result.BlendMode); |
|||
Assert.Equal(FrameDisposalMode.DoNotDispose, result.DisposalMode); |
|||
} |
|||
|
|||
[Fact] |
|||
public void ZeroDenominatorConvertsToUnspecifiedDuration() |
|||
{ |
|||
HeifFrameMetadata metadata = new() { FrameDelay = new Rational(1, 0) }; |
|||
|
|||
FormatConnectingFrameMetadata result = metadata.ToFormatConnectingFrameMetadata(); |
|||
|
|||
Assert.Equal(TimeSpan.Zero, result.Duration); |
|||
} |
|||
|
|||
[Fact] |
|||
public void ImageFrameMetadataExtensionsReturnAndCloneHeifMetadata() |
|||
{ |
|||
using Image<Rgba32> image = new(1, 1); |
|||
HeifFrameMetadata metadata = image.Frames.RootFrame.Metadata.GetHeifMetadata(); |
|||
metadata.FrameDelay = new Rational(1, 5); |
|||
|
|||
HeifFrameMetadata clone = image.Frames.RootFrame.Metadata.CloneHeifMetadata(); |
|||
|
|||
Assert.NotSame(metadata, clone); |
|||
Assert.Equal(metadata.FrameDelay, clone.FrameDelay); |
|||
} |
|||
} |
|||
Loading…
Reference in new issue