avifRGBImageAllocatePixels() returns avifResult

To catch out-of-memory issues.

Change printf(ERROR) into fprintf(stderr,ERROR) in avifyuv.c.
Use RGBImageFreePixels() in RGBImageAllocatePixels().
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2786bd8..f760dd0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,7 @@
   those pointers.
 * Check the return value of avifEncoderSetCodecSpecificOption().
 * The maxThreads member was added to the avifRGBImage struct.
+* Check the return value of avifRGBImageAllocatePixels().
 
 ### Added
 * Add STATIC library target avif_internal to allow tests to access functions
@@ -60,6 +61,8 @@
 * avifEncoderSetCodecSpecificOption() now returns avifResult instead of void to
   report memory allocation failures.
 * At decoding, avifIOStats now returns the same values as at encoding.
+* avifRGBImageAllocatePixels() now returns avifResult instead of void to report
+  memory allocation failures.
 
 ## [0.11.1] - 2022-10-19
 
diff --git a/apps/shared/avifjpeg.c b/apps/shared/avifjpeg.c
index 57f271f..87ff123 100644
--- a/apps/shared/avifjpeg.c
+++ b/apps/shared/avifjpeg.c
@@ -366,7 +366,10 @@
         rgb.format = AVIF_RGB_FORMAT_RGB;
         rgb.chromaDownsampling = chromaDownsampling;
         rgb.depth = 8;
-        avifRGBImageAllocatePixels(&rgb);
+        if (avifRGBImageAllocatePixels(&rgb) != AVIF_RESULT_OK) {
+            fprintf(stderr, "Conversion to YUV failed: %s (out of memory)\n", inputFilename);
+            goto cleanup;
+        }
 
         int row = 0;
         while (cinfo.output_scanline < cinfo.output_height) {
@@ -557,7 +560,10 @@
     rgb.format = AVIF_RGB_FORMAT_RGB;
     rgb.chromaUpsampling = chromaUpsampling;
     rgb.depth = 8;
-    avifRGBImageAllocatePixels(&rgb);
+    if (avifRGBImageAllocatePixels(&rgb) != AVIF_RESULT_OK) {
+        fprintf(stderr, "Conversion to RGB failed: %s (out of memory)\n", outputFilename);
+        goto cleanup;
+    }
     if (avifImageYUVToRGB(avif, &rgb) != AVIF_RESULT_OK) {
         fprintf(stderr, "Conversion to RGB failed: %s\n", outputFilename);
         goto cleanup;
diff --git a/apps/shared/avifpng.c b/apps/shared/avifpng.c
index a91a121..4bbe8d6 100644
--- a/apps/shared/avifpng.c
+++ b/apps/shared/avifpng.c
@@ -339,7 +339,10 @@
     avifRGBImageSetDefaults(&rgb, avif);
     rgb.chromaDownsampling = chromaDownsampling;
     rgb.depth = imgBitDepth;
-    avifRGBImageAllocatePixels(&rgb);
+    if (avifRGBImageAllocatePixels(&rgb) != AVIF_RESULT_OK) {
+        fprintf(stderr, "Conversion to YUV failed: %s (out of memory)\n", inputFilename);
+        goto cleanup;
+    }
     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];
@@ -416,7 +419,10 @@
             colorType = PNG_COLOR_TYPE_RGB;
             rgb.format = AVIF_RGB_FORMAT_RGB;
         }
-        avifRGBImageAllocatePixels(&rgb);
+        if (avifRGBImageAllocatePixels(&rgb) != AVIF_RESULT_OK) {
+            fprintf(stderr, "Conversion to RGB failed: %s (out of memory)\n", outputFilename);
+            goto cleanup;
+        }
         if (avifImageYUVToRGB(avif, &rgb) != AVIF_RESULT_OK) {
             fprintf(stderr, "Conversion to RGB failed: %s\n", outputFilename);
             goto cleanup;
diff --git a/examples/avif_example_decode_file.c b/examples/avif_example_decode_file.c
index f3fafb9..c25822a 100644
--- a/examples/avif_example_decode_file.c
+++ b/examples/avif_example_decode_file.c
@@ -58,10 +58,15 @@
 
         // Alternative: set rgb.pixels and rgb.rowBytes yourself, which should match your chosen rgb.format
         // Be sure to use uint16_t* instead of uint8_t* for rgb.pixels/rgb.rowBytes if (rgb.depth > 8)
-        avifRGBImageAllocatePixels(&rgb);
+        result = avifRGBImageAllocatePixels(&rgb);
+        if (result != AVIF_RESULT_OK) {
+            fprintf(stderr, "Allocation of RGB samples failed: %s (%s)\n", inputFilename, avifResultToString(result));
+            goto cleanup;
+        }
 
-        if (avifImageYUVToRGB(decoder->image, &rgb) != AVIF_RESULT_OK) {
-            fprintf(stderr, "Conversion from YUV failed: %s\n", inputFilename);
+        result = avifImageYUVToRGB(decoder->image, &rgb);
+        if (result != AVIF_RESULT_OK) {
+            fprintf(stderr, "Conversion from YUV failed: %s (%s)\n", inputFilename, avifResultToString(result));
             goto cleanup;
         }
 
diff --git a/examples/avif_example_decode_memory.c b/examples/avif_example_decode_memory.c
index 2cf4a0b..1a5fbec 100644
--- a/examples/avif_example_decode_memory.c
+++ b/examples/avif_example_decode_memory.c
@@ -80,10 +80,15 @@
 
         // Alternative: set rgb.pixels and rgb.rowBytes yourself, which should match your chosen rgb.format
         // Be sure to use uint16_t* instead of uint8_t* for rgb.pixels/rgb.rowBytes if (rgb.depth > 8)
-        avifRGBImageAllocatePixels(&rgb);
+        result = avifRGBImageAllocatePixels(&rgb);
+        if (result != AVIF_RESULT_OK) {
+            fprintf(stderr, "Allocation of RGB samples failed: %s (%s)\n", inputFilename, avifResultToString(result));
+            goto cleanup;
+        }
 
-        if (avifImageYUVToRGB(decoder->image, &rgb) != AVIF_RESULT_OK) {
-            fprintf(stderr, "Conversion from YUV failed: %s\n", inputFilename);
+        result = avifImageYUVToRGB(decoder->image, &rgb);
+        if (result != AVIF_RESULT_OK) {
+            fprintf(stderr, "Conversion from YUV failed: %s (%s)\n", inputFilename, avifResultToString(result));
             goto cleanup;
         }
 
diff --git a/examples/avif_example_encode.c b/examples/avif_example_encode.c
index 31b00d1..ec508db 100644
--- a/examples/avif_example_encode.c
+++ b/examples/avif_example_encode.c
@@ -66,7 +66,11 @@
 
         // Alternative: set rgb.pixels and rgb.rowBytes yourself, which should match your chosen rgb.format
         // Be sure to use uint16_t* instead of uint8_t* for rgb.pixels/rgb.rowBytes if (rgb.depth > 8)
-        avifRGBImageAllocatePixels(&rgb);
+        avifResult allocationResult = avifRGBImageAllocatePixels(&rgb);
+        if (allocationResult != AVIF_RESULT_OK) {
+            fprintf(stderr, "Allocation of RGB samples failed: %s\n", avifResultToString(allocationResult));
+            goto cleanup;
+        }
 
         // Fill your RGB(A) data here
         memset(rgb.pixels, 255, rgb.rowBytes * image->height);
diff --git a/include/avif/avif.h b/include/avif/avif.h
index 8eb629a..79f0158 100644
--- a/include/avif/avif.h
+++ b/include/avif/avif.h
@@ -680,7 +680,7 @@
 AVIF_API uint32_t avifRGBImagePixelSize(const avifRGBImage * rgb);
 
 // Convenience functions. If you supply your own pixels/rowBytes, you do not need to use these.
-AVIF_API void avifRGBImageAllocatePixels(avifRGBImage * rgb);
+AVIF_API avifResult avifRGBImageAllocatePixels(avifRGBImage * rgb);
 AVIF_API void avifRGBImageFreePixels(avifRGBImage * rgb);
 
 // The main conversion functions
diff --git a/src/avif.c b/src/avif.c
index e74aba7..b29505b 100644
--- a/src/avif.c
+++ b/src/avif.c
@@ -579,14 +579,14 @@
     rgb->maxThreads = 1;
 }
 
-void avifRGBImageAllocatePixels(avifRGBImage * rgb)
+avifResult avifRGBImageAllocatePixels(avifRGBImage * rgb)
 {
-    if (rgb->pixels) {
-        avifFree(rgb->pixels);
-    }
-
-    rgb->rowBytes = rgb->width * avifRGBImagePixelSize(rgb);
-    rgb->pixels = avifAlloc((size_t)rgb->rowBytes * rgb->height);
+    avifRGBImageFreePixels(rgb);
+    const uint32_t rowBytes = rgb->width * avifRGBImagePixelSize(rgb);
+    rgb->pixels = avifAlloc((size_t)rowBytes * rgb->height);
+    AVIF_CHECKERR(rgb->pixels, AVIF_RESULT_OUT_OF_MEMORY);
+    rgb->rowBytes = rowBytes;
+    return AVIF_RESULT_OK;
 }
 
 void avifRGBImageFreePixels(avifRGBImage * rgb)
diff --git a/tests/avifyuv.c b/tests/avifyuv.c
index 5576767..c9b38d2 100644
--- a/tests/avifyuv.c
+++ b/tests/avifyuv.c
@@ -151,7 +151,7 @@
 
                         avifImage * image = avifImageCreate(dim, dim, yuvDepth, AVIF_PIXEL_FORMAT_YUV444);
                         if (!image) {
-                            printf("ERROR: Out of memory\n");
+                            fprintf(stderr, "ERROR: Out of memory\n");
                             return 1;
                         }
                         image->colorPrimaries = cicp->cp;
@@ -168,13 +168,23 @@
                         avifRGBImageSetDefaults(&srcRGB, image);
                         srcRGB.format = AVIF_RGB_FORMAT_RGB;
                         srcRGB.depth = rgbDepth;
-                        avifRGBImageAllocatePixels(&srcRGB);
 
                         avifRGBImage dstRGB;
                         avifRGBImageSetDefaults(&dstRGB, image);
                         dstRGB.format = AVIF_RGB_FORMAT_RGB;
                         dstRGB.depth = rgbDepth;
-                        avifRGBImageAllocatePixels(&dstRGB);
+
+                        if ((avifRGBImageAllocatePixels(&srcRGB) != AVIF_RESULT_OK)) {
+                            avifImageDestroy(image);
+                            fprintf(stderr, "ERROR: Out of memory\n");
+                            return 1;
+                        }
+                        if ((avifRGBImageAllocatePixels(&dstRGB) != AVIF_RESULT_OK)) {
+                            avifRGBImageFreePixels(&srcRGB);
+                            avifImageDestroy(image);
+                            fprintf(stderr, "ERROR: Out of memory\n");
+                            return 1;
+                        }
 
                         uint64_t driftPixelCounts[MAX_DRIFT];
                         for (int i = 0; i < MAX_DRIFT; ++i) {
@@ -259,7 +269,10 @@
                                             maxDrift = drift;
                                         }
                                     } else {
-                                        printf("ERROR: Encountered a drift greater than or equal to MAX_DRIFT(%d): %d\n", MAX_DRIFT, drift);
+                                        fprintf(stderr,
+                                                "ERROR: Encountered a drift greater than or equal to MAX_DRIFT(%d): %d\n",
+                                                MAX_DRIFT,
+                                                drift);
                                         return 1;
                                     }
                                 }
@@ -307,7 +320,7 @@
 
         avifImage * image = avifImageCreate(originalWidth, originalHeight, 8, AVIF_PIXEL_FORMAT_YUV444);
         if (!image) {
-            printf("ERROR: Out of memory\n");
+            fprintf(stderr, "ERROR: Out of memory\n");
             return 1;
         }
 
@@ -317,7 +330,11 @@
             avifRGBImage srcRGB;
             avifRGBImageSetDefaults(&srcRGB, image);
             srcRGB.depth = yuvDepth;
-            avifRGBImageAllocatePixels(&srcRGB);
+            if (avifRGBImageAllocatePixels(&srcRGB) != AVIF_RESULT_OK) {
+                avifImageDestroy(image);
+                fprintf(stderr, "ERROR: Out of memory\n");
+                return 1;
+            }
             if (yuvDepth > 8) {
                 float maxChannelF = (float)((1 << yuvDepth) - 1);
                 for (uint32_t j = 0; j < srcRGB.height; ++j) {
@@ -362,7 +379,12 @@
                         avifRGBImageSetDefaults(&intermediateRGB, image);
                         intermediateRGB.depth = rgbDepth;
                         intermediateRGB.format = rgbFormat;
-                        avifRGBImageAllocatePixels(&intermediateRGB);
+                        if (avifRGBImageAllocatePixels(&intermediateRGB) != AVIF_RESULT_OK) {
+                            avifRGBImageFreePixels(&srcRGB);
+                            avifImageDestroy(image);
+                            fprintf(stderr, "ERROR: Out of memory\n");
+                            return 1;
+                        }
                         avifImageYUVToRGB(image, &intermediateRGB);
 
                         avifImageFreePlanes(image, AVIF_PLANES_ALL);
@@ -371,7 +393,13 @@
                         avifRGBImage dstRGB;
                         avifRGBImageSetDefaults(&dstRGB, image);
                         dstRGB.depth = yuvDepth;
-                        avifRGBImageAllocatePixels(&dstRGB);
+                        if (avifRGBImageAllocatePixels(&dstRGB) != AVIF_RESULT_OK) {
+                            avifRGBImageFreePixels(&intermediateRGB);
+                            avifRGBImageFreePixels(&srcRGB);
+                            avifImageDestroy(image);
+                            fprintf(stderr, "ERROR: Out of memory\n");
+                            return 1;
+                        }
                         avifImageYUVToRGB(image, &dstRGB);
 
                         avifBool moveOn = AVIF_FALSE;
@@ -463,7 +491,10 @@
             for (int i = 0; i < MAX_DRIFT; ++i) {
                 driftPixelCounts[i] = 0;
             }
-            avifRGBImageAllocatePixels(&rgb);
+            if (avifRGBImageAllocatePixels(&rgb) != AVIF_RESULT_OK) {
+                fprintf(stderr, "ERROR: Out of memory\n");
+                return 1;
+            }
 
             for (uint32_t a = 0; a < size; ++a) {
                 // meaningful premultiplied RGB value can't exceed A value, so stop at R = A
@@ -492,12 +523,13 @@
                         uint8_t * pixel = &rgb.pixels[r * sizeof(uint8_t) * 4];
                         int drift = abs((int)pixel[0] - (int)r);
                         if (drift >= MAX_DRIFT) {
-                            printf("ERROR: Premultiply round-trip difference greater than or equal to MAX_DRIFT(%d): RGB depth: %d, src: %d, dst: %d, alpha: %d.\n",
-                                   MAX_DRIFT,
-                                   rgbDepth,
-                                   pixel[0],
-                                   r,
-                                   a);
+                            fprintf(stderr,
+                                    "ERROR: Premultiply round-trip difference greater than or equal to MAX_DRIFT(%d): RGB depth: %d, src: %d, dst: %d, alpha: %d.\n",
+                                    MAX_DRIFT,
+                                    rgbDepth,
+                                    pixel[0],
+                                    r,
+                                    a);
                             return 1;
                         }
                         if (maxDrift < drift) {
@@ -508,12 +540,13 @@
                         uint16_t * pixel = (uint16_t *)&rgb.pixels[r * sizeof(uint16_t) * 4];
                         int drift = abs((int)pixel[0] - (int)r);
                         if (drift >= MAX_DRIFT) {
-                            printf("ERROR: Premultiply round-trip difference greater than or equal to MAX_DRIFT(%d): RGB depth: %d, src: %d, dst: %d, alpha: %d.\n",
-                                   MAX_DRIFT,
-                                   rgbDepth,
-                                   pixel[0],
-                                   r,
-                                   a);
+                            fprintf(stderr,
+                                    "ERROR: Premultiply round-trip difference greater than or equal to MAX_DRIFT(%d): RGB depth: %d, src: %d, dst: %d, alpha: %d.\n",
+                                    MAX_DRIFT,
+                                    rgbDepth,
+                                    pixel[0],
+                                    r,
+                                    a);
                             return 1;
                         }
                         if (maxDrift < drift) {
diff --git a/tests/gtest/aviftest_helpers.cc b/tests/gtest/aviftest_helpers.cc
index 283a681..12eed18 100644
--- a/tests/gtest/aviftest_helpers.cc
+++ b/tests/gtest/aviftest_helpers.cc
@@ -6,6 +6,7 @@
 #include <algorithm>
 #include <cassert>
 #include <cstdint>
+#include <cstdlib>
 #include <string>
 
 #include "avif/avif.h"
@@ -21,7 +22,9 @@
   avifRGBImageSetDefaults(this, yuv);
   depth = rgbDepth;
   format = rgbFormat;
-  avifRGBImageAllocatePixels(this);
+  if (avifRGBImageAllocatePixels(this) != AVIF_RESULT_OK) {
+    std::abort();
+  }
 }
 
 AvifRwData::AvifRwData(AvifRwData&& other) : avifRWData{other} {
diff --git a/tests/oss-fuzz/avif_decode_fuzzer.cc b/tests/oss-fuzz/avif_decode_fuzzer.cc
index 74c65e7..117aae5 100644
--- a/tests/oss-fuzz/avif_decode_fuzzer.cc
+++ b/tests/oss-fuzz/avif_decode_fuzzer.cc
@@ -50,7 +50,9 @@
                             rgb.depth = rgbDepths[rgbDepthsIndex];
                             rgb.chromaUpsampling = upsamplings[upsamplingsIndex];
                             rgb.avoidLibYUV = AVIF_TRUE;
-                            avifRGBImageAllocatePixels(&rgb);
+                            if (avifRGBImageAllocatePixels(&rgb) != AVIF_RESULT_OK) {
+                                continue;
+                            }
                             avifResult rgbResult = avifImageYUVToRGB(decoder->image, &rgb);
                             // Since avifImageRGBToYUV() ignores rgb.chromaUpsampling, we only need
                             // to test avifImageRGBToYUV() with a single upsamplingsIndex.
@@ -61,9 +63,10 @@
                                                                             decoder->image->height,
                                                                             yuvDepths[yuvDepthsIndex],
                                                                             decoder->image->yuvFormat);
-                                    avifResult yuvResult = avifImageRGBToYUV(tempImage, &rgb);
-                                    if (yuvResult != AVIF_RESULT_OK) {
+                                    if (!tempImage) {
+                                        continue;
                                     }
+                                    (void)avifImageRGBToYUV(tempImage, &rgb);
                                     avifImageDestroy(tempImage);
                                 }
                             }