blob: e90e98ddbecca7560f49f34de79c70fb9aa8ea75 [file] [log] [blame]
import 'dart:math' as math;
import 'dart:typed_data';
import '../image.dart';
import '../image_exception.dart';
import 'hdr_image.dart';
/// Convert a high dynamic range image to a low dynamic range image,
/// with optional exposure control.
Image hdrToImage(HdrImage hdr, {num exposure}) {
num _knee(num x, num f) {
return math.log(x * f + 1.0) / f;
}
num _gamma(num h, num m) {
num x = math.max(0, h * m);
if (x > 1.0) {
x = 1.0 + _knee(x - 1, 0.184874);
}
return math.pow(x, 0.4545) * 84.66;
}
Image image = Image(hdr.width, hdr.height);
Uint8List pixels = image.getBytes();
if (!hdr.hasColor) {
throw new ImageException('Only RGB[A] images are currently supported.');
}
num m = (exposure != null)
? math.pow(2.0, (exposure + 2.47393).clamp(-20.0, 20.0))
: 1.0;
for (int y = 0, di = 0; y < hdr.height; ++y) {
for (int x = 0; x < hdr.width; ++x) {
double r = hdr.getRed(x, y);
double g = hdr.getGreen(x, y);
double b = hdr.getBlue(x, y);
if (r.isInfinite || r.isNaN) {
r = 0.0;
}
if (g.isInfinite || g.isNaN) {
g = 0.0;
}
if (b.isInfinite || b.isNaN) {
b = 0.0;
}
num ri, gi, bi;
if (exposure != null) {
ri = _gamma(r, m);
gi = _gamma(g, m);
bi = _gamma(b, m);
} else {
ri = (r * 255.0);
gi = (g * 255.0);
bi = (b * 255.0);
}
// Normalize the color
num mi = math.max(ri, math.max(gi, bi));
if (mi > 255.0) {
ri = 255.0 * (ri / mi);
gi = 255.0 * (gi / mi);
bi = 255.0 * (bi / mi);
}
pixels[di++] = ri.clamp(0, 255).toInt();
pixels[di++] = gi.clamp(0, 255).toInt();
pixels[di++] = bi.clamp(0, 255).toInt();
if (hdr.alpha != null) {
double a = hdr.alpha.getFloat(x, y);
if (a.isInfinite || a.isNaN) {
a = 1.0;
}
pixels[di++] = (a * 255.0).clamp(0, 255).toInt();
} else {
pixels[di++] = 255;
}
}
}
return image;
}