Support a normalize option on the GeoTIFF source

This commit is contained in:
Tim Schaub
2021-09-29 10:25:22 -06:00
parent 5f118b0244
commit d7b0191c78
2 changed files with 72 additions and 12 deletions
+40 -12
View File
@@ -273,6 +273,10 @@ function getMaxForDataType(array) {
* @property {boolean} [convertToRGB = false] By default, bands from the sources are read as-is. When * @property {boolean} [convertToRGB = false] By default, bands from the sources are read as-is. When
* reading GeoTIFFs with the purpose of displaying them as RGB images, setting this to `true` will * reading GeoTIFFs with the purpose of displaying them as RGB images, setting this to `true` will
* convert other color spaces (YCbCr, CMYK) to RGB. * convert other color spaces (YCbCr, CMYK) to RGB.
* @property {boolean} [normalize=true] By default, the source data is normalized to values between
* 0 and 1 with scaling factors based on the `min` and `max` properties of each source. If instead
* you want to work with the raw values in a style expression, set this to `false`. Setting this option
* to `false` will make it so any `min` and `max` properties on sources are ignored.
* @property {boolean} [opaque=false] Whether the layer is opaque. * @property {boolean} [opaque=false] Whether the layer is opaque.
* @property {number} [transition=250] Duration of the opacity transition for rendering. * @property {number} [transition=250] Duration of the opacity transition for rendering.
* To disable the opacity transition, pass `transition: 0`. * To disable the opacity transition, pass `transition: 0`.
@@ -328,6 +332,12 @@ class GeoTIFFSource extends DataTile {
*/ */
this.nodataValues_; this.nodataValues_;
/**
* @type {boolean}
* @private
*/
this.normalize_ = options.normalize !== false;
/** /**
* @type {boolean} * @type {boolean}
* @private * @private
@@ -603,25 +613,37 @@ class GeoTIFFSource extends DataTile {
const pixelCount = size[0] * size[1]; const pixelCount = size[0] * size[1];
const dataLength = pixelCount * bandCount; const dataLength = pixelCount * bandCount;
const nodataValues = this.nodataValues_; const nodataValues = this.nodataValues_;
const normalize = this.normalize_;
return Promise.all(requests).then(function (sourceSamples) { return Promise.all(requests).then(function (sourceSamples) {
const data = new Uint8Array(dataLength); /** @type {Uint8Array|Float32Array} */
let data;
if (normalize) {
data = new Uint8Array(dataLength);
} else {
data = new Float32Array(dataLength);
}
let dataIndex = 0; let dataIndex = 0;
for (let pixelIndex = 0; pixelIndex < pixelCount; ++pixelIndex) { for (let pixelIndex = 0; pixelIndex < pixelCount; ++pixelIndex) {
let transparent = addAlpha; let transparent = addAlpha;
for (let sourceIndex = 0; sourceIndex < sourceCount; ++sourceIndex) { for (let sourceIndex = 0; sourceIndex < sourceCount; ++sourceIndex) {
const source = sourceInfo[sourceIndex]; const source = sourceInfo[sourceIndex];
let min = source.min;
if (min === undefined) {
min = getMinForDataType(sourceSamples[sourceIndex][0]);
}
let max = source.max;
if (max === undefined) {
max = getMaxForDataType(sourceSamples[sourceIndex][0]);
}
const gain = 255 / (max - min); let min = source.min;
const bias = -min * gain; let max = source.max;
let gain, bias;
if (normalize) {
if (min === undefined) {
min = getMinForDataType(sourceSamples[sourceIndex][0]);
}
if (max === undefined) {
max = getMaxForDataType(sourceSamples[sourceIndex][0]);
}
gain = 255 / (max - min);
bias = -min * gain;
}
for ( for (
let sampleIndex = 0; let sampleIndex = 0;
@@ -631,7 +653,13 @@ class GeoTIFFSource extends DataTile {
const sourceValue = const sourceValue =
sourceSamples[sourceIndex][sampleIndex][pixelIndex]; sourceSamples[sourceIndex][sampleIndex][pixelIndex];
const value = clamp(gain * sourceValue + bias, 0, 255); let value;
if (normalize) {
value = clamp(gain * sourceValue + bias, 0, 255);
} else {
value = sourceValue;
}
if (!addAlpha) { if (!addAlpha) {
data[dataIndex] = value; data[dataIndex] = value;
} else { } else {
@@ -14,6 +14,7 @@ describe('ol/source/GeoTIFF', function () {
}); });
expect(source.readMethod_).to.be('readRasters'); expect(source.readMethod_).to.be('readRasters');
}); });
it('configures readMethod_ to read RGB', function () { it('configures readMethod_ to read RGB', function () {
const source = new GeoTIFFSource({ const source = new GeoTIFFSource({
convertToRGB: true, convertToRGB: true,
@@ -25,6 +26,37 @@ describe('ol/source/GeoTIFF', function () {
}); });
expect(source.readMethod_).to.be('readRGB'); expect(source.readMethod_).to.be('readRGB');
}); });
it('generates Float32Array data if normalize is set to false', (done) => {
const source = new GeoTIFFSource({
normalize: false,
sources: [{url: 'spec/ol/source/images/0-0-0.tif'}],
});
source.on('change', () => {
const tile = source.getTile(0, 0, 0);
source.on('tileloadend', () => {
expect(tile.getState()).to.be(TileState.LOADED);
expect(tile.getData()).to.be.a(Float32Array);
done();
});
tile.load();
});
});
it('generates Uint8Array data if normalize is not set to false', (done) => {
const source = new GeoTIFFSource({
sources: [{url: 'spec/ol/source/images/0-0-0.tif'}],
});
source.on('change', () => {
const tile = source.getTile(0, 0, 0);
source.on('tileloadend', () => {
expect(tile.getState()).to.be(TileState.LOADED);
expect(tile.getData()).to.be.a(Uint8Array);
done();
});
tile.load();
});
});
}); });
describe('loading', function () { describe('loading', function () {