Round dimensions down when decoding subsampled YUV with odd dimensions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b48ce47..1ea5718 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@
 
 ### Changed
 - avifenc - Removed accidental double-delete of avifImage when failing to read a y4m file input
+- Round dimensions down when decoding subsampled YUV with odd dimensions
 
 ## [0.5.2] - 2019-11-23
 ### Changed
diff --git a/include/avif/internal.h b/include/avif/internal.h
index f4d39ed..fe2edf5 100644
--- a/include/avif/internal.h
+++ b/include/avif/internal.h
@@ -12,6 +12,7 @@
 
 // Yes, clamp macros are nasty. Do not use them.
 #define AVIF_CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
+#define AVIF_MIN(a, b) (((a) < (b)) ? (a) : (b))
 
 // Used by stream related things.
 #define CHECK(A)               \
diff --git a/src/reformat.c b/src/reformat.c
index bf71940..0278fdf 100644
--- a/src/reformat.c
+++ b/src/reformat.c
@@ -190,12 +190,14 @@
     const float kr = state->kr;
     const float kg = state->kg;
     const float kb = state->kb;
+    const uint32_t maxUVI = (image->width > 1) ? (image->width >> state->formatInfo.chromaShiftX) - 1 : 0;
+    const uint32_t maxUVJ = (image->height > 1) ? (image->height >> state->formatInfo.chromaShiftY) - 1 : 0;
 
     float maxChannel = (float)((1 << image->depth) - 1);
     uint8_t ** rgbPlanes = image->rgbPlanes;
     uint32_t * rgbRowBytes = image->rgbRowBytes;
     for (uint32_t j = 0; j < image->height; ++j) {
-        const int uvJ = j >> state->formatInfo.chromaShiftY;
+        const uint32_t uvJ = AVIF_MIN(j >> state->formatInfo.chromaShiftY, maxUVJ);
         uint16_t * ptrY = (uint16_t *)&image->yuvPlanes[AVIF_CHAN_Y][(j * image->yuvRowBytes[AVIF_CHAN_Y])];
         uint16_t * ptrU = (uint16_t *)&image->yuvPlanes[AVIF_CHAN_U][(uvJ * image->yuvRowBytes[AVIF_CHAN_U])];
         uint16_t * ptrV = (uint16_t *)&image->yuvPlanes[AVIF_CHAN_V][(uvJ * image->yuvRowBytes[AVIF_CHAN_V])];
@@ -205,7 +207,7 @@
 
         for (uint32_t i = 0; i < image->width; ++i) {
             // Unpack YUV into unorm
-            const int uvI = i >> state->formatInfo.chromaShiftX;
+            uint32_t uvI = AVIF_MIN(i >> state->formatInfo.chromaShiftX, maxUVI);
             uint32_t unormY = ptrY[i];
             uint32_t unormU = ptrU[uvI];
             uint32_t unormV = ptrV[uvI];
@@ -286,12 +288,14 @@
     const float kr = state->kr;
     const float kg = state->kg;
     const float kb = state->kb;
+    const uint32_t maxUVI = (image->width > 1) ? (image->width >> state->formatInfo.chromaShiftX) - 1 : 0;
+    const uint32_t maxUVJ = (image->height > 1) ? (image->height >> state->formatInfo.chromaShiftY) - 1 : 0;
 
     float maxChannel = (float)((1 << image->depth) - 1);
     uint8_t ** rgbPlanes = image->rgbPlanes;
     uint32_t * rgbRowBytes = image->rgbRowBytes;
     for (uint32_t j = 0; j < image->height; ++j) {
-        int uvJ = j >> state->formatInfo.chromaShiftY;
+        const uint32_t uvJ = AVIF_MIN(j >> state->formatInfo.chromaShiftY, maxUVJ);
         uint8_t * ptrY = &image->yuvPlanes[AVIF_CHAN_Y][(j * image->yuvRowBytes[AVIF_CHAN_Y])];
         uint8_t * ptrU = &image->yuvPlanes[AVIF_CHAN_U][(uvJ * image->yuvRowBytes[AVIF_CHAN_U])];
         uint8_t * ptrV = &image->yuvPlanes[AVIF_CHAN_V][(uvJ * image->yuvRowBytes[AVIF_CHAN_V])];
@@ -301,7 +305,7 @@
 
         for (uint32_t i = 0; i < image->width; ++i) {
             // Unpack YUV into unorm
-            const int uvI = i >> state->formatInfo.chromaShiftX;
+            uint32_t uvI = AVIF_MIN(i >> state->formatInfo.chromaShiftX, maxUVI);
             uint32_t unormY = ptrY[i];
             uint32_t unormU = ptrU[uvI];
             uint32_t unormV = ptrV[uvI];