Browse Source

Scaffolding for HEIC file format

pull/2633/head
Ynse Hoornenborg 2 years ago
parent
commit
0829e868f5
  1. 3
      .gitattributes
  2. 5
      src/ImageSharp/Configuration.cs
  3. 18
      src/ImageSharp/Formats/Heic/HeicConfigurationModule.cs
  4. 20
      src/ImageSharp/Formats/Heic/HeicConstants.cs
  5. 45
      src/ImageSharp/Formats/Heic/HeicDecoder.cs
  6. 65
      src/ImageSharp/Formats/Heic/HeicDecoderCore.cs
  7. 18
      src/ImageSharp/Formats/Heic/HeicEncoder.cs
  8. 53
      src/ImageSharp/Formats/Heic/HeicEncoderCore.cs
  9. 34
      src/ImageSharp/Formats/Heic/HeicFormat.cs
  10. 26
      src/ImageSharp/Formats/Heic/HeicImageFormatDetector.cs
  11. 26
      src/ImageSharp/Formats/Heic/HeicMetadata.cs
  12. 38
      src/ImageSharp/Formats/Heic/HeicNalUnitType.cs
  13. 12
      src/ImageSharp/Formats/Heic/IHeicEncoderOptions.cs
  14. 20
      src/ImageSharp/Formats/Heic/MetadataExtensions.cs
  15. 3
      tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs
  16. 2
      tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs

3
.gitattributes

@ -136,3 +136,6 @@
*.ico filter=lfs diff=lfs merge=lfs -text
*.cur filter=lfs diff=lfs merge=lfs -text
*.ani filter=lfs diff=lfs merge=lfs -text
*.heic filter=lfs diff=lfs merge=lfs -text
*.heif filter=lfs diff=lfs merge=lfs -text
*.avif filter=lfs diff=lfs merge=lfs -text

5
src/ImageSharp/Configuration.cs

@ -6,6 +6,7 @@ using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Heic;
using SixLabors.ImageSharp.Formats.Pbm;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Qoi;
@ -211,6 +212,7 @@ public sealed class Configuration
/// <see cref="TiffConfigurationModule"/>.
/// <see cref="WebpConfigurationModule"/>.
/// <see cref="QoiConfigurationModule"/>.
/// <see cref="HeicConfigurationModule"/>.
/// </summary>
/// <returns>The default configuration of <see cref="Configuration"/>.</returns>
internal static Configuration CreateDefaultInstance() => new(
@ -222,5 +224,6 @@ public sealed class Configuration
new TgaConfigurationModule(),
new TiffConfigurationModule(),
new WebpConfigurationModule(),
new QoiConfigurationModule());
new QoiConfigurationModule(),
new HeicConfigurationModule());
}

18
src/ImageSharp/Formats/Heic/HeicConfigurationModule.cs

@ -0,0 +1,18 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heic;
/// <summary>
/// Registers the image encoders, decoders and mime type detectors for the HEIC format.
/// </summary>
public sealed class HeicConfigurationModule : IImageFormatConfigurationModule
{
/// <inheritdoc/>
public void Configure(Configuration configuration)
{
configuration.ImageFormatsManager.SetEncoder(HeicFormat.Instance, new HeicEncoder());
configuration.ImageFormatsManager.SetDecoder(HeicFormat.Instance, HeicDecoder.Instance);
configuration.ImageFormatsManager.AddImageFormatDetector(new HeicImageFormatDetector());
}
}

20
src/ImageSharp/Formats/Heic/HeicConstants.cs

@ -0,0 +1,20 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heic;
/// <summary>
/// Contains HEIC (and H.265) constant values defined in the specification.
/// </summary>
internal static class HeicConstants
{
/// <summary>
/// The list of mimetypes that equate to a HEIC.
/// </summary>
public static readonly IEnumerable<string> MimeTypes = new[] { "image/heif", "image/heif-sequence", "image/heic", "image/heic-sequence", "image/avif" };
/// <summary>
/// The list of file extensions that equate to a HEIC.
/// </summary>
public static readonly IEnumerable<string> FileExtensions = new[] { "heic", "heif", "avif" };
}

45
src/ImageSharp/Formats/Heic/HeicDecoder.cs

@ -0,0 +1,45 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Heic;
/// <summary>
/// Image decoder for reading HEIC images from a stream.
public sealed class HeicDecoder : ImageDecoder
{
private HeicDecoder()
{
}
/// <summary>
/// Gets the shared instance.
/// </summary>
public static HeicDecoder Instance { get; } = new();
/// <inheritdoc/>
protected override ImageInfo Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
{
Guard.NotNull(options, nameof(options));
Guard.NotNull(stream, nameof(stream));
return new HeicDecoderCore(options).Identify(options.Configuration, stream, cancellationToken);
}
/// <inheritdoc />
protected override Image<TPixel> Decode<TPixel>(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
{
Guard.NotNull(options, nameof(options));
Guard.NotNull(stream, nameof(stream));
HeicDecoderCore decoder = new(options);
Image<TPixel> image = decoder.Decode<TPixel>(options.Configuration, stream, cancellationToken);
return image;
}
/// <inheritdoc />
protected override Image Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
=> this.Decode<Rgb24>(options, stream, cancellationToken);
}

65
src/ImageSharp/Formats/Heic/HeicDecoderCore.cs

@ -0,0 +1,65 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Diagnostics.CodeAnalysis;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
namespace SixLabors.ImageSharp.Formats.Heic;
/// <summary>
/// Performs the PBM decoding operation.
/// </summary>
internal sealed class HeicDecoderCore : IImageDecoderInternals
{
/// <summary>
/// The general configuration.
/// </summary>
private readonly Configuration configuration;
/// <summary>
/// The <see cref="ImageMetadata"/> decoded by this decoder instance.
/// </summary>
private ImageMetadata? metadata;
/// <summary>
/// Initializes a new instance of the <see cref="PbmDecoderCore" /> class.
/// </summary>
/// <param name="options">The decoder options.</param>
public HeicDecoderCore(DecoderOptions options)
{
this.Options = options;
this.configuration = options.Configuration;
}
/// <inheritdoc/>
public DecoderOptions Options { get; }
/// <inheritdoc/>
public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
{
this.ProcessHeader(stream);
var image = new Image<TPixel>(this.configuration, this.pixelSize.Width, this.pixelSize.Height, this.metadata);
Buffer2D<TPixel> pixels = image.GetRootFramePixelBuffer();
// TODO: Implement
return image;
}
/// <inheritdoc/>
public ImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken)
{
this.ProcessHeader(stream);
// TODO: Implement
return new ImageInfo(new PixelTypeInfo(bitsPerPixel), new(this.pixelSize.Width, this.pixelSize.Height), this.metadata);
}
}

18
src/ImageSharp/Formats/Heic/HeicEncoder.cs

@ -0,0 +1,18 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Advanced;
namespace SixLabors.ImageSharp.Formats.Heic;
/// <summary>
/// Image encoder for writing an image to a stream as HEIC images.
public sealed class HeicEncoder : ImageEncoder
{
/// <inheritdoc/>
protected override void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken cancellationToken)
{
HeicEncoderCore encoder = new(image.Configuration, this);
encoder.Encode(image, stream, cancellationToken);
}
}

53
src/ImageSharp/Formats/Heic/HeicEncoderCore.cs

@ -0,0 +1,53 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers.Text;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Heic;
/// <summary>
/// Image encoder for writing an image to a stream as a HEIC image.
/// </summary>
internal sealed class HeicEncoderCore : IImageEncoderInternals
{
/// <summary>
/// The global configuration.
/// </summary>
private Configuration configuration;
/// <summary>
/// The encoder with options.
/// </summary>
private readonly HeicEncoder encoder;
/// <summary>
/// Initializes a new instance of the <see cref="HeicEncoderCore"/> class.
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="encoder">The encoder with options.</param>
public HeicEncoderCore(Configuration configuration, HeicEncoder encoder)
{
this.configuration = configuration;
this.encoder = encoder;
}
/// <summary>
/// Encodes the image to the specified stream from the <see cref="ImageFrame{TPixel}"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="image">The <see cref="ImageFrame{TPixel}"/> to encode from.</param>
/// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param>
/// <param name="cancellationToken">The token to request cancellation.</param>
public void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
{
Guard.NotNull(image, nameof(image));
Guard.NotNull(stream, nameof(stream));
// TODO: Implement
stream.Flush();
}
}

34
src/ImageSharp/Formats/Heic/HeicFormat.cs

@ -0,0 +1,34 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heic;
/// <summary>
/// Registers the image encoders, decoders and mime type detectors for the HEIC format.
/// </summary>
public sealed class HeicFormat : IImageFormat<HeicMetadata>
{
private HeicFormat()
{
}
/// <summary>
/// Gets the shared instance.
/// </summary>
public static HeicFormat Instance { get; } = new();
/// <inheritdoc/>
public string Name => "HEIC";
/// <inheritdoc/>
public string DefaultMimeType => "image/heif";
/// <inheritdoc/>
public IEnumerable<string> MimeTypes => HeicConstants.MimeTypes;
/// <inheritdoc/>
public IEnumerable<string> FileExtensions => HeicConstants.FileExtensions;
/// <inheritdoc/>
public HeicMetadata CreateDefaultFormatMetadata() => new();
}

26
src/ImageSharp/Formats/Heic/HeicImageFormatDetector.cs

@ -0,0 +1,26 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Diagnostics.CodeAnalysis;
namespace SixLabors.ImageSharp.Formats.Heic;
/// <summary>
/// Detects HEIC file headers.
/// </summary>
public sealed class HeicImageFormatDetector : IImageFormatDetector
{
/// <inheritdoc/>
public bool TryDetectFormat(ReadOnlySpan<byte> header, [NotNullWhen(true)] out IImageFormat? format)
{
format = IsSupportedFileFormat(header) ? HeicFormat.Instance : null;
return format != null;
}
private static bool IsSupportedFileFormat(ReadOnlySpan<byte> header)
{
// TODO: Implement
return false;
}
}

26
src/ImageSharp/Formats/Heic/HeicMetadata.cs

@ -0,0 +1,26 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heic;
/// <summary>
/// Provides HEIC specific metadata information for the image.
/// </summary>
public class HeicMetadata : IDeepCloneable
{
/// <summary>
/// Initializes a new instance of the <see cref="HeicMetadata"/> class.
/// </summary>
public HeicMetadata() =>
/// <summary>
/// Initializes a new instance of the <see cref="HeicMetadata"/> class.
/// </summary>
/// <param name="other">The metadata to create an instance from.</param>
private HeicMetadata(HeicMetadata other)
{
}
/// <inheritdoc/>
public IDeepCloneable DeepClone() => new HeicMetadata(this);
}

38
src/ImageSharp/Formats/Heic/HeicNalUnitType.cs

@ -0,0 +1,38 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heic;
/// <summary>
/// Provides enumeration of supported x265's LAN Unit Types.
/// </summary>
public enum HeicNalUnitType : uint
{
NAL_UNIT_CODED_SLICE_TRAIL_N = 0,
NAL_UNIT_CODED_SLICE_TRAIL_R,
NAL_UNIT_CODED_SLICE_TSA_N,
NAL_UNIT_CODED_SLICE_TSA_R,
NAL_UNIT_CODED_SLICE_STSA_N,
NAL_UNIT_CODED_SLICE_STSA_R,
NAL_UNIT_CODED_SLICE_RADL_N,
NAL_UNIT_CODED_SLICE_RADL_R,
NAL_UNIT_CODED_SLICE_RASL_N,
NAL_UNIT_CODED_SLICE_RASL_R,
NAL_UNIT_CODED_SLICE_BLA_W_LP = 16,
NAL_UNIT_CODED_SLICE_BLA_W_RADL,
NAL_UNIT_CODED_SLICE_BLA_N_LP,
NAL_UNIT_CODED_SLICE_IDR_W_RADL,
NAL_UNIT_CODED_SLICE_IDR_N_LP,
NAL_UNIT_CODED_SLICE_CRA,
NAL_UNIT_VPS = 32,
NAL_UNIT_SPS,
NAL_UNIT_PPS,
NAL_UNIT_ACCESS_UNIT_DELIMITER,
NAL_UNIT_EOS,
NAL_UNIT_EOB,
NAL_UNIT_FILLER_DATA,
NAL_UNIT_PREFIX_SEI,
NAL_UNIT_SUFFIX_SEI,
Unspecified = 62,
Invalid = 64,
}

12
src/ImageSharp/Formats/Heic/IHeicEncoderOptions.cs

@ -0,0 +1,12 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heic;
/// <summary>
/// Configuration options for use during HEIC encoding.
/// </summary>
internal interface IHeicEncoderOptions
{
// None defined yet.
}

20
src/ImageSharp/Formats/Heic/MetadataExtensions.cs

@ -0,0 +1,20 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats.Heic;
using SixLabors.ImageSharp.Metadata;
namespace SixLabors.ImageSharp;
/// <summary>
/// Extension methods for the <see cref="ImageMetadata"/> type.
/// </summary>
public static partial class MetadataExtensions
{
/// <summary>
/// Gets the pbm format specific metadata for the image.
/// </summary>
/// <param name="metadata">The metadata this method extends.</param>
/// <returns>The <see cref="HeicMetadata"/>.</returns>
public static HeicMetadata GetHeicMetadata(this ImageMetadata metadata) => metadata.GetFormatMetadata(HeicFormat.Instance);
}

3
tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs

@ -6,6 +6,7 @@ using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Heic;
using SixLabors.ImageSharp.Formats.Pbm;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Tga;
@ -35,6 +36,7 @@ public class ImageFormatManagerTests
Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType<BmpEncoder>().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType<JpegEncoder>().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType<GifEncoder>().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType<HeicEncoder>().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType<TgaEncoder>().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType<TiffEncoder>().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType<WebpEncoder>().Count());
@ -44,6 +46,7 @@ public class ImageFormatManagerTests
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType<BmpDecoder>().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType<JpegDecoder>().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType<GifDecoder>().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType<HeicDecoder>().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType<TgaDecoder>().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType<TiffDecoder>().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType<WebpDecoder>().Count());

2
tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs

@ -5,6 +5,7 @@ using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Heic;
using SixLabors.ImageSharp.Formats.Pbm;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Qoi;
@ -59,6 +60,7 @@ public static partial class TestEnvironment
Configuration cfg = new(
new JpegConfigurationModule(),
new GifConfigurationModule(),
new HeicConfigurationModule(),
new PbmConfigurationModule(),
new TgaConfigurationModule(),
new WebpConfigurationModule(),

Loading…
Cancel
Save