Support a normalize option on the GeoTIFF source
This commit is contained in:
+40
-12
@@ -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 {
|
||||||
|
|||||||
+32
@@ -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 () {
|
||||||
Reference in New Issue
Block a user