// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using SixLabors.ImageSharp.Formats.Heif; using SixLabors.ImageSharp.Formats.Heif.Av1; namespace SixLabors.ImageSharp.Tests.Formats.Heif; /// /// Verifies parsing and interpretation of HEIF image-item property payloads. /// [Trait("Format", "Heif")] public class HeifPropertyParserTests { /// /// Verifies that every AV1 operating-point index representable by a sequence header is accepted. /// /// The zero-based operating-point index. [Theory] [InlineData(0)] [InlineData(31)] public void ParseAv1OperatingPointSelectorAcceptsSequenceHeaderRange(byte index) { Av1OperatingPointSelector selector = HeifPropertyParser.ParseAv1OperatingPointSelector([index]); Assert.Equal(index, selector.Index); } /// /// Verifies that an AV1 operating-point index outside the sequence-header range is rejected. /// [Fact] public void ParseAv1OperatingPointSelectorRejectsOutOfRangeIndex() => Assert.Throws(() => HeifPropertyParser.ParseAv1OperatingPointSelector([32])); /// /// Verifies the four AV1 spatial-layer identifiers and the progressive final-layer selector. /// /// The most-significant selector byte. /// The least-significant selector byte. /// The parsed layer identifier. [Theory] [InlineData(0, 0, 0)] [InlineData(0, 3, 3)] [InlineData(255, 255, Av1LayerSelector.AllLayers)] public void ParseAv1LayerSelectorAcceptsDefinedValues(byte highByte, byte lowByte, ushort expected) { Av1LayerSelector selector = HeifPropertyParser.ParseAv1LayerSelector([highByte, lowByte]); Assert.Equal(expected, selector.LayerId); } /// /// Verifies that an AV1 spatial-layer identifier wider than the OBU extension field is rejected. /// [Fact] public void ParseAv1LayerSelectorRejectsOutOfRangeLayer() => Assert.Throws(() => HeifPropertyParser.ParseAv1LayerSelector([0, 4])); /// /// Verifies the compact 16-bit representation of the three explicit layered-image boundaries. /// [Fact] public void ParseAv1LayeredImageIndexReadsSmallSizes() { Av1LayeredImageIndex index = HeifPropertyParser.ParseAv1LayeredImageIndex([0, 0, 55, 0, 17, 1, 2]); Assert.Equal(55U, index.FirstLayerSize); Assert.Equal(17U, index.SecondLayerSize); Assert.Equal(258U, index.ThirdLayerSize); } /// /// Verifies the 32-bit representation used when a layered-image boundary exceeds 16 bits. /// [Fact] public void ParseAv1LayeredImageIndexReadsLargeSizes() { Av1LayeredImageIndex index = HeifPropertyParser.ParseAv1LayeredImageIndex( [1, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0]); Assert.Equal(65536U, index.FirstLayerSize); Assert.Equal(131072U, index.SecondLayerSize); Assert.Equal(196608U, index.ThirdLayerSize); } /// /// Verifies that reserved layered-image flag bits cannot alter the payload interpretation. /// [Fact] public void ParseAv1LayeredImageIndexRejectsReservedBits() => Assert.Throws(() => HeifPropertyParser.ParseAv1LayeredImageIndex([2, 0, 1, 0, 0, 0, 0])); /// /// Verifies cumulative selection through the two-layer payload used by the libavif progressive fixture. /// /// The selected spatial layer. /// The cumulative payload length through that layer. [Theory] [InlineData(0, 55)] [InlineData(1, 72)] [InlineData(Av1LayerSelector.AllLayers, 72)] public void GetPayloadLengthSelectsCumulativeLayerBytes(ushort layerId, int expectedLength) { Av1LayeredImageIndex index = new(55, 0, 0); Av1LayerSelector selector = new(layerId); Assert.Equal(expectedLength, index.GetPayloadLength(72, selector)); } /// /// Verifies that a selector cannot address a layer absent from the indexed item payload. /// [Fact] public void GetPayloadLengthRejectsAbsentLayer() { Av1LayeredImageIndex index = new(55, 0, 0); Av1LayerSelector selector = new(2); Assert.Throws(() => index.GetPayloadLength(72, selector)); } /// /// Verifies that every explicit layer boundary leaves bytes for the following implicit layer. /// [Fact] public void GetPayloadLengthRejectsBoundaryAtItemEnd() { Av1LayeredImageIndex index = new(72, 0, 0); Assert.Throws(() => index.GetPayloadLength(72, null)); } }