diff --git a/src/ol/source/GeoTIFF.js b/src/ol/source/GeoTIFF.js index 07ec7e6b91..27843c5992 100644 --- a/src/ol/source/GeoTIFF.js +++ b/src/ol/source/GeoTIFF.js @@ -5,6 +5,7 @@ import DataTile from './DataTile.js'; import TileGrid from '../tilegrid/TileGrid.js'; import { Pool, + globals as geotiffGlobals, fromBlob as tiffFromBlob, fromUrl as tiffFromUrl, fromUrls as tiffFromUrls, @@ -31,6 +32,31 @@ function isMask(image) { return (type & 4) === 4; } +/** + * @param {true|false|'auto'} preference The convertToRGB option. + * @param {GeoTIFFImage} image The image. + * @return {boolean} Use the `image.readRGB()` method. + */ +function readRGB(preference, image) { + if (!preference) { + return false; + } + if (preference === true) { + return true; + } + if (image.getSamplesPerPixel() !== 3) { + return false; + } + const interpretation = image.fileDirectory.PhotometricInterpretation; + const interpretations = geotiffGlobals.photometricInterpretations; + return ( + interpretation === interpretations.CMYK || + interpretation === interpretations.YCbCr || + interpretation === interpretations.CIELab || + interpretation === interpretations.ICCLab + ); +} + /** * @typedef {Object} SourceInfo * @property {string} [url] URL for the source GeoTIFF. @@ -320,9 +346,10 @@ function getMaxForDataType(array) { * 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 {GeoTIFFSourceOptions} [sourceOptions] Additional options to be passed to [geotiff.js](https://geotiffjs.github.io/geotiff.js/module-geotiff.html)'s `fromUrl` or `fromUrls` methods. - * @property {boolean} [convertToRGB = false] By default, bands from the sources are read as-is. When + * @property {true|false|'auto'} [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. + * convert other color spaces (YCbCr, CMYK) to RGB. Setting the option to `'auto'` will make it so CMYK, YCbCr, + * CIELab, and ICCLab images will automatically be converted 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 raster statistics or `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 @@ -424,9 +451,9 @@ class GeoTIFFSource extends DataTile { this.error_ = null; /** - * @type {'readRasters' | 'readRGB'} + * @type {true|false|'auto'} */ - this.readMethod_ = options.convertToRGB ? 'readRGB' : 'readRasters'; + this.convertToRGB_ = options.convertToRGB || false; this.setKey(this.sourceInfo_.map((source) => source.url).join(',')); @@ -747,7 +774,7 @@ class GeoTIFFSource extends DataTile { } } - requests[sourceIndex] = image[this.readMethod_]({ + const readOptions = { window: pixelBounds, width: sourceTileSize[0], height: sourceTileSize[1], @@ -755,7 +782,12 @@ class GeoTIFFSource extends DataTile { fillValue: fillValue, pool: pool, interleave: false, - }); + }; + if (readRGB(this.convertToRGB_, image)) { + requests[sourceIndex] = image.readRGB(readOptions); + } else { + requests[sourceIndex] = image.readRasters(readOptions); + } // requests after `sourceCount` are for mask data (if any) const maskIndex = sourceCount + sourceIndex; diff --git a/test/browser/spec/ol/source/GeoTIFF.test.js b/test/browser/spec/ol/source/GeoTIFF.test.js index 8db17f449a..ba8cae8dc0 100644 --- a/test/browser/spec/ol/source/GeoTIFF.test.js +++ b/test/browser/spec/ol/source/GeoTIFF.test.js @@ -3,7 +3,7 @@ import TileState from '../../../../../src/ol/TileState.js'; describe('ol/source/GeoTIFF', function () { describe('constructor', function () { - it('configures readMethod_ to read rasters', function () { + it('sets convertToRGB false by default', function () { const source = new GeoTIFFSource({ sources: [ { @@ -11,10 +11,10 @@ describe('ol/source/GeoTIFF', function () { }, ], }); - expect(source.readMethod_).to.be('readRasters'); + expect(source.convertToRGB_).to.be(false); }); - it('configures readMethod_ to read RGB', function () { + it('respects the convertToRGB option', function () { const source = new GeoTIFFSource({ convertToRGB: true, sources: [ @@ -23,7 +23,19 @@ describe('ol/source/GeoTIFF', function () { }, ], }); - expect(source.readMethod_).to.be('readRGB'); + expect(source.convertToRGB_).to.be(true); + }); + + it('accepts auto convertToRGB', function () { + const source = new GeoTIFFSource({ + convertToRGB: 'auto', + sources: [ + { + url: 'spec/ol/source/images/0-0-0.tif', + }, + ], + }); + expect(source.convertToRGB_).to.be('auto'); }); it('defaults to wrapX: false', function () { diff --git a/test/rendering/cases/cog-rgb-auto/expected.png b/test/rendering/cases/cog-rgb-auto/expected.png new file mode 100644 index 0000000000..9d9f82a22a Binary files /dev/null and b/test/rendering/cases/cog-rgb-auto/expected.png differ diff --git a/test/rendering/cases/cog-rgb-auto/main.js b/test/rendering/cases/cog-rgb-auto/main.js new file mode 100644 index 0000000000..17e943198f --- /dev/null +++ b/test/rendering/cases/cog-rgb-auto/main.js @@ -0,0 +1,22 @@ +import GeoTIFF from '../../../../src/ol/source/GeoTIFF.js'; +import Map from '../../../../src/ol/Map.js'; +import TileLayer from '../../../../src/ol/layer/WebGLTile.js'; + +const source = new GeoTIFF({ + convertToRGB: 'auto', + sources: [{url: '/data/raster/masked.tif'}], +}); + +new Map({ + layers: [ + new TileLayer({ + source: source, + }), + ], + target: 'map', + view: source.getView(), +}); + +render({ + message: 'automatically converts to rgb', +}); diff --git a/test/rendering/cases/cog-rgb-no-auto/expected.png b/test/rendering/cases/cog-rgb-no-auto/expected.png new file mode 100644 index 0000000000..4c3063e978 Binary files /dev/null and b/test/rendering/cases/cog-rgb-no-auto/expected.png differ diff --git a/test/rendering/cases/cog-rgb-no-auto/main.js b/test/rendering/cases/cog-rgb-no-auto/main.js new file mode 100644 index 0000000000..dc1c808cfe --- /dev/null +++ b/test/rendering/cases/cog-rgb-no-auto/main.js @@ -0,0 +1,22 @@ +import GeoTIFF from '../../../../src/ol/source/GeoTIFF.js'; +import Map from '../../../../src/ol/Map.js'; +import TileLayer from '../../../../src/ol/layer/WebGLTile.js'; + +const source = new GeoTIFF({ + convertToRGB: false, + sources: [{url: '/data/raster/masked.tif'}], +}); + +new Map({ + layers: [ + new TileLayer({ + source: source, + }), + ], + target: 'map', + view: source.getView(), +}); + +render({ + message: 'can be overridden to read raw YCbCr', +});