From cde6417d622e49e18319fb6de987bf229fa9e4f3 Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Mon, 6 Sep 2021 22:48:18 +0200 Subject: [PATCH] Add convertToRGB option to GeoTIFF source --- package-lock.json | 26 ++++-- package.json | 2 +- src/ol/source/GeoTIFF.js | 11 ++- test/browser/spec/ol/source/geotiff.test.js | 92 +++++++++++++-------- 4 files changed, 89 insertions(+), 42 deletions(-) diff --git a/package-lock.json b/package-lock.json index 71d5e0a887..7e2abf04ad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "6.6.2-dev", "license": "BSD-2-Clause", "dependencies": { - "geotiff": "^1.0.4", + "geotiff": "^1.0.5", "ol-mapbox-style": "^6.4.1", "pbf": "3.2.1", "rbush": "^3.0.1" @@ -5354,12 +5354,13 @@ } }, "node_modules/geotiff": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/geotiff/-/geotiff-1.0.4.tgz", - "integrity": "sha512-JmtpvVHlxvyrWgT6Uf0sy7flmXhjWtG0cqVv+G9fMcupV4DAPdTv7tkhsoMnn9RpIIwolveB/VnyII8cRMOD7A==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/geotiff/-/geotiff-1.0.5.tgz", + "integrity": "sha512-PK1dA22HJrgSjpDKXCcmihi/3NOTvAwZRV93pDCAI/bu3JYhgealCPMmzRQ6zJ/osfrrd9U4WXl3IHrwA9hqfg==", "dependencies": { "@petamoriken/float16": "^1.0.7", "content-type-parser": "^1.0.2", + "lerc": "^3.0.0", "lru-cache": "^6.0.0", "pako": "^1.0.11", "parse-headers": "^2.0.2", @@ -7069,6 +7070,11 @@ "lcov-parse": "bin/cli.js" } }, + "node_modules/lerc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lerc/-/lerc-3.0.0.tgz", + "integrity": "sha512-Rm4J/WaHhRa93nCN2mwWDZFoRVF18G1f47C+kvQWyHGEZxFpTUi73p7lMVSAndyxGt6lJ2/CFbOcf9ra5p8aww==" + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -15568,12 +15574,13 @@ "dev": true }, "geotiff": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/geotiff/-/geotiff-1.0.4.tgz", - "integrity": "sha512-JmtpvVHlxvyrWgT6Uf0sy7flmXhjWtG0cqVv+G9fMcupV4DAPdTv7tkhsoMnn9RpIIwolveB/VnyII8cRMOD7A==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/geotiff/-/geotiff-1.0.5.tgz", + "integrity": "sha512-PK1dA22HJrgSjpDKXCcmihi/3NOTvAwZRV93pDCAI/bu3JYhgealCPMmzRQ6zJ/osfrrd9U4WXl3IHrwA9hqfg==", "requires": { "@petamoriken/float16": "^1.0.7", "content-type-parser": "^1.0.2", + "lerc": "^3.0.0", "lru-cache": "^6.0.0", "pako": "^1.0.11", "parse-headers": "^2.0.2", @@ -16856,6 +16863,11 @@ "integrity": "sha1-6w1GtUER68VhrLTECO+TY73I9+A=", "dev": true }, + "lerc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lerc/-/lerc-3.0.0.tgz", + "integrity": "sha512-Rm4J/WaHhRa93nCN2mwWDZFoRVF18G1f47C+kvQWyHGEZxFpTUi73p7lMVSAndyxGt6lJ2/CFbOcf9ra5p8aww==" + }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", diff --git a/package.json b/package.json index 5bfa0cba6b..a478403a72 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "url": "https://opencollective.com/openlayers" }, "dependencies": { - "geotiff": "^1.0.4", + "geotiff": "^1.0.5", "ol-mapbox-style": "^6.4.1", "pbf": "3.2.1", "rbush": "^3.0.1" diff --git a/src/ol/source/GeoTIFF.js b/src/ol/source/GeoTIFF.js index 1ee25e94ff..b417a41a07 100644 --- a/src/ol/source/GeoTIFF.js +++ b/src/ol/source/GeoTIFF.js @@ -261,6 +261,9 @@ function getMaxForDataType(array) { * sources, one with 3 bands and {@link import("./GeoTIFF.js").SourceInfo nodata} configured, and * another with 1 band, the resulting data tiles will have 5 bands: 3 from the first source, 1 alpha * band from the first source, and 1 band from the second source. + * @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} [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 +331,11 @@ class GeoTIFFSource extends DataTile { */ this.error_ = null; + /** + * @type {'readRasters' | 'readRGB'} + */ + this.readMethod_ = options.convertToRGB ? 'readRGB' : 'readRasters'; + this.setKey(this.sourceInfo_.map((source) => source.url).join(',')); const self = this; @@ -563,13 +571,14 @@ class GeoTIFFSource extends DataTile { return bandNumber - 1; }); } - requests[sourceIndex] = image.readRasters({ + requests[sourceIndex] = image[this.readMethod_]({ window: pixelBounds, width: size[0], height: size[1], samples: samples, fillValue: source.nodata, pool: getWorkerPool(), + interleave: false, }); } diff --git a/test/browser/spec/ol/source/geotiff.test.js b/test/browser/spec/ol/source/geotiff.test.js index 80842afeae..c6cd9354d1 100644 --- a/test/browser/spec/ol/source/geotiff.test.js +++ b/test/browser/spec/ol/source/geotiff.test.js @@ -3,46 +3,72 @@ import State from '../../../../../src/ol/source/State.js'; import TileState from '../../../../../src/ol/TileState.js'; describe('ol/source/GeoTIFF', function () { - /** @type {GeoTIFFSource} */ - let source; - beforeEach(function () { - source = new GeoTIFFSource({ - sources: [ - { - url: 'spec/ol/source/images/0-0-0.tif', - }, - ], + describe('constructor', function () { + it('configures readMethod_ to read rasters', function () { + const source = new GeoTIFFSource({ + sources: [ + { + url: 'spec/ol/source/images/0-0-0.tif', + }, + ], + }); + expect(source.readMethod_).to.be('readRasters'); + }); + it('configures readMethod_ to read RGB', function () { + const source = new GeoTIFFSource({ + convertToRGB: true, + sources: [ + { + url: 'spec/ol/source/images/0-0-0.tif', + }, + ], + }); + expect(source.readMethod_).to.be('readRGB'); }); }); - it('manages load states', function (done) { - expect(source.getState()).to.be(State.LOADING); - source.on('change', () => { - expect(source.getState()).to.be(State.READY); - done(); + describe('loading', function () { + /** @type {GeoTIFFSource} */ + let source; + beforeEach(function () { + source = new GeoTIFFSource({ + sources: [ + { + url: 'spec/ol/source/images/0-0-0.tif', + }, + ], + }); }); - }); - it('configures itself from source metadata', function (done) { - source.on('change', () => { - expect(source.addAlpha_).to.be(true); - expect(source.bandCount).to.be(4); - expect(source.nodataValues_).to.eql([[0]]); - expect(source.getTileGrid().getResolutions().length).to.be(1); - expect(source.projection.getCode()).to.be('EPSG:4326'); - expect(source.projection.getUnits()).to.be('degrees'); - done(); - }); - }); - - it('loads tiles', function (done) { - source.on('change', () => { - const tile = source.getTile(0, 0, 0); - source.on('tileloadend', () => { - expect(tile.getState()).to.be(TileState.LOADED); + it('manages load states', function (done) { + expect(source.getState()).to.be(State.LOADING); + source.on('change', () => { + expect(source.getState()).to.be(State.READY); done(); }); - tile.load(); + }); + + it('configures itself from source metadata', function (done) { + source.on('change', () => { + expect(source.addAlpha_).to.be(true); + expect(source.bandCount).to.be(4); + expect(source.nodataValues_).to.eql([[0]]); + expect(source.getTileGrid().getResolutions().length).to.be(1); + expect(source.projection.getCode()).to.be('EPSG:4326'); + expect(source.projection.getUnits()).to.be('degrees'); + done(); + }); + }); + + it('loads tiles', function (done) { + source.on('change', () => { + const tile = source.getTile(0, 0, 0); + source.on('tileloadend', () => { + expect(tile.getState()).to.be(TileState.LOADED); + done(); + }); + tile.load(); + }); }); }); });