![Maven Central Adds Sigstore Signature Validation](https://cdn.sanity.io/images/cgdhsj6q/production/7da3bc8a946cfb5df15d7fcf49767faedc72b483-1024x1024.webp?w=400&fit=max&auto=format)
Security News
Maven Central Adds Sigstore Signature Validation
Maven Central now validates Sigstore signatures, making it easier for developers to verify the provenance of Java packages.
gdal-exprtk
Advanced tools
This is a plugin that adds support for ExprTk.js expressions to gdal-async.
It allows for truly asynchronous background processing performing only O(1) operations on the V8 main thread. Multiple operations run in parallel and never block the event loop.
Requires gdal-async@3.4
and ExprTk.js@2.0
.
To use as a library in a project:
npm install --save gdal-exprtk
Install globally to use the command-line version:
sudo npm install -g gdal-exprtk
The command-line utility supports both JS functions and ExprTk expressions. It uses parallel processing whenever possible.
gdal_calc.js -i AROME_D2m_10.tiff=d -i AROME_T2m_10.tiff=t
-o CLOUDBASE.tiff \
-e -c '125*(t-d)' -f GTiff -t Float64
gdal_calc.js -i AROME_D2m_10.tiff=d -i AROME_T2m_10.tiff=t
-o CLOUDBASE.tiff \
-j -c 'return 125*(t-d);' -f GTiff -t Float64
gdal_calc.js -i multiband.tif@1 -i multiband.tif@2
-o output.tiff \
-e -c '(a+b)/2' -f GTiff -t Float64
gdal_calc.js -i multiband.tif@1=x -i multiband.tif@2=y
-o output.tiff \
-e -c '(x+y)/2' -c '(x-y)/2' -f GTiff -t Float64
NoData
<->Nan
conversionIf a NoData
value is specified for the output file, then all input NoData
values will be converted to NaN
before invoking the user function and all NaN
values returned from the user function will be written as the NoData
value. This works only if the output data type is a floating point type. gdal-async@3.5
supports converting integer types to NaN
, gdal-async@3.4
requires that all input files have a floating point type for this to work.
gdal_calc.js -i AROME_D2m_10.tiff=d -i AROME_T2m_10.tiff=t
-o CLOUDBASE.tiff \
-e -c '125*(t-d)' -f GTiff -t Float64 -n -1e-38
gdal_calc.js
can use both a default and a named export. The arguments order must be given explicitly.
espy.js
:
module.exports = {};
module.exports.espy = (t, td) => (125 * (t - td));
module.exports.espy.args = ['t', 'td'];
Then:
gdal_calc.js -i AROME_D2m_10.tiff=td -i AROME_T2m_10.tiff=t
-o CLOUDBASE.tiff \
-j -c =./espy.js@espy -f GTiff -t Float64 -n -1e-38
espy.exprtk
:
125 * (t - td)
Then:
gdal_calc.js -i AROME_D2m_10.tiff=td -i AROME_T2m_10.tiff=t
-o CLOUDBASE.tiff \
-e -c =./espy.exprtk -f GTiff -t Float64 -n -1e-38
calcAsync
import * as gdal from 'gdal-async';
import { Float64 as Float64Expression } from 'exprtk.js';
import { calcAsync } from 'gdal-exprtk';
const T2m = await gdal.openAsync('AROME_T2m_10.tiff'));
const D2m = await gdal.openAsync('AROME_D2m_10.tiff'));
const size = await T2m.rasterSizeAsync;
const filename = `/vsimem/AROME_CLOUDBASE.tiff`;
const dsCloudBase = gdal.open(filename, 'w', 'GTiff',
size.x, size.y, 1, gdal.GDT_Float64);
// Espy's estimation for cloud base height
const espyExpr = new Float64Expression('125 * (T2m - D2m)');
// This is required for the automatic NoData handling
// (it will get converted from/to NaN)
(await cloudBase.bands.getAsync(1)).noDataValue = -1e38;
// Mapping to ExprTk.js variables is by (case-insensitive) name
// and does not depend on the order
await calcAsync({
T2m: await T2m.bands.getAsync(1),
D2m: await D2m.bands.getAsync(1)
}, await cloudBase.bands.getAsync(1), espyExpr, { convertNoData: true });
import * as gdal from 'gdal-async';
import { Float64 as Float64Expression } from 'exprtk.js';
import { RasterTransform } from 'gdal-exprtk';
import { finished as _finished } from 'stream';
import { promisify } from 'util';
const finished = promisify(_finished);
// Espy's estimation for cloud base height (lifted condensation level)
// LCL = 125 * (T2m - Td2m)
// where T2m is the temperature at 2m and Td2m is the dew point at 2m
const expr = new Float64Expression('125 * (T2m - D2m)');
const dsT2m = gdal.open('AROME_T2m_10.tiff'));
const dsD2m = gdal.open('AROME_D2m_10.tiff'));
const filename = `/vsimem/AROME_CLOUDBASE.tiff`;
const dsCloudBase = gdal.open(filename, 'w', 'GTiff',
dsT2m.rasterSize.x, dsT2m.rasterSize.y, 1, gdal.GDT_Float64);
// Mapping to ExprTk.js variables is by (case-insensitive) name
// and does not depend on the order
const mux = new gdal.RasterMuxStream({
T2m: dsT2m.bands.get(1).pixels.createReadStream(),
D2m: dsD2m.bands.get(1).pixels.createReadStream()
});
const ws = dsCloudBase.bands.get(1).pixels.createWriteStream();
const espyEstimation = new RasterTransform({ type: Float64Array, expr });
mux.pipe(espyEstimation).pipe(ws);
await finished(ws);
dsCloudBase.close();
Extends stream.Transform
A raster Transform stream
Applies an ExprTk.js Expression on all data elements.
Input must be a gdal.RasterMuxStream
calcAsync provides a higher-level interface for the same feature
options
RasterTransformOptions?
options.exr
(Function | Expression) Function to be applied on all dataconst dsT2m = gdal.open('AROME_T2m_10.tiff'));
const dsD2m = gdal.open('AROME_D2m_10.tiff'));
const dsCloudBase = gdal.open('CLOUDBASE.tiff', 'w', 'GTiff',
dsT2m.rasterSize.x, dsT2m.rasterSize.y, 1, gdal.GDT_Float64);
const mux = new gdal.RasterMuxStream({
T2m: dsT2m.bands.get(1).pixels.createReadStream(),
D2m: dsD2m.bands.get(1).pixels.createReadStream()
});
const ws = dsCloudBase.bands.get(1).pixels.createWriteStream();
// Espy's estimation for cloud base height (lifted condensation level)
// LCL = 125 * (T2m - Td2m)
// where T2m is the temperature at 2m and Td2m is the dew point at 2m
const expr = new Float64Expression('125 * (t - td)');
const espyEstimation = new RasterTransform({ type: Float64Array, expr });
mux.pipe(espyEstimation).pipe(ws);
Extends stream.TransformOptions
expr
Expression Function to be applied on all dataType: object
convertNoData
boolean? progress_cb
ProgressCb? Type: Function
complete
number Compute a new output band as a pixel-wise function of given input bands
This is an alternative implementation of gdal_calc.py
.
It is identical to the one in gdal-async except that it accepts an ExprTK.js expression as function instead of a JS function.
It's main advantage is that it does not solicit the V8's main thread for any
operation that is not O(1) - all computation is performed in background
async threads. The only exception is the convertNoData
option with gdal-async@3.4
which is implemented in JS. gdal-async@3.5
supports C++ conversion of NoData
to NaN.
It internally uses a RasterTransform which can also be used directly for a finer-grained control over the transformation.
There is no sync version.
inputs
Record<string, gdal.RasterBand> An object containing all the input bands
output
gdal.RasterBand Output raster band
expr
Expression ExprTk.js expression
options
CalcOptions? Options
options.convertNoData
boolean Input bands will have their
NoData pixels converted toNaN and a NaN output value of the given function
will be converted to a NoData pixel, provided that the output raster band
has its RasterBand.noDataValue
set (optional, default false
)options.progress_cb
ProgressCb Progress callback (optional, default undefined
)const T2m = await gdal.openAsync('TEMP_2M.tiff'));
const D2m = await gdal.openAsync('DEWPOINT_2M.tiff'));
const size = await T2m.rasterSizeAsync
const cloudBase = await gdal.openAsync('CLOUDBASE.tiff', 'w', 'GTiff',
size.x, size.y, 1, gdal.GDT_Float64);
(await cloudBase.bands.getAsync(1)).noDataValue = -1e38
// Espy's estimation for cloud base height
const espyFn = (t, td) => 125 * (t - td);
await calcAsync({
t: await T2m.bands.getAsync(1),
td: await D2m.bands.getAsync(1)
}, cloudBase.bands.getAsync(1), espyFn, { convertNoData: true });
Returns Promise<void>
Get a gdal-async
pixel function descriptor for this ExprTk.js
expression.
Every call of this function produces a permanent GDAL descriptor that cannot
be garbage-collected, so it must be called only once per ExprTk.js
expression.
As of GDAL 3.4, GDAL does not allow unregistering a previously registered function.
The returned object can be used across multiple V8 instances (ie worker threads).
gdal-async
does not support multiple V8 instances.
If the V8 instance containing the ExprTk.js
expression is destroyed, further attempts
to read from Datasets referencing the function will produce an exception.
expression
Expression // This example will register a new GDAL pixel function called sum2
// that requires a VRT dataset with 2 values per pixel
const gdal = require('gdal-async);
const Float64Expression = require('exprtk.js').Float64;
const { toPixelFunc } = require('gdal-exprtk');
const sum2 = new Float64Expression('a + b');
gdal.addPixelFunc('sum2', toPixelFunc(sum2));
Returns gdal.PixelFunction
[2.0.0] 2024-01-08
Expression
to a GDAL pixel function:
with @
to achieve better compatibility with Windows where :
is a common symbol in a filename (C:\...
)FAQs
ExprTk.js plugin for gdal-async
The npm package gdal-exprtk receives a total of 1 weekly downloads. As such, gdal-exprtk popularity was classified as not popular.
We found that gdal-exprtk demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Maven Central now validates Sigstore signatures, making it easier for developers to verify the provenance of Java packages.
Security News
CISOs are racing to adopt AI for cybersecurity, but hurdles in budgets and governance may leave some falling behind in the fight against cyber threats.
Research
Security News
Socket researchers uncovered a backdoored typosquat of BoltDB in the Go ecosystem, exploiting Go Module Proxy caching to persist undetected for years.