diff --git a/.gitattributes b/.gitattributes
index b5f742ab47..b1cf4dbd0a 100644
--- a/.gitattributes
+++ b/.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
diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs
index 1ca5d0a46b..5d1f66a22e 100644
--- a/src/ImageSharp/Configuration.cs
+++ b/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
/// .
/// .
/// .
+ /// .
///
/// The default configuration of .
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());
}
diff --git a/src/ImageSharp/Formats/Heic/HeicConfigurationModule.cs b/src/ImageSharp/Formats/Heic/HeicConfigurationModule.cs
new file mode 100644
index 0000000000..0ba7ceef67
--- /dev/null
+++ b/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;
+
+///
+/// Registers the image encoders, decoders and mime type detectors for the HEIC format.
+///
+public sealed class HeicConfigurationModule : IImageFormatConfigurationModule
+{
+ ///
+ public void Configure(Configuration configuration)
+ {
+ configuration.ImageFormatsManager.SetEncoder(HeicFormat.Instance, new HeicEncoder());
+ configuration.ImageFormatsManager.SetDecoder(HeicFormat.Instance, HeicDecoder.Instance);
+ configuration.ImageFormatsManager.AddImageFormatDetector(new HeicImageFormatDetector());
+ }
+}
diff --git a/src/ImageSharp/Formats/Heic/HeicConstants.cs b/src/ImageSharp/Formats/Heic/HeicConstants.cs
new file mode 100644
index 0000000000..99c9b8da66
--- /dev/null
+++ b/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;
+
+///
+/// Contains HEIC (and H.265) constant values defined in the specification.
+///
+internal static class HeicConstants
+{
+ ///
+ /// The list of mimetypes that equate to a HEIC.
+ ///
+ public static readonly IEnumerable MimeTypes = new[] { "image/heif", "image/heif-sequence", "image/heic", "image/heic-sequence", "image/avif" };
+
+ ///
+ /// The list of file extensions that equate to a HEIC.
+ ///
+ public static readonly IEnumerable FileExtensions = new[] { "heic", "heif", "avif" };
+}
diff --git a/src/ImageSharp/Formats/Heic/HeicDecoder.cs b/src/ImageSharp/Formats/Heic/HeicDecoder.cs
new file mode 100644
index 0000000000..71c8bdd363
--- /dev/null
+++ b/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;
+
+///
+/// Image decoder for reading HEIC images from a stream.
+public sealed class HeicDecoder : ImageDecoder
+{
+ private HeicDecoder()
+ {
+ }
+
+ ///
+ /// Gets the shared instance.
+ ///
+ public static HeicDecoder Instance { get; } = new();
+
+ ///
+ 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);
+ }
+
+ ///
+ protected override Image Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
+ {
+ Guard.NotNull(options, nameof(options));
+ Guard.NotNull(stream, nameof(stream));
+
+ HeicDecoderCore decoder = new(options);
+ Image image = decoder.Decode(options.Configuration, stream, cancellationToken);
+
+ return image;
+ }
+
+ ///
+ protected override Image Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
+ => this.Decode(options, stream, cancellationToken);
+}
diff --git a/src/ImageSharp/Formats/Heic/HeicDecoderCore.cs b/src/ImageSharp/Formats/Heic/HeicDecoderCore.cs
new file mode 100644
index 0000000000..c935af778d
--- /dev/null
+++ b/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;
+
+///
+/// Performs the PBM decoding operation.
+///
+internal sealed class HeicDecoderCore : IImageDecoderInternals
+{
+ ///
+ /// The general configuration.
+ ///
+ private readonly Configuration configuration;
+
+ ///
+ /// The decoded by this decoder instance.
+ ///
+ private ImageMetadata? metadata;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The decoder options.
+ public HeicDecoderCore(DecoderOptions options)
+ {
+ this.Options = options;
+ this.configuration = options.Configuration;
+ }
+
+ ///
+ public DecoderOptions Options { get; }
+
+ ///
+ public Image Decode(BufferedReadStream stream, CancellationToken cancellationToken)
+ where TPixel : unmanaged, IPixel
+ {
+ this.ProcessHeader(stream);
+
+ var image = new Image(this.configuration, this.pixelSize.Width, this.pixelSize.Height, this.metadata);
+
+ Buffer2D pixels = image.GetRootFramePixelBuffer();
+
+ // TODO: Implement
+
+ return image;
+ }
+
+ ///
+ 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);
+ }
+
+}
diff --git a/src/ImageSharp/Formats/Heic/HeicEncoder.cs b/src/ImageSharp/Formats/Heic/HeicEncoder.cs
new file mode 100644
index 0000000000..90ecc754a6
--- /dev/null
+++ b/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;
+
+///
+/// Image encoder for writing an image to a stream as HEIC images.
+public sealed class HeicEncoder : ImageEncoder
+{
+ ///
+ protected override void Encode(Image image, Stream stream, CancellationToken cancellationToken)
+ {
+ HeicEncoderCore encoder = new(image.Configuration, this);
+ encoder.Encode(image, stream, cancellationToken);
+ }
+}
diff --git a/src/ImageSharp/Formats/Heic/HeicEncoderCore.cs b/src/ImageSharp/Formats/Heic/HeicEncoderCore.cs
new file mode 100644
index 0000000000..291ece9d52
--- /dev/null
+++ b/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;
+
+///
+/// Image encoder for writing an image to a stream as a HEIC image.
+///
+internal sealed class HeicEncoderCore : IImageEncoderInternals
+{
+ ///
+ /// The global configuration.
+ ///
+ private Configuration configuration;
+
+ ///
+ /// The encoder with options.
+ ///
+ private readonly HeicEncoder encoder;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The configuration.
+ /// The encoder with options.
+ public HeicEncoderCore(Configuration configuration, HeicEncoder encoder)
+ {
+ this.configuration = configuration;
+ this.encoder = encoder;
+ }
+
+ ///
+ /// Encodes the image to the specified stream from the .
+ ///
+ /// The pixel format.
+ /// The to encode from.
+ /// The to encode the image data to.
+ /// The token to request cancellation.
+ public void Encode(Image image, Stream stream, CancellationToken cancellationToken)
+ where TPixel : unmanaged, IPixel
+ {
+ Guard.NotNull(image, nameof(image));
+ Guard.NotNull(stream, nameof(stream));
+
+ // TODO: Implement
+
+ stream.Flush();
+ }
+}
diff --git a/src/ImageSharp/Formats/Heic/HeicFormat.cs b/src/ImageSharp/Formats/Heic/HeicFormat.cs
new file mode 100644
index 0000000000..be47afce00
--- /dev/null
+++ b/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;
+
+///
+/// Registers the image encoders, decoders and mime type detectors for the HEIC format.
+///
+public sealed class HeicFormat : IImageFormat
+{
+ private HeicFormat()
+ {
+ }
+
+ ///
+ /// Gets the shared instance.
+ ///
+ public static HeicFormat Instance { get; } = new();
+
+ ///
+ public string Name => "HEIC";
+
+ ///
+ public string DefaultMimeType => "image/heif";
+
+ ///
+ public IEnumerable MimeTypes => HeicConstants.MimeTypes;
+
+ ///
+ public IEnumerable FileExtensions => HeicConstants.FileExtensions;
+
+ ///
+ public HeicMetadata CreateDefaultFormatMetadata() => new();
+}
diff --git a/src/ImageSharp/Formats/Heic/HeicImageFormatDetector.cs b/src/ImageSharp/Formats/Heic/HeicImageFormatDetector.cs
new file mode 100644
index 0000000000..a220320f35
--- /dev/null
+++ b/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;
+
+///
+/// Detects HEIC file headers.
+///
+public sealed class HeicImageFormatDetector : IImageFormatDetector
+{
+ ///
+ public bool TryDetectFormat(ReadOnlySpan header, [NotNullWhen(true)] out IImageFormat? format)
+ {
+ format = IsSupportedFileFormat(header) ? HeicFormat.Instance : null;
+ return format != null;
+ }
+
+ private static bool IsSupportedFileFormat(ReadOnlySpan header)
+ {
+ // TODO: Implement
+
+ return false;
+ }
+}
diff --git a/src/ImageSharp/Formats/Heic/HeicMetadata.cs b/src/ImageSharp/Formats/Heic/HeicMetadata.cs
new file mode 100644
index 0000000000..ddad88cc46
--- /dev/null
+++ b/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;
+
+///
+/// Provides HEIC specific metadata information for the image.
+///
+public class HeicMetadata : IDeepCloneable
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public HeicMetadata() =>
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The metadata to create an instance from.
+ private HeicMetadata(HeicMetadata other)
+ {
+ }
+
+ ///
+ public IDeepCloneable DeepClone() => new HeicMetadata(this);
+}
diff --git a/src/ImageSharp/Formats/Heic/HeicNalUnitType.cs b/src/ImageSharp/Formats/Heic/HeicNalUnitType.cs
new file mode 100644
index 0000000000..127a8dcdca
--- /dev/null
+++ b/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;
+
+///
+/// Provides enumeration of supported x265's LAN Unit Types.
+///
+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,
+}
diff --git a/src/ImageSharp/Formats/Heic/IHeicEncoderOptions.cs b/src/ImageSharp/Formats/Heic/IHeicEncoderOptions.cs
new file mode 100644
index 0000000000..fb73ae3ab2
--- /dev/null
+++ b/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;
+
+///
+/// Configuration options for use during HEIC encoding.
+///
+internal interface IHeicEncoderOptions
+{
+ // None defined yet.
+}
diff --git a/src/ImageSharp/Formats/Heic/MetadataExtensions.cs b/src/ImageSharp/Formats/Heic/MetadataExtensions.cs
new file mode 100644
index 0000000000..b708bfc308
--- /dev/null
+++ b/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;
+
+///
+/// Extension methods for the type.
+///
+public static partial class MetadataExtensions
+{
+ ///
+ /// Gets the pbm format specific metadata for the image.
+ ///
+ /// The metadata this method extends.
+ /// The .
+ public static HeicMetadata GetHeicMetadata(this ImageMetadata metadata) => metadata.GetFormatMetadata(HeicFormat.Instance);
+}
diff --git a/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs b/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs
index 324bd4783a..7d21de6dee 100644
--- a/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs
+++ b/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().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType().Count());
+ Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType().Count());
@@ -44,6 +46,7 @@ public class ImageFormatManagerTests
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType().Count());
+ Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType().Count());
Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType().Count());
diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs
index 9508de2469..be3de2a4f8 100644
--- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs
+++ b/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(),