From d7b0191c789bf77007a99e15760605acc4b943b0 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Wed, 29 Sep 2021 10:25:22 -0600 Subject: [PATCH] Support a normalize option on the GeoTIFF source --- src/ol/source/GeoTIFF.js | 52 ++++++++++++++----- .../{geotiff.test.js => GeoTIFF.test.js} | 32 ++++++++++++ 2 files changed, 72 insertions(+), 12 deletions(-) rename test/browser/spec/ol/source/{geotiff.test.js => GeoTIFF.test.js} (71%) diff --git a/src/ol/source/GeoTIFF.js b/src/ol/source/GeoTIFF.js index 2ddf191018..eadf679630 100644 --- a/src/ol/source/GeoTIFF.js +++ b/src/ol/source/GeoTIFF.js @@ -273,6 +273,10 @@ function getMaxForDataType(array) { * @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 * 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 {number} [transition=250] Duration of the opacity transition for rendering. * To disable the opacity transition, pass `transition: 0`. @@ -328,6 +332,12 @@ class GeoTIFFSource extends DataTile { */ this.nodataValues_; + /** + * @type {boolean} + * @private + */ + this.normalize_ = options.normalize !== false; + /** * @type {boolean} * @private @@ -603,25 +613,37 @@ class GeoTIFFSource extends DataTile { const pixelCount = size[0] * size[1]; const dataLength = pixelCount * bandCount; const nodataValues = this.nodataValues_; + const normalize = this.normalize_; 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; for (let pixelIndex = 0; pixelIndex < pixelCount; ++pixelIndex) { let transparent = addAlpha; for (let sourceIndex = 0; sourceIndex < sourceCount; ++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); - const bias = -min * gain; + let min = source.min; + 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 ( let sampleIndex = 0; @@ -631,7 +653,13 @@ class GeoTIFFSource extends DataTile { const sourceValue = 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) { data[dataIndex] = value; } else { diff --git a/test/browser/spec/ol/source/geotiff.test.js b/test/browser/spec/ol/source/GeoTIFF.test.js similarity index 71% rename from test/browser/spec/ol/source/geotiff.test.js rename to test/browser/spec/ol/source/GeoTIFF.test.js index 588c1b88a8..2ad410dacf 100644 --- a/test/browser/spec/ol/source/geotiff.test.js +++ b/test/browser/spec/ol/source/GeoTIFF.test.js @@ -14,6 +14,7 @@ describe('ol/source/GeoTIFF', function () { }); expect(source.readMethod_).to.be('readRasters'); }); + it('configures readMethod_ to read RGB', function () { const source = new GeoTIFFSource({ convertToRGB: true, @@ -25,6 +26,37 @@ describe('ol/source/GeoTIFF', function () { }); 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 () {