diff --git a/src/ImageSharp/Formats/Heif/Av1/Av1BlockSize.cs b/src/ImageSharp/Formats/Heif/Av1/Av1BlockSize.cs
index 5a524c261d..92a651d60f 100644
--- a/src/ImageSharp/Formats/Heif/Av1/Av1BlockSize.cs
+++ b/src/ImageSharp/Formats/Heif/Av1/Av1BlockSize.cs
@@ -3,7 +3,7 @@
namespace SixLabors.ImageSharp.Formats.Heif.Av1;
-internal enum Av1BlockSize
+internal enum Av1BlockSize : byte
{
// See sction 6.10.4 of the Av1 Specification.
diff --git a/src/ImageSharp/Formats/Heif/Av1/Av1LookupTables.cs b/src/ImageSharp/Formats/Heif/Av1/Av1LookupTables.cs
new file mode 100644
index 0000000000..a7e9ab7998
--- /dev/null
+++ b/src/ImageSharp/Formats/Heif/Av1/Av1LookupTables.cs
@@ -0,0 +1,34 @@
+// Copyright (c) Six Labors.
+// Licensed under the Six Labors Split License.
+
+namespace SixLabors.ImageSharp.Formats.Heif.Av1;
+
+internal static class Av1LookupTables
+{
+ // The Subsampled_Size table in the spec (Section 5.11.38. Get plane residual size function).
+ public static Av1BlockSize[,,] SubSampledSize =
+ {
+ { { Av1BlockSize.Block4x4, Av1BlockSize.Block4x4 }, { Av1BlockSize.Block4x4, Av1BlockSize.Block4x4 } },
+ { { Av1BlockSize.Block4x8, Av1BlockSize.Block4x4 }, { Av1BlockSize.Invalid, Av1BlockSize.Block4x4 } },
+ { { Av1BlockSize.Block8x4, Av1BlockSize.Invalid }, { Av1BlockSize.Block4x4, Av1BlockSize.Block4x4 } },
+ { { Av1BlockSize.Block8x8, Av1BlockSize.Block8x4 }, { Av1BlockSize.Block4x8, Av1BlockSize.Block4x4 } },
+ { { Av1BlockSize.Block8x16, Av1BlockSize.Block8x8 }, { Av1BlockSize.Invalid, Av1BlockSize.Block4x8 } },
+ { { Av1BlockSize.Block16x8, Av1BlockSize.Invalid }, { Av1BlockSize.Block8x8, Av1BlockSize.Block8x4 } },
+ { { Av1BlockSize.Block16x16, Av1BlockSize.Block16x8 }, { Av1BlockSize.Block8x16, Av1BlockSize.Block8x8 } },
+ { { Av1BlockSize.Block16x32, Av1BlockSize.Block16x16 }, { Av1BlockSize.Invalid, Av1BlockSize.Block8x16 } },
+ { { Av1BlockSize.Block32x16, Av1BlockSize.Invalid }, { Av1BlockSize.Block16x16, Av1BlockSize.Block16x8 } },
+ { { Av1BlockSize.Block32x32, Av1BlockSize.Block32x16 }, { Av1BlockSize.Block16x32, Av1BlockSize.Block16x16 } },
+ { { Av1BlockSize.Block32x64, Av1BlockSize.Block32x32 }, { Av1BlockSize.Invalid, Av1BlockSize.Block16x32 } },
+ { { Av1BlockSize.Block64x32, Av1BlockSize.Invalid }, { Av1BlockSize.Block32x32, Av1BlockSize.Block32x16 } },
+ { { Av1BlockSize.Block64x64, Av1BlockSize.Block64x32 }, { Av1BlockSize.Block32x64, Av1BlockSize.Block32x32 } },
+ { { Av1BlockSize.Block64x128, Av1BlockSize.Block64x64 }, { Av1BlockSize.Invalid, Av1BlockSize.Block32x64 } },
+ { { Av1BlockSize.Block128x64, Av1BlockSize.Invalid }, { Av1BlockSize.Block64x64, Av1BlockSize.Block64x32 } },
+ { { Av1BlockSize.Block128x128, Av1BlockSize.Block128x64 }, { Av1BlockSize.Block64x128, Av1BlockSize.Block64x64 } },
+ { { Av1BlockSize.Block4x16, Av1BlockSize.Block4x8 }, { Av1BlockSize.Invalid, Av1BlockSize.Block4x8 } },
+ { { Av1BlockSize.Block16x4, Av1BlockSize.Invalid }, { Av1BlockSize.Block8x4, Av1BlockSize.Block8x4 } },
+ { { Av1BlockSize.Block8x32, Av1BlockSize.Block8x16 }, { Av1BlockSize.Invalid, Av1BlockSize.Block4x16 } },
+ { { Av1BlockSize.Block32x8, Av1BlockSize.Invalid }, { Av1BlockSize.Block16x8, Av1BlockSize.Block16x4 } },
+ { { Av1BlockSize.Block16x64, Av1BlockSize.Block16x32 }, { Av1BlockSize.Invalid, Av1BlockSize.Block8x32 } },
+ { { Av1BlockSize.Block64x16, Av1BlockSize.Invalid }, { Av1BlockSize.Block32x16, Av1BlockSize.Block32x8 } },
+ };
+}
diff --git a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileDecoder.cs b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileDecoder.cs
index c286b34b6a..4308ff3326 100644
--- a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileDecoder.cs
+++ b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileDecoder.cs
@@ -451,7 +451,19 @@ internal class Av1TileDecoder : IAv1TileDecoder
private Av1TransformSize GetSize(int plane, object transformSize) => throw new NotImplementedException();
- private Av1BlockSize GetPlaneResidualSize(Av1BlockSize sizeChunk, int plane) => throw new NotImplementedException();
+ ///
+ /// 5.11.38. Get plane residual size function.
+ /// The GetPlaneResidualSize returns the size of a residual block for the specified plane. (The residual block will always
+ /// have width and height at least equal to 4.)
+ ///
+ private Av1BlockSize GetPlaneResidualSize(Av1BlockSize sizeChunk, int plane)
+ {
+ int subsamplingX = this.SequenceHeader.ColorConfig.SubSamplingX ? 1 : 0;
+ int subsamplingY = this.SequenceHeader.ColorConfig.SubSamplingY ? 1 : 0;
+ int subX = plane > 0 ? subsamplingX : 0;
+ int subY = plane > 0 ? subsamplingY : 0;
+ return Av1LookupTables.SubSampledSize[(byte)sizeChunk, subX, subY];
+ }
///
/// 5.11.35. Transform block syntax.