From e8ead306ffe40ce06270cd552f371636fe526bb2 Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Fri, 6 Aug 2021 22:05:15 +0200 Subject: [PATCH] Remove multi-source restrictions and fix alpha --- examples/cog-math-multisource.html | 3 +- examples/cog-math-multisource.js | 15 +++---- src/ol/source/GeoTIFF.js | 63 ++++++++++++------------------ 3 files changed, 36 insertions(+), 45 deletions(-) diff --git a/examples/cog-math-multisource.html b/examples/cog-math-multisource.html index 08e09a0105..b5889c5bfe 100644 --- a/examples/cog-math-multisource.html +++ b/examples/cog-math-multisource.html @@ -6,7 +6,8 @@ docs: > The GeoTIFF layer in this example calculates the Normalized Difference Vegetation Index (NDVI) and Normalized Difference Water Index (NDWI) from two cloud-optimized Sentinel 2 GeoTIFFs: one with 10 m resolution and red and a near infrared bands, and one with 60 m resolution and a short - wave infrared channel. The NDVI is shown as green, the NDWI as blue. + wave infrared channel. The NDVI is shown as green, the NDWI as blue. The 4th band is the alpha + band, which gets added when a source has a `nodata` value configured. tags: "cog, ndvi, ndwi, sentinel, geotiff" ---
diff --git a/examples/cog-math-multisource.js b/examples/cog-math-multisource.js index e585b24305..0ba74e9d80 100644 --- a/examples/cog-math-multisource.js +++ b/examples/cog-math-multisource.js @@ -7,17 +7,16 @@ const source = new GeoTIFF({ sources: [ { url: 'https://s2downloads.eox.at/demo/Sentinel-2/3857/R10m.tif', - samples: [2], - max: 65535, - }, - { - url: 'https://s2downloads.eox.at/demo/Sentinel-2/3857/R10m.tif', - samples: [3], + bands: [2, 3], + min: 0, + nodata: 0, max: 65535, }, { url: 'https://s2downloads.eox.at/demo/Sentinel-2/3857/R60m.tif', - samples: [8], + bands: [8], + min: 0, + nodata: 0, max: 65535, }, ], @@ -51,6 +50,8 @@ const map = new Map({ ['*', 255, ndvi], // blue: NDWI ['*', 255, ndwi], + // alpha + ['band', 4], ], }, source, diff --git a/src/ol/source/GeoTIFF.js b/src/ol/source/GeoTIFF.js index 6465b406e8..3cc6c45d9a 100644 --- a/src/ol/source/GeoTIFF.js +++ b/src/ol/source/GeoTIFF.js @@ -18,9 +18,10 @@ import {toSize} from '../size.js'; * the configured min and max. * @property {number} [max] The maximum source data value. Rendered values are scaled from 0 to 1 based on * the configured min and max. - * @property {number} [nodata] Values to discard. - * @property {Array} [samples] Indices of the samples to be read from. If not provided, all samples - * will be read. + * @property {number} [nodata] Values to discard. When provided, an additional band (alpha) will be added + * to the data. + * @property {Array} [bands] Indices of the bands to be read from. If not provided, all bands will + * be read. */ let workerPool; @@ -179,7 +180,7 @@ class GeoTIFFSource extends DataTile { this.resolutionFactors_ = new Array(numSources); /** - * @type {number} + * @type {Array} * @private */ this.samplesPerPixel_; @@ -239,7 +240,7 @@ class GeoTIFFSource extends DataTile { let origin; let tileSizes; let resolutions; - let samplesPerPixel; + const samplesPerPixel = new Array(sources.length); let minZoom = 0; const sourceCount = sources.length; @@ -254,16 +255,10 @@ class GeoTIFFSource extends DataTile { for (let imageIndex = 0; imageIndex < imageCount; ++imageIndex) { const image = images[imageIndex]; - const wantedSamples = this.sourceInfo_[sourceIndex].samples; - const imageSamplesPerPixel = wantedSamples + const wantedSamples = this.sourceInfo_[sourceIndex].bands; + samplesPerPixel[sourceIndex] = wantedSamples ? wantedSamples.length : image.getSamplesPerPixel(); - if (!samplesPerPixel) { - samplesPerPixel = imageSamplesPerPixel; - } else { - const message = `Band count mismatch for source ${sourceIndex}, got ${imageSamplesPerPixel} but expected ${samplesPerPixel}`; - assertEqual(samplesPerPixel, imageSamplesPerPixel, 0, message); - } const level = imageCount - (imageIndex + 1); if (!sourceExtent) { @@ -347,12 +342,6 @@ class GeoTIFFSource extends DataTile { } } - if (sourceCount > 1 && samplesPerPixel !== 1) { - throw new Error( - 'Expected single band GeoTIFFs when using multiple sources' - ); - } - this.samplesPerPixel_ = samplesPerPixel; const sourceInfo = this.sourceInfo_; for (let sourceIndex = 0; sourceIndex < sourceCount; ++sourceIndex) { @@ -361,15 +350,12 @@ class GeoTIFFSource extends DataTile { break; } } - let additionalBands = 0; - if (this.addAlpha_) { - if (sourceCount === 2 && samplesPerPixel === 1) { - additionalBands = 2; - } else { - additionalBands = 1; - } - } - this.bandCount = samplesPerPixel * sourceCount + additionalBands; + const additionalBands = this.addAlpha_ ? 1 : 0; + this.bandCount = + samplesPerPixel.reduce((accumulator, value) => { + accumulator += value; + return accumulator; + }, 0) + additionalBands; const tileGrid = new TileGrid({ extent: extent, @@ -408,7 +394,8 @@ class GeoTIFFSource extends DataTile { window: pixelBounds, width: size[0], height: size[1], - samples: source.samples, + samples: source.bands, + fillValue: source.nodata, pool: getWorkerPool(), }); } @@ -418,9 +405,9 @@ class GeoTIFFSource extends DataTile { return Promise.all(requests).then(function (sourceSamples) { const data = new Uint8ClampedArray(dataLength); + let dataIndex = 0; for (let pixelIndex = 0; pixelIndex < pixelCount; ++pixelIndex) { let transparent = addAlpha; - const sourceOffset = pixelIndex * bandCount; for (let sourceIndex = 0; sourceIndex < sourceCount; ++sourceIndex) { const source = sourceInfo[sourceIndex]; let min = source.min; @@ -437,10 +424,9 @@ class GeoTIFFSource extends DataTile { const nodata = source.nodata; - const sampleOffset = sourceOffset + sourceIndex * samplesPerPixel; for ( let sampleIndex = 0; - sampleIndex < samplesPerPixel; + sampleIndex < samplesPerPixel[sourceIndex]; ++sampleIndex ) { const sourceValue = @@ -448,18 +434,21 @@ class GeoTIFFSource extends DataTile { const value = gain * sourceValue + bias; if (!addAlpha) { - data[sampleOffset + sampleIndex] = value; + data[dataIndex] = value; } else { if (sourceValue !== nodata) { transparent = false; - data[sampleOffset + sampleIndex] = value; + data[dataIndex] = value; } } + dataIndex++; } - - if (addAlpha && !transparent) { - data[sampleOffset + samplesPerPixel] = 255; + } + if (addAlpha) { + if (!transparent) { + data[dataIndex] = 255; } + dataIndex++; } }