decodeOpenExr function Assets and loading

DecodedHdr decodeOpenExr(
  1. Uint8List bytes, {
  2. int? maxWidth,
})

Decodes an OpenEXR image from bytes to linear RGBA float pixels (alpha 1), row-major, row 0 at the top (the equirect up pole).

Only 16-bit half-float channels are supported (the common format for HDRI panoramas); a 32-bit-float or uint EXR throws with a clear message rather than decoding to garbage. TODO(exr-float): support 32-bit-float channels (the underlying decoder reads them as 16 bits; needs an upstream fix or a custom float path).

When maxWidth is set and the source is wider, the result is box-downsampled by an integer factor (averaged in linear space) so a very large panorama is not kept at full resolution. Alpha is discarded (set to 1); an environment map is opaque.

Implementation

DecodedHdr decodeOpenExr(Uint8List bytes, {int? maxWidth}) {
  _requireHalfChannels(bytes);
  final image = img.decodeExr(bytes);
  if (image == null) {
    throw ExrFormatException('Not a decodable OpenEXR image');
  }
  final width = image.width;
  final height = image.height;
  // package:image decodes top-down (row 0 = top), matching the equirect up-pole
  // convention, so the scanline order is preserved.
  final pixels = Float32List(width * height * 4);
  var i = 0;
  // The iterator reuses one Pixel, so this stays allocation-light.
  // TODO(exr-perf): read the float image buffer directly if this is a hot path.
  for (final pixel in image) {
    pixels[i] = pixel.r.toDouble();
    pixels[i + 1] = pixel.g.toDouble();
    pixels[i + 2] = pixel.b.toDouble();
    pixels[i + 3] = 1.0;
    i += 4;
  }
  final decoded = DecodedHdr(pixels, width, height);
  if (maxWidth == null || width <= maxWidth) return decoded;
  return boxDownsampleEquirect(decoded, maxWidth);
}