Use PNG_COLOR_TYPE_GRAY for 8-bit grayscale output

When writing a PNG output file, if the AVIF image is 8-bit monochrome
with no alpha and the PNG output bit depth is 8, use the Y plane of the
AVIF image directly for the PNG_COLOR_TYPE_GRAY color type.

Partially fix https://github.com/AOMediaCodec/libavif/issues/1123.
diff --git a/apps/shared/avifpng.c b/apps/shared/avifpng.c
index 90358ac..fe9fb7b 100644
--- a/apps/shared/avifpng.c
+++ b/apps/shared/avifpng.c
@@ -381,7 +381,7 @@
     avifRGBImage rgb;
     memset(&rgb, 0, sizeof(avifRGBImage));
 
-    int rgbDepth = requestedDepth;
+    volatile int rgbDepth = requestedDepth;
     if (rgbDepth == 0) {
         if (avif->depth > 8) {
             rgbDepth = 16;
@@ -390,18 +390,26 @@
         }
     }
 
-    avifRGBImageSetDefaults(&rgb, avif);
-    rgb.chromaUpsampling = chromaUpsampling;
-    rgb.depth = rgbDepth;
-    int colorType = PNG_COLOR_TYPE_RGBA;
-    if (!avif->alphaPlane) {
-        colorType = PNG_COLOR_TYPE_RGB;
-        rgb.format = AVIF_RGB_FORMAT_RGB;
-    }
-    avifRGBImageAllocatePixels(&rgb);
-    if (avifImageYUVToRGB(avif, &rgb) != AVIF_RESULT_OK) {
-        fprintf(stderr, "Conversion to RGB failed: %s\n", outputFilename);
-        goto cleanup;
+    avifBool monochrome8bit = (avif->yuvFormat == AVIF_PIXEL_FORMAT_YUV400) && !avif->alphaPlane && (avif->depth == 8) &&
+                              (rgbDepth == 8);
+
+    int colorType;
+    if (monochrome8bit) {
+        colorType = PNG_COLOR_TYPE_GRAY;
+    } else {
+        avifRGBImageSetDefaults(&rgb, avif);
+        rgb.chromaUpsampling = chromaUpsampling;
+        rgb.depth = rgbDepth;
+        colorType = PNG_COLOR_TYPE_RGBA;
+        if (!avif->alphaPlane) {
+            colorType = PNG_COLOR_TYPE_RGB;
+            rgb.format = AVIF_RGB_FORMAT_RGB;
+        }
+        avifRGBImageAllocatePixels(&rgb);
+        if (avifImageYUVToRGB(avif, &rgb) != AVIF_RESULT_OK) {
+            fprintf(stderr, "Conversion to RGB failed: %s\n", outputFilename);
+            goto cleanup;
+        }
     }
 
     f = fopen(outputFilename, "wb");
@@ -438,18 +446,26 @@
         png_set_compression_level(png, compressionLevel);
     }
 
-    png_set_IHDR(png, info, avif->width, avif->height, rgb.depth, colorType, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+    png_set_IHDR(png, info, avif->width, avif->height, rgbDepth, colorType, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
     if (avif->icc.data && (avif->icc.size > 0)) {
         png_set_iCCP(png, info, "libavif", 0, (png_iccp_datap)avif->icc.data, (png_uint_32)avif->icc.size);
     }
     png_write_info(png, info);
 
-    rowPointers = (png_bytep *)malloc(sizeof(png_bytep) * rgb.height);
-    for (uint32_t y = 0; y < rgb.height; ++y) {
-        rowPointers[y] = &rgb.pixels[y * rgb.rowBytes];
+    rowPointers = (png_bytep *)malloc(sizeof(png_bytep) * avif->height);
+    if (monochrome8bit) {
+        uint8_t * yPlane = avif->yuvPlanes[AVIF_CHAN_Y];
+        uint32_t yRowBytes = avif->yuvRowBytes[AVIF_CHAN_Y];
+        for (uint32_t y = 0; y < avif->height; ++y) {
+            rowPointers[y] = &yPlane[y * yRowBytes];
+        }
+    } else {
+        for (uint32_t y = 0; y < avif->height; ++y) {
+            rowPointers[y] = &rgb.pixels[y * rgb.rowBytes];
+        }
     }
 
-    if (rgb.depth > 8) {
+    if (rgbDepth > 8) {
         png_set_swap(png);
     }