diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1InverseTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1InverseTransformer.cs index 6b36f191fc..49bbdd2e60 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1InverseTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1InverseTransformer.cs @@ -47,4 +47,23 @@ internal class Av1InverseTransformer Av1InverseTransformerFactory.InverseTransformAdd( coefficientsBuffer, reconstructionBufferRead, reconstructionReadStride, reconstructionBufferWrite, reconstructionWriteStride, transformFunctionParameters); } + + /// + /// AV1: 7.11.2 Reconstruct. + /// + public static void ReconstructHighBitDepth(Span coefficientsBuffer, Span reconstructionBuffer, int reconstructionStride, Av1TransformSize transformSize, Av1TransformType transformType, int plane, int numberOfCoefficients, bool isLossless, Av1BitDepth bitDepth) + { + Av1TransformFunctionParameters transformFunctionParameters = new() + { + TransformType = transformType, + TransformSize = transformSize, + EndOfBuffer = numberOfCoefficients, + IsLossless = isLossless, + BitDepth = bitDepth.GetBitCount(), + Is16BitPipeline = true + }; + + Av1InverseTransformerFactory.InverseTransformAdd( + coefficientsBuffer, reconstructionBuffer, reconstructionStride, reconstructionBuffer, reconstructionStride, transformFunctionParameters); + } } diff --git a/tests/ImageSharp.Tests/Formats/Heif/Av1/Av1InverseTransformTests.cs b/tests/ImageSharp.Tests/Formats/Heif/Av1/Av1InverseTransformTests.cs index 31554a94b8..30d50394eb 100644 --- a/tests/ImageSharp.Tests/Formats/Heif/Av1/Av1InverseTransformTests.cs +++ b/tests/ImageSharp.Tests/Formats/Heif/Av1/Av1InverseTransformTests.cs @@ -267,6 +267,56 @@ public class Av1InverseTransformTests Assert.Equal(expected.Select(value => (byte)value), actual); } + [Theory] + [InlineData((int)Av1BitDepth.TenBit, 1023)] + [InlineData((int)Av1BitDepth.TwelveBit, 4095)] + public void HighBitDepthReconstructionClipsPositiveValues(int bitDepthIndex, short maximum) + { + const int width = 4; + int[] coefficients = new int[width * width]; + coefficients[0] = 64; + short[] reconstruction = new short[width * width]; + Array.Fill(reconstruction, (short)(maximum - 1)); + + Av1InverseTransformer.ReconstructHighBitDepth( + coefficients, + reconstruction, + width, + Av1TransformSize.Size4x4, + Av1TransformType.DctDct, + 0, + 1, + false, + (Av1BitDepth)bitDepthIndex); + + Assert.All(reconstruction, value => Assert.Equal(maximum, value)); + } + + [Theory] + [InlineData((int)Av1BitDepth.TenBit)] + [InlineData((int)Av1BitDepth.TwelveBit)] + public void HighBitDepthReconstructionClipsNegativeValues(int bitDepthIndex) + { + const int width = 4; + int[] coefficients = new int[width * width]; + coefficients[0] = -64; + short[] reconstruction = new short[width * width]; + Array.Fill(reconstruction, (short)1); + + Av1InverseTransformer.ReconstructHighBitDepth( + coefficients, + reconstruction, + width, + Av1TransformSize.Size4x4, + Av1TransformType.DctDct, + 0, + 1, + false, + (Av1BitDepth)bitDepthIndex); + + Assert.All(reconstruction, value => Assert.Equal((short)0, value)); + } + private static void AssertAccuracy1d( Av1TransformType transformType, Av1TransformSize transformSize,