geotiff-from
Version:
With One Function, Load a GeoTIFF from an ArrayBuffer, Blob, Buffer, DataView, File or URL
118 lines (102 loc) • 3.69 kB
JavaScript
const { fromArrayBuffer, fromBlob, fromUrl, fromUrls } = require("geotiff");
const LRUCache = require("lru-cache");
const toab = require("toab");
const doesUrlExist = require("does-url-exist");
const isURL = data => typeof data === "string" && data.startsWith("http");
const cache = new LRUCache({
max: 10,
maxAge: 1000 * 60 * 60
});
async function findOverviewURL({ debug, url }) {
if (debug)
console.log("[geotiff-from.findOverviewURL] starting with url", url);
const candidates = [url + ".ovr", url + ".OVR"];
for (let i = 0; i < candidates.length; i++) {
const candidate = candidates[i];
if (await doesUrlExist({ url: candidate })) {
if (debug)
console.log("[geotiff-from.findOverviewURL] found " + candidate);
return candidate;
}
}
}
async function from(data, { debug, ovr = false } = {}) {
// check if using legacy method
if (typeof arguments[0] === "object" && "data" in arguments[0]) {
return from(data.data, arguments[0]);
}
if (debug)
console.log(
"[geotiff-from] starting with options",
JSON.stringify({ data: typeof data, debug, ovr })
);
// quick return
if (typeof data === "string" && cache.has(data)) {
return cache.get(data);
}
// if data is a promise, wait for it
if (typeof data === "object" && typeof data.then === "function") {
data = await data;
}
// filter out any empties
if (Array.isArray(data))
data = data.filter(it => it !== null && it !== undefined && it !== "");
// [data] to data
if (Array.isArray(data) && data.length === 1 && typeof data[0] !== "number") {
data = data[0];
}
// one url
if (typeof data === "string") {
const url = data;
if (debug) console.log("[geotiff-from] data is probably a url");
const ovrURL = ovr === true ? await findOverviewURL({ debug, url }) : null;
if (ovrURL) {
const key = JSON.stringify([url, ovrURL]);
if (!cache.has(key)) cache.set(key, fromUrls(url, ovrURL));
return cache.get(key);
} else {
if (!cache.has(url)) cache.set(url, fromUrl(url));
return cache.get(url);
}
}
// array of urls
if (Array.isArray(data) && data.every(it => typeof it === "string")) {
if (debug) console.log("[geotiff-from] data is an array");
if (data.length === 1) {
const url = data[0];
if (!cache.has(url)) cache.set(url, fromUrl(url));
return cache.get(url);
} else {
const mainURL = data.find(
url =>
url.toLowerCase().includes(".tif") &&
!url.toLowerCase().includes(".ovr")
);
const overviewURLs = data.filter(url =>
url.toLowerCase().includes(".ovr")
);
if (mainURL && overviewURLs.length === data.length - 1) {
const key = JSON.stringify([mainURL, overviewURLs]);
if (!cache.has(key)) cache.set(key, fromUrls(mainURL, overviewURLs));
return cache.get(key);
} else if (mainURL && overviewURLs.length === 0) {
// if we couldn't find any overview urls using the .ovr extension
// just assume all the non-main URLs are overviews
const otherURLs = data.filter(url => url !== mainURL);
if (!cache.has(key)) cache.set(key, fromUrls(mainURL, otherURLs));
return cache.get(key);
}
}
}
if (typeof Blob !== "undefined" && data instanceof Blob) {
return fromBlob(data);
}
// if not successfull so far, try to convert everything
// to an array buffer
const arrayBuffer = await toab(data);
if (arrayBuffer) {
return fromArrayBuffer(arrayBuffer);
}
throw new Error("[geotiff-from] unsuccessful");
}
if (typeof module === "object") module.exports = from;