diff --git a/src/ImageSharp/Formats/Ani/AniDecoder.cs b/src/ImageSharp/Formats/Ani/AniDecoder.cs new file mode 100644 index 0000000000..9794867feb --- /dev/null +++ b/src/ImageSharp/Formats/Ani/AniDecoder.cs @@ -0,0 +1,35 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats.Ani; + +internal sealed class AniDecoder : ImageDecoder +{ + private AniDecoder() + { + } + + /// + /// Gets the shared instance. + /// + public static AniDecoder Instance { get; } = new(); + + protected override Image Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken) + { + Guard.NotNull(options, nameof(options)); + Guard.NotNull(stream, nameof(stream)); + Image image = new AniDecoderCore(options).Decode(options.Configuration, stream, cancellationToken); + ScaleToTargetSize(options, image); + return image; + } + + protected override Image Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken) => this.Decode(options, stream, cancellationToken); + + 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); + } +} diff --git a/src/ImageSharp/Formats/Ani/AniDecoderCore.cs b/src/ImageSharp/Formats/Ani/AniDecoderCore.cs new file mode 100644 index 0000000000..c60036c465 --- /dev/null +++ b/src/ImageSharp/Formats/Ani/AniDecoderCore.cs @@ -0,0 +1,35 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.Formats.Icon; +using SixLabors.ImageSharp.IO; + +namespace SixLabors.ImageSharp.Formats.Ani; + +internal class AniDecoderCore : ImageDecoderCore +{ + public AniDecoderCore(DecoderOptions options) + : base(options) + { + } + + protected override Image Decode(BufferedReadStream stream, CancellationToken cancellationToken) + { + this.ReadHeader(stream); + throw new NotImplementedException(); + } + + protected override ImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + private void ReadHeader(Stream stream) + { + // Skip the identifier + stream.Skip(12); + Span buffer = stackalloc byte[AniHeader.Size]; + _ = stream.Read(buffer); + AniHeader header = AniHeader.Parse(buffer); + } +} diff --git a/src/ImageSharp/Formats/Ani/AniHeader.cs b/src/ImageSharp/Formats/Ani/AniHeader.cs new file mode 100644 index 0000000000..8f985c4c6e --- /dev/null +++ b/src/ImageSharp/Formats/Ani/AniHeader.cs @@ -0,0 +1,34 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.Formats.Ani; + +[StructLayout(LayoutKind.Sequential, Pack = 1, Size = Size)] +internal readonly struct AniHeader +{ + public const int Size = 36; + + public ushort Frames { get; } + + public ushort Steps { get; } + + public ushort Width { get; } + + public ushort Height { get; } + + public ushort BitCount { get; } + + public ushort Planes { get; } + + public ushort DisplayRate { get; } + + public ushort Flags { get; } + + public static AniHeader Parse(in ReadOnlySpan data) + => MemoryMarshal.Cast(data)[0]; + + public readonly unsafe void WriteTo(in Stream stream) + => stream.Write(MemoryMarshal.Cast([this])); +} diff --git a/src/ImageSharp/Formats/Ani/AniMetadata.cs b/src/ImageSharp/Formats/Ani/AniMetadata.cs new file mode 100644 index 0000000000..ce862b5eef --- /dev/null +++ b/src/ImageSharp/Formats/Ani/AniMetadata.cs @@ -0,0 +1,23 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats.Ani; + +internal class AniMetadata : IFormatMetadata +{ + + public static AniMetadata FromFormatConnectingMetadata(FormatConnectingMetadata metadata) => throw new NotImplementedException(); + + public void AfterImageApply(Image destination) + where TPixel : unmanaged, IPixel => throw new NotImplementedException(); + + public IDeepCloneable DeepClone() => throw new NotImplementedException(); + + public PixelTypeInfo GetPixelTypeInfo() => throw new NotImplementedException(); + + public FormatConnectingMetadata ToFormatConnectingMetadata() => throw new NotImplementedException(); + + AniMetadata IDeepCloneable.DeepClone() => throw new NotImplementedException(); +}