Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ANI decoder support #2899

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
70 changes: 70 additions & 0 deletions src/ImageSharp/Formats/Ani/AniChunkType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

namespace SixLabors.ImageSharp.Formats.Ani;

internal enum AniChunkType : uint
{
/// <summary>
/// "anih"
/// </summary>
AniH = 0x68_69_6E_61,

/// <summary>
/// "seq "
/// </summary>
Seq = 0x20_71_65_73,

/// <summary>
/// "rate"
/// </summary>
Rate = 0x65_74_61_72,

/// <summary>
/// "LIST"
/// </summary>
List = 0x54_53_49_4C
}

/// <summary>
/// ListType
/// </summary>
internal enum AniListType : uint
{
/// <summary>
/// "INFO" (ListType)
/// </summary>
Info = 0x4F_46_4E_49,

/// <summary>
/// "fram"
/// </summary>
Fram = 0x6D_61_72_66
}

/// <summary>
/// in "INFO"
/// </summary>
internal enum AniListInfoType : uint
{
/// <summary>
/// "INAM"
/// </summary>
INam = 0x4D_41_4E_49,

/// <summary>
/// "IART"
/// </summary>
IArt = 0x54_52_41_49
}

/// <summary>
/// in "Fram"
/// </summary>
internal enum AniListFrameType : uint
{
/// <summary>
/// "icon"
/// </summary>
Icon = 0x6E_6F_63_69
}
18 changes: 18 additions & 0 deletions src/ImageSharp/Formats/Ani/AniConfigurationModule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

namespace SixLabors.ImageSharp.Formats.Ani;

/// <summary>
/// Registers the image encoders, decoders and mime type detectors for the Ico format.
/// </summary>
public sealed class AniConfigurationModule : IImageFormatConfigurationModule
{
/// <inheritdoc/>
public void Configure(Configuration configuration)
{
// configuration.ImageFormatsManager.SetEncoder(AniFormat.Instance, new AniEncoder());
configuration.ImageFormatsManager.SetDecoder(AniFormat.Instance, AniDecoder.Instance);
configuration.ImageFormatsManager.AddImageFormatDetector(new AniImageFormatDetector());
}
}
27 changes: 27 additions & 0 deletions src/ImageSharp/Formats/Ani/AniConstants.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

namespace SixLabors.ImageSharp.Formats.Ani;

internal static class AniConstants
{
/// <summary>
/// Gets the header bytes identifying an ani.
/// </summary>
public const uint AniFourCc = 0x41_43_4F_4E;

/// <summary>
/// The list of mime types that equate to an ani.
/// </summary>
public static readonly IEnumerable<string> MimeTypes = ["application/x-navi-animation"];

/// <summary>
/// The list of file extensions that equate to an ani.
/// </summary>
public static readonly IEnumerable<string> FileExtensions = ["ani"];

/// <summary>
/// Gets the header bytes identifying an ani.
/// </summary>
public static ReadOnlySpan<byte> AniFormTypeFourCc => "ACON"u8;
}
41 changes: 41 additions & 0 deletions src/ImageSharp/Formats/Ani/AniDecoder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.PixelFormats;

namespace SixLabors.ImageSharp.Formats.Ani;

/// <summary>
/// Decoder for generating an image out of an ani encoded stream.
/// </summary>
public sealed class AniDecoder : ImageDecoder
{
private AniDecoder()
{
}

/// <summary>
/// Gets the shared instance.
/// </summary>
public static AniDecoder Instance { get; } = new();

/// <inheritdoc/>
protected override Image<TPixel> Decode<TPixel>(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
{
Guard.NotNull(options, nameof(options));
Guard.NotNull(stream, nameof(stream));
Image<TPixel> image = new AniDecoderCore(options).Decode<TPixel>(options.Configuration, stream, cancellationToken);
ScaleToTargetSize(options, image);
return image;
}

/// <inheritdoc/>
protected override Image Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken) => this.Decode<Rgba32>(options, stream, cancellationToken);

/// <inheritdoc/>
protected override ImageInfo Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
{
Guard.NotNull(options, nameof(options));
Guard.NotNull(stream, nameof(stream));
return new AniDecoderCore(options).Identify(options.Configuration, stream, cancellationToken);
}
}
Loading
Loading