readHdr function
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);
}