dwa_uncompress() writes the RLE section, which carries the alpha channel,
to slot 0, and guards that with nb_channels >= 4. That is a proxy for
"this image has an alpha channel" and it is wrong as soon as the image
carries other channels instead. With four or more channels and no alpha,
slot 0 belongs to B, and the RLE data overwrites the blue plane. Whether
it does depends on whether the encoder placed any channel into the RLE
section, so the same channel list decodes correctly or loses its blue
depending on the file.

Test the actual condition instead: the alpha channel has to be the one
sitting in slot 0.

The patch is attached as git format-patch output.
From 68472d1b10103688bca6f2b2472607c83ee8adc1 Mon Sep 17 00:00:00 2001
From: Nexory <[email protected]>
Date: Sat, 22 Aug 2026 15:51:24 +0200
Subject: [PATCH 1/2] avcodec/exr: Write the DWA alpha slot only when alpha
 occupies it

dwa_uncompress() writes the RLE section, which carries the alpha channel,
to slot 0, and guards that with nb_channels >= 4. That is a proxy for
"this image has an alpha channel" and it is wrong as soon as the image
carries other channels instead. With four or more channels and no alpha,
slot 0 belongs to B, and the RLE data overwrites the blue plane. Whether
it does depends on whether the encoder placed any channel into the RLE
section, so the same channel list decodes correctly or loses its blue
depending on the file.

Test the actual condition instead: the alpha channel has to be the one
sitting in slot 0.

Signed-off-by: Nexory <[email protected]>
---
 libavcodec/exr.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/libavcodec/exr.c b/libavcodec/exr.c
index 0e9c734a..cbd80d75 100644
--- a/libavcodec/exr.c
+++ b/libavcodec/exr.c
@@ -1210,7 +1210,13 @@ static int dwa_uncompress(const EXRContext *s, const uint8_t *src, int compresse
         }
     }
 
-    if (s->nb_channels < 4)
+    /* The RLE section carries the alpha channel, and the loops below write it
+     * to slot 0. nb_channels >= 4 is only a proxy for "this image has an alpha
+     * channel"; the accurate test is that the alpha channel is the one sitting
+     * in slot 0. Without it an image that carries extra channels after B, G
+     * and R loses its blue plane whenever the encoder put a channel into the
+     * RLE section. */
+    if (s->channel_offsets[3] != 0)
         return 0;
 
     if (s->pixel_type == EXR_HALF) {
-- 
2.47.3

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to