GDAL for WebAssembly
v3.13.3WebAssemblyGDAL 3.13.3 for browsers, Node.js and edge runtimes, precompiled for wasm32, single-threaded and multi-threaded as @crossbind/port-gdal-wasm.
npm install @crossbind/port-gdal-wasm@betaInstall
crossbind itself arrives with your bundler plugin, or with a new project from npm create crossbind@beta; Bundlers has Vite, Webpack, Rspack and Rollup.
Usage
Each example runs here, in this tab, and prints what the site build checked.
Each example also has a JavaScript only tab: the same task with no C++ file, calling GDAL's own headers from @crossbind/port-gdal directly. 4 of 5 work that way; the other says what stops it.
Imported straight from JavaScript, the headers need this configuration today; its comments say why.
Convert GeoJSON to GeoPackage and Shapefile, reprojected
Format conversion is what GDAL is used for most, as the ogr2ogr tool: GDALVectorTranslate takes the same arguments, here -f for the format and -t_srs for the coordinate system. The input is text handed over through /vsimem/, and a zipped Shapefile is one file.
GPKG: 3 features, EPSG:3857, extent 3021523 4639455 3657925 5013551 ESRI Shapefile: 3 features, EPSG:32635, extent 512465 4252837 1000822 4541552
The same GDALVectorTranslate and GDALVectorInfo calls the C++ makes. Their arguments are NULL-terminated string lists, which JavaScript builds with allocPointer and cstring, and flags that are macros, such as GDAL_OF_VECTOR, are written as numbers. The module is larger than the C++ one: binding gdal.h links GDALAllRegister and with it every driver, while the C++ version registers only the drivers it uses.
GPKG: 3 features, EPSG:3857, extent 3021523 4639455 3657925 5013551 ESRI Shapefile: 3 features, EPSG:32635, extent 512465 4252837 1000822 4541552
Write a GeoTIFF and read its georeferencing back
GDALCreate writes a raster with GDALSetGeoTransform and a CRS from OSRImportFromEPSG; GDALOpenEx opens it again as it opens any of the formats GDAL reads, and the size, band type, geotransform and CRS come back from the dataset. GDALInfo returns the report the gdalinfo tool prints.
GTiff, 200 x 150 pixels, 1 band of Float32 origin 500000, 4450000; pixel size 30 x -30 WGS 84 / UTM zone 35N, EPSG:32635 values 100 to 597 Upper Left ( 500000.000, 4450000.000) ( 27d 0' 0.00"E, 40d12' 1.44"N) Lower Right ( 506000.000, 4445500.000) ( 27d 4'13.64"E, 40d 9'35.41"N)
JavaScript writes the pixels and the six geotransform numbers into allocBuffer memory and reads the transform and the value range back the same way. GDALSetProjection takes EPSG:32635 as text, and GDAL_OF_RASTER is a macro, so the open flag is written as 2.
GTiff, 200 x 150 pixels, 1 band of Float32 origin 500000, 4450000; pixel size 30 x -30 WGS 84 / UTM zone 35N, EPSG:32635 values 100 to 597 Upper Left ( 500000.000, 4450000.000) ( 27d 0' 0.00"E, 40d12' 1.44"N) Lower Right ( 506000.000, 4445500.000) ( 27d 4'13.64"E, 40d 9'35.41"N)
Reproject a raster and write a Cloud-Optimized GeoTIFF
GDALWarp reprojects as the gdalwarp tool does, here into a virtual raster that is computed while it is read; GDALTranslate with -of COG then writes it tiled, compressed and with overviews, the layout web maps read with HTTP range requests.
1093 x 672 pixels of 0.000322 x 0.000322 degrees LAYOUT=COG, COMPRESSION=DEFLATE, 256 x 256 blocks overviews 546 x 336, 273 x 168, 136 x 84
GDALWarp and GDALTranslate take their arguments as NULL-terminated string lists that JavaScript builds with allocPointer and cstring; the block size comes back through two 4-byte out-parameters. The COG driver calls zstd even when it writes Deflate, so zstd has to stay in the link (see the configuration above).
1093 x 672 pixels of 0.000322 x 0.000322 degrees LAYOUT=COG, COMPRESSION=DEFLATE, 256 x 256 blocks overviews 546 x 336, 273 x 168, 136 x 84
Hillshade, slope and contour lines from an elevation model
GDALDEMProcessing is the gdaldem tool: hillshade, slope, aspect, roughness, TRI and TPI by name. GDALContourGenerateEx draws the contour lines gdal_contour draws, into any vector layer; here an in-memory one, measured with OGR_G_Length.
hillshade: 12.00 to 255.00, mean 156.63, checksum 58516 slope: 0.00 to 42.97, mean 27.46, checksum 54054 contours every 100 m: 11 lines from 200 to 900 m, 46.9 km long
GDALDEMProcessing and GDALContourGenerateEx are called as in C++. The options are string lists built with allocPointer and cstring, the statistics come back through four 8-byte out-parameters, and GDALContourGenerateEx returns a CPLErr enum member, so its .value is what is compared with 0.
hillshade: 12.00 to 255.00, mean 156.63, checksum 58516 slope: 0.00 to 42.97, mean 27.46, checksum 54054 contours every 100 m: 11 lines from 200 to 900 m, 46.9 km long
Read features and filter them by attribute and area
OGR reads every vector format through one API: the schema from OGR_L_GetLayerDefn, then OGR_L_GetNextFeature over the features that pass OGR_L_SetAttributeFilter, a SQL WHERE clause, and OGR_L_SetSpatialFilterRect. Open options turn the lon and lat columns of a CSV into points.
sensors: 6 features of Point, fields id Integer, kind String, reading Real 1 air 31.5 POINT (28.9784 41.0082) 3 water 22.7 POINT (27.1428 38.4237) 6 air 27.3 POINT (29.061 40.1885)
OGR_L_SetSpatialFilterRect then aborts it with "missing function: initGEOS_r". With GEOS linked the wasm is 27,393,760 bytes, over the 25 MiB (26,214,400-byte) limit the site's host puts on one file, and no configuration wins that back: crossbind puts -O3 after the emccFlags a config adds, so -Oz changes nothing. Binding gdal.h links GDALAllRegister and every driver with it, which already takes this module to 26,159,961 bytes without GEOS; the C++ version registers only the drivers it uses and is 16,451,235 bytes with GEOS.What is different on WebAssembly
- In a browser the module runs in a Worker by default (
useWorker), so every call returns a promise:awaitcalls and constructors alike. - The module has its own filesystem:
m.FSwrites files,m.getFileBytesreads them back andm.autoMountFilesmountsFileobjects from an<input type=file>./memfslives in memory;/opfspersists across reloads and needs the Worker. See Filesystem. - In Node.js,
m.FSis the real disk, so use real paths there. - Multi-threaded builds (
runtime: 'mt') need COOP and COEP headers in production. See Threading.
Other platforms
- GDAL overview: the apps, every platform's setup and the packages.
- GDAL for Android: React Native apps on Android.
- GDAL for iOS: React Native apps on iOS.
- GDAL for WASI: command-line programs under wasmtime.
Facts on this page come from the port manifests in the repository and from what npm served on beta when the site was built. See the Libraries guide for the full consumer flow.