diff --git a/examples/cog-blob.html b/examples/cog-blob.html new file mode 100644 index 0000000000..f876e635ce --- /dev/null +++ b/examples/cog-blob.html @@ -0,0 +1,10 @@ +--- +layout: example.html +title: Cloud Optimized GeoTIFF (COG) from a Blob +shortdesc: Rendering a COG as a tiled layer from a Blob. +docs: > + Tiled data from a Cloud Optimized GeoTIFF (COG) can be rendered as a layer. In this + example, a single 3-band GeoTIFF is used to render RGB data from a Blob. +tags: "cog" +--- +
diff --git a/examples/cog-blob.js b/examples/cog-blob.js new file mode 100644 index 0000000000..0d16dd0273 --- /dev/null +++ b/examples/cog-blob.js @@ -0,0 +1,28 @@ +import GeoTIFF from '../src/ol/source/GeoTIFF.js'; +import Map from '../src/ol/Map.js'; +import TileLayer from '../src/ol/layer/WebGLTile.js'; + +fetch('data/example.tif') + .then((response) => response.blob()) + .then((blob) => { + const source = new GeoTIFF({ + sources: [ + { + blob: blob, + }, + ], + }); + + const map = new Map({ + target: 'map', + layers: [ + new TileLayer({ + source: source, + }), + ], + view: source.getView().then((viewConfig) => { + viewConfig.showFullExtent = true; + return viewConfig; + }), + }); + }); diff --git a/examples/data/example.tif b/examples/data/example.tif new file mode 100644 index 0000000000..6ee9b0e226 Binary files /dev/null and b/examples/data/example.tif differ diff --git a/examples/resources/common.js b/examples/resources/common.js index d7b4db7682..c210631f7c 100644 --- a/examples/resources/common.js +++ b/examples/resources/common.js @@ -9,7 +9,7 @@ function fetchResource(resource) { return new Promise(function (resolve, reject) { - const isImage = /\.(png|jpe?g|gif|tiff|svg|kmz)$/.test(resource); + const isImage = /\.(png|jpe?g|gif|tiff?|svg|kmz)$/.test(resource); if (isImage) { resolve ({ isBinary: true, diff --git a/src/ol/source/GeoTIFF.js b/src/ol/source/GeoTIFF.js index 2188a297b1..c252877be9 100644 --- a/src/ol/source/GeoTIFF.js +++ b/src/ol/source/GeoTIFF.js @@ -4,7 +4,12 @@ import DataTile from './DataTile.js'; import State from './State.js'; import TileGrid from '../tilegrid/TileGrid.js'; -import {Pool, fromUrl as tiffFromUrl, fromUrls as tiffFromUrls} from 'geotiff'; +import { + Pool, + fromBlob as tiffFromBlob, + fromUrl as tiffFromUrl, + fromUrls as tiffFromUrls, +} from 'geotiff'; import { Projection, get as getCachedProjection, @@ -17,8 +22,9 @@ import {fromCode as unitsFromCode} from '../proj/Units.js'; /** * @typedef {Object} SourceInfo - * @property {string} url URL for the source GeoTIFF. - * @property {Array} [overviews] List of any overview URLs. + * @property {string} [url] URL for the source GeoTIFF. + * @property {Array} [overviews] List of any overview URLs, only applies if the url parameter is given. + * @property {Blob} [blob] Blob containing the source GeoTIFF. `blob` and `url` are mutually exclusive. * @property {number} [min=0] The minimum source data value. Rendered values are scaled from 0 to 1 based on * the configured min and max. If not provided and raster statistics are available, those will be used instead. * If neither are available, the minimum for the data type will be used. To disable this behavior, set @@ -189,7 +195,9 @@ function getImagesForTIFF(tiff) { */ function getImagesForSource(source, options) { let request; - if (source.overviews) { + if (source.blob) { + request = tiffFromBlob(source.blob); + } else if (source.overviews) { request = tiffFromUrls(source.url, source.overviews, options); } else { request = tiffFromUrl(source.url, options); diff --git a/test/browser/spec/ol/source/GeoTIFF.test.js b/test/browser/spec/ol/source/GeoTIFF.test.js index 778f965956..699bd13201 100644 --- a/test/browser/spec/ol/source/GeoTIFF.test.js +++ b/test/browser/spec/ol/source/GeoTIFF.test.js @@ -80,6 +80,25 @@ describe('ol/source/GeoTIFF', function () { tile.load(); }); }); + + it('loads from blob', (done) => { + fetch('spec/ol/source/images/0-0-0.tif') + .then((response) => response.blob()) + .then((blob) => { + const source = new GeoTIFFSource({ + sources: [{blob: blob}], + }); + 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 () {