Browse Source

Parse HIF metadata

pull/2633/head
Ynse Hoornenborg 3 years ago
parent
commit
d6dc2b1473
  1. 22
      src/ImageSharp/Formats/Heic/Heic4CharCode.cs
  2. 6
      src/ImageSharp/Formats/Heic/Heic4CharCode.tt
  3. 22
      src/ImageSharp/Formats/Heic/HeicDecoderCore.cs
  4. 8
      src/ImageSharp/Formats/Heic/HeicImageFormatDetector.cs
  5. 4
      tests/ImageSharp.Tests/Formats/Heic/HeicDecoderTests.cs
  6. 2
      tests/ImageSharp.Tests/TestImages.cs

22
src/ImageSharp/Formats/Heic/Heic4CharCode.cs

@ -124,15 +124,30 @@ public enum Heic4CharCode : uint
ipma = 0x69706D61U, ipma = 0x69706D61U,
/// <summary> /// <summary>
/// High Efficient Image Coding. /// High Efficient Image Coding brand.
/// </summary> /// </summary>
heic = 0x68656963U, heic = 0x68656963U,
/// <summary>
/// High Efficient Image Coding brand (legacy name).
/// </summary>
heix = 0x68656978U,
/// <summary>
/// High Efficient File brand.
/// </summary>
hif1 = 0x68696631U,
/// <summary> /// <summary>
/// High Efficiency Coding tile. /// High Efficiency Coding tile.
/// </summary> /// </summary>
hvc1 = 0x68766331U, hvc1 = 0x68766331U,
/// <summary>
/// Legacy JPEG coded tile.
/// </summary>
jpeg = 0x6A706567U,
/// <summary> /// <summary>
/// Data Information. /// Data Information.
/// </summary> /// </summary>
@ -203,4 +218,9 @@ public enum Heic4CharCode : uint
/// </summary> /// </summary>
pict = 0x70696374U, pict = 0x70696374U,
/// <summary>
/// Unique Identifier.
/// </summary>
uuid = 0x75756964U,
} }

6
src/ImageSharp/Formats/Heic/Heic4CharCode.tt

@ -29,8 +29,11 @@
"udes", "User Description", "udes", "User Description",
"ipco", "Item Property Container", "ipco", "Item Property Container",
"ipma", "Item Property Association", "ipma", "Item Property Association",
"heic", "High Efficient Image Coding", "heic", "High Efficient Image Coding brand",
"heix", "High Efficient Image Coding brand (legacy name)",
"hif1", "High Efficient File brand",
"hvc1", "High Efficiency Coding tile", "hvc1", "High Efficiency Coding tile",
"jpeg", "Legacy JPEG coded tile",
"dinf", "Data Information", "dinf", "Data Information",
"grpl", "Group list", "grpl", "Group list",
"hdlr", "Handler", "hdlr", "Handler",
@ -45,6 +48,7 @@
"mime", "MIME type", "mime", "MIME type",
"uri ", "URI", "uri ", "URI",
"pict", "Picture handler type", "pict", "Picture handler type",
"uuid", "Unique Identifier",
}; };
#> #>

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

@ -202,11 +202,12 @@ internal sealed class HeicDecoderCore : IImageDecoderInternals
case Heic4CharCode.idat: case Heic4CharCode.idat:
case Heic4CharCode.grpl: case Heic4CharCode.grpl:
case Heic4CharCode.ipro: case Heic4CharCode.ipro:
case Heic4CharCode.uuid:
// Silently skip these boxes. // Silently skip these boxes.
SkipBox(stream, length); SkipBox(stream, length);
break; break;
default: default:
throw new ImageFormatException($"Unknown metadata box type of '{Enum.GetName(boxType)}'"); throw new ImageFormatException($"Unknown metadata box type of '{PrettyPrint(boxType)}'");
} }
} }
} }
@ -373,8 +374,7 @@ internal sealed class HeicDecoderCore : IImageDecoderInternals
} }
else else
{ {
string enumName = Enum.GetName(containerType) ?? ((uint)containerType).ToString("X", CultureInfo.InvariantCulture); throw new ImageFormatException($"Unknown container type in property box of '{PrettyPrint(containerType)}'");
throw new ImageFormatException($"Unknown container type in property box of '{enumName}'");
} }
} }
} }
@ -424,8 +424,7 @@ internal sealed class HeicDecoderCore : IImageDecoderInternals
// TODO: Implement // TODO: Implement
break; break;
default: default:
string enumName = Enum.GetName(itemType) ?? ((uint)itemType).ToString("X", CultureInfo.InvariantCulture); throw new ImageFormatException($"Unknown item type in property box of '{PrettyPrint(itemType)}'");
throw new ImageFormatException($"Unknown item type in property box of '{enumName}'");
} }
} }
} }
@ -601,4 +600,17 @@ internal sealed class HeicDecoderCore : IImageDecoderInternals
Span<byte> bytes = span[..span.IndexOf((byte)0)]; Span<byte> bytes = span[..span.IndexOf((byte)0)];
return Encoding.UTF8.GetString(bytes); return Encoding.UTF8.GetString(bytes);
} }
private static string PrettyPrint(Heic4CharCode code)
{
string? pretty = Enum.GetName(code);
if (string.IsNullOrEmpty(pretty))
{
Span<byte> bytes = stackalloc byte[4];
BinaryPrimitives.WriteUInt32BigEndian(bytes, (uint)code);
pretty = Encoding.ASCII.GetString(bytes);
}
return pretty;
}
} }

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

@ -21,7 +21,9 @@ public sealed class HeicImageFormatDetector : IImageFormatDetector
return format != null; return format != null;
} }
private static bool IsSupportedFileFormat(ReadOnlySpan<byte> header) => private static bool IsSupportedFileFormat(ReadOnlySpan<byte> header) {
BinaryPrimitives.ReadUInt32BigEndian(header.Slice(4)) == (uint)Heic4CharCode.ftyp && bool hasFtyp = BinaryPrimitives.ReadUInt32BigEndian(header.Slice(4)) == (uint)Heic4CharCode.ftyp;
BinaryPrimitives.ReadUInt32BigEndian(header.Slice(8)) == (uint)Heic4CharCode.heic; uint brand = BinaryPrimitives.ReadUInt32BigEndian(header.Slice(8));
return hasFtyp && (brand == (uint)Heic4CharCode.heic || brand == (uint)Heic4CharCode.heix);
}
} }

4
tests/ImageSharp.Tests/Formats/Heic/HeicDecoderTests.cs

@ -13,6 +13,7 @@ public class HeicDecoderTests
[Theory] [Theory]
[InlineData(TestImages.Heic.Image1)] [InlineData(TestImages.Heic.Image1)]
[InlineData(TestImages.Heic.Sample640x427)] [InlineData(TestImages.Heic.Sample640x427)]
[InlineData(TestImages.Heic.FujiFilmHif)]
public void Identify(string imagePath) public void Identify(string imagePath)
{ {
TestFile testFile = TestFile.Create(imagePath); TestFile testFile = TestFile.Create(imagePath);
@ -27,8 +28,7 @@ public class HeicDecoderTests
} }
[Theory] [Theory]
[WithFile(TestImages.Heic.Image1, PixelTypes.Rgba32)] [WithFile(TestImages.Heic.FujiFilmHif, PixelTypes.Rgba32)]
[WithFile(TestImages.Heic.Sample640x427, PixelTypes.Rgba32)]
public void Decode<TPixel>(TestImageProvider<TPixel> provider) public void Decode<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {

2
tests/ImageSharp.Tests/TestImages.cs

@ -1112,6 +1112,6 @@ public static class TestImages
public const string Image3 = "Heic/image3.heic"; public const string Image3 = "Heic/image3.heic";
public const string Image4 = "Heic/image4.heic"; public const string Image4 = "Heic/image4.heic";
public const string Sample640x427 = "Heic/dwsample-heic-640.heic"; public const string Sample640x427 = "Heic/dwsample-heic-640.heic";
public const string FujiFilm-HIF = "Heic/IMG-20230508-0053.hif"; public const string FujiFilmHif = "Heic/IMG-20230508-0053.hif";
} }
} }

Loading…
Cancel
Save