From e972551bb5970783398768fe80a55221e34cc8cb Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Thu, 28 Dec 2023 11:06:51 +0100 Subject: [PATCH] Exposed used compression method in metadata --- .../Formats/Heic/HeicCompressionMethod.cs | 45 +++++++++++++++++++ .../Formats/Heic/HeicDecoderCore.cs | 12 ++++- src/ImageSharp/Formats/Heic/HeicMetadata.cs | 8 +++- .../Formats/Heic/HeicDecoderTests.cs | 16 +++---- tests/ImageSharp.Tests/TestImages.cs | 1 + 5 files changed, 71 insertions(+), 11 deletions(-) create mode 100644 src/ImageSharp/Formats/Heic/HeicCompressionMethod.cs diff --git a/src/ImageSharp/Formats/Heic/HeicCompressionMethod.cs b/src/ImageSharp/Formats/Heic/HeicCompressionMethod.cs new file mode 100644 index 0000000000..efe826f85c --- /dev/null +++ b/src/ImageSharp/Formats/Heic/HeicCompressionMethod.cs @@ -0,0 +1,45 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Formats.Heic; + +/// +/// Compression algorithms possible inside an HEIF (High Efficiency File Format) based file. +/// +public enum HeicCompressionMethod +{ + /// + /// High Efficiency Video Coding + /// + Hevc, + + /// + /// Legact JPEG + /// + LegacyJpeg, + + /// + /// JPEG 2000 + /// + Jpeg2000, + + /// + /// JPEG-XR + /// + JpegXR, + + /// + /// JPEG-XS + /// + JpegXS, + + /// + /// AOMedia's Video 1 coding + /// + Av1, + + /// + /// Advanced Video Coding + /// + Avc, +} diff --git a/src/ImageSharp/Formats/Heic/HeicDecoderCore.cs b/src/ImageSharp/Formats/Heic/HeicDecoderCore.cs index 0d3a31f0d3..ed2381cc62 100644 --- a/src/ImageSharp/Formats/Heic/HeicDecoderCore.cs +++ b/src/ImageSharp/Formats/Heic/HeicDecoderCore.cs @@ -25,7 +25,7 @@ internal sealed class HeicDecoderCore : IImageDecoderInternals /// /// The decoded by this decoder instance. /// - private ImageMetadata? metadata; + private readonly ImageMetadata metadata; private uint primaryItem; @@ -130,6 +130,12 @@ internal sealed class HeicDecoderCore : IImageDecoderInternals throw new ImageFormatException("No primary item found"); } + HeicMetadata meta = this.metadata.GetHeicMetadata(); + if (this.itemLinks.Any(link => link.Type == Heic4CharCode.thmb)) + { + meta.CompressionMethod = HeicCompressionMethod.LegacyJpeg; + } + return new ImageInfo(new PixelTypeInfo(item.BitsPerPixel), new(item.Extent.Width, item.Extent.Height), this.metadata); } @@ -432,6 +438,7 @@ internal sealed class HeicDecoderCore : IImageDecoderInternals case Heic4CharCode.rloc: case Heic4CharCode.udes: // TODO: Implement + properties.Add(new KeyValuePair(itemType, new object())); break; default: throw new ImageFormatException($"Unknown item type in property box of '{PrettyPrint(itemType)}'"); @@ -594,6 +601,9 @@ internal sealed class HeicDecoderCore : IImageDecoderInternals Span thumbSpan = thumbMemory.GetSpan(); stream.Read(thumbSpan); + HeicMetadata meta = this.metadata.GetHeicMetadata(); + meta.CompressionMethod = HeicCompressionMethod.LegacyJpeg; + return Image.Load(thumbSpan); } diff --git a/src/ImageSharp/Formats/Heic/HeicMetadata.cs b/src/ImageSharp/Formats/Heic/HeicMetadata.cs index 55f3d7ba82..f6f95a86cd 100644 --- a/src/ImageSharp/Formats/Heic/HeicMetadata.cs +++ b/src/ImageSharp/Formats/Heic/HeicMetadata.cs @@ -20,8 +20,12 @@ public class HeicMetadata : IDeepCloneable /// /// The metadata to create an instance from. private HeicMetadata(HeicMetadata other) - { - } + => this.CompressionMethod = other.CompressionMethod; + + /// + /// Gets or sets the compression method used for the primary frame. + /// + public HeicCompressionMethod CompressionMethod { get; set; } /// public IDeepCloneable DeepClone() => new HeicMetadata(this); diff --git a/tests/ImageSharp.Tests/Formats/Heic/HeicDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Heic/HeicDecoderTests.cs index 8f50b2298f..b3862c3d06 100644 --- a/tests/ImageSharp.Tests/Formats/Heic/HeicDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Heic/HeicDecoderTests.cs @@ -11,10 +11,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Heic; public class HeicDecoderTests { [Theory] - [InlineData(TestImages.Heic.Image1)] - [InlineData(TestImages.Heic.Sample640x427)] - [InlineData(TestImages.Heic.FujiFilmHif)] - public void Identify(string imagePath) + [InlineData(TestImages.Heic.Image1, HeicCompressionMethod.Hevc)] + [InlineData(TestImages.Heic.Sample640x427, HeicCompressionMethod.Hevc)] + [InlineData(TestImages.Heic.FujiFilmHif, HeicCompressionMethod.LegacyJpeg)] + public void Identify(string imagePath, HeicCompressionMethod compressionMethod) { TestFile testFile = TestFile.Create(imagePath); using MemoryStream stream = new(testFile.Bytes, false); @@ -23,8 +23,8 @@ public class HeicDecoderTests HeicMetadata heicMetadata = imageInfo.Metadata.GetHeicMetadata(); Assert.NotNull(imageInfo); - Assert.Equal(imageInfo.Metadata.DecodedImageFormat, HeicFormat.Instance); - //Assert.Equal(heicMetadata.Channels, channels); + Assert.Equal(HeicFormat.Instance, imageInfo.Metadata.DecodedImageFormat); + Assert.Equal(compressionMethod, heicMetadata.CompressionMethod); } [Theory] @@ -33,10 +33,10 @@ public class HeicDecoderTests where TPixel : unmanaged, IPixel { using Image image = provider.GetImage(); - HeicMetadata qoiMetadata = image.Metadata.GetHeicMetadata(); + HeicMetadata heicMetadata = image.Metadata.GetHeicMetadata(); image.DebugSave(provider); image.CompareToReferenceOutput(provider); - //Assert.Equal(heicMetadata.Channels, channels); + Assert.Equal(HeicCompressionMethod.LegacyJpeg, heicMetadata.CompressionMethod); } } diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index d30974fa1d..ef80704b08 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -1112,6 +1112,7 @@ public static class TestImages public const string Image3 = "Heic/image3.heic"; public const string Image4 = "Heic/image4.heic"; public const string Sample640x427 = "Heic/dwsample-heic-640.heic"; + // Downloaded from: https://github.com/draktable-org/darktable/issues/14473 public const string FujiFilmHif = "Heic/IMG-20230508-0053.hif"; } }