From eb355a10b275e485639b735698b9dada765e5e3e Mon Sep 17 00:00:00 2001 From: Jim Phillips Date: Wed, 2 Aug 2023 21:47:08 -0500 Subject: [PATCH 1/2] add readOnDemand option for faster File/Blob loading --- README.md | 28 +++++++++++++++++++++++++++- src/index.js | 20 ++++++++++++++------ src/parseData.js | 3 ++- 3 files changed, 43 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index b8468a0..6c52200 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,18 @@ fs.readFile("data/GeogToWGS84GeoKey5.tif", (error, data) => { }); ``` +# load from File (or other Blob) on front-end +```javascript +const parseGeoraster = require("georaster"); +document.querySelector("input").addEventListener("change", e => { + const file = e.target.files[0]; + parseGeoraster(file) + .then(georaster => { + console.log("georaster:", georaster); + }); +}); +``` + # load from simple object on front-end ```javascript const parseGeoraster = require("georaster"); @@ -37,7 +49,8 @@ const georaster = parseGeoraster(values, metadata); ``` # load [cloud optimized geotiff](https://www.cogeo.org/) -This option allows you to basically load the pixels only when you need them versus the other options +This option (and File with readOnDemand, below) allows you to basically +load the pixels only when you need them versus the other options that require you to load the whole image into memory. It will also attempt to automatically discover any available overview files. *where to clip* @@ -72,6 +85,19 @@ that require you to load the whole image into memory. It will also attempt to a }); ``` +# load from File on demand +By default, a File or ArrayBuffer will be read and parsed completely +at full resolution in a worker thread (if available) before +the promise returned by parseGeoraster() is resolved. +If less data is required (such as when the file includes overviews), +then the readOnDemand option allows reading and parsing to be deferred +until getValues() is called. +```javascript + parseGeoraster(file, { readOnDemand: true }) + .then(georaster => georaster.getValues(options)) + .then(values => ... +``` + # required properties | name | description | | ---- | ----------- | diff --git a/src/index.js b/src/index.js index 3f0cf47..5b01cd4 100644 --- a/src/index.js +++ b/src/index.js @@ -53,12 +53,14 @@ class GeoRaster { data = new Buffer(data); } + this.readOnDemand = false; if (typeof data === 'string') { if (debug) console.log('data is a url'); this._data = data; this._url = data; this.rasterType = 'geotiff'; this.sourceType = 'url'; + this.readOnDemand = true; } else if (typeof Blob !== 'undefined' && data instanceof Blob) { this._data = data; this.rasterType = 'geotiff'; @@ -80,6 +82,9 @@ class GeoRaster { this.rasterType = 'object'; this._metadata = metadata; } + if ( metadata && metadata.readOnDemand !== undefined ) { + this.readOnDemand = metadata.readOnDemand; + } if (debug) console.log('this after construction:', this); } @@ -112,7 +117,7 @@ class GeoRaster { if (debug) console.log('this', this); if (this.rasterType === 'object' || this.rasterType === 'geotiff' || this.rasterType === 'tiff') { - if (this._web_worker_is_available) { + if (this._web_worker_is_available && ! this.readOnDemand) { const worker = new Worker(); worker.onmessage = (e) => { if (debug) console.log('main thread received message:', e); @@ -120,8 +125,8 @@ class GeoRaster { for (const key in data) { this[key] = data[key]; } - if (this._url) { - this._geotiff = geotiff; + if (this.readOnDemand) { + if (this._url) this._geotiff = geotiff; this.getValues = function(options) { return getValues(this._geotiff, options); }; @@ -137,6 +142,7 @@ class GeoRaster { data: this._data, rasterType: this.rasterType, sourceType: this.sourceType, + readOnDemand: this.readOnDemand, metadata: this._metadata, }, [this._data]); } else { @@ -144,20 +150,22 @@ class GeoRaster { data: this._data, rasterType: this.rasterType, sourceType: this.sourceType, + readOnDemand: this.readOnDemand, metadata: this._metadata, }); } } else { - if (debug) console.log('web worker is not available'); + if (debug && ! this._web_worker_is_available) console.log('web worker is not available'); parseData({ data: this._data, rasterType: this.rasterType, sourceType: this.sourceType, + readOnDemand: this.readOnDemand, metadata: this._metadata, }, debug).then(result => { if (debug) console.log('result:', result); - if (this._url) { - result._geotiff = geotiff; + if (this.readOnDemand) { + if (this._url) result._geotiff = geotiff; result.getValues = function(options) { return getValues(this._geotiff, options); }; diff --git a/src/parseData.js b/src/parseData.js index 59353cf..a421434 100644 --- a/src/parseData.js +++ b/src/parseData.js @@ -98,7 +98,7 @@ export default function parseData(data, debug) { result.palette = getPalette(image); } - if (data.sourceType !== 'url') { + if (! data.readOnDemand) { return image.readRasters().then(rasters => { result.values = rasters.map(valuesInOneDimension => { return unflatten(valuesInOneDimension, {height, width}); @@ -106,6 +106,7 @@ export default function parseData(data, debug) { return processResult(result); }); } else { + result._geotiff = geotiff; return result; } } catch (error) { From fadcb07b00d9ef478ee9bfa9a5640a7fc3bce0c9 Mon Sep 17 00:00:00 2001 From: Jim Phillips Date: Wed, 2 Aug 2023 22:45:52 -0500 Subject: [PATCH 2/2] refactor parseData args --- src/index.js | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/src/index.js b/src/index.js index 5b01cd4..c9824b7 100644 --- a/src/index.js +++ b/src/index.js @@ -117,6 +117,13 @@ class GeoRaster { if (debug) console.log('this', this); if (this.rasterType === 'object' || this.rasterType === 'geotiff' || this.rasterType === 'tiff') { + const parseDataArgs = { + data: this._data, + rasterType: this.rasterType, + sourceType: this.sourceType, + readOnDemand: this.readOnDemand, + metadata: this._metadata, + }; if (this._web_worker_is_available && ! this.readOnDemand) { const worker = new Worker(); worker.onmessage = (e) => { @@ -138,31 +145,13 @@ class GeoRaster { }; if (debug) console.log('about to postMessage'); if (this._data instanceof ArrayBuffer) { - worker.postMessage({ - data: this._data, - rasterType: this.rasterType, - sourceType: this.sourceType, - readOnDemand: this.readOnDemand, - metadata: this._metadata, - }, [this._data]); + worker.postMessage(parseDataArgs, [this._data]); } else { - worker.postMessage({ - data: this._data, - rasterType: this.rasterType, - sourceType: this.sourceType, - readOnDemand: this.readOnDemand, - metadata: this._metadata, - }); + worker.postMessage(parseDataArgs); } } else { if (debug && ! this._web_worker_is_available) console.log('web worker is not available'); - parseData({ - data: this._data, - rasterType: this.rasterType, - sourceType: this.sourceType, - readOnDemand: this.readOnDemand, - metadata: this._metadata, - }, debug).then(result => { + parseData(parseDataArgs, debug).then(result => { if (debug) console.log('result:', result); if (this.readOnDemand) { if (this._url) result._geotiff = geotiff;