readHdr function

HdrImage readHdr(
  1. Uint8List bytes
)

bytes as an HDR image.

Throws HdrFormatException for anything this cannot read, naming what it found rather than what it wanted.

Implementation

HdrImage readHdr(Uint8List bytes) {
  final _Header header = _readHeader(bytes);
  final int width = header.width;
  final int height = header.height;
  var at = header.pixelsFrom;

  // The fewest bytes a scanline can take: a run-length row is its four-byte
  // marker and, per channel, a two-byte run for every 127 pixels; a flat row
  // is four bytes a pixel. A header that names more rows than the file could
  // hold is refused here, before the float buffer it sizes is allocated.
  final int leastPerRow = width >= 8 && width < 32768
      ? 4 + 4 * 2 * ((width + 126) ~/ 127)
      : 4 * width;
  if (height * leastPerRow > bytes.length - at) {
    throw HdrFormatException(
      'a $width by $height image runs off the end of the file: '
      '${bytes.length - at} bytes of pixels cannot hold that many rows',
    );
  }

  final Float32List rgb = Float32List(width * height * 3);
  final Uint8List scanline = Uint8List(width * 4);

  for (var y = 0; y < height; y++) {
    at = _readScanline(bytes, at, scanline, width, y);
    for (var x = 0; x < width; x++) {
      final int e = scanline[x * 4 + 3];
      // Exponent zero is Radiance's own "black": the mantissas are ignored
      // rather than scaled by 2^-136, which would be a denormal.
      final double scale = e == 0 ? 0.0 : _exponent(e);
      final int out = (y * width + x) * 3;
      rgb[out] = scanline[x * 4] * scale;
      rgb[out + 1] = scanline[x * 4 + 1] * scale;
      rgb[out + 2] = scanline[x * 4 + 2] * scale;
    }
  }
  return (width: width, height: height, rgb: rgb);
}