Skip to content

Commit

Permalink
Fix channel order when encoding EXR files.
Browse files Browse the repository at this point in the history
Fixes #2070.
  • Loading branch information
slime73 committed Aug 3, 2024
1 parent d73ad9e commit 29ae5e6
Showing 1 changed file with 17 additions and 6 deletions.
23 changes: 17 additions & 6 deletions src/modules/image/magpie/EXRHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,15 +125,15 @@ static T *readEXRChannels(int width, int height, T *rgba[4], T one)
}

template <typename T>
static void writeEXRChannels(int width, int height, int components, const T *pixels, T *rgba[4])
static void writeEXRChannels(int width, int height, int components, const int *channelmapping, const T *pixels, T *rgba[4])
{
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
size_t offset = y * width + x;
for (int c = 0; c < components; c++)
rgba[c][offset] = pixels[offset * components + c];
rgba[channelmapping[c]][offset] = pixels[offset * components + c];
}
}
}
Expand Down Expand Up @@ -303,12 +303,23 @@ FormatHandler::EncodedImage EXRHandler::encode(const DecodedImage &img, EncodedF
throw love::Exception("Cannot convert the given pixel format to an EXR pixel type.");
}

// EXR parsers tend to only handle (A)BGR order,
// the spec says channels should be stored alphabetically.
const int channelmappings[4][4] = {
{0},
{1, 0},
{2, 1, 0},
{3, 2, 1, 0},
};

const int *channelmapping = channelmappings[exrHeader.num_channels - 1];

for (int i = 0; i < exrHeader.num_channels; i++)
{
exrHeader.channels[i] = EXRChannelInfo();

const char names[] = {'R', 'G', 'B', 'A'};
exrHeader.channels[i].name[0] = names[i];
exrHeader.channels[i].name[0] = names[channelmapping[i]];

exrHeader.pixel_types[i] = pixeltype;
exrHeader.requested_pixel_types[i] = pixeltype;
Expand Down Expand Up @@ -339,15 +350,15 @@ FormatHandler::EncodedImage EXRHandler::encode(const DecodedImage &img, EncodedF

if (pixeltype == TINYEXR_PIXELTYPE_UINT)
{
writeEXRChannels(img.width, img.height, formatinfo.components, (const uint32 *) img.data, (uint32 **) exrImage.images);
writeEXRChannels(img.width, img.height, formatinfo.components, channelmapping, (const uint32 *) img.data, (uint32 **) exrImage.images);
}
else if (pixeltype == TINYEXR_PIXELTYPE_HALF)
{
writeEXRChannels(img.width, img.height, formatinfo.components, (const float16 *) img.data, (float16 **) exrImage.images);
writeEXRChannels(img.width, img.height, formatinfo.components, channelmapping, (const float16 *) img.data, (float16 **) exrImage.images);
}
else if (pixeltype == TINYEXR_PIXELTYPE_FLOAT)
{
writeEXRChannels(img.width, img.height, formatinfo.components, (const float *) img.data, (float **) exrImage.images);
writeEXRChannels(img.width, img.height, formatinfo.components, channelmapping, (const float *) img.data, (float **) exrImage.images);
}

EncodedImage encimg;
Expand Down

0 comments on commit 29ae5e6

Please sign in to comment.