Reject grids exceeding the 'dimg' reference count limit (#3354)

avifEncoderAddImageGrid() now refuses grids with more than 65535 cells
(e.g. 256x256 cells) upfront with AVIF_RESULT_INVALID_IMAGE_GRID and a
diagnostic: Section 8.11.12.1 of ISO/IEC 14496-12 requires all the
references from one item to be collected into a single item type
reference box whose reference_count field is unsigned int(16) whatever
the 'iref' version, and ISO/IEC 23008-12 (HEIF) Section 6.6.1 forbids
more than one 'dimg' box with the same from_item_ID. Such grids
therefore cannot be encoded in a conformant way, whatever the item ID
width, and used to silently generate a broken file instead.

Co-authored-by: krishna28238-arch <319297638+krishna28238-arch@users.noreply.github.com>
diff --git a/src/write.c b/src/write.c
index 6980909..50a451e 100644
--- a/src/write.c
+++ b/src/write.c
@@ -2154,6 +2154,20 @@
     if ((gridCols == 0) || (gridCols > 256) || (gridRows == 0) || (gridRows > 256)) {
         return AVIF_RESULT_INVALID_IMAGE_GRID;
     }
+    if ((uint64_t)gridCols * gridRows > 65535) {
+        // Section 8.11.12.1 of ISO/IEC 14496-12: "All the references for one item of a specific type
+        // are collected into a single item type reference box", whose reference_count field is
+        // unsigned int(16) whatever the 'iref' version (Section 8.11.12.2). Moreover, ISO/IEC 23008-12
+        // (HEIF) Section 6.6.1 states that "The number of SingleItemTypeReferenceBoxes with the box
+        // type 'dimg' and with the same value of from_item_ID shall not be greater than 1".
+        // A grid item therefore cannot reference more than 65535 cell items, so a 256x256-cell grid
+        // cannot be encoded in a conformant way, whatever the item ID width.
+        avifDiagnosticsPrintf(&encoder->diag,
+                              "avifEncoderAddImageGrid() failed because a grid cannot have more than 65535 cells due to the 16-bit 'dimg' reference_count field (%u columns x %u rows)",
+                              gridCols,
+                              gridRows);
+        return AVIF_RESULT_INVALID_IMAGE_GRID;
+    }
     if (encoder->extraLayerCount == 0) {
         addImageFlags |= AVIF_ADD_IMAGE_FLAG_SINGLE; // image grids cannot be image sequences
     }
diff --git a/tests/gtest/avifgridapitest.cc b/tests/gtest/avifgridapitest.cc
index 26efff0..2168e7a 100644
--- a/tests/gtest/avifgridapitest.cc
+++ b/tests/gtest/avifgridapitest.cc
@@ -277,5 +277,29 @@
       AVIF_RESULT_INVALID_IMAGE_GRID);
 }
 
+TEST(GridApiTest, CellsTooManyForDimgReferenceCount) {
+  // Section 8.11.12.1 of ISO/IEC 14496-12 requires all the references from one
+  // item to be collected into a single item type reference box, whose
+  // reference_count field is unsigned int(16) whatever the 'iref' version
+  // (Section 8.11.12.2). ISO/IEC 23008-12 (HEIF) Section 6.6.1 additionally
+  // forbids more than one 'dimg' box with the same from_item_ID. A grid item
+  // therefore cannot have more than 65535 cells, so a 256x256-cell grid is
+  // rejected upfront instead of silently generating a broken file.
+  ImagePtr cell = testutil::CreateImage(
+      /*width=*/64, /*height=*/64, /*depth=*/8, AVIF_PIXEL_FORMAT_YUV400,
+      AVIF_PLANES_YUV);
+  ASSERT_NE(cell, nullptr);
+  testutil::FillImageGradient(cell.get());
+  const std::vector<avifImage*> cell_image_ptrs(256 * 256, cell.get());
+
+  EncoderPtr encoder(avifEncoderCreate());
+  ASSERT_NE(encoder, nullptr);
+  encoder->speed = AVIF_SPEED_FASTEST;
+  ASSERT_EQ(avifEncoderAddImageGrid(encoder.get(), /*gridCols=*/256,
+                                    /*gridRows=*/256, cell_image_ptrs.data(),
+                                    AVIF_ADD_IMAGE_FLAG_SINGLE),
+            AVIF_RESULT_INVALID_IMAGE_GRID);
+}
+
 }  // namespace
 }  // namespace avif