Add avifIsAlpha() to internal.h (#2057)

Also fix avifGetErrorForItemCategory() returned result for gain maps.
diff --git a/include/avif/internal.h b/include/avif/internal.h
index 3cf3aa0..ceb6110 100644
--- a/include/avif/internal.h
+++ b/include/avif/internal.h
@@ -156,6 +156,9 @@
 // Ignores the gainMap field (which exists only if AVIF_ENABLE_EXPERIMENTAL_GAIN_MAP is defined).
 void avifImageCopySamples(avifImage * dstImage, const avifImage * srcImage, avifPlanesFlags planes);
 
+// ---------------------------------------------------------------------------
+// Alpha
+
 typedef struct avifAlphaParams
 {
     uint32_t width;
@@ -321,6 +324,8 @@
     AVIF_ITEM_CATEGORY_COUNT
 } avifItemCategory;
 
+avifBool avifIsAlpha(avifItemCategory itemCategory);
+
 // ---------------------------------------------------------------------------
 
 #if defined(AVIF_ENABLE_EXPERIMENTAL_AVIR)
diff --git a/src/avif.c b/src/avif.c
index 264d004..aa7d8e6 100644
--- a/src/avif.c
+++ b/src/avif.c
@@ -868,6 +868,16 @@
 
 // ---------------------------------------------------------------------------
 
+avifBool avifIsAlpha(avifItemCategory itemCategory)
+{
+    if (itemCategory == AVIF_ITEM_ALPHA) {
+        return AVIF_TRUE;
+    }
+    return AVIF_FALSE;
+}
+
+// ---------------------------------------------------------------------------
+
 avifBool avifAreGridDimensionsValid(avifPixelFormat yuvFormat, uint32_t imageW, uint32_t imageH, uint32_t tileW, uint32_t tileH, avifDiagnostics * diag)
 {
     // ISO/IEC 23000-22:2019, Section 7.3.11.4.2:
diff --git a/src/read.c b/src/read.c
index 1a0d0b7..87005a7 100644
--- a/src/read.c
+++ b/src/read.c
@@ -1523,7 +1523,7 @@
         return AVIF_RESULT_INVALID_IMAGE_GRID;
     }
 
-    avifBool alpha = (tile->input->itemCategory == AVIF_ITEM_ALPHA);
+    const avifBool alpha = avifIsAlpha(tile->input->itemCategory);
     if (alpha) {
         // An alpha tile does not contain any YUV pixels.
         AVIF_ASSERT_OR_RETURN(tile->image->yuvFormat == AVIF_PIXEL_FORMAT_NONE);
@@ -1618,8 +1618,7 @@
 #endif
     AVIF_ASSERT_OR_RETURN(avifImageSetViewRect(&dstView, dst, &dstViewRect) == AVIF_RESULT_OK &&
                           avifImageSetViewRect(&srcView, tile->image, &srcViewRect) == AVIF_RESULT_OK);
-    avifImageCopySamples(&dstView, &srcView, (tile->input->itemCategory == AVIF_ITEM_ALPHA) ? AVIF_PLANES_A : AVIF_PLANES_YUV);
-
+    avifImageCopySamples(&dstView, &srcView, avifIsAlpha(tile->input->itemCategory) ? AVIF_PLANES_A : AVIF_PLANES_YUV);
     return AVIF_RESULT_OK;
 }
 
@@ -4970,7 +4969,7 @@
                 continue;
             }
 #endif
-            if (c == AVIF_ITEM_ALPHA && !mainItems[c]->width && !mainItems[c]->height) {
+            if (avifIsAlpha(c) && !mainItems[c]->width && !mainItems[c]->height) {
                 // NON-STANDARD: Alpha subimage does not have an ispe property; adopt width/height from color item
                 AVIF_ASSERT_OR_RETURN(!(decoder->strictFlags & AVIF_STRICT_ALPHA_ISPE_REQUIRED));
                 mainItems[c]->width = mainItems[AVIF_ITEM_COLOR]->width;
@@ -4980,7 +4979,7 @@
             AVIF_CHECKRES(avifDecoderGenerateImageTiles(decoder, &data->tileInfos[c], mainItems[c], c));
 
             avifStrictFlags strictFlags = decoder->strictFlags;
-            if (c == AVIF_ITEM_ALPHA && !isAlphaItemInInput) {
+            if (avifIsAlpha(c) && !isAlphaItemInInput) {
                 // In this case, the made up grid item will not have an associated pixi property. So validate everything else
                 // but the pixi property.
                 strictFlags &= ~AVIF_STRICT_PIXI_REQUIRED;
@@ -4991,7 +4990,7 @@
 
         if (mainItems[AVIF_ITEM_COLOR]->progressive) {
             decoder->progressiveState = AVIF_PROGRESSIVE_STATE_AVAILABLE;
-            // data->color.firstTileIndex is not yet defined but will be set to 0 a few lines below.
+            // data->tileInfos[AVIF_ITEM_COLOR].firstTileIndex is not yet defined but will be set to 0 a few lines below.
             const avifTile * colorTile = &data->tiles.tile[0];
             if (colorTile->input->samples.count > 1) {
                 decoder->progressiveState = AVIF_PROGRESSIVE_STATE_ACTIVE;
@@ -5186,7 +5185,7 @@
         return AVIF_RESULT_DECODE_GAIN_MAP_FAILED;
     }
 #endif
-    return (itemCategory == AVIF_ITEM_ALPHA) ? AVIF_RESULT_DECODE_ALPHA_FAILED : AVIF_RESULT_DECODE_COLOR_FAILED;
+    return avifIsAlpha(itemCategory) ? AVIF_RESULT_DECODE_ALPHA_FAILED : AVIF_RESULT_DECODE_COLOR_FAILED;
 }
 
 static avifResult avifDecoderDecodeTiles(avifDecoder * decoder, uint32_t nextImageIndex, avifTileInfo * info)
@@ -5203,7 +5202,7 @@
         }
 
         avifBool isLimitedRangeAlpha = AVIF_FALSE;
-        if (!tile->codec->getNextImage(tile->codec, decoder, sample, tile->input->itemCategory == AVIF_ITEM_ALPHA, &isLimitedRangeAlpha, tile->image)) {
+        if (!tile->codec->getNextImage(tile->codec, decoder, sample, avifIsAlpha(tile->input->itemCategory), &isLimitedRangeAlpha, tile->image)) {
             avifDiagnosticsPrintf(&decoder->diag, "tile->codec->getNextImage() failed");
             return avifGetErrorForItemCategory(tile->input->itemCategory);
         }
@@ -5231,7 +5230,7 @@
         // of the specification. However, it was allowed in version 1.0.0 of the
         // specification. To allow such files, simply convert the alpha plane to
         // full range.
-        if ((tile->input->itemCategory == AVIF_ITEM_ALPHA) && isLimitedRangeAlpha) {
+        if (avifIsAlpha(tile->input->itemCategory) && isLimitedRangeAlpha) {
             avifResult result = avifImageLimitedToFullAlpha(tile->image);
             if (result != AVIF_RESULT_OK) {
                 avifDiagnosticsPrintf(&decoder->diag, "avifImageLimitedToFullAlpha failed");
@@ -5283,7 +5282,7 @@
                 default:
                     if ((decoder->image->width != src->width) || (decoder->image->height != src->height) ||
                         (decoder->image->depth != src->depth)) {
-                        if (tile->input->itemCategory == AVIF_ITEM_ALPHA) {
+                        if (avifIsAlpha(tile->input->itemCategory)) {
                             avifDiagnosticsPrintf(&decoder->diag,
                                                   "The color image item does not match the alpha image item in width, height, or bit depth");
                             return AVIF_RESULT_DECODE_ALPHA_FAILED;
@@ -5297,7 +5296,7 @@
                     break;
             }
 
-            if (tile->input->itemCategory == AVIF_ITEM_ALPHA) {
+            if (avifIsAlpha(tile->input->itemCategory)) {
                 avifImageStealPlanes(decoder->image, src, AVIF_PLANES_A);
 #if defined(AVIF_ENABLE_EXPERIMENTAL_GAIN_MAP)
             } else if (tile->input->itemCategory == AVIF_ITEM_GAIN_MAP) {
diff --git a/src/write.c b/src/write.c
index 9cbe1f8..f7f510c 100644
--- a/src/write.c
+++ b/src/write.c
@@ -1115,7 +1115,7 @@
                                            uint16_t * topLevelItemID)
 {
     const uint32_t cellCount = gridCols * gridRows;
-    const char * infeName = (itemCategory == AVIF_ITEM_ALPHA) ? infeNameAlpha
+    const char * infeName = avifIsAlpha(itemCategory) ? infeNameAlpha
 #if defined(AVIF_ENABLE_EXPERIMENTAL_GAIN_MAP)
                             : (itemCategory == AVIF_ITEM_GAIN_MAP) ? infeNameGainMap
 #endif
@@ -1192,7 +1192,12 @@
 
 static avifResult avifGetErrorForItemCategory(avifItemCategory itemCategory)
 {
-    return (itemCategory == AVIF_ITEM_ALPHA) ? AVIF_RESULT_ENCODE_ALPHA_FAILED : AVIF_RESULT_ENCODE_COLOR_FAILED;
+#if defined(AVIF_ENABLE_EXPERIMENTAL_GAIN_MAP)
+    if (itemCategory == AVIF_ITEM_GAIN_MAP) {
+        return AVIF_RESULT_ENCODE_GAIN_MAP_FAILED;
+    }
+#endif
+    return avifIsAlpha(itemCategory) ? AVIF_RESULT_ENCODE_ALPHA_FAILED : AVIF_RESULT_ENCODE_COLOR_FAILED;
 }
 
 static avifResult avifValidateImageBasicProperties(const avifImage * avifImage)
@@ -1662,7 +1667,9 @@
                 }
                 cellImage = paddedCellImage;
             }
-            const int quantizer = (item->itemCategory == AVIF_ITEM_ALPHA) ? encoder->data->quantizerAlpha
+
+            const avifBool isAlpha = avifIsAlpha(item->itemCategory);
+            const int quantizer = isAlpha ? encoder->data->quantizerAlpha
 #if defined(AVIF_ENABLE_EXPERIMENTAL_GAIN_MAP)
                                   : (item->itemCategory == AVIF_ITEM_GAIN_MAP) ? encoder->data->quantizerGainMap
 #endif
@@ -1673,7 +1680,7 @@
             avifResult encodeResult = item->codec->encodeImage(item->codec,
                                                                encoder,
                                                                cellImage,
-                                                               item->itemCategory == AVIF_ITEM_ALPHA,
+                                                               isAlpha,
                                                                encoder->data->tileRowsLog2,
                                                                encoder->data->tileColsLog2,
                                                                quantizer,
@@ -1780,10 +1787,12 @@
                 // only process metadata (XMP/Exif) payloads when metadataPass is true
                 continue;
             }
-            avifBool isAlphaOrGainMap = item->itemCategory == AVIF_ITEM_ALPHA;
+            const avifBool isAlpha = avifIsAlpha(item->itemCategory);
+            const avifBool isAlphaOrGainMap = isAlpha
 #if defined(AVIF_ENABLE_EXPERIMENTAL_GAIN_MAP)
-            isAlphaOrGainMap = isAlphaOrGainMap || item->itemCategory == AVIF_ITEM_GAIN_MAP;
+                                              || item->itemCategory == AVIF_ITEM_GAIN_MAP
 #endif
+                ;
             if (alphaAndGainMapPass != isAlphaOrGainMap) {
                 // only process alpha payloads when alphaPass is true
                 continue;
@@ -1794,8 +1803,7 @@
                 // We always interleave all AV1 items for layered images.
                 AVIF_ASSERT_OR_RETURN(item->encodeOutput->samples.count == item->mdatFixups.count);
 
-                avifEncoderItemReference * ref = (item->itemCategory == AVIF_ITEM_ALPHA) ? avifArrayPush(layeredAlphaItems)
-                                                                                         : avifArrayPush(layeredColorItems);
+                avifEncoderItemReference * ref = avifArrayPush(isAlpha ? layeredAlphaItems : layeredColorItems);
                 AVIF_CHECKERR(ref != NULL, AVIF_RESULT_OUT_OF_MEMORY);
                 *ref = item;
                 continue;
@@ -1820,7 +1828,7 @@
                         avifEncodeSample * sample = &item->encodeOutput->samples.sample[sampleIndex];
                         AVIF_CHECKRES(avifRWStreamWrite(s, sample->data.data, sample->data.size));
 
-                        if (item->itemCategory == AVIF_ITEM_ALPHA) {
+                        if (isAlpha) {
                             encoder->ioStats.alphaOBUSize += sample->data.size;
                         } else if (item->itemCategory == AVIF_ITEM_COLOR) {
                             encoder->ioStats.colorOBUSize += sample->data.size;
@@ -2254,7 +2262,7 @@
             imageHeight = item->gridHeight;
         }
 
-        // Properties all image items need
+        // Properties all image items need (coded and derived)
         // ispe = image spatial extent (width, height)
         avifItemPropertyDedupStart(dedup);
         avifBoxMarker ispe;
@@ -2272,15 +2280,16 @@
             hasPixi = AVIF_FALSE;
         }
 #endif
+        const avifBool isAlpha = avifIsAlpha(item->itemCategory);
+        const uint8_t depth = (uint8_t)itemMetadata->depth;
         if (hasPixi) {
             avifItemPropertyDedupStart(dedup);
-            uint8_t channelCount =
-                (item->itemCategory == AVIF_ITEM_ALPHA || (itemMetadata->yuvFormat == AVIF_PIXEL_FORMAT_YUV400)) ? 1 : 3;
+            uint8_t channelCount = (isAlpha || (itemMetadata->yuvFormat == AVIF_PIXEL_FORMAT_YUV400)) ? 1 : 3;
             avifBoxMarker pixi;
             AVIF_CHECKRES(avifRWStreamWriteFullBox(&dedup->s, "pixi", AVIF_BOX_SIZE_TBD, 0, 0, &pixi));
             AVIF_CHECKRES(avifRWStreamWriteU8(&dedup->s, channelCount)); // unsigned int (8) num_channels;
             for (uint8_t chan = 0; chan < channelCount; ++chan) {
-                AVIF_CHECKRES(avifRWStreamWriteU8(&dedup->s, (uint8_t)itemMetadata->depth)); // unsigned int (8) bits_per_channel;
+                AVIF_CHECKRES(avifRWStreamWriteU8(&dedup->s, depth)); // unsigned int (8) bits_per_channel;
             }
             avifRWStreamFinishBox(&dedup->s, pixi);
             AVIF_CHECKRES(avifItemPropertyDedupFinish(dedup, s, &item->ipma, AVIF_FALSE));
@@ -2293,7 +2302,7 @@
             AVIF_CHECKRES(avifItemPropertyDedupFinish(dedup, s, &item->ipma, AVIF_TRUE));
         }
 
-        if (item->itemCategory == AVIF_ITEM_ALPHA) {
+        if (isAlpha) {
             // Alpha specific properties
 
             avifItemPropertyDedupStart(dedup);