mapshaper 0.7.13 → 0.7.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/mapshaper.js +1729 -21
- package/package.json +7 -2
- package/www/geotiff.js +26355 -0
- package/www/index.html +2 -2
- package/www/mapshaper-gui.js +1865 -314
- package/www/mapshaper.js +1729 -21
- package/www/page.css +9 -0
package/mapshaper.js
CHANGED
|
@@ -1443,6 +1443,10 @@
|
|
|
1443
1443
|
return layerHasPaths(lyr) || layerHasPoints(lyr);
|
|
1444
1444
|
}
|
|
1445
1445
|
|
|
1446
|
+
function layerHasRaster(lyr) {
|
|
1447
|
+
return !!(lyr && lyr.raster_type && lyr.raster);
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1446
1450
|
function layerIsGeometric(lyr) {
|
|
1447
1451
|
return !!lyr.geometry_type; // only checks type, includes empty layers
|
|
1448
1452
|
}
|
|
@@ -4772,6 +4776,628 @@
|
|
|
4772
4776
|
pathIsRectangle: pathIsRectangle
|
|
4773
4777
|
});
|
|
4774
4778
|
|
|
4779
|
+
var DEFAULT_MAX_PREVIEW_PIXELS = 4e6;
|
|
4780
|
+
|
|
4781
|
+
function getRasterGrid(raster) {
|
|
4782
|
+
return raster && (raster.grid || raster);
|
|
4783
|
+
}
|
|
4784
|
+
|
|
4785
|
+
function getRasterView(raster) {
|
|
4786
|
+
return raster && (raster.view || raster);
|
|
4787
|
+
}
|
|
4788
|
+
|
|
4789
|
+
function getRasterPreview(raster) {
|
|
4790
|
+
var view = getRasterView(raster);
|
|
4791
|
+
return view && (view.preview || raster.preview);
|
|
4792
|
+
}
|
|
4793
|
+
|
|
4794
|
+
function getRasterBBox(raster) {
|
|
4795
|
+
var grid = getRasterGrid(raster);
|
|
4796
|
+
return grid && grid.bbox || raster && raster.bbox || null;
|
|
4797
|
+
}
|
|
4798
|
+
|
|
4799
|
+
function getRasterTransform(raster) {
|
|
4800
|
+
var grid = getRasterGrid(raster);
|
|
4801
|
+
return grid && grid.transform || raster && raster.transform || null;
|
|
4802
|
+
}
|
|
4803
|
+
|
|
4804
|
+
function getRasterWidth(raster) {
|
|
4805
|
+
var grid = getRasterGrid(raster);
|
|
4806
|
+
return grid && grid.width || 0;
|
|
4807
|
+
}
|
|
4808
|
+
|
|
4809
|
+
function getRasterHeight(raster) {
|
|
4810
|
+
var grid = getRasterGrid(raster);
|
|
4811
|
+
return grid && grid.height || 0;
|
|
4812
|
+
}
|
|
4813
|
+
|
|
4814
|
+
function getRasterBandCount(raster) {
|
|
4815
|
+
var grid = getRasterGrid(raster);
|
|
4816
|
+
return grid && grid.bands || 0;
|
|
4817
|
+
}
|
|
4818
|
+
|
|
4819
|
+
function getRasterPixelType(raster) {
|
|
4820
|
+
var grid = getRasterGrid(raster);
|
|
4821
|
+
return grid && grid.pixelType || null;
|
|
4822
|
+
}
|
|
4823
|
+
|
|
4824
|
+
function copyRasterData(raster) {
|
|
4825
|
+
var copy = utils.extend({}, raster);
|
|
4826
|
+
if (raster.grid) {
|
|
4827
|
+
copy.grid = copyRasterGrid(raster.grid);
|
|
4828
|
+
}
|
|
4829
|
+
if (raster.view) {
|
|
4830
|
+
copy.view = copyRasterView(raster.view);
|
|
4831
|
+
}
|
|
4832
|
+
if (raster.derivation) {
|
|
4833
|
+
copy.derivation = utils.extend({}, raster.derivation);
|
|
4834
|
+
if (raster.derivation.bands) copy.derivation.bands = copyObjectOrArray(raster.derivation.bands);
|
|
4835
|
+
}
|
|
4836
|
+
if (raster.source) copy.source = utils.extend({}, raster.source);
|
|
4837
|
+
|
|
4838
|
+
// Back-compat for the first raster model.
|
|
4839
|
+
if (raster.pixels) copy.pixels = copyTypedArray(raster.pixels);
|
|
4840
|
+
if (raster.preview) copy.preview = copyRasterPreview(raster.preview);
|
|
4841
|
+
if (raster.bbox) copy.bbox = raster.bbox.concat();
|
|
4842
|
+
if (raster.transform) copy.transform = copyObjectOrArray(raster.transform);
|
|
4843
|
+
return copy;
|
|
4844
|
+
}
|
|
4845
|
+
|
|
4846
|
+
function copyRasterGrid(grid) {
|
|
4847
|
+
var copy = utils.extend({}, grid);
|
|
4848
|
+
if (grid.samples) copy.samples = copyTypedArray(grid.samples);
|
|
4849
|
+
if (grid.sampleBands) copy.sampleBands = grid.sampleBands.concat();
|
|
4850
|
+
if (grid.bbox) copy.bbox = grid.bbox.concat();
|
|
4851
|
+
if (grid.transform) copy.transform = copyObjectOrArray(grid.transform);
|
|
4852
|
+
return copy;
|
|
4853
|
+
}
|
|
4854
|
+
|
|
4855
|
+
function copyRasterView(view) {
|
|
4856
|
+
var copy = utils.extend({}, view);
|
|
4857
|
+
if (view.recipe) copy.recipe = copyObjectOrArray(view.recipe);
|
|
4858
|
+
if (view.preview) copy.preview = copyRasterPreview(view.preview);
|
|
4859
|
+
if (view.scalingStats) copy.scalingStats = copyObjectOrArray(view.scalingStats);
|
|
4860
|
+
return copy;
|
|
4861
|
+
}
|
|
4862
|
+
|
|
4863
|
+
function copyRasterPreview(preview) {
|
|
4864
|
+
var copy = utils.extend({}, preview);
|
|
4865
|
+
delete copy.canvas;
|
|
4866
|
+
if (preview.pixels) copy.pixels = copyTypedArray(preview.pixels);
|
|
4867
|
+
return copy;
|
|
4868
|
+
}
|
|
4869
|
+
|
|
4870
|
+
function copyTypedArray(arr) {
|
|
4871
|
+
if (Array.isArray(arr)) return arr.map(copyTypedArray);
|
|
4872
|
+
return arr && arr.slice ? arr.slice() : arr;
|
|
4873
|
+
}
|
|
4874
|
+
|
|
4875
|
+
function createRasterPreview(raster, opts) {
|
|
4876
|
+
opts = opts || {};
|
|
4877
|
+
var grid = getRasterGrid(raster);
|
|
4878
|
+
var recipe = getRasterViewRecipe(grid, raster.view && raster.view.recipe, opts);
|
|
4879
|
+
var stats = getRasterViewScalingStats(raster, recipe);
|
|
4880
|
+
var maxPixels = opts.maxPixels || opts.raster_max_pixels || opts.rasterMaxPixels || DEFAULT_MAX_PREVIEW_PIXELS;
|
|
4881
|
+
var scale = Math.min(1, Math.sqrt(maxPixels / (grid.width * grid.height)));
|
|
4882
|
+
var width = Math.max(1, Math.round(grid.width * scale));
|
|
4883
|
+
var height = Math.max(1, Math.round(grid.height * scale));
|
|
4884
|
+
return renderRasterPreview(grid, recipe, width, height, stats);
|
|
4885
|
+
}
|
|
4886
|
+
|
|
4887
|
+
function getRasterViewRecipe(grid, recipeArg, opts) {
|
|
4888
|
+
var recipe = Object.assign({}, recipeArg || {});
|
|
4889
|
+
var scaling = opts && opts.scaling || recipe.scaling || getDefaultRasterScaling(grid);
|
|
4890
|
+
var scaleRange = opts && (opts.scale_range || opts.scaleRange) || recipe.scaleRange;
|
|
4891
|
+
var percentileRange = opts && (opts.percentile_range || opts.percentileRange) || recipe.percentileRange;
|
|
4892
|
+
if (scaling != 'none' && scaling != 'minmax' && scaling != 'percentile') {
|
|
4893
|
+
stop$1('Unsupported raster scaling method:', scaling);
|
|
4894
|
+
}
|
|
4895
|
+
return Object.assign(recipe, {
|
|
4896
|
+
type: recipe.type || (grid.bands >= 3 ? 'rgb' : 'gray'),
|
|
4897
|
+
bands: recipe.bands || grid.sampleBands || null,
|
|
4898
|
+
scaling: scaling,
|
|
4899
|
+
scaleRange: parseRangeOption(scaleRange, [0, 100], 'scale-range'),
|
|
4900
|
+
percentileRange: parseRangeOption(percentileRange, [2, 98], 'percentile-range')
|
|
4901
|
+
});
|
|
4902
|
+
}
|
|
4903
|
+
|
|
4904
|
+
function renderRasterPreview(grid, recipe, width, height, statsArg) {
|
|
4905
|
+
recipe = getRasterViewRecipe(grid, recipe);
|
|
4906
|
+
if (useFastRawEightBitRendering(grid, recipe)) {
|
|
4907
|
+
return renderRawEightBitPreview(grid, width, height, null);
|
|
4908
|
+
}
|
|
4909
|
+
return renderRasterGridPreview(grid, recipe, width, height, statsArg || getRasterScalingStats(grid, recipe), null);
|
|
4910
|
+
}
|
|
4911
|
+
|
|
4912
|
+
function renderRasterViewportPreview(grid, recipe, bbox, width, height, statsArg) {
|
|
4913
|
+
recipe = getRasterViewRecipe(grid, recipe);
|
|
4914
|
+
if (!intersectBboxes(grid.bbox, bbox)) return null;
|
|
4915
|
+
if (useFastRawEightBitRendering(grid, recipe)) {
|
|
4916
|
+
return Object.assign(renderRawEightBitPreview(grid, width, height, bbox), {
|
|
4917
|
+
bbox: bbox.concat()
|
|
4918
|
+
});
|
|
4919
|
+
}
|
|
4920
|
+
return Object.assign(renderRasterGridPreview(grid, recipe, width, height, statsArg || getRasterScalingStats(grid, recipe), bbox), {
|
|
4921
|
+
bbox: bbox.concat()
|
|
4922
|
+
});
|
|
4923
|
+
}
|
|
4924
|
+
|
|
4925
|
+
function getRasterScalingStats(grid, recipe) {
|
|
4926
|
+
recipe = getRasterViewRecipe(grid, recipe);
|
|
4927
|
+
return getScalingStats(grid.samples, grid.bands, grid.nodata, recipe);
|
|
4928
|
+
}
|
|
4929
|
+
|
|
4930
|
+
function getRasterViewScalingStats(raster, recipeArg) {
|
|
4931
|
+
var grid = getRasterGrid(raster);
|
|
4932
|
+
var view = getRasterView(raster);
|
|
4933
|
+
var recipe = getRasterViewRecipe(grid, recipeArg || view && view.recipe);
|
|
4934
|
+
var key, cached, stats;
|
|
4935
|
+
if (recipe.scaling == 'none') return null;
|
|
4936
|
+
key = getRasterScalingStatsKey(grid, recipe);
|
|
4937
|
+
cached = view && view.scalingStats;
|
|
4938
|
+
if (cached && cached.key == key) return cached.stats;
|
|
4939
|
+
stats = getRasterScalingStats(grid, recipe);
|
|
4940
|
+
if (view) {
|
|
4941
|
+
view.scalingStats = {
|
|
4942
|
+
key: key,
|
|
4943
|
+
stats: stats
|
|
4944
|
+
};
|
|
4945
|
+
}
|
|
4946
|
+
return stats;
|
|
4947
|
+
}
|
|
4948
|
+
|
|
4949
|
+
function renderRasterGridPreview(grid, recipe, width, height, statsArg, sourceBbox) {
|
|
4950
|
+
var samples = grid.samples;
|
|
4951
|
+
var bands = grid.bands;
|
|
4952
|
+
var noData = grid.nodata;
|
|
4953
|
+
var pixels = new Uint8ClampedArray(width * height * 4);
|
|
4954
|
+
var stats = statsArg || getScalingStats(samples, bands, noData, recipe);
|
|
4955
|
+
var sourceRange = recipe.scaling == 'none' ? getPixelTypeRange(grid.pixelType) : null;
|
|
4956
|
+
var displayRange = getDisplayRange(recipe.scaleRange);
|
|
4957
|
+
var src, dest, val, isNoData, j;
|
|
4958
|
+
for (var y = 0; y < height; y++) {
|
|
4959
|
+
for (var x = 0; x < width; x++) {
|
|
4960
|
+
src = getPreviewSourceOffset(grid, sourceBbox, x, y, width, height, bands);
|
|
4961
|
+
dest = (y * width + x) * 4;
|
|
4962
|
+
isNoData = noData !== null && noData !== undefined && allSamplesAreNoData(samples, src, bands, noData);
|
|
4963
|
+
if (bands == 1) {
|
|
4964
|
+
val = scaleSample(samples[src], stats && stats[0], sourceRange, displayRange);
|
|
4965
|
+
pixels[dest] = val;
|
|
4966
|
+
pixels[dest + 1] = val;
|
|
4967
|
+
pixels[dest + 2] = val;
|
|
4968
|
+
pixels[dest + 3] = isNoData ? 0 : 255;
|
|
4969
|
+
} else {
|
|
4970
|
+
for (j = 0; j < 3; j++) {
|
|
4971
|
+
pixels[dest + j] = scaleSample(samples[src + j], stats && stats[j], sourceRange, displayRange);
|
|
4972
|
+
}
|
|
4973
|
+
pixels[dest + 3] = isNoData ? 0 : bands >= 4 ? scaleSample(samples[src + 3], stats && stats[3], sourceRange, [0, 255]) : 255;
|
|
4974
|
+
}
|
|
4975
|
+
}
|
|
4976
|
+
}
|
|
4977
|
+
return {
|
|
4978
|
+
width: width,
|
|
4979
|
+
height: height,
|
|
4980
|
+
bands: 4,
|
|
4981
|
+
pixelType: 'uint8',
|
|
4982
|
+
colorModel: 'rgba',
|
|
4983
|
+
pixels: pixels
|
|
4984
|
+
};
|
|
4985
|
+
}
|
|
4986
|
+
|
|
4987
|
+
function renderRawEightBitPreview(grid, width, height, sourceBbox) {
|
|
4988
|
+
var samples = grid.samples;
|
|
4989
|
+
var bands = grid.bands;
|
|
4990
|
+
var pixels = new Uint8ClampedArray(width * height * 4);
|
|
4991
|
+
var src, dest, val;
|
|
4992
|
+
for (var y = 0; y < height; y++) {
|
|
4993
|
+
for (var x = 0; x < width; x++) {
|
|
4994
|
+
src = getPreviewSourceOffset(grid, sourceBbox, x, y, width, height, bands);
|
|
4995
|
+
dest = (y * width + x) * 4;
|
|
4996
|
+
if (bands == 1) {
|
|
4997
|
+
val = samples[src];
|
|
4998
|
+
pixels[dest] = val;
|
|
4999
|
+
pixels[dest + 1] = val;
|
|
5000
|
+
pixels[dest + 2] = val;
|
|
5001
|
+
pixels[dest + 3] = 255;
|
|
5002
|
+
} else {
|
|
5003
|
+
pixels[dest] = samples[src];
|
|
5004
|
+
pixels[dest + 1] = samples[src + 1];
|
|
5005
|
+
pixels[dest + 2] = samples[src + 2];
|
|
5006
|
+
pixels[dest + 3] = bands >= 4 ? samples[src + 3] : 255;
|
|
5007
|
+
}
|
|
5008
|
+
}
|
|
5009
|
+
}
|
|
5010
|
+
return {
|
|
5011
|
+
width: width,
|
|
5012
|
+
height: height,
|
|
5013
|
+
bands: 4,
|
|
5014
|
+
pixelType: 'uint8',
|
|
5015
|
+
colorModel: 'rgba',
|
|
5016
|
+
pixels: pixels
|
|
5017
|
+
};
|
|
5018
|
+
}
|
|
5019
|
+
|
|
5020
|
+
function getPreviewSourceOffset(grid, sourceBbox, x, y, width, height, bands) {
|
|
5021
|
+
var sx, sy, mapX, mapY, rb;
|
|
5022
|
+
if (!sourceBbox) {
|
|
5023
|
+
sy = Math.min(grid.height - 1, Math.floor((y + 0.5) * grid.height / height));
|
|
5024
|
+
sx = Math.min(grid.width - 1, Math.floor((x + 0.5) * grid.width / width));
|
|
5025
|
+
} else {
|
|
5026
|
+
rb = grid.bbox;
|
|
5027
|
+
mapX = sourceBbox[0] + (x + 0.5) / width * (sourceBbox[2] - sourceBbox[0]);
|
|
5028
|
+
mapY = sourceBbox[3] - (y + 0.5) / height * (sourceBbox[3] - sourceBbox[1]);
|
|
5029
|
+
sx = Math.max(0, Math.min(grid.width - 1, Math.floor((mapX - rb[0]) / (rb[2] - rb[0]) * grid.width)));
|
|
5030
|
+
sy = Math.max(0, Math.min(grid.height - 1, Math.floor((rb[3] - mapY) / (rb[3] - rb[1]) * grid.height)));
|
|
5031
|
+
}
|
|
5032
|
+
return (sy * grid.width + sx) * bands;
|
|
5033
|
+
}
|
|
5034
|
+
|
|
5035
|
+
function clipRasterToBBox(lyr, bbox, opts) {
|
|
5036
|
+
var raster = lyr.raster;
|
|
5037
|
+
var grid = getRasterGrid(raster);
|
|
5038
|
+
var clipBbox = intersectBboxes(grid.bbox, bbox);
|
|
5039
|
+
if (!clipBbox) {
|
|
5040
|
+
warn('Raster clipping rectangle does not intersect the raster layer');
|
|
5041
|
+
return false;
|
|
5042
|
+
}
|
|
5043
|
+
var crop = getRasterCrop(grid, clipBbox);
|
|
5044
|
+
if (crop.width === 0 || crop.height === 0) {
|
|
5045
|
+
warn('Raster clipping rectangle does not intersect the raster layer');
|
|
5046
|
+
return false;
|
|
5047
|
+
}
|
|
5048
|
+
noteLayerWillChange(lyr, {operation: 'clipRasterToBBox', unit: 'raster'});
|
|
5049
|
+
raster.grid = cropRasterGrid(grid, crop, clipBbox);
|
|
5050
|
+
raster.view = raster.view || {};
|
|
5051
|
+
raster.view.preview = createRasterPreview(raster, opts || {});
|
|
5052
|
+
clearLegacyRasterFields(raster);
|
|
5053
|
+
markLayerChanged(lyr, {operation: 'clipRasterToBBox', unit: 'raster'});
|
|
5054
|
+
return true;
|
|
5055
|
+
}
|
|
5056
|
+
|
|
5057
|
+
function intersectBboxes(a, b) {
|
|
5058
|
+
var bbox = [
|
|
5059
|
+
Math.max(a[0], b[0]),
|
|
5060
|
+
Math.max(a[1], b[1]),
|
|
5061
|
+
Math.min(a[2], b[2]),
|
|
5062
|
+
Math.min(a[3], b[3])
|
|
5063
|
+
];
|
|
5064
|
+
return bbox[2] <= bbox[0] || bbox[3] <= bbox[1] ? null : bbox;
|
|
5065
|
+
}
|
|
5066
|
+
|
|
5067
|
+
function getRasterCrop(grid, bbox) {
|
|
5068
|
+
var rb = grid.bbox;
|
|
5069
|
+
var x0 = Math.max(0, Math.floor((bbox[0] - rb[0]) / (rb[2] - rb[0]) * grid.width));
|
|
5070
|
+
var x1 = Math.min(grid.width, Math.ceil((bbox[2] - rb[0]) / (rb[2] - rb[0]) * grid.width));
|
|
5071
|
+
var y0 = Math.max(0, Math.floor((rb[3] - bbox[3]) / (rb[3] - rb[1]) * grid.height));
|
|
5072
|
+
var y1 = Math.min(grid.height, Math.ceil((rb[3] - bbox[1]) / (rb[3] - rb[1]) * grid.height));
|
|
5073
|
+
return {
|
|
5074
|
+
x: x0,
|
|
5075
|
+
y: y0,
|
|
5076
|
+
width: Math.max(0, x1 - x0),
|
|
5077
|
+
height: Math.max(0, y1 - y0)
|
|
5078
|
+
};
|
|
5079
|
+
}
|
|
5080
|
+
|
|
5081
|
+
function cropRasterGrid(grid, crop, bbox) {
|
|
5082
|
+
var samples = new grid.samples.constructor(crop.width * crop.height * grid.bands);
|
|
5083
|
+
var rowCount = crop.width * grid.bands;
|
|
5084
|
+
var src, dest;
|
|
5085
|
+
for (var y = 0; y < crop.height; y++) {
|
|
5086
|
+
src = ((crop.y + y) * grid.width + crop.x) * grid.bands;
|
|
5087
|
+
dest = y * rowCount;
|
|
5088
|
+
samples.set(grid.samples.subarray(src, src + rowCount), dest);
|
|
5089
|
+
}
|
|
5090
|
+
return Object.assign({}, grid, {
|
|
5091
|
+
width: crop.width,
|
|
5092
|
+
height: crop.height,
|
|
5093
|
+
samples: samples,
|
|
5094
|
+
bbox: bbox,
|
|
5095
|
+
transform: updateTransformForBBox(grid.transform, bbox, crop.width, crop.height)
|
|
5096
|
+
});
|
|
5097
|
+
}
|
|
5098
|
+
|
|
5099
|
+
function getRasterLayerBounds(lyr) {
|
|
5100
|
+
var bbox = lyr.raster && getRasterBBox(lyr.raster);
|
|
5101
|
+
return bbox && bbox.length == 4 ? new Bounds(bbox) : null;
|
|
5102
|
+
}
|
|
5103
|
+
|
|
5104
|
+
function requireRasterLayer(lyr) {
|
|
5105
|
+
if (!lyr || !lyr.raster_type || !lyr.raster) {
|
|
5106
|
+
stop$1('Expected a raster layer');
|
|
5107
|
+
}
|
|
5108
|
+
}
|
|
5109
|
+
|
|
5110
|
+
function clearLegacyRasterFields(raster) {
|
|
5111
|
+
delete raster.width;
|
|
5112
|
+
delete raster.height;
|
|
5113
|
+
delete raster.bands;
|
|
5114
|
+
delete raster.pixelType;
|
|
5115
|
+
delete raster.nodata;
|
|
5116
|
+
delete raster.bbox;
|
|
5117
|
+
delete raster.transform;
|
|
5118
|
+
delete raster.colorModel;
|
|
5119
|
+
delete raster.preview;
|
|
5120
|
+
delete raster.pixels;
|
|
5121
|
+
}
|
|
5122
|
+
|
|
5123
|
+
function updateTransformForBBox(transform, bbox, width, height) {
|
|
5124
|
+
if (!transform) return null;
|
|
5125
|
+
return [
|
|
5126
|
+
(bbox[2] - bbox[0]) / width,
|
|
5127
|
+
0,
|
|
5128
|
+
bbox[0],
|
|
5129
|
+
0,
|
|
5130
|
+
-(bbox[3] - bbox[1]) / height,
|
|
5131
|
+
bbox[3]
|
|
5132
|
+
];
|
|
5133
|
+
}
|
|
5134
|
+
|
|
5135
|
+
function getBandStats(data, bands, noData) {
|
|
5136
|
+
var stats = [];
|
|
5137
|
+
for (var band = 0; band < bands; band++) {
|
|
5138
|
+
stats[band] = getSingleBandStats(data, bands, band, noData);
|
|
5139
|
+
}
|
|
5140
|
+
return stats;
|
|
5141
|
+
}
|
|
5142
|
+
|
|
5143
|
+
function getSingleBandStats(data, bands, band, noData) {
|
|
5144
|
+
var min = Infinity;
|
|
5145
|
+
var max = -Infinity;
|
|
5146
|
+
var val;
|
|
5147
|
+
for (var i = band; i < data.length; i += bands) {
|
|
5148
|
+
val = data[i];
|
|
5149
|
+
if (!isValidBandValue(val, noData)) continue;
|
|
5150
|
+
if (val < min) min = val;
|
|
5151
|
+
if (val > max) max = val;
|
|
5152
|
+
}
|
|
5153
|
+
return min < Infinity && max > min ? {min: min, max: max} : {min: 0, max: 255};
|
|
5154
|
+
}
|
|
5155
|
+
|
|
5156
|
+
function getSharedBandStats(data, bands, noData) {
|
|
5157
|
+
var stats = getBandStats(data, bands, noData);
|
|
5158
|
+
var min = Math.min(stats[0].min, stats[1].min, stats[2].min);
|
|
5159
|
+
var max = Math.max(stats[0].max, stats[1].max, stats[2].max);
|
|
5160
|
+
var shared = max > min ? {min: min, max: max} : {min: 0, max: 255};
|
|
5161
|
+
stats[0] = stats[1] = stats[2] = shared;
|
|
5162
|
+
return stats;
|
|
5163
|
+
}
|
|
5164
|
+
|
|
5165
|
+
function getScalingStats(data, bands, noData, recipe) {
|
|
5166
|
+
var shared = recipe.type == 'rgb' && bands >= 3;
|
|
5167
|
+
if (recipe.scaling == 'minmax') {
|
|
5168
|
+
return shared ? getSharedBandStats(data, bands, noData) : getBandStats(data, bands, noData);
|
|
5169
|
+
}
|
|
5170
|
+
if (recipe.scaling == 'percentile') {
|
|
5171
|
+
return shared ? getSharedPercentileStats(data, bands, noData, recipe.percentileRange) :
|
|
5172
|
+
getBandPercentileStats(data, bands, noData, recipe.percentileRange);
|
|
5173
|
+
}
|
|
5174
|
+
return null;
|
|
5175
|
+
}
|
|
5176
|
+
|
|
5177
|
+
function scaleSample(val, stats, sourceRange, displayRange) {
|
|
5178
|
+
var range = stats || sourceRange || {min: 0, max: 255};
|
|
5179
|
+
var pct = range.max > range.min ? (val - range.min) / (range.max - range.min) : 0;
|
|
5180
|
+
var scaled = displayRange[0] + pct * (displayRange[1] - displayRange[0]);
|
|
5181
|
+
return Math.max(0, Math.min(255, Math.round(scaled)));
|
|
5182
|
+
}
|
|
5183
|
+
|
|
5184
|
+
function getDefaultRasterScaling(grid, recipe) {
|
|
5185
|
+
return isEightBitPixelType(grid.pixelType) ? 'none' : 'percentile';
|
|
5186
|
+
}
|
|
5187
|
+
|
|
5188
|
+
function parseRangeOption(val, def, name) {
|
|
5189
|
+
var range;
|
|
5190
|
+
if (val == null || val === '') return def;
|
|
5191
|
+
range = Array.isArray(val) ? val : String(val).split(',');
|
|
5192
|
+
if (range.length != 2) {
|
|
5193
|
+
stop$1('Expected ' + name + '= to contain two comma-separated numbers');
|
|
5194
|
+
}
|
|
5195
|
+
range = range.map(Number);
|
|
5196
|
+
if (!isFinite(range[0]) || !isFinite(range[1]) || range[0] < 0 || range[1] > 100 || range[1] < range[0]) {
|
|
5197
|
+
stop$1('Expected ' + name + '= values between 0 and 100');
|
|
5198
|
+
}
|
|
5199
|
+
return range;
|
|
5200
|
+
}
|
|
5201
|
+
|
|
5202
|
+
function getDisplayRange(scaleRange) {
|
|
5203
|
+
return [
|
|
5204
|
+
scaleRange[0] / 100 * 255,
|
|
5205
|
+
scaleRange[1] / 100 * 255
|
|
5206
|
+
];
|
|
5207
|
+
}
|
|
5208
|
+
|
|
5209
|
+
function getPixelTypeRange(pixelType) {
|
|
5210
|
+
switch (pixelType) {
|
|
5211
|
+
case 'uint8': return {min: 0, max: 255};
|
|
5212
|
+
case 'uint16': return {min: 0, max: 65535};
|
|
5213
|
+
case 'uint32': return {min: 0, max: 4294967295};
|
|
5214
|
+
case 'int8': return {min: -128, max: 127};
|
|
5215
|
+
case 'int16': return {min: -32768, max: 32767};
|
|
5216
|
+
case 'int32': return {min: -2147483648, max: 2147483647};
|
|
5217
|
+
}
|
|
5218
|
+
return null;
|
|
5219
|
+
}
|
|
5220
|
+
|
|
5221
|
+
function isEightBitPixelType(pixelType) {
|
|
5222
|
+
return pixelType == 'uint8' || pixelType == 'int8';
|
|
5223
|
+
}
|
|
5224
|
+
|
|
5225
|
+
function useFastRawEightBitRendering(grid, recipe) {
|
|
5226
|
+
return grid.pixelType == 'uint8' &&
|
|
5227
|
+
recipe.scaling == 'none' &&
|
|
5228
|
+
recipe.scaleRange[0] === 0 &&
|
|
5229
|
+
recipe.scaleRange[1] === 100 &&
|
|
5230
|
+
(recipe.type == 'gray' && grid.bands == 1 || recipe.type == 'rgb' && grid.bands >= 3) &&
|
|
5231
|
+
(grid.nodata === null || grid.nodata === undefined);
|
|
5232
|
+
}
|
|
5233
|
+
|
|
5234
|
+
function getRasterScalingStatsKey(grid, recipe) {
|
|
5235
|
+
return [
|
|
5236
|
+
grid.width,
|
|
5237
|
+
grid.height,
|
|
5238
|
+
grid.bands,
|
|
5239
|
+
grid.pixelType,
|
|
5240
|
+
grid.samples && grid.samples.length,
|
|
5241
|
+
grid.nodata,
|
|
5242
|
+
recipe.type,
|
|
5243
|
+
recipe.scaling,
|
|
5244
|
+
recipe.scaleRange && recipe.scaleRange.join(','),
|
|
5245
|
+
recipe.percentileRange && recipe.percentileRange.join(',')
|
|
5246
|
+
].join('|');
|
|
5247
|
+
}
|
|
5248
|
+
|
|
5249
|
+
function getBandPercentileStats(data, bands, noData, range) {
|
|
5250
|
+
var stats = [];
|
|
5251
|
+
for (var band = 0; band < bands; band++) {
|
|
5252
|
+
stats[band] = getPercentileStats(data, bands, [band], noData, range);
|
|
5253
|
+
}
|
|
5254
|
+
return stats;
|
|
5255
|
+
}
|
|
5256
|
+
|
|
5257
|
+
function getSharedPercentileStats(data, bands, noData, range) {
|
|
5258
|
+
var stats = getBandPercentileStats(data, bands, noData, range);
|
|
5259
|
+
var shared = getPercentileStats(data, bands, [0, 1, 2], noData, range);
|
|
5260
|
+
stats[0] = stats[1] = stats[2] = shared;
|
|
5261
|
+
return stats;
|
|
5262
|
+
}
|
|
5263
|
+
|
|
5264
|
+
function getPercentileStats(data, bands, bandIds, noData, range) {
|
|
5265
|
+
var integerRange = getSmallIntegerRange(data);
|
|
5266
|
+
return integerRange ?
|
|
5267
|
+
getHistogramPercentileStats(data, bands, bandIds, noData, range, integerRange) :
|
|
5268
|
+
getApproxHistogramPercentileStats(data, bands, bandIds, noData, range);
|
|
5269
|
+
}
|
|
5270
|
+
|
|
5271
|
+
function getSmallIntegerRange(data) {
|
|
5272
|
+
if (data instanceof Uint8Array || data instanceof Uint8ClampedArray) return {min: 0, max: 255};
|
|
5273
|
+
if (data instanceof Int8Array) return {min: -128, max: 127};
|
|
5274
|
+
if (data instanceof Uint16Array) return {min: 0, max: 65535};
|
|
5275
|
+
if (data instanceof Int16Array) return {min: -32768, max: 32767};
|
|
5276
|
+
return null;
|
|
5277
|
+
}
|
|
5278
|
+
|
|
5279
|
+
function getHistogramPercentileStats(data, bands, bandIds, noData, range, integerRange) {
|
|
5280
|
+
var counts = new Uint32Array(integerRange.max - integerRange.min + 1);
|
|
5281
|
+
var count = 0, val;
|
|
5282
|
+
forEachBandValue(data, bands, bandIds, noData, function(v) {
|
|
5283
|
+
val = v - integerRange.min;
|
|
5284
|
+
counts[val]++;
|
|
5285
|
+
count++;
|
|
5286
|
+
});
|
|
5287
|
+
return count > 0 ? {
|
|
5288
|
+
min: getHistogramPercentileValue(counts, integerRange.min, count, range[0]),
|
|
5289
|
+
max: getHistogramPercentileValue(counts, integerRange.min, count, range[1])
|
|
5290
|
+
} : {min: 0, max: 255};
|
|
5291
|
+
}
|
|
5292
|
+
|
|
5293
|
+
function getApproxHistogramPercentileStats(data, bands, bandIds, noData, range) {
|
|
5294
|
+
var bounds = getBandValueBounds(data, bands, bandIds, noData);
|
|
5295
|
+
var binCount = 65536;
|
|
5296
|
+
var counts, count, scale, maxBin;
|
|
5297
|
+
if (!bounds || bounds.max <= bounds.min) {
|
|
5298
|
+
return bounds || {min: 0, max: 255};
|
|
5299
|
+
}
|
|
5300
|
+
counts = new Uint32Array(binCount);
|
|
5301
|
+
count = 0;
|
|
5302
|
+
scale = (binCount - 1) / (bounds.max - bounds.min);
|
|
5303
|
+
maxBin = binCount - 1;
|
|
5304
|
+
forEachBandValue(data, bands, bandIds, noData, function(val) {
|
|
5305
|
+
counts[Math.max(0, Math.min(maxBin, Math.floor((val - bounds.min) * scale)))]++;
|
|
5306
|
+
count++;
|
|
5307
|
+
});
|
|
5308
|
+
return count > 0 ? {
|
|
5309
|
+
min: getApproxHistogramPercentileValue(counts, bounds, count, range[0]),
|
|
5310
|
+
max: getApproxHistogramPercentileValue(counts, bounds, count, range[1])
|
|
5311
|
+
} : {min: 0, max: 255};
|
|
5312
|
+
}
|
|
5313
|
+
|
|
5314
|
+
function getBandValueBounds(data, bands, bandIds, noData) {
|
|
5315
|
+
var min = Infinity;
|
|
5316
|
+
var max = -Infinity;
|
|
5317
|
+
forEachBandValue(data, bands, bandIds, noData, function(val) {
|
|
5318
|
+
if (val < min) min = val;
|
|
5319
|
+
if (val > max) max = val;
|
|
5320
|
+
});
|
|
5321
|
+
return min < Infinity ? {min: min, max: max} : null;
|
|
5322
|
+
}
|
|
5323
|
+
|
|
5324
|
+
function getHistogramPercentileValue(counts, offset, count, pct) {
|
|
5325
|
+
var target = getPercentileRank(count, pct);
|
|
5326
|
+
var sum = 0;
|
|
5327
|
+
for (var i = 0; i < counts.length; i++) {
|
|
5328
|
+
sum += counts[i];
|
|
5329
|
+
if (sum > target) return i + offset;
|
|
5330
|
+
}
|
|
5331
|
+
return counts.length - 1 + offset;
|
|
5332
|
+
}
|
|
5333
|
+
|
|
5334
|
+
function getApproxHistogramPercentileValue(counts, bounds, count, pct) {
|
|
5335
|
+
var bin = getHistogramPercentileValue(counts, 0, count, pct);
|
|
5336
|
+
return bounds.min + bin / (counts.length - 1) * (bounds.max - bounds.min);
|
|
5337
|
+
}
|
|
5338
|
+
|
|
5339
|
+
function forEachBandValue(data, bands, bandIds, noData, cb) {
|
|
5340
|
+
var val;
|
|
5341
|
+
for (var i = 0; i < data.length; i += bands) {
|
|
5342
|
+
for (var j = 0; j < bandIds.length; j++) {
|
|
5343
|
+
val = data[i + bandIds[j]];
|
|
5344
|
+
if (!isValidBandValue(val, noData)) continue;
|
|
5345
|
+
cb(val);
|
|
5346
|
+
}
|
|
5347
|
+
}
|
|
5348
|
+
}
|
|
5349
|
+
|
|
5350
|
+
function isValidBandValue(val, noData) {
|
|
5351
|
+
return isFinite(val) && (noData === null || noData === undefined || val != noData);
|
|
5352
|
+
}
|
|
5353
|
+
|
|
5354
|
+
function getPercentileRank(count, pct) {
|
|
5355
|
+
return Math.max(0, Math.min(count - 1, Math.floor((count - 1) * pct / 100)));
|
|
5356
|
+
}
|
|
5357
|
+
|
|
5358
|
+
function allSamplesAreNoData(data, offset, bands, noData) {
|
|
5359
|
+
var n = Math.min(bands, 3);
|
|
5360
|
+
for (var i = 0; i < n; i++) {
|
|
5361
|
+
if (data[offset + i] != noData) return false;
|
|
5362
|
+
}
|
|
5363
|
+
return true;
|
|
5364
|
+
}
|
|
5365
|
+
|
|
5366
|
+
function copyObjectOrArray(obj) {
|
|
5367
|
+
return obj && obj.concat ? obj.concat() : utils.extend({}, obj);
|
|
5368
|
+
}
|
|
5369
|
+
|
|
5370
|
+
var RasterUtils = /*#__PURE__*/Object.freeze({
|
|
5371
|
+
__proto__: null,
|
|
5372
|
+
clipRasterToBBox: clipRasterToBBox,
|
|
5373
|
+
copyRasterData: copyRasterData,
|
|
5374
|
+
copyRasterGrid: copyRasterGrid,
|
|
5375
|
+
copyRasterPreview: copyRasterPreview,
|
|
5376
|
+
copyRasterView: copyRasterView,
|
|
5377
|
+
copyTypedArray: copyTypedArray,
|
|
5378
|
+
createRasterPreview: createRasterPreview,
|
|
5379
|
+
cropRasterGrid: cropRasterGrid,
|
|
5380
|
+
getRasterBBox: getRasterBBox,
|
|
5381
|
+
getRasterBandCount: getRasterBandCount,
|
|
5382
|
+
getRasterCrop: getRasterCrop,
|
|
5383
|
+
getRasterGrid: getRasterGrid,
|
|
5384
|
+
getRasterHeight: getRasterHeight,
|
|
5385
|
+
getRasterLayerBounds: getRasterLayerBounds,
|
|
5386
|
+
getRasterPixelType: getRasterPixelType,
|
|
5387
|
+
getRasterPreview: getRasterPreview,
|
|
5388
|
+
getRasterScalingStats: getRasterScalingStats,
|
|
5389
|
+
getRasterScalingStatsKey: getRasterScalingStatsKey,
|
|
5390
|
+
getRasterTransform: getRasterTransform,
|
|
5391
|
+
getRasterView: getRasterView,
|
|
5392
|
+
getRasterViewRecipe: getRasterViewRecipe,
|
|
5393
|
+
getRasterViewScalingStats: getRasterViewScalingStats,
|
|
5394
|
+
getRasterWidth: getRasterWidth,
|
|
5395
|
+
intersectBboxes: intersectBboxes,
|
|
5396
|
+
renderRasterPreview: renderRasterPreview,
|
|
5397
|
+
renderRasterViewportPreview: renderRasterViewportPreview,
|
|
5398
|
+
requireRasterLayer: requireRasterLayer
|
|
5399
|
+
});
|
|
5400
|
+
|
|
4775
5401
|
// Insert a column of values into a (new or existing) data field
|
|
4776
5402
|
function insertFieldValues(lyr, fieldName, values) {
|
|
4777
5403
|
var size = getFeatureCount(lyr) || values.length,
|
|
@@ -4864,7 +5490,9 @@
|
|
|
4864
5490
|
|
|
4865
5491
|
function getFeatureCount(lyr) {
|
|
4866
5492
|
var count = 0;
|
|
4867
|
-
if (lyr
|
|
5493
|
+
if (layerHasRaster(lyr)) {
|
|
5494
|
+
count = 1;
|
|
5495
|
+
} else if (lyr.data) {
|
|
4868
5496
|
count = lyr.data.size();
|
|
4869
5497
|
} else if (lyr.shapes) {
|
|
4870
5498
|
count = lyr.shapes.length;
|
|
@@ -5052,6 +5680,7 @@
|
|
|
5052
5680
|
if (lyr.shapes) {
|
|
5053
5681
|
copy.shapes = cloneShapes(lyr.shapes);
|
|
5054
5682
|
}
|
|
5683
|
+
if (lyr.raster) copy.raster = copyRasterData(lyr.raster);
|
|
5055
5684
|
return copy;
|
|
5056
5685
|
}
|
|
5057
5686
|
|
|
@@ -5087,10 +5716,13 @@
|
|
|
5087
5716
|
bounds = getPointBounds$1(lyr.shapes);
|
|
5088
5717
|
} else if (lyr.geometry_type == 'polygon' || lyr.geometry_type == 'polyline') {
|
|
5089
5718
|
bounds = getPathBounds(lyr.shapes, arcs);
|
|
5719
|
+
} else if (layerHasRaster(lyr)) {
|
|
5720
|
+
bounds = getRasterLayerBounds(lyr);
|
|
5090
5721
|
} else ;
|
|
5091
5722
|
return bounds;
|
|
5092
5723
|
}
|
|
5093
5724
|
|
|
5725
|
+
|
|
5094
5726
|
function isolateLayer(layer, dataset) {
|
|
5095
5727
|
return utils.defaults({
|
|
5096
5728
|
layers: dataset.layers.filter(function(lyr) {return lyr == layer;})
|
|
@@ -5129,6 +5761,7 @@
|
|
|
5129
5761
|
layerHasNonNullShapes: layerHasNonNullShapes,
|
|
5130
5762
|
layerHasPaths: layerHasPaths,
|
|
5131
5763
|
layerHasPoints: layerHasPoints,
|
|
5764
|
+
layerHasRaster: layerHasRaster,
|
|
5132
5765
|
layerIsEmpty: layerIsEmpty,
|
|
5133
5766
|
layerIsGeometric: layerIsGeometric,
|
|
5134
5767
|
layerIsRectangle: layerIsRectangle,
|
|
@@ -8260,6 +8893,12 @@
|
|
|
8260
8893
|
});
|
|
8261
8894
|
}
|
|
8262
8895
|
|
|
8896
|
+
function datasetHasRaster(dataset) {
|
|
8897
|
+
return utils.some(dataset.layers, function(lyr) {
|
|
8898
|
+
return layerHasRaster(lyr);
|
|
8899
|
+
});
|
|
8900
|
+
}
|
|
8901
|
+
|
|
8263
8902
|
function datasetHasPaths(dataset) {
|
|
8264
8903
|
return utils.some(dataset.layers, function(lyr) {
|
|
8265
8904
|
return layerHasPaths(lyr);
|
|
@@ -8377,6 +9016,7 @@
|
|
|
8377
9016
|
copyDatasetInfo: copyDatasetInfo,
|
|
8378
9017
|
datasetHasGeometry: datasetHasGeometry,
|
|
8379
9018
|
datasetHasPaths: datasetHasPaths,
|
|
9019
|
+
datasetHasRaster: datasetHasRaster,
|
|
8380
9020
|
datasetIsEmpty: datasetIsEmpty,
|
|
8381
9021
|
getDatasetBounds: getDatasetBounds,
|
|
8382
9022
|
mergeDatasetInfo: mergeDatasetInfo,
|
|
@@ -8489,8 +9129,14 @@
|
|
|
8489
9129
|
function guessInputFileType(file) {
|
|
8490
9130
|
var ext = getFileExtension(file || '').toLowerCase(),
|
|
8491
9131
|
type = null;
|
|
8492
|
-
if (ext == 'dbf' || ext == 'shp' || ext == 'kml' || ext == 'svg' || ext == 'fgb' || ext == 'gpkg') {
|
|
9132
|
+
if (ext == 'dbf' || ext == 'shp' || ext == 'kml' || ext == 'svg' || ext == 'fgb' || ext == 'gpkg' || ext == 'png') {
|
|
8493
9133
|
type = ext;
|
|
9134
|
+
} else if (ext == 'jpg' || ext == 'jpeg') {
|
|
9135
|
+
type = 'jpeg';
|
|
9136
|
+
} else if (ext == 'tif' || ext == 'tiff') {
|
|
9137
|
+
type = 'geotiff';
|
|
9138
|
+
} else if (isWorldFileExtension(ext)) {
|
|
9139
|
+
type = 'world';
|
|
8494
9140
|
} else if (ext == 'parquet' || ext == 'geoparquet') {
|
|
8495
9141
|
type = 'parquet';
|
|
8496
9142
|
} else if (isAuxiliaryInputFileType(ext)) {
|
|
@@ -8507,7 +9153,15 @@
|
|
|
8507
9153
|
|
|
8508
9154
|
// File types that can be imported but are not convertible to datasets
|
|
8509
9155
|
function isAuxiliaryInputFileType(type) {
|
|
8510
|
-
return type == 'prj' || type == 'shx' || type == 'cpg';
|
|
9156
|
+
return type == 'prj' || type == 'shx' || type == 'cpg' || type == 'world';
|
|
9157
|
+
}
|
|
9158
|
+
|
|
9159
|
+
function isRasterImageInputType(type) {
|
|
9160
|
+
return type == 'png' || type == 'jpeg';
|
|
9161
|
+
}
|
|
9162
|
+
|
|
9163
|
+
function isWorldFileExtension(ext) {
|
|
9164
|
+
return /^(tfw|pgw|pngw|jgw|jpw|jpgw|jpegw|wld)$/i.test(ext || '');
|
|
8511
9165
|
}
|
|
8512
9166
|
|
|
8513
9167
|
function guessInputContentType(content) {
|
|
@@ -8634,7 +9288,9 @@
|
|
|
8634
9288
|
function isSupportedBinaryInputType(path) {
|
|
8635
9289
|
var ext = getFileExtension(path).toLowerCase();
|
|
8636
9290
|
return ext == 'shp' || ext == 'shx' || ext == 'dbf' ||
|
|
8637
|
-
ext == 'fgb' || ext == 'gpkg' || ext == 'parquet' || ext == 'geoparquet' ||
|
|
9291
|
+
ext == 'fgb' || ext == 'gpkg' || ext == 'parquet' || ext == 'geoparquet' ||
|
|
9292
|
+
ext == 'tif' || ext == 'tiff' || ext == 'png' || ext == 'jpg' || ext == 'jpeg' ||
|
|
9293
|
+
ext == PACKAGE_EXT; // GUI also supports zip files
|
|
8638
9294
|
}
|
|
8639
9295
|
|
|
8640
9296
|
function isImportableAsBinary(path) {
|
|
@@ -8663,7 +9319,9 @@
|
|
|
8663
9319
|
isKmzFile: isKmzFile,
|
|
8664
9320
|
isPackageFile: isPackageFile,
|
|
8665
9321
|
isPotentialCommandFile: isPotentialCommandFile,
|
|
9322
|
+
isRasterImageInputType: isRasterImageInputType,
|
|
8666
9323
|
isSupportedBinaryInputType: isSupportedBinaryInputType,
|
|
9324
|
+
isWorldFileExtension: isWorldFileExtension,
|
|
8667
9325
|
isZipFile: isZipFile,
|
|
8668
9326
|
looksLikeContentFile: looksLikeContentFile,
|
|
8669
9327
|
looksLikeImportableFile: looksLikeImportableFile,
|
|
@@ -19041,6 +19699,8 @@
|
|
|
19041
19699
|
var obj;
|
|
19042
19700
|
if (layerHasFurniture(lyr)) {
|
|
19043
19701
|
obj = exportFurnitureLayerForSVG(lyr, frame, opts);
|
|
19702
|
+
} else if (layerHasRaster(lyr)) {
|
|
19703
|
+
obj = exportRasterLayerForSVG(lyr, frame, opts);
|
|
19044
19704
|
} else {
|
|
19045
19705
|
obj = exportLayerForSVG(lyr, dataset, opts);
|
|
19046
19706
|
}
|
|
@@ -19157,6 +19817,141 @@ ${svg}
|
|
|
19157
19817
|
return layerObj;
|
|
19158
19818
|
}
|
|
19159
19819
|
|
|
19820
|
+
function exportRasterLayerForSVG(lyr, frame, opts) {
|
|
19821
|
+
var raster = lyr.raster;
|
|
19822
|
+
var clipped = clipRasterPreviewToFrame(raster, frame);
|
|
19823
|
+
var bbox = transformRasterBboxForSVG(clipped.bbox, frame);
|
|
19824
|
+
var href;
|
|
19825
|
+
var layerObj = getEmptyLayerForSVG(lyr, opts);
|
|
19826
|
+
if (!clipped.preview.width || !clipped.preview.height) {
|
|
19827
|
+
layerObj.children = [];
|
|
19828
|
+
return layerObj;
|
|
19829
|
+
}
|
|
19830
|
+
href = encodeRasterPreview(clipped.preview, opts);
|
|
19831
|
+
layerObj.children = [{
|
|
19832
|
+
tag: 'image',
|
|
19833
|
+
properties: {
|
|
19834
|
+
x: bbox[0],
|
|
19835
|
+
y: bbox[1],
|
|
19836
|
+
width: bbox[2] - bbox[0],
|
|
19837
|
+
height: bbox[3] - bbox[1],
|
|
19838
|
+
href: href,
|
|
19839
|
+
preserveAspectRatio: 'none'
|
|
19840
|
+
}
|
|
19841
|
+
}];
|
|
19842
|
+
return layerObj;
|
|
19843
|
+
}
|
|
19844
|
+
|
|
19845
|
+
function clipRasterPreviewToFrame(raster, frame) {
|
|
19846
|
+
var rasterBbox = getRasterBBox(raster);
|
|
19847
|
+
var preview = getRasterPreview(raster);
|
|
19848
|
+
var rasterBounds = new Bounds(rasterBbox);
|
|
19849
|
+
var clipBounds = new Bounds(frame.bbox);
|
|
19850
|
+
var bbox = intersectBboxes(rasterBounds.toArray(), clipBounds.toArray()) || [0, 0, 0, 0];
|
|
19851
|
+
var crop = getRasterPreviewCrop(rasterBbox, preview, bbox);
|
|
19852
|
+
return {
|
|
19853
|
+
bbox: bbox,
|
|
19854
|
+
preview: cropRasterPreview(preview, crop)
|
|
19855
|
+
};
|
|
19856
|
+
}
|
|
19857
|
+
|
|
19858
|
+
function getRasterPreviewCrop(rasterBbox, preview, bbox) {
|
|
19859
|
+
var rb = rasterBbox;
|
|
19860
|
+
var p = preview;
|
|
19861
|
+
var x0 = Math.max(0, Math.floor((bbox[0] - rb[0]) / (rb[2] - rb[0]) * p.width));
|
|
19862
|
+
var x1 = Math.min(p.width, Math.ceil((bbox[2] - rb[0]) / (rb[2] - rb[0]) * p.width));
|
|
19863
|
+
var y0 = Math.max(0, Math.floor((rb[3] - bbox[3]) / (rb[3] - rb[1]) * p.height));
|
|
19864
|
+
var y1 = Math.min(p.height, Math.ceil((rb[3] - bbox[1]) / (rb[3] - rb[1]) * p.height));
|
|
19865
|
+
return {
|
|
19866
|
+
x: x0,
|
|
19867
|
+
y: y0,
|
|
19868
|
+
width: Math.max(0, x1 - x0),
|
|
19869
|
+
height: Math.max(0, y1 - y0)
|
|
19870
|
+
};
|
|
19871
|
+
}
|
|
19872
|
+
|
|
19873
|
+
function cropRasterPreview(preview, crop) {
|
|
19874
|
+
if (crop.x === 0 && crop.y === 0 && crop.width == preview.width && crop.height == preview.height) {
|
|
19875
|
+
return preview;
|
|
19876
|
+
}
|
|
19877
|
+
var pixels = new Uint8ClampedArray(crop.width * crop.height * 4);
|
|
19878
|
+
var src, dest, rowBytes = crop.width * 4;
|
|
19879
|
+
for (var y = 0; y < crop.height; y++) {
|
|
19880
|
+
src = ((crop.y + y) * preview.width + crop.x) * 4;
|
|
19881
|
+
dest = y * rowBytes;
|
|
19882
|
+
pixels.set(preview.pixels.subarray(src, src + rowBytes), dest);
|
|
19883
|
+
}
|
|
19884
|
+
return Object.assign({}, preview, {
|
|
19885
|
+
width: crop.width,
|
|
19886
|
+
height: crop.height,
|
|
19887
|
+
pixels: pixels
|
|
19888
|
+
});
|
|
19889
|
+
}
|
|
19890
|
+
|
|
19891
|
+
function transformRasterBboxForSVG(bbox, frame) {
|
|
19892
|
+
var srcBounds = new Bounds(frame.bbox);
|
|
19893
|
+
var destBounds = frame.bbox2 ? new Bounds(frame.bbox2) : new Bounds(0, 0, frame.width, frame.height);
|
|
19894
|
+
srcBounds.fillOut(destBounds.width() / destBounds.height());
|
|
19895
|
+
var fwd = srcBounds.getTransform(destBounds, frame.invert_y);
|
|
19896
|
+
var p1 = fwd.transform(bbox[0], bbox[3]);
|
|
19897
|
+
var p2 = fwd.transform(bbox[2], bbox[1]);
|
|
19898
|
+
return [p1[0], p1[1], p2[0], p2[1]];
|
|
19899
|
+
}
|
|
19900
|
+
|
|
19901
|
+
function encodeRasterPreview(preview, opts) {
|
|
19902
|
+
var format = getSvgRasterFormat(preview, opts);
|
|
19903
|
+
var data = format == 'png' ? encodePng(preview) : encodeJpeg(preview, opts);
|
|
19904
|
+
return 'data:image/' + format + ';base64,' + data;
|
|
19905
|
+
}
|
|
19906
|
+
|
|
19907
|
+
function getSvgRasterFormat(preview, opts) {
|
|
19908
|
+
var fmt = opts.svg_raster_format || opts.raster_format || null;
|
|
19909
|
+
if (fmt) return fmt == 'jpg' ? 'jpeg' : fmt;
|
|
19910
|
+
return previewHasTransparency(preview) ? 'png' : 'jpeg';
|
|
19911
|
+
}
|
|
19912
|
+
|
|
19913
|
+
function previewHasTransparency(preview) {
|
|
19914
|
+
var pixels = preview.pixels;
|
|
19915
|
+
for (var i = 3; i < pixels.length; i += 4) {
|
|
19916
|
+
if (pixels[i] < 255) return true;
|
|
19917
|
+
}
|
|
19918
|
+
return false;
|
|
19919
|
+
}
|
|
19920
|
+
|
|
19921
|
+
function encodeJpeg(preview, opts) {
|
|
19922
|
+
if (runningInBrowser() && typeof document != 'undefined') {
|
|
19923
|
+
return encodeWithCanvas(preview, 'image/jpeg', opts.svg_raster_quality || 0.85);
|
|
19924
|
+
}
|
|
19925
|
+
var jpeg = require$1('jpeg-js');
|
|
19926
|
+
var quality = Math.round((opts.svg_raster_quality || 0.85) * 100);
|
|
19927
|
+
return Buffer.from(jpeg.encode({
|
|
19928
|
+
data: Buffer.from(preview.pixels),
|
|
19929
|
+
width: preview.width,
|
|
19930
|
+
height: preview.height
|
|
19931
|
+
}, quality).data).toString('base64');
|
|
19932
|
+
}
|
|
19933
|
+
|
|
19934
|
+
function encodePng(preview) {
|
|
19935
|
+
if (runningInBrowser() && typeof document != 'undefined') {
|
|
19936
|
+
return encodeWithCanvas(preview, 'image/png');
|
|
19937
|
+
}
|
|
19938
|
+
var PNG = require$1('pngjs').PNG;
|
|
19939
|
+
var png = new PNG({width: preview.width, height: preview.height});
|
|
19940
|
+
png.data = Buffer.from(preview.pixels);
|
|
19941
|
+
return Buffer.from(PNG.sync.write(png)).toString('base64');
|
|
19942
|
+
}
|
|
19943
|
+
|
|
19944
|
+
function encodeWithCanvas(preview, type, quality) {
|
|
19945
|
+
var canvas = document.createElement('canvas');
|
|
19946
|
+
var ctx = canvas.getContext('2d');
|
|
19947
|
+
var dataUrl;
|
|
19948
|
+
canvas.width = preview.width;
|
|
19949
|
+
canvas.height = preview.height;
|
|
19950
|
+
ctx.putImageData(new ImageData(preview.pixels, preview.width, preview.height), 0, 0);
|
|
19951
|
+
dataUrl = canvas.toDataURL(type, quality);
|
|
19952
|
+
return dataUrl.split(',')[1];
|
|
19953
|
+
}
|
|
19954
|
+
|
|
19160
19955
|
function exportSymbolsForSVG(lyr, dataset, opts) {
|
|
19161
19956
|
// TODO: convert geojson features one at a time
|
|
19162
19957
|
var d = utils.defaults({layers: [lyr]}, dataset);
|
|
@@ -19373,6 +20168,7 @@ ${svg}
|
|
|
19373
20168
|
exportDataAttributesForSVG: exportDataAttributesForSVG,
|
|
19374
20169
|
exportFurnitureLayerForSVG: exportFurnitureLayerForSVG,
|
|
19375
20170
|
exportLayerForSVG: exportLayerForSVG,
|
|
20171
|
+
exportRasterLayerForSVG: exportRasterLayerForSVG,
|
|
19376
20172
|
exportSVG: exportSVG,
|
|
19377
20173
|
featureHasLabel: featureHasLabel,
|
|
19378
20174
|
featureHasSvgSymbol: featureHasSvgSymbol,
|
|
@@ -22609,6 +23405,8 @@ ${svg}
|
|
|
22609
23405
|
name: lyr.name || null,
|
|
22610
23406
|
geometry_type: lyr.geometry_type || null,
|
|
22611
23407
|
shapes: lyr.shapes || null,
|
|
23408
|
+
raster_type: lyr.raster_type || null,
|
|
23409
|
+
raster: lyr.raster ? exportRasterData(lyr.raster) : null,
|
|
22612
23410
|
data: data,
|
|
22613
23411
|
menu_order: lyr.menu_order || null,
|
|
22614
23412
|
pinned: lyr.pinned || opts.show_all || false,
|
|
@@ -22616,6 +23414,37 @@ ${svg}
|
|
|
22616
23414
|
};
|
|
22617
23415
|
}
|
|
22618
23416
|
|
|
23417
|
+
function exportRasterData(raster) {
|
|
23418
|
+
var copy = Object.assign({}, raster);
|
|
23419
|
+
if (raster.grid) {
|
|
23420
|
+
copy.grid = Object.assign({}, raster.grid);
|
|
23421
|
+
if (raster.grid.samples) {
|
|
23422
|
+
copy.grid.samples = typedArrayToBuffer(raster.grid.samples);
|
|
23423
|
+
}
|
|
23424
|
+
}
|
|
23425
|
+
if (raster.view) {
|
|
23426
|
+
copy.view = Object.assign({}, raster.view);
|
|
23427
|
+
if (raster.view.preview) {
|
|
23428
|
+
copy.view.preview = Object.assign({}, raster.view.preview);
|
|
23429
|
+
delete copy.view.preview.canvas;
|
|
23430
|
+
if (raster.view.preview.pixels) {
|
|
23431
|
+
copy.view.preview.pixels = typedArrayToBuffer(raster.view.preview.pixels);
|
|
23432
|
+
}
|
|
23433
|
+
}
|
|
23434
|
+
}
|
|
23435
|
+
if (raster.preview) {
|
|
23436
|
+
copy.preview = Object.assign({}, raster.preview);
|
|
23437
|
+
delete copy.preview.canvas;
|
|
23438
|
+
if (raster.preview.pixels) {
|
|
23439
|
+
copy.preview.pixels = typedArrayToBuffer(raster.preview.pixels);
|
|
23440
|
+
}
|
|
23441
|
+
}
|
|
23442
|
+
if (raster.pixels) {
|
|
23443
|
+
copy.pixels = typedArrayToBuffer(raster.pixels);
|
|
23444
|
+
}
|
|
23445
|
+
return copy;
|
|
23446
|
+
}
|
|
23447
|
+
|
|
22619
23448
|
function exportInfo(info) {
|
|
22620
23449
|
info = Object.assign({}, info);
|
|
22621
23450
|
if (info.crs && !info.crs_string && !info.wkt1) {
|
|
@@ -26256,7 +27085,7 @@ ${svg}
|
|
|
26256
27085
|
|
|
26257
27086
|
var writerPromise = null;
|
|
26258
27087
|
var zstdPromise = null;
|
|
26259
|
-
var dynamicImportModule$
|
|
27088
|
+
var dynamicImportModule$2 = Function('id', 'return import(id)');
|
|
26260
27089
|
|
|
26261
27090
|
async function exportGeoParquet(dataset, opts, filenameOverride) {
|
|
26262
27091
|
var writer = await loadGeoParquetWriter();
|
|
@@ -26471,7 +27300,7 @@ ${svg}
|
|
|
26471
27300
|
return mod;
|
|
26472
27301
|
}
|
|
26473
27302
|
if (!writerPromise) {
|
|
26474
|
-
writerPromise = dynamicImportModule$
|
|
27303
|
+
writerPromise = dynamicImportModule$2('hyparquet-writer');
|
|
26475
27304
|
}
|
|
26476
27305
|
var nodeMod = await writerPromise;
|
|
26477
27306
|
return nodeMod.default && !nodeMod.parquetWriteBuffer ? nodeMod.default : nodeMod;
|
|
@@ -26540,7 +27369,7 @@ ${svg}
|
|
|
26540
27369
|
mod = require$1('@bokuweb/zstd-wasm');
|
|
26541
27370
|
} else {
|
|
26542
27371
|
if (!zstdPromise) {
|
|
26543
|
-
zstdPromise = dynamicImportModule$
|
|
27372
|
+
zstdPromise = dynamicImportModule$2('@bokuweb/zstd-wasm');
|
|
26544
27373
|
}
|
|
26545
27374
|
mod = await zstdPromise;
|
|
26546
27375
|
}
|
|
@@ -26663,6 +27492,7 @@ ${svg}
|
|
|
26663
27492
|
async function exportDatasets(datasets, opts) {
|
|
26664
27493
|
var format = getOutputFormat(datasets[0], opts);
|
|
26665
27494
|
var files;
|
|
27495
|
+
validateRasterExportFormat(datasets, format);
|
|
26666
27496
|
if (format != 'geoparquet' && (opts.compression || opts.level !== undefined)) {
|
|
26667
27497
|
error('The compression= and level= options only apply to GeoParquet output');
|
|
26668
27498
|
}
|
|
@@ -26732,6 +27562,18 @@ ${svg}
|
|
|
26732
27562
|
return files;
|
|
26733
27563
|
}
|
|
26734
27564
|
|
|
27565
|
+
function validateRasterExportFormat(datasets, format) {
|
|
27566
|
+
if (!datasetsHaveRasterLayers(datasets)) return;
|
|
27567
|
+
if (format == 'svg' || format == PACKAGE_EXT) return;
|
|
27568
|
+
stop$1('Raster layers can only be exported as SVG or ' + PACKAGE_EXT + ' files');
|
|
27569
|
+
}
|
|
27570
|
+
|
|
27571
|
+
function datasetsHaveRasterLayers(datasets) {
|
|
27572
|
+
return datasets.some(function(dataset) {
|
|
27573
|
+
return dataset.layers && dataset.layers.some(layerHasRaster);
|
|
27574
|
+
});
|
|
27575
|
+
}
|
|
27576
|
+
|
|
26735
27577
|
// Return an array of objects with 'filename' and 'content' members.
|
|
26736
27578
|
//
|
|
26737
27579
|
function exportFileContent(dataset, opts) {
|
|
@@ -26744,6 +27586,7 @@ ${svg}
|
|
|
26744
27586
|
} else if (!exporter) {
|
|
26745
27587
|
error('Unknown output format:', outFmt);
|
|
26746
27588
|
}
|
|
27589
|
+
validateRasterExportFormat([dataset], outFmt);
|
|
26747
27590
|
|
|
26748
27591
|
// shallow-copy dataset and layers, so layers can be renamed for export
|
|
26749
27592
|
dataset = utils.defaults({
|
|
@@ -26819,7 +27662,11 @@ ${svg}
|
|
|
26819
27662
|
// Throw errors for various error conditions
|
|
26820
27663
|
function validateLayerData(layers) {
|
|
26821
27664
|
layers.forEach(function(lyr) {
|
|
26822
|
-
if (
|
|
27665
|
+
if (layerHasRaster(lyr)) {
|
|
27666
|
+
if (!getRasterBBox(lyr.raster) || !getRasterPreview(lyr.raster) && !(getRasterGrid(lyr.raster) && getRasterGrid(lyr.raster).samples)) {
|
|
27667
|
+
error('A raster layer is missing preview data or bounds');
|
|
27668
|
+
}
|
|
27669
|
+
} else if (!lyr.geometry_type) {
|
|
26823
27670
|
// allowing data-only layers
|
|
26824
27671
|
if (lyr.shapes && utils.some(lyr.shapes, function(o) {
|
|
26825
27672
|
return !!o;
|
|
@@ -29108,6 +29955,18 @@ ${svg}
|
|
|
29108
29955
|
type: 'strings',
|
|
29109
29956
|
describe: '[GPKG] comma-sep. list of layers to import'
|
|
29110
29957
|
})
|
|
29958
|
+
.option('scaling', {
|
|
29959
|
+
describe: '[raster] raster display scaling method: none,minmax,percentile'
|
|
29960
|
+
})
|
|
29961
|
+
.option('scale-range', {
|
|
29962
|
+
describe: '[raster] display intensity range in percent, e.g. 0,100'
|
|
29963
|
+
})
|
|
29964
|
+
.option('percentile-range', {
|
|
29965
|
+
describe: '[raster] input percentile range for percentile scaling, e.g. 2,98'
|
|
29966
|
+
})
|
|
29967
|
+
.option('rendition', {
|
|
29968
|
+
describe: '[GeoTIFF] import a GeoTIFF rendition: full,overview-1,etc.'
|
|
29969
|
+
})
|
|
29111
29970
|
.option('geometry-type', {
|
|
29112
29971
|
// undocumented; GeoJSON import rejects all but one kind of geometry
|
|
29113
29972
|
// describe: '[GeoJSON] Import one kind of geometry (point|polygon|polyline)'
|
|
@@ -34446,7 +35305,7 @@ ${svg}
|
|
|
34446
35305
|
|
|
34447
35306
|
var hyparquetPromise = null;
|
|
34448
35307
|
var compressorsPromise = null;
|
|
34449
|
-
var dynamicImportModule = Function('id', 'return import(id)');
|
|
35308
|
+
var dynamicImportModule$1 = Function('id', 'return import(id)');
|
|
34450
35309
|
var mproj = null;
|
|
34451
35310
|
|
|
34452
35311
|
async function importGeoParquet(input, optsArg) {
|
|
@@ -34493,7 +35352,7 @@ ${svg}
|
|
|
34493
35352
|
return mod;
|
|
34494
35353
|
}
|
|
34495
35354
|
if (!hyparquetPromise) {
|
|
34496
|
-
hyparquetPromise = dynamicImportModule('hyparquet');
|
|
35355
|
+
hyparquetPromise = dynamicImportModule$1('hyparquet');
|
|
34497
35356
|
}
|
|
34498
35357
|
var nodeMod = await hyparquetPromise;
|
|
34499
35358
|
return nodeMod.default && !nodeMod.parquetReadObjects ? nodeMod.default : nodeMod;
|
|
@@ -34504,7 +35363,7 @@ ${svg}
|
|
|
34504
35363
|
return getHyparquetCompressors(require$1('hyparquet-compressors'));
|
|
34505
35364
|
}
|
|
34506
35365
|
if (!compressorsPromise) {
|
|
34507
|
-
compressorsPromise = dynamicImportModule('hyparquet-compressors');
|
|
35366
|
+
compressorsPromise = dynamicImportModule$1('hyparquet-compressors');
|
|
34508
35367
|
}
|
|
34509
35368
|
return getHyparquetCompressors(await compressorsPromise);
|
|
34510
35369
|
}
|
|
@@ -34833,6 +35692,668 @@ ${svg}
|
|
|
34833
35692
|
};
|
|
34834
35693
|
}
|
|
34835
35694
|
|
|
35695
|
+
var geotiffPromise = null;
|
|
35696
|
+
var geoKeysToProj4Promise = null;
|
|
35697
|
+
var dynamicImportModule = Function('id', 'return import(id)');
|
|
35698
|
+
var DEFAULT_MAX_IMPORT_PIXELS = 16e6;
|
|
35699
|
+
|
|
35700
|
+
async function importGeoTIFF(input, optsArg) {
|
|
35701
|
+
var opts = optsArg || {};
|
|
35702
|
+
var geotiff = await loadGeoTIFFLib();
|
|
35703
|
+
var source = getGeoTIFFSource(input);
|
|
35704
|
+
var tiff = await openGeoTIFF(source, geotiff);
|
|
35705
|
+
var sourceImage = await tiff.getImage();
|
|
35706
|
+
var importImage = await selectGeoTIFFImportImage(tiff, sourceImage, opts);
|
|
35707
|
+
var imported = await importGeoTIFFImage(importImage, input, opts, sourceImage);
|
|
35708
|
+
var dataset = {
|
|
35709
|
+
info: {
|
|
35710
|
+
raster_sources: [imported.source]
|
|
35711
|
+
},
|
|
35712
|
+
layers: [{
|
|
35713
|
+
name: input && input.filename ? getFileBase(input.filename) : null,
|
|
35714
|
+
raster_type: 'grid',
|
|
35715
|
+
raster: imported.raster
|
|
35716
|
+
}]
|
|
35717
|
+
};
|
|
35718
|
+
await importGeoTIFFCrs(dataset, sourceImage);
|
|
35719
|
+
return dataset;
|
|
35720
|
+
}
|
|
35721
|
+
|
|
35722
|
+
async function loadGeoTIFFLib() {
|
|
35723
|
+
var mod;
|
|
35724
|
+
if (runningInBrowser()) {
|
|
35725
|
+
mod = require$1('geotiff');
|
|
35726
|
+
if (!mod || !mod.fromArrayBuffer) {
|
|
35727
|
+
stop$1('GeoTIFF library is not loaded');
|
|
35728
|
+
}
|
|
35729
|
+
return mod;
|
|
35730
|
+
}
|
|
35731
|
+
if (!geotiffPromise) {
|
|
35732
|
+
geotiffPromise = dynamicImportModule('geotiff');
|
|
35733
|
+
}
|
|
35734
|
+
mod = await geotiffPromise;
|
|
35735
|
+
return mod.default && !mod.fromArrayBuffer ? mod.default : mod;
|
|
35736
|
+
}
|
|
35737
|
+
|
|
35738
|
+
async function loadGeoKeysToProj4Lib() {
|
|
35739
|
+
var mod;
|
|
35740
|
+
if (runningInBrowser()) {
|
|
35741
|
+
return require$1('geotiff-geokeys-to-proj4');
|
|
35742
|
+
}
|
|
35743
|
+
if (!geoKeysToProj4Promise) {
|
|
35744
|
+
geoKeysToProj4Promise = dynamicImportModule('geotiff-geokeys-to-proj4');
|
|
35745
|
+
}
|
|
35746
|
+
mod = await geoKeysToProj4Promise;
|
|
35747
|
+
return mod.default || mod;
|
|
35748
|
+
}
|
|
35749
|
+
|
|
35750
|
+
async function openGeoTIFF(source, geotiff) {
|
|
35751
|
+
if (!source) {
|
|
35752
|
+
stop$1('Missing GeoTIFF source data');
|
|
35753
|
+
}
|
|
35754
|
+
return geotiff.fromArrayBuffer(source);
|
|
35755
|
+
}
|
|
35756
|
+
|
|
35757
|
+
function getGeoTIFFSource(input) {
|
|
35758
|
+
var content = input && input.content;
|
|
35759
|
+
if (!content) return null;
|
|
35760
|
+
if (content instanceof ArrayBuffer) return content;
|
|
35761
|
+
return content.buffer.slice(content.byteOffset || 0, (content.byteOffset || 0) + content.byteLength);
|
|
35762
|
+
}
|
|
35763
|
+
|
|
35764
|
+
async function importGeoTIFFImage(importImage, input, opts, sourceImage) {
|
|
35765
|
+
var image = importImage.image;
|
|
35766
|
+
var width = importImage.width;
|
|
35767
|
+
var height = importImage.height;
|
|
35768
|
+
var samplesPerPixel = image.getSamplesPerPixel();
|
|
35769
|
+
var samples = getDisplaySamples(samplesPerPixel);
|
|
35770
|
+
var imageBbox = getImageBoundingBox(sourceImage);
|
|
35771
|
+
repairDeferredOffsetArrays(image);
|
|
35772
|
+
var data = await readGeoTIFFSamples(image, samples, width, height);
|
|
35773
|
+
var noData = getNoDataValue(image);
|
|
35774
|
+
var sourceId = getSourceId(input);
|
|
35775
|
+
var raster = {
|
|
35776
|
+
sourceId: sourceId,
|
|
35777
|
+
grid: {
|
|
35778
|
+
width: width,
|
|
35779
|
+
height: height,
|
|
35780
|
+
bands: samples.length,
|
|
35781
|
+
pixelType: getPixelType(image),
|
|
35782
|
+
samples: data,
|
|
35783
|
+
sampleBands: samples,
|
|
35784
|
+
nodata: noData,
|
|
35785
|
+
bbox: imageBbox,
|
|
35786
|
+
transform: getImageTransformForSize(sourceImage, width, height, imageBbox)
|
|
35787
|
+
},
|
|
35788
|
+
derivation: {
|
|
35789
|
+
type: samples.length >= 3 ? 'rgb' : 'gray',
|
|
35790
|
+
sourceId: sourceId,
|
|
35791
|
+
bands: samples
|
|
35792
|
+
},
|
|
35793
|
+
view: {
|
|
35794
|
+
recipe: {
|
|
35795
|
+
type: samples.length >= 3 ? 'rgb' : 'gray',
|
|
35796
|
+
bands: samples
|
|
35797
|
+
}
|
|
35798
|
+
}
|
|
35799
|
+
};
|
|
35800
|
+
raster.view.recipe = getRasterViewRecipe(raster.grid, raster.view.recipe, opts);
|
|
35801
|
+
raster.view.preview = createRasterPreview(raster, opts);
|
|
35802
|
+
return {
|
|
35803
|
+
raster: raster,
|
|
35804
|
+
source: getSourceInfo$1(input, sourceId, sourceImage)
|
|
35805
|
+
};
|
|
35806
|
+
}
|
|
35807
|
+
|
|
35808
|
+
async function selectGeoTIFFImportImage(tiff, sourceImage, opts) {
|
|
35809
|
+
var maxPixels = getMaxImportPixels(opts);
|
|
35810
|
+
var renditions = await getGeoTIFFRenditions(tiff, sourceImage);
|
|
35811
|
+
var source = renditions[0];
|
|
35812
|
+
var best = getRequestedRendition(renditions, opts.rendition);
|
|
35813
|
+
var bestPixels;
|
|
35814
|
+
if (!best) {
|
|
35815
|
+
best = source;
|
|
35816
|
+
bestPixels = best.width * best.height;
|
|
35817
|
+
if (bestPixels > maxPixels) {
|
|
35818
|
+
best = getAutomaticRendition(renditions, maxPixels);
|
|
35819
|
+
bestPixels = best.width * best.height;
|
|
35820
|
+
if (bestPixels > maxPixels) {
|
|
35821
|
+
best = getResizedImportImage(best, maxPixels);
|
|
35822
|
+
}
|
|
35823
|
+
}
|
|
35824
|
+
}
|
|
35825
|
+
if (renditions.length > 1 && (runningInBrowser() || opts.rendition)) {
|
|
35826
|
+
message(getRenditionsMessage(renditions, best));
|
|
35827
|
+
}
|
|
35828
|
+
if (best.slug != 'full' || best.width != source.width || best.height != source.height) {
|
|
35829
|
+
warnOnce(getImportRenditionMessage(best, source));
|
|
35830
|
+
}
|
|
35831
|
+
return best;
|
|
35832
|
+
}
|
|
35833
|
+
|
|
35834
|
+
async function getGeoTIFFRenditions(tiff, sourceImage) {
|
|
35835
|
+
var imageCount = await tiff.getImageCount();
|
|
35836
|
+
var renditions = [getRenditionInfo(sourceImage, 0)];
|
|
35837
|
+
var image;
|
|
35838
|
+
for (var i = 1; i < imageCount; i++) {
|
|
35839
|
+
image = await tiff.getImage(i);
|
|
35840
|
+
renditions.push(getRenditionInfo(image, i));
|
|
35841
|
+
}
|
|
35842
|
+
return renditions;
|
|
35843
|
+
}
|
|
35844
|
+
|
|
35845
|
+
function getRenditionInfo(image, index) {
|
|
35846
|
+
return {
|
|
35847
|
+
image: image,
|
|
35848
|
+
index: index,
|
|
35849
|
+
slug: index === 0 ? 'full' : 'overview-' + index,
|
|
35850
|
+
width: image.getWidth(),
|
|
35851
|
+
height: image.getHeight()
|
|
35852
|
+
};
|
|
35853
|
+
}
|
|
35854
|
+
|
|
35855
|
+
function getRequestedRendition(renditions, slug) {
|
|
35856
|
+
var match;
|
|
35857
|
+
if (!slug) return null;
|
|
35858
|
+
slug = String(slug);
|
|
35859
|
+
match = renditions.find(function(rendition) {
|
|
35860
|
+
return rendition.slug == slug || rendition.width + 'x' + rendition.height == slug;
|
|
35861
|
+
});
|
|
35862
|
+
if (!match) {
|
|
35863
|
+
stop$1('Unknown GeoTIFF rendition:', slug + '.', 'Use one of:', renditions.map(function(rendition) {
|
|
35864
|
+
return rendition.slug;
|
|
35865
|
+
}).join(','));
|
|
35866
|
+
}
|
|
35867
|
+
return match;
|
|
35868
|
+
}
|
|
35869
|
+
|
|
35870
|
+
function getAutomaticRendition(renditions, maxPixels) {
|
|
35871
|
+
var best = renditions[0];
|
|
35872
|
+
var bestPixels = best.width * best.height;
|
|
35873
|
+
var rendition, pixels;
|
|
35874
|
+
for (var i = 1; i < renditions.length; i++) {
|
|
35875
|
+
rendition = renditions[i];
|
|
35876
|
+
pixels = rendition.width * rendition.height;
|
|
35877
|
+
if (pixels <= maxPixels && (bestPixels > maxPixels || pixels > bestPixels)) {
|
|
35878
|
+
best = rendition;
|
|
35879
|
+
bestPixels = pixels;
|
|
35880
|
+
} else if (bestPixels > maxPixels && pixels < bestPixels) {
|
|
35881
|
+
best = rendition;
|
|
35882
|
+
bestPixels = pixels;
|
|
35883
|
+
}
|
|
35884
|
+
}
|
|
35885
|
+
return best;
|
|
35886
|
+
}
|
|
35887
|
+
|
|
35888
|
+
function getRenditionsMessage(renditions, selected) {
|
|
35889
|
+
var lines = ['GeoTIFF renditions:'];
|
|
35890
|
+
renditions.forEach(function(rendition) {
|
|
35891
|
+
lines.push(' ' + rendition.slug + ': ' + rendition.width + 'x' + rendition.height +
|
|
35892
|
+
(rendition.slug == selected.slug ? ' [selected]' : ''));
|
|
35893
|
+
});
|
|
35894
|
+
lines.push('Use import option rendition=<slug> to select a different rendition.');
|
|
35895
|
+
return lines.join('\n');
|
|
35896
|
+
}
|
|
35897
|
+
|
|
35898
|
+
function getImportRenditionMessage(importImage, source) {
|
|
35899
|
+
if (importImage.resampled) {
|
|
35900
|
+
return 'Using resampled GeoTIFF ' + (importImage.sourceSlug == 'full' ? 'full-resolution image' : 'rendition ' + importImage.sourceSlug) +
|
|
35901
|
+
' for import: ' + importImage.width + 'x' + importImage.height +
|
|
35902
|
+
' (source: ' + source.width + 'x' + source.height + ').';
|
|
35903
|
+
}
|
|
35904
|
+
return 'Using reduced-resolution GeoTIFF rendition for import: ' + importImage.slug + ' ' +
|
|
35905
|
+
importImage.width + 'x' + importImage.height + ' (source: ' + source.width + 'x' + source.height + ').';
|
|
35906
|
+
}
|
|
35907
|
+
|
|
35908
|
+
function getResizedImportImage(importImage, maxPixels) {
|
|
35909
|
+
var scale = Math.min(1, Math.sqrt(maxPixels / (importImage.width * importImage.height)));
|
|
35910
|
+
return Object.assign({}, importImage, {
|
|
35911
|
+
sourceSlug: importImage.slug,
|
|
35912
|
+
slug: importImage.slug + '-resampled',
|
|
35913
|
+
resampled: true,
|
|
35914
|
+
width: Math.max(1, Math.round(importImage.width * scale)),
|
|
35915
|
+
height: Math.max(1, Math.round(importImage.height * scale))
|
|
35916
|
+
});
|
|
35917
|
+
}
|
|
35918
|
+
|
|
35919
|
+
function getMaxImportPixels(opts) {
|
|
35920
|
+
return opts.maxPixels || opts.raster_max_pixels || opts.rasterMaxPixels ||
|
|
35921
|
+
DEFAULT_MAX_IMPORT_PIXELS;
|
|
35922
|
+
}
|
|
35923
|
+
|
|
35924
|
+
async function readGeoTIFFSamples(image, samples, width, height) {
|
|
35925
|
+
var opts = {
|
|
35926
|
+
interleave: true,
|
|
35927
|
+
width: width,
|
|
35928
|
+
height: height
|
|
35929
|
+
};
|
|
35930
|
+
if (useRGBRead(image, samples)) {
|
|
35931
|
+
return image.readRGB(opts);
|
|
35932
|
+
}
|
|
35933
|
+
opts.samples = samples;
|
|
35934
|
+
return image.readRasters(opts);
|
|
35935
|
+
}
|
|
35936
|
+
|
|
35937
|
+
function useRGBRead(image, samples) {
|
|
35938
|
+
return samples.length == 3 && getPhotometricInterpretation(image) == 6 && image.readRGB;
|
|
35939
|
+
}
|
|
35940
|
+
|
|
35941
|
+
function getDisplaySamples(samplesPerPixel) {
|
|
35942
|
+
if (samplesPerPixel >= 4) return [0, 1, 2, 3];
|
|
35943
|
+
if (samplesPerPixel >= 3) return [0, 1, 2];
|
|
35944
|
+
return [0];
|
|
35945
|
+
}
|
|
35946
|
+
|
|
35947
|
+
function getNoDataValue(image) {
|
|
35948
|
+
var val = image.getGDALNoData && image.getGDALNoData();
|
|
35949
|
+
return val == null || val === '' ? null : +val;
|
|
35950
|
+
}
|
|
35951
|
+
|
|
35952
|
+
function getPixelType(image) {
|
|
35953
|
+
var fmt = image.getSampleFormat && image.getSampleFormat();
|
|
35954
|
+
var bits = image.getBitsPerSample && image.getBitsPerSample();
|
|
35955
|
+
if (Array.isArray(fmt)) fmt = fmt[0];
|
|
35956
|
+
if (Array.isArray(bits)) bits = bits[0];
|
|
35957
|
+
var type = fmt == 3 ? 'float' : fmt == 2 ? 'int' : 'uint';
|
|
35958
|
+
return bits ? type + bits : type;
|
|
35959
|
+
}
|
|
35960
|
+
|
|
35961
|
+
function getImageBoundingBox(image) {
|
|
35962
|
+
try {
|
|
35963
|
+
return image.getBoundingBox().map(Number);
|
|
35964
|
+
} catch(e) {
|
|
35965
|
+
stop$1('GeoTIFF is missing georeferencing metadata');
|
|
35966
|
+
}
|
|
35967
|
+
}
|
|
35968
|
+
|
|
35969
|
+
function getImageTransformForSize(image, width, height, bbox) {
|
|
35970
|
+
var sourceBbox = bbox || getImageBoundingBox(image);
|
|
35971
|
+
return [
|
|
35972
|
+
(sourceBbox[2] - sourceBbox[0]) / width,
|
|
35973
|
+
0,
|
|
35974
|
+
sourceBbox[0],
|
|
35975
|
+
0,
|
|
35976
|
+
(sourceBbox[1] - sourceBbox[3]) / height,
|
|
35977
|
+
sourceBbox[3]
|
|
35978
|
+
];
|
|
35979
|
+
}
|
|
35980
|
+
|
|
35981
|
+
function getImageTransform(image) {
|
|
35982
|
+
var origin = image.getOrigin && image.getOrigin();
|
|
35983
|
+
var resolution = image.getResolution && image.getResolution();
|
|
35984
|
+
if (!origin || !resolution) return null;
|
|
35985
|
+
return [resolution[0], 0, origin[0], 0, resolution[1], origin[1]];
|
|
35986
|
+
}
|
|
35987
|
+
|
|
35988
|
+
function getPhotometricInterpretation(image) {
|
|
35989
|
+
var fileDirectory = image && image.fileDirectory;
|
|
35990
|
+
return fileDirectory && fileDirectory.actualizedFields && fileDirectory.actualizedFields.get(262);
|
|
35991
|
+
}
|
|
35992
|
+
|
|
35993
|
+
function repairDeferredOffsetArrays(image) {
|
|
35994
|
+
var fileDirectory = image && image.fileDirectory;
|
|
35995
|
+
var arrays = fileDirectory && fileDirectory.deferredArrays;
|
|
35996
|
+
if (!arrays || !fileDirectory.actualizedFields) return;
|
|
35997
|
+
// Work around geotiff.js decoding big-endian deferred offset/count arrays as little-endian.
|
|
35998
|
+
[273, 279, 324, 325].forEach(function(tag) {
|
|
35999
|
+
var deferred = arrays.get(tag);
|
|
36000
|
+
var values;
|
|
36001
|
+
if (!deferred || deferred.littleEndian) return;
|
|
36002
|
+
values = decodeDeferredIntegerArray(deferred);
|
|
36003
|
+
if (!values) return;
|
|
36004
|
+
fileDirectory.actualizedFields.set(tag, values);
|
|
36005
|
+
arrays.delete(tag);
|
|
36006
|
+
});
|
|
36007
|
+
}
|
|
36008
|
+
|
|
36009
|
+
function decodeDeferredIntegerArray(deferred) {
|
|
36010
|
+
var source = deferred.source && deferred.source.arrayBuffer;
|
|
36011
|
+
var offset = deferred.arrayOffset;
|
|
36012
|
+
var length = deferred.length;
|
|
36013
|
+
var itemSize = deferred.itemSize;
|
|
36014
|
+
var view, values;
|
|
36015
|
+
if (!source || !length || !itemSize) return null;
|
|
36016
|
+
view = new DataView(source, offset, length * itemSize);
|
|
36017
|
+
if (itemSize == 2) {
|
|
36018
|
+
values = new Uint16Array(length);
|
|
36019
|
+
for (var i = 0; i < length; i++) values[i] = view.getUint16(i * itemSize, false);
|
|
36020
|
+
return values;
|
|
36021
|
+
}
|
|
36022
|
+
if (itemSize == 4) {
|
|
36023
|
+
values = new Uint32Array(length);
|
|
36024
|
+
for (var j = 0; j < length; j++) values[j] = view.getUint32(j * itemSize, false);
|
|
36025
|
+
return values;
|
|
36026
|
+
}
|
|
36027
|
+
if (itemSize == 8 && typeof view.getBigUint64 == 'function') {
|
|
36028
|
+
values = [];
|
|
36029
|
+
for (var k = 0; k < length; k++) values[k] = Number(view.getBigUint64(k * itemSize, false));
|
|
36030
|
+
return values;
|
|
36031
|
+
}
|
|
36032
|
+
return null;
|
|
36033
|
+
}
|
|
36034
|
+
|
|
36035
|
+
function getSourceId(input) {
|
|
36036
|
+
return input && input.filename ? getFileBase(input.filename) : 'geotiff-source';
|
|
36037
|
+
}
|
|
36038
|
+
|
|
36039
|
+
function getSourceInfo$1(input, sourceId, image) {
|
|
36040
|
+
var content = input && input.content;
|
|
36041
|
+
return {
|
|
36042
|
+
id: sourceId,
|
|
36043
|
+
filename: input && input.filename || null,
|
|
36044
|
+
byteLength: content && content.byteLength || null,
|
|
36045
|
+
storage: runningInBrowser() ? 'indexeddb-pending' : 'path',
|
|
36046
|
+
width: image.getWidth(),
|
|
36047
|
+
height: image.getHeight(),
|
|
36048
|
+
bands: image.getSamplesPerPixel(),
|
|
36049
|
+
pixelType: getPixelType(image),
|
|
36050
|
+
bbox: getImageBoundingBox(image),
|
|
36051
|
+
transform: getImageTransform(image)
|
|
36052
|
+
};
|
|
36053
|
+
}
|
|
36054
|
+
|
|
36055
|
+
async function importGeoTIFFCrs(dataset, image) {
|
|
36056
|
+
var crsInfo = await getGeoTIFFCrsInfo(image);
|
|
36057
|
+
var crsString = crsInfo.crsString;
|
|
36058
|
+
if (!crsString) {
|
|
36059
|
+
warnOnce(getGeoTIFFCrsWarning(crsInfo));
|
|
36060
|
+
return;
|
|
36061
|
+
}
|
|
36062
|
+
try {
|
|
36063
|
+
await initProjLibrary({crs: crsString});
|
|
36064
|
+
setDatasetCrsInfo(dataset, getCrsInfo(crsString));
|
|
36065
|
+
} catch(e) {
|
|
36066
|
+
dataset.info = dataset.info || {};
|
|
36067
|
+
warnOnce(getGeoTIFFCrsWarning(crsInfo, e.message || e));
|
|
36068
|
+
}
|
|
36069
|
+
}
|
|
36070
|
+
|
|
36071
|
+
async function getGeoTIFFCrsInfo(image) {
|
|
36072
|
+
var keys = image.getGeoKeys && image.getGeoKeys() || {};
|
|
36073
|
+
var code = keys.ProjectedCSTypeGeoKey;
|
|
36074
|
+
var customProjection;
|
|
36075
|
+
if (isGeoTIFFAuthorityCode(code)) {
|
|
36076
|
+
return {crsString: 'EPSG:' + code};
|
|
36077
|
+
}
|
|
36078
|
+
customProjection = await getGeoTIFFCustomProjection(keys);
|
|
36079
|
+
if (customProjection.crsString) return customProjection;
|
|
36080
|
+
code = keys.GeographicTypeGeoKey;
|
|
36081
|
+
if (isGeoTIFFAuthorityCode(code)) return {crsString: 'EPSG:' + code};
|
|
36082
|
+
return {crsString: null, warning: customProjection.warning};
|
|
36083
|
+
}
|
|
36084
|
+
|
|
36085
|
+
function getGeoTIFFCrsWarning(crsInfo, detail) {
|
|
36086
|
+
if (detail || crsInfo && crsInfo.warning) {
|
|
36087
|
+
logGeoTIFFCrsWarningDetails(detail, crsInfo && crsInfo.warning);
|
|
36088
|
+
}
|
|
36089
|
+
return 'The GeoTIFF does not contain usable CRS data';
|
|
36090
|
+
}
|
|
36091
|
+
|
|
36092
|
+
function isGeoTIFFAuthorityCode(code) {
|
|
36093
|
+
return code > 0 && code != 32767;
|
|
36094
|
+
}
|
|
36095
|
+
|
|
36096
|
+
async function getGeoTIFFCustomProjection(keys) {
|
|
36097
|
+
var converted = await getGeoTIFFProj4FromGeoKeys(keys);
|
|
36098
|
+
if (converted.crsString) return converted;
|
|
36099
|
+
if (keys.ProjectedCSTypeGeoKey != 32767 && keys.ProjectionGeoKey != 32767) return converted;
|
|
36100
|
+
if (keys.ProjCoordTransGeoKey == 11) {
|
|
36101
|
+
return {
|
|
36102
|
+
crsString: getGeoTIFFAlbersProjection(keys),
|
|
36103
|
+
warning: converted.warning
|
|
36104
|
+
};
|
|
36105
|
+
}
|
|
36106
|
+
return converted;
|
|
36107
|
+
}
|
|
36108
|
+
|
|
36109
|
+
async function getGeoTIFFProj4FromGeoKeys(keys) {
|
|
36110
|
+
var geokeysToProj4, result;
|
|
36111
|
+
try {
|
|
36112
|
+
geokeysToProj4 = await loadGeoKeysToProj4Lib();
|
|
36113
|
+
result = geokeysToProj4.toProj4(keys);
|
|
36114
|
+
} catch(e) {
|
|
36115
|
+
return {crsString: null, warning: {type: 'GeoKey converter error', error: e.message || e}};
|
|
36116
|
+
}
|
|
36117
|
+
if (result && result.proj4) {
|
|
36118
|
+
return {crsString: normalizeGeoTIFFProj4(result.proj4)};
|
|
36119
|
+
}
|
|
36120
|
+
return {crsString: null, warning: result && result.errors || null};
|
|
36121
|
+
}
|
|
36122
|
+
|
|
36123
|
+
function normalizeGeoTIFFProj4(str) {
|
|
36124
|
+
return String(str).replace(/\s\+axis=[^ ]+/g, '').trim();
|
|
36125
|
+
}
|
|
36126
|
+
|
|
36127
|
+
function logGeoTIFFCrsWarningDetails(parseError, converterDetails) {
|
|
36128
|
+
if (typeof console == 'undefined' || !console.warn) return;
|
|
36129
|
+
console.warn('Unable to import GeoTIFF CRS metadata', {
|
|
36130
|
+
parseError: parseError || null,
|
|
36131
|
+
converterDetails: converterDetails || null
|
|
36132
|
+
});
|
|
36133
|
+
}
|
|
36134
|
+
|
|
36135
|
+
function getGeoTIFFAlbersProjection(keys) {
|
|
36136
|
+
var units = getGeoTIFFLinearUnits(keys);
|
|
36137
|
+
var ellipsoid = getGeoTIFFEllipsoid(keys);
|
|
36138
|
+
if (!units || !ellipsoid ||
|
|
36139
|
+
!isFinite(keys.ProjStdParallel1GeoKey) || !isFinite(keys.ProjStdParallel2GeoKey) ||
|
|
36140
|
+
!isFinite(keys.ProjNatOriginLatGeoKey) || !isFinite(keys.ProjNatOriginLongGeoKey)) {
|
|
36141
|
+
return null;
|
|
36142
|
+
}
|
|
36143
|
+
return [
|
|
36144
|
+
'+proj=aea',
|
|
36145
|
+
'+lat_1=' + keys.ProjStdParallel1GeoKey,
|
|
36146
|
+
'+lat_2=' + keys.ProjStdParallel2GeoKey,
|
|
36147
|
+
'+lat_0=' + keys.ProjNatOriginLatGeoKey,
|
|
36148
|
+
'+lon_0=' + keys.ProjNatOriginLongGeoKey,
|
|
36149
|
+
'+x_0=' + (keys.ProjFalseEastingGeoKey || 0),
|
|
36150
|
+
'+y_0=' + (keys.ProjFalseNorthingGeoKey || 0),
|
|
36151
|
+
ellipsoid,
|
|
36152
|
+
units
|
|
36153
|
+
].join(' ');
|
|
36154
|
+
}
|
|
36155
|
+
|
|
36156
|
+
function getGeoTIFFLinearUnits(keys) {
|
|
36157
|
+
var code = keys.ProjLinearUnitsGeoKey;
|
|
36158
|
+
if (!code || code == 9001) return '+units=m';
|
|
36159
|
+
if (code == 9002) return '+units=ft';
|
|
36160
|
+
if (code == 9003) return '+to_meter=0.3048006096012192';
|
|
36161
|
+
return null;
|
|
36162
|
+
}
|
|
36163
|
+
|
|
36164
|
+
function getGeoTIFFEllipsoid(keys) {
|
|
36165
|
+
if (keys.GeographicTypeGeoKey == 4326) return '+datum=WGS84';
|
|
36166
|
+
if (isFinite(keys.GeogSemiMajorAxisGeoKey) && isFinite(keys.GeogInvFlatteningGeoKey)) {
|
|
36167
|
+
return '+a=' + keys.GeogSemiMajorAxisGeoKey + ' +rf=' + keys.GeogInvFlatteningGeoKey;
|
|
36168
|
+
}
|
|
36169
|
+
if (isFinite(keys.GeogSemiMajorAxisGeoKey) && isFinite(keys.GeogSemiMinorAxisGeoKey)) {
|
|
36170
|
+
return '+a=' + keys.GeogSemiMajorAxisGeoKey + ' +b=' + keys.GeogSemiMinorAxisGeoKey;
|
|
36171
|
+
}
|
|
36172
|
+
return null;
|
|
36173
|
+
}
|
|
36174
|
+
|
|
36175
|
+
async function importImageRaster(input, optsArg) {
|
|
36176
|
+
var opts = optsArg || {};
|
|
36177
|
+
var imageType = input.png ? 'png' : input.jpeg ? 'jpeg' : null;
|
|
36178
|
+
var imageInput = input[imageType];
|
|
36179
|
+
var decoded = await decodeImage(imageInput, imageType);
|
|
36180
|
+
var world = parseWorldFile(input.world && input.world.content);
|
|
36181
|
+
var sourceId = getFileBase(imageInput.filename || imageType);
|
|
36182
|
+
var transform, bbox, raster, dataset;
|
|
36183
|
+
if (!world) {
|
|
36184
|
+
stop$1('Image raster import requires a world file');
|
|
36185
|
+
}
|
|
36186
|
+
transform = getWorldTransform(world);
|
|
36187
|
+
bbox = getWorldFileBBox(transform, decoded.width, decoded.height);
|
|
36188
|
+
raster = {
|
|
36189
|
+
sourceId: sourceId,
|
|
36190
|
+
grid: {
|
|
36191
|
+
width: decoded.width,
|
|
36192
|
+
height: decoded.height,
|
|
36193
|
+
bands: decoded.bands,
|
|
36194
|
+
pixelType: 'uint8',
|
|
36195
|
+
samples: decoded.samples,
|
|
36196
|
+
sampleBands: decoded.sampleBands,
|
|
36197
|
+
nodata: null,
|
|
36198
|
+
bbox: bbox,
|
|
36199
|
+
transform: transform
|
|
36200
|
+
},
|
|
36201
|
+
derivation: {
|
|
36202
|
+
type: decoded.bands >= 3 ? 'rgb' : 'gray',
|
|
36203
|
+
sourceId: sourceId,
|
|
36204
|
+
bands: decoded.sampleBands
|
|
36205
|
+
},
|
|
36206
|
+
view: {
|
|
36207
|
+
recipe: {
|
|
36208
|
+
type: decoded.bands >= 3 ? 'rgb' : 'gray',
|
|
36209
|
+
bands: decoded.sampleBands
|
|
36210
|
+
}
|
|
36211
|
+
}
|
|
36212
|
+
};
|
|
36213
|
+
raster.view.recipe = getRasterViewRecipe(raster.grid, raster.view.recipe, opts);
|
|
36214
|
+
raster.view.preview = createRasterPreview(raster, opts);
|
|
36215
|
+
dataset = {
|
|
36216
|
+
info: {
|
|
36217
|
+
raster_sources: [getSourceInfo(imageInput, sourceId, imageType, input)]
|
|
36218
|
+
},
|
|
36219
|
+
layers: [{
|
|
36220
|
+
name: imageInput.filename ? getFileBase(imageInput.filename) : null,
|
|
36221
|
+
raster_type: 'grid',
|
|
36222
|
+
raster: raster
|
|
36223
|
+
}]
|
|
36224
|
+
};
|
|
36225
|
+
importImageCrs(dataset, input.prj);
|
|
36226
|
+
return dataset;
|
|
36227
|
+
}
|
|
36228
|
+
|
|
36229
|
+
async function decodeImage(input, imageType) {
|
|
36230
|
+
if (runningInBrowser()) {
|
|
36231
|
+
return decodeImageInBrowser(input.content, imageType);
|
|
36232
|
+
}
|
|
36233
|
+
return imageType == 'png' ? decodePng(input.content) : decodeJpeg(input.content);
|
|
36234
|
+
}
|
|
36235
|
+
|
|
36236
|
+
function decodePng(content) {
|
|
36237
|
+
var png = require$1('pngjs').PNG.sync.read(Buffer.from(content));
|
|
36238
|
+
return rgbaToImageData(png.data, png.width, png.height, true);
|
|
36239
|
+
}
|
|
36240
|
+
|
|
36241
|
+
function decodeJpeg(content) {
|
|
36242
|
+
var jpeg = require$1('jpeg-js');
|
|
36243
|
+
var image = jpeg.decode(Buffer.from(content), {useTArray: true});
|
|
36244
|
+
return rgbaToImageData(image.data, image.width, image.height, false);
|
|
36245
|
+
}
|
|
36246
|
+
|
|
36247
|
+
async function decodeImageInBrowser(content, imageType) {
|
|
36248
|
+
var blob = new Blob([content], {type: imageType == 'png' ? 'image/png' : 'image/jpeg'});
|
|
36249
|
+
var bitmap = await createImageBitmap(blob);
|
|
36250
|
+
var canvas = document.createElement('canvas');
|
|
36251
|
+
var ctx, data;
|
|
36252
|
+
canvas.width = bitmap.width;
|
|
36253
|
+
canvas.height = bitmap.height;
|
|
36254
|
+
ctx = canvas.getContext('2d');
|
|
36255
|
+
ctx.drawImage(bitmap, 0, 0);
|
|
36256
|
+
data = ctx.getImageData(0, 0, canvas.width, canvas.height).data;
|
|
36257
|
+
if (bitmap.close) bitmap.close();
|
|
36258
|
+
return rgbaToImageData(data, canvas.width, canvas.height, imageType == 'png');
|
|
36259
|
+
}
|
|
36260
|
+
|
|
36261
|
+
function rgbaToImageData(rgba, width, height, keepAlpha) {
|
|
36262
|
+
var bands = keepAlpha ? 4 : 3;
|
|
36263
|
+
var samples = new Uint8Array(width * height * bands);
|
|
36264
|
+
var src, dest;
|
|
36265
|
+
for (var i = 0, n = width * height; i < n; i++) {
|
|
36266
|
+
src = i * 4;
|
|
36267
|
+
dest = i * bands;
|
|
36268
|
+
samples[dest] = rgba[src];
|
|
36269
|
+
samples[dest + 1] = rgba[src + 1];
|
|
36270
|
+
samples[dest + 2] = rgba[src + 2];
|
|
36271
|
+
if (keepAlpha) samples[dest + 3] = rgba[src + 3];
|
|
36272
|
+
}
|
|
36273
|
+
return {
|
|
36274
|
+
width: width,
|
|
36275
|
+
height: height,
|
|
36276
|
+
bands: bands,
|
|
36277
|
+
samples: samples,
|
|
36278
|
+
sampleBands: bands == 4 ? [0, 1, 2, 3] : [0, 1, 2]
|
|
36279
|
+
};
|
|
36280
|
+
}
|
|
36281
|
+
|
|
36282
|
+
function parseWorldFile(content) {
|
|
36283
|
+
if (!content) return null;
|
|
36284
|
+
var vals = String(content).trim().split(/\s+/).map(Number);
|
|
36285
|
+
if (vals.length < 6 || vals.some(function(val) { return !isFinite(val); })) {
|
|
36286
|
+
stop$1('Invalid world file');
|
|
36287
|
+
}
|
|
36288
|
+
return vals.slice(0, 6);
|
|
36289
|
+
}
|
|
36290
|
+
|
|
36291
|
+
function getWorldTransform(world) {
|
|
36292
|
+
var a = world[0], d = world[1], b = world[2], e = world[3],
|
|
36293
|
+
c = world[4], f = world[5];
|
|
36294
|
+
return [
|
|
36295
|
+
a,
|
|
36296
|
+
b,
|
|
36297
|
+
c - a / 2 - b / 2,
|
|
36298
|
+
d,
|
|
36299
|
+
e,
|
|
36300
|
+
f - d / 2 - e / 2
|
|
36301
|
+
];
|
|
36302
|
+
}
|
|
36303
|
+
|
|
36304
|
+
function getWorldFileBBox(transform, width, height) {
|
|
36305
|
+
var corners = [
|
|
36306
|
+
transformPoint(transform, 0, 0),
|
|
36307
|
+
transformPoint(transform, width, 0),
|
|
36308
|
+
transformPoint(transform, width, height),
|
|
36309
|
+
transformPoint(transform, 0, height)
|
|
36310
|
+
];
|
|
36311
|
+
var xs = corners.map(function(p) { return p[0]; });
|
|
36312
|
+
var ys = corners.map(function(p) { return p[1]; });
|
|
36313
|
+
return [
|
|
36314
|
+
Math.min.apply(null, xs),
|
|
36315
|
+
Math.min.apply(null, ys),
|
|
36316
|
+
Math.max.apply(null, xs),
|
|
36317
|
+
Math.max.apply(null, ys)
|
|
36318
|
+
];
|
|
36319
|
+
}
|
|
36320
|
+
|
|
36321
|
+
function transformPoint(t, col, row) {
|
|
36322
|
+
return [
|
|
36323
|
+
t[0] * col + t[1] * row + t[2],
|
|
36324
|
+
t[3] * col + t[4] * row + t[5]
|
|
36325
|
+
];
|
|
36326
|
+
}
|
|
36327
|
+
|
|
36328
|
+
function importImageCrs(dataset, prj) {
|
|
36329
|
+
var wkt = prj && prj.content;
|
|
36330
|
+
if (!wkt) {
|
|
36331
|
+
warn('Image raster is missing a .prj file; CRS is unknown');
|
|
36332
|
+
return;
|
|
36333
|
+
}
|
|
36334
|
+
try {
|
|
36335
|
+
setDatasetCrsInfo(dataset, {
|
|
36336
|
+
wkt1: wkt,
|
|
36337
|
+
crs: parsePrj(wkt)
|
|
36338
|
+
});
|
|
36339
|
+
} catch(e) {
|
|
36340
|
+
dataset.info.wkt1 = wkt;
|
|
36341
|
+
}
|
|
36342
|
+
}
|
|
36343
|
+
|
|
36344
|
+
function getSourceInfo(input, sourceId, imageType, group) {
|
|
36345
|
+
var content = input && input.content;
|
|
36346
|
+
return {
|
|
36347
|
+
id: sourceId,
|
|
36348
|
+
type: imageType,
|
|
36349
|
+
filename: input && input.filename || null,
|
|
36350
|
+
byteLength: content && content.byteLength || null,
|
|
36351
|
+
storage: runningInBrowser() ? 'indexeddb-pending' : 'path',
|
|
36352
|
+
worldFile: group.world && group.world.filename || null,
|
|
36353
|
+
prjFile: group.prj && group.prj.filename || null
|
|
36354
|
+
};
|
|
36355
|
+
}
|
|
36356
|
+
|
|
34836
36357
|
var INHERITED_STYLE_KEYS = [
|
|
34837
36358
|
'fill', 'fill-opacity',
|
|
34838
36359
|
'stroke', 'stroke-width', 'stroke-opacity', 'stroke-dasharray',
|
|
@@ -35786,6 +37307,10 @@ ${svg}
|
|
|
35786
37307
|
stop$1("GeoPackage import requires async import path");
|
|
35787
37308
|
} else if (obj.parquet) {
|
|
35788
37309
|
stop$1("GeoParquet import requires async import path");
|
|
37310
|
+
} else if (obj.geotiff) {
|
|
37311
|
+
stop$1("GeoTIFF import requires async import path");
|
|
37312
|
+
} else if (obj.png || obj.jpeg) {
|
|
37313
|
+
stop$1("Image raster import requires async import path");
|
|
35789
37314
|
}
|
|
35790
37315
|
|
|
35791
37316
|
return finalizeImportedDataset(dataset, dataFmt, data, opts);
|
|
@@ -35806,6 +37331,14 @@ ${svg}
|
|
|
35806
37331
|
dataFmt = 'geoparquet';
|
|
35807
37332
|
data = obj.parquet;
|
|
35808
37333
|
dataset = await importGeoParquet(data, opts);
|
|
37334
|
+
} else if (obj.geotiff) {
|
|
37335
|
+
dataFmt = 'geotiff';
|
|
37336
|
+
data = obj.geotiff;
|
|
37337
|
+
dataset = await importGeoTIFF(data, opts);
|
|
37338
|
+
} else if (obj.png || obj.jpeg) {
|
|
37339
|
+
dataFmt = obj.png ? 'png' : 'jpeg';
|
|
37340
|
+
data = obj[dataFmt];
|
|
37341
|
+
dataset = await importImageRaster(obj, opts);
|
|
35809
37342
|
} else {
|
|
35810
37343
|
return importContent(obj, opts);
|
|
35811
37344
|
}
|
|
@@ -36007,11 +37540,63 @@ ${svg}
|
|
|
36007
37540
|
if (data) {
|
|
36008
37541
|
data = importTable(data);
|
|
36009
37542
|
}
|
|
37543
|
+
if (lyr.raster) {
|
|
37544
|
+
lyr.raster = importRasterData(lyr.raster);
|
|
37545
|
+
}
|
|
36010
37546
|
return Object.assign(lyr, {
|
|
36011
37547
|
data: lyr.data ? new DataTable(data) : null
|
|
36012
37548
|
});
|
|
36013
37549
|
}
|
|
36014
37550
|
|
|
37551
|
+
function importRasterData(raster) {
|
|
37552
|
+
var copy = Object.assign({}, raster);
|
|
37553
|
+
if (raster.grid) {
|
|
37554
|
+
copy.grid = Object.assign({}, raster.grid);
|
|
37555
|
+
if (raster.grid.samples) {
|
|
37556
|
+
copy.grid.samples = restoreRasterSamples(raster.grid.samples, raster.grid.pixelType);
|
|
37557
|
+
}
|
|
37558
|
+
}
|
|
37559
|
+
if (raster.view) {
|
|
37560
|
+
copy.view = Object.assign({}, raster.view);
|
|
37561
|
+
if (raster.view.preview) {
|
|
37562
|
+
copy.view.preview = Object.assign({}, raster.view.preview);
|
|
37563
|
+
if (raster.view.preview.pixels) {
|
|
37564
|
+
copy.view.preview.pixels = new Uint8ClampedArray(BinArray.copyToArrayBuffer(raster.view.preview.pixels));
|
|
37565
|
+
}
|
|
37566
|
+
}
|
|
37567
|
+
}
|
|
37568
|
+
if (raster.preview) {
|
|
37569
|
+
copy.preview = Object.assign({}, raster.preview);
|
|
37570
|
+
if (raster.preview.pixels) {
|
|
37571
|
+
copy.preview.pixels = new Uint8ClampedArray(BinArray.copyToArrayBuffer(raster.preview.pixels));
|
|
37572
|
+
}
|
|
37573
|
+
}
|
|
37574
|
+
if (raster.pixels) {
|
|
37575
|
+
copy.pixels = new Uint8ClampedArray(BinArray.copyToArrayBuffer(raster.pixels));
|
|
37576
|
+
}
|
|
37577
|
+
return copy;
|
|
37578
|
+
}
|
|
37579
|
+
|
|
37580
|
+
function restoreRasterSamples(buf, pixelType) {
|
|
37581
|
+
var arrbuf = BinArray.copyToArrayBuffer(buf);
|
|
37582
|
+
var Ctor = getRasterSampleArrayConstructor(pixelType);
|
|
37583
|
+
return new Ctor(arrbuf);
|
|
37584
|
+
}
|
|
37585
|
+
|
|
37586
|
+
function getRasterSampleArrayConstructor(pixelType) {
|
|
37587
|
+
switch (pixelType) {
|
|
37588
|
+
case 'uint8': return Uint8Array;
|
|
37589
|
+
case 'int8': return Int8Array;
|
|
37590
|
+
case 'uint16': return Uint16Array;
|
|
37591
|
+
case 'int16': return Int16Array;
|
|
37592
|
+
case 'uint32': return Uint32Array;
|
|
37593
|
+
case 'int32': return Int32Array;
|
|
37594
|
+
case 'float32': return Float32Array;
|
|
37595
|
+
case 'float64': return Float64Array;
|
|
37596
|
+
}
|
|
37597
|
+
return Uint8Array;
|
|
37598
|
+
}
|
|
37599
|
+
|
|
36015
37600
|
var Unpack = /*#__PURE__*/Object.freeze({
|
|
36016
37601
|
__proto__: null,
|
|
36017
37602
|
restoreSessionData: restoreSessionData,
|
|
@@ -36143,11 +37728,18 @@ ${svg}
|
|
|
36143
37728
|
function expandKmzFile(file, cache) {
|
|
36144
37729
|
var files = expandZipFile(file, cache);
|
|
36145
37730
|
var name = replaceFileExtension(parseLocalPath(file).filename, 'kml');
|
|
36146
|
-
|
|
36147
|
-
|
|
37731
|
+
files = files.map(function(file) {
|
|
37732
|
+
if (file == 'doc.kml') {
|
|
37733
|
+
return name;
|
|
37734
|
+
}
|
|
37735
|
+
return file;
|
|
37736
|
+
});
|
|
37737
|
+
if ('doc.kml' in cache) {
|
|
36148
37738
|
cache[name] = cache['doc.kml'];
|
|
36149
37739
|
}
|
|
36150
|
-
return files
|
|
37740
|
+
return files.filter(function(file) {
|
|
37741
|
+
return guessInputFileType(file) == 'kml';
|
|
37742
|
+
});
|
|
36151
37743
|
}
|
|
36152
37744
|
|
|
36153
37745
|
function expandZipFile(file, cache) {
|
|
@@ -36239,6 +37831,8 @@ ${svg}
|
|
|
36239
37831
|
content = null; // for g.c.
|
|
36240
37832
|
if (fileType == 'shp' || fileType == 'dbf') {
|
|
36241
37833
|
readShapefileAuxFiles(path, input, cache);
|
|
37834
|
+
} else if (isRasterImageInputType(fileType)) {
|
|
37835
|
+
readRasterImageAuxFiles(path, input, cache);
|
|
36242
37836
|
}
|
|
36243
37837
|
if (fileType == 'shp' && !input.dbf) {
|
|
36244
37838
|
message(utils.format("[%s] .dbf file is missing - shapes imported without attribute data.", path));
|
|
@@ -36293,11 +37887,13 @@ ${svg}
|
|
|
36293
37887
|
content = null;
|
|
36294
37888
|
if (fileType == 'shp' || fileType == 'dbf') {
|
|
36295
37889
|
readShapefileAuxFiles(path, input, cache);
|
|
37890
|
+
} else if (isRasterImageInputType(fileType)) {
|
|
37891
|
+
readRasterImageAuxFiles(path, input, cache);
|
|
36296
37892
|
}
|
|
36297
37893
|
if (fileType == 'shp' && !input.dbf) {
|
|
36298
37894
|
message(utils.format("[%s] .dbf file is missing - shapes imported without attribute data.", path));
|
|
36299
37895
|
}
|
|
36300
|
-
return fileType == 'gpkg' || fileType == 'fgb' || fileType == 'parquet' ? importContentAsync(input, opts) : importContent(input, opts);
|
|
37896
|
+
return fileType == 'gpkg' || fileType == 'fgb' || fileType == 'parquet' || fileType == 'geotiff' || isRasterImageInputType(fileType) ? importContentAsync(input, opts) : importContent(input, opts);
|
|
36301
37897
|
}
|
|
36302
37898
|
|
|
36303
37899
|
// Import multiple files to a single dataset
|
|
@@ -36331,6 +37927,7 @@ ${svg}
|
|
|
36331
37927
|
async function importFilesTogetherAsync(files, opts) {
|
|
36332
37928
|
var unbuiltTopology = false;
|
|
36333
37929
|
var datasets = [];
|
|
37930
|
+
files = removeRasterImageSidecars(files);
|
|
36334
37931
|
for (var fname of files) {
|
|
36335
37932
|
// import without topology or snapping
|
|
36336
37933
|
var importOpts = utils.defaults({no_topology: true, snap: false, snap_interval: null, files: [fname]}, opts);
|
|
@@ -36439,6 +38036,60 @@ ${svg}
|
|
|
36439
38036
|
}
|
|
36440
38037
|
}
|
|
36441
38038
|
|
|
38039
|
+
function readRasterImageAuxFiles(path, obj, cache) {
|
|
38040
|
+
var prjPath = replaceFileExtension(path, 'prj');
|
|
38041
|
+
var worldPath = findWorldFile(path, cache);
|
|
38042
|
+
if (cli.isFile(prjPath, cache)) {
|
|
38043
|
+
obj.prj = {filename: prjPath, content: cli.readFile(prjPath, 'utf-8', cache)};
|
|
38044
|
+
}
|
|
38045
|
+
if (worldPath) {
|
|
38046
|
+
obj.world = {filename: worldPath, content: cli.readFile(worldPath, 'utf-8', cache)};
|
|
38047
|
+
}
|
|
38048
|
+
}
|
|
38049
|
+
|
|
38050
|
+
function findWorldFile(path, cache) {
|
|
38051
|
+
var candidates = getWorldFileCandidates(path);
|
|
38052
|
+
for (var i = 0; i < candidates.length; i++) {
|
|
38053
|
+
if (cli.isFile(candidates[i], cache)) return candidates[i];
|
|
38054
|
+
}
|
|
38055
|
+
return null;
|
|
38056
|
+
}
|
|
38057
|
+
|
|
38058
|
+
function getWorldFileCandidates(path) {
|
|
38059
|
+
var ext = getFileExtension(path).toLowerCase();
|
|
38060
|
+
var candidates = [replaceFileExtension(path, 'wld'), replaceFileExtension(path, 'tfw')];
|
|
38061
|
+
if (ext == 'png') {
|
|
38062
|
+
candidates.unshift(replaceFileExtension(path, 'pgw'), replaceFileExtension(path, 'pngw'));
|
|
38063
|
+
} else if (ext == 'jpg' || ext == 'jpeg') {
|
|
38064
|
+
candidates.unshift(
|
|
38065
|
+
replaceFileExtension(path, 'jgw'),
|
|
38066
|
+
replaceFileExtension(path, 'jpw'),
|
|
38067
|
+
replaceFileExtension(path, 'jpgw'),
|
|
38068
|
+
replaceFileExtension(path, 'jpegw')
|
|
38069
|
+
);
|
|
38070
|
+
}
|
|
38071
|
+
return utils.uniq(candidates);
|
|
38072
|
+
}
|
|
38073
|
+
|
|
38074
|
+
function removeRasterImageSidecars(files) {
|
|
38075
|
+
var imageBases = {};
|
|
38076
|
+
files.forEach(function(file) {
|
|
38077
|
+
var type = guessInputFileType(file);
|
|
38078
|
+
if (isRasterImageInputType(type)) {
|
|
38079
|
+
imageBases[getFileBase(file).toLowerCase()] = true;
|
|
38080
|
+
}
|
|
38081
|
+
});
|
|
38082
|
+
return files.filter(function(file) {
|
|
38083
|
+
var ext = getFileExtension(file).toLowerCase();
|
|
38084
|
+
var type = guessInputFileType(file);
|
|
38085
|
+
var base = getFileBase(file).toLowerCase();
|
|
38086
|
+
if ((type == 'prj' || isWorldFileExtension(ext)) && imageBases[base]) {
|
|
38087
|
+
return false;
|
|
38088
|
+
}
|
|
38089
|
+
return true;
|
|
38090
|
+
});
|
|
38091
|
+
}
|
|
38092
|
+
|
|
36442
38093
|
var FileImport = /*#__PURE__*/Object.freeze({
|
|
36443
38094
|
__proto__: null,
|
|
36444
38095
|
importFile: importFile,
|
|
@@ -43263,6 +44914,10 @@ ${svg}
|
|
|
43263
44914
|
var lyr2 = outputLayers[i];
|
|
43264
44915
|
lyr.shapes = lyr2.shapes;
|
|
43265
44916
|
lyr.data = lyr2.data;
|
|
44917
|
+
if (lyr2.raster) {
|
|
44918
|
+
lyr.raster = lyr2.raster;
|
|
44919
|
+
lyr.raster_type = lyr2.raster_type;
|
|
44920
|
+
}
|
|
43266
44921
|
});
|
|
43267
44922
|
dissolveArcs(dataset);
|
|
43268
44923
|
}
|
|
@@ -43273,8 +44928,15 @@ ${svg}
|
|
|
43273
44928
|
profileStart('clipLayers');
|
|
43274
44929
|
opts = opts || {no_cleanup: true}; // TODO: update testing functions
|
|
43275
44930
|
var usingPathClip = utils.some(targetLayers, layerHasPaths);
|
|
44931
|
+
var usingRasterClip = utils.some(targetLayers, layerHasRaster);
|
|
43276
44932
|
var mergedDataset, clipLyr, nodes, result;
|
|
43277
|
-
var clipDataset
|
|
44933
|
+
var clipDataset;
|
|
44934
|
+
if (usingRasterClip) {
|
|
44935
|
+
result = clipRasterLayers(targetLayers, clipSrc, targetDataset, type, opts);
|
|
44936
|
+
profileEnd('clipLayers');
|
|
44937
|
+
return result;
|
|
44938
|
+
}
|
|
44939
|
+
clipDataset = normalizeOverlaySource(clipSrc, targetDataset, opts);
|
|
43278
44940
|
if (!opts.no_warn) {
|
|
43279
44941
|
warnIfBoundsDontOverlap(targetLayers, targetDataset, clipDataset, type);
|
|
43280
44942
|
}
|
|
@@ -43308,6 +44970,30 @@ ${svg}
|
|
|
43308
44970
|
return result;
|
|
43309
44971
|
}
|
|
43310
44972
|
|
|
44973
|
+
function clipRasterLayers(targetLayers, clipSrc, targetDataset, type, opts) {
|
|
44974
|
+
var clipDataset, clipBounds, bbox;
|
|
44975
|
+
if (type != 'clip') {
|
|
44976
|
+
stop$1('Raster layers only support clipping');
|
|
44977
|
+
}
|
|
44978
|
+
if (utils.some(targetLayers, function(lyr) {return !layerHasRaster(lyr);})) {
|
|
44979
|
+
stop$1('Raster clipping cannot be mixed with vector target layers');
|
|
44980
|
+
}
|
|
44981
|
+
if (opts.bbox2) {
|
|
44982
|
+
bbox = opts.bbox2;
|
|
44983
|
+
} else {
|
|
44984
|
+
clipDataset = normalizeOverlaySource(clipSrc, targetDataset, opts);
|
|
44985
|
+
clipBounds = getLayerBounds(clipDataset.layers[0], clipDataset.arcs);
|
|
44986
|
+
if (!clipBounds || !clipBounds.hasBounds()) {
|
|
44987
|
+
stop$1('Missing raster clipping bounds');
|
|
44988
|
+
}
|
|
44989
|
+
bbox = clipBounds.toArray();
|
|
44990
|
+
}
|
|
44991
|
+
return targetLayers.map(function(lyr) {
|
|
44992
|
+
clipRasterToBBox(lyr, bbox, opts);
|
|
44993
|
+
return lyr;
|
|
44994
|
+
});
|
|
44995
|
+
}
|
|
44996
|
+
|
|
43311
44997
|
function clipLayersByBBox(layers, dataset, opts) {
|
|
43312
44998
|
var bbox = opts.bbox2;
|
|
43313
44999
|
var clipLyr = divideDatasetByBBox(dataset, bbox);
|
|
@@ -44215,6 +45901,16 @@ ${svg}
|
|
|
44215
45901
|
null_shape_count: 0,
|
|
44216
45902
|
null_data_count: lyr.data ? countNullRecords(lyr.data.getRecords()) : n
|
|
44217
45903
|
};
|
|
45904
|
+
if (layerHasRaster(lyr)) {
|
|
45905
|
+
o.geometry_type = null;
|
|
45906
|
+
o.raster_type = lyr.raster_type;
|
|
45907
|
+
o.raster_width = getRasterWidth(lyr.raster);
|
|
45908
|
+
o.raster_height = getRasterHeight(lyr.raster);
|
|
45909
|
+
o.raster_bands = getRasterBandCount(lyr.raster);
|
|
45910
|
+
o.raster_pixel_type = getRasterPixelType(lyr.raster);
|
|
45911
|
+
o.bbox = getLayerBounds(lyr, dataset.arcs).toArray();
|
|
45912
|
+
o.proj4 = getProjInfo(dataset);
|
|
45913
|
+
}
|
|
44218
45914
|
if (lyr.shapes && lyr.shapes.length > 0) {
|
|
44219
45915
|
o.null_shape_count = countNullShapes(lyr.shapes);
|
|
44220
45916
|
o.bbox = getLayerBounds(lyr, dataset.arcs).toArray();
|
|
@@ -44244,7 +45940,7 @@ ${svg}
|
|
|
44244
45940
|
var str = '';
|
|
44245
45941
|
arr.forEach(function(info, i) {
|
|
44246
45942
|
var title = 'Layer: ' + (info.layer_name || '[unnamed layer]');
|
|
44247
|
-
var tableStr = formatAttributeTableInfo(info.attribute_data);
|
|
45943
|
+
var tableStr = info.raster_type ? '' : formatAttributeTableInfo(info.attribute_data);
|
|
44248
45944
|
var tableWidth = measureLongestLine(tableStr);
|
|
44249
45945
|
var ruleLen = Math.min(Math.max(title.length, tableWidth), MAX_RULE_LEN);
|
|
44250
45946
|
str += '\n';
|
|
@@ -44259,12 +45955,17 @@ ${svg}
|
|
|
44259
45955
|
|
|
44260
45956
|
function formatLayerInfo(data) {
|
|
44261
45957
|
var str = '';
|
|
44262
|
-
str += "Type: " + (data.geometry_type || "tabular data") + "\n";
|
|
44263
|
-
|
|
45958
|
+
str += "Type: " + (data.raster_type ? "raster data" : data.geometry_type || "tabular data") + "\n";
|
|
45959
|
+
if (data.raster_type) {
|
|
45960
|
+
str += utils.format("Size: %,d x %,d x %,d\n", data.raster_width, data.raster_height, data.raster_bands);
|
|
45961
|
+
str += "Data: " + (data.raster_pixel_type || 'unknown') + "\n";
|
|
45962
|
+
} else {
|
|
45963
|
+
str += utils.format("Records: %,d\n",data.feature_count);
|
|
45964
|
+
}
|
|
44264
45965
|
if (data.null_shape_count > 0) {
|
|
44265
45966
|
str += utils.format("Nulls: %'d", data.null_shape_count) + "\n";
|
|
44266
45967
|
}
|
|
44267
|
-
if (data.geometry_type && data.feature_count > data.null_shape_count) {
|
|
45968
|
+
if (data.raster_type || data.geometry_type && data.feature_count > data.null_shape_count) {
|
|
44268
45969
|
str += "Bounds: " + data.bbox.join(',') + "\n";
|
|
44269
45970
|
str += "CRS: " + data.proj4 + "\n";
|
|
44270
45971
|
}
|
|
@@ -55681,7 +57382,7 @@ ${svg}
|
|
|
55681
57382
|
});
|
|
55682
57383
|
}
|
|
55683
57384
|
|
|
55684
|
-
var version = "0.7.
|
|
57385
|
+
var version = "0.7.15";
|
|
55685
57386
|
|
|
55686
57387
|
// Parse command line args into commands and run them
|
|
55687
57388
|
// Function takes an optional Node-style callback. A Promise is returned if no callback is given.
|
|
@@ -56582,6 +58283,8 @@ ${svg}
|
|
|
56582
58283
|
detail: copyDetail(detail),
|
|
56583
58284
|
name: layer.name,
|
|
56584
58285
|
geometry_type: layer.geometry_type,
|
|
58286
|
+
raster_type: layer.raster_type || null,
|
|
58287
|
+
raster: layer.raster ? copyRasterData(layer.raster) : null,
|
|
56585
58288
|
shapes: layer.shapes ? cloneShapes(layer.shapes) : null,
|
|
56586
58289
|
data: layer.data || null
|
|
56587
58290
|
});
|
|
@@ -56875,6 +58578,8 @@ ${svg}
|
|
|
56875
58578
|
revision: getUndoRevision(unit.target),
|
|
56876
58579
|
name: unit.target.name,
|
|
56877
58580
|
geometry_type: unit.target.geometry_type,
|
|
58581
|
+
raster_type: unit.target.raster_type || null,
|
|
58582
|
+
raster: unit.target.raster ? copyRasterData(unit.target.raster) : null,
|
|
56878
58583
|
shapes: unit.target.shapes ? cloneShapes(unit.target.shapes) : null,
|
|
56879
58584
|
data: unit.target.data || null
|
|
56880
58585
|
});
|
|
@@ -57001,6 +58706,8 @@ ${svg}
|
|
|
57001
58706
|
function restoreLayer(unit) {
|
|
57002
58707
|
unit.target.name = unit.name;
|
|
57003
58708
|
unit.target.geometry_type = unit.geometry_type;
|
|
58709
|
+
unit.target.raster_type = unit.raster_type || null;
|
|
58710
|
+
unit.target.raster = unit.raster ? copyRasterData(unit.raster) : null;
|
|
57004
58711
|
unit.target.shapes = unit.shapes ? cloneShapes(unit.shapes) : null;
|
|
57005
58712
|
unit.target.data = unit.data;
|
|
57006
58713
|
}
|
|
@@ -57204,6 +58911,7 @@ ${svg}
|
|
|
57204
58911
|
Lines,
|
|
57205
58912
|
Logging,
|
|
57206
58913
|
Profile,
|
|
58914
|
+
RasterUtils,
|
|
57207
58915
|
Merging,
|
|
57208
58916
|
MosaicIndex$1,
|
|
57209
58917
|
OptionParsingUtils,
|