mmomtchev / node-gdal-async

Node.js bindings for GDAL (Geospatial Data Abstraction Library) with full async support
https://mmomtchev.github.io/node-gdal-async/
Apache License 2.0
133 stars 26 forks source link

Error copying vector dataset to GPKG #61

Closed bertday closed 1 year ago

bertday commented 1 year ago

Hello! I'm really enjoying getting to know this awesome project 😄 👋

I'm trying to convert GeoJSON file to GPKG (adapted from #55):

import gdal from 'gdal-async';

const datasetIn = gdal.open('/path/to/some.geojson', 'r');
const gpkgDriver = gdal.drivers.get('GPKG');

const datasetOut = gpkgDriver.createCopy('test.gpkg', datasetIn);

datasetOut.close();

and getting the error:

Uncaught Error Error: Only 1 (Grey/ColorTable), 2 (Grey+Alpha), 3 (RGB) or 4 (RGBA) band dataset supported

It looks like maybe it's expecting raster, but I'm not sure why that would be 🤔 I can run ogr2ogr and it works OK:

ogr2ogr test.gpkg  /path/to/the/same.geojson

One thing to note is that the output GPKG doesn't exist yet (I normally rely on ogr2ogr to create GPKGs).

Is there something I'm doing wrong here? Would appreciate any tips on this... thank you!

mmomtchev commented 1 year ago

GDALDriver::createCopy works only for raster datasets. The correct code to do what you want is:

const gdal = require('.')

const datasetIn = gdal.open('test/data/park.geo.json', 'r')
const gpkgDriver = gdal.drivers.get('GPKG')

const datasetOut = gpkgDriver.create('test.gpkg')
const layerOut = datasetOut.layers.create('testLayer', gdal.SpatialReference.fromEPSG(4326), gdal.Point)

for (const f of datasetIn.layers.get(0).fields) {
  layerOut.fields.add(f)
}

for (const featureIn of datasetIn.layers.get(0).features) {
  const featureOut = new gdal.Feature(layerOut)
  for (const field of featureIn.fields.getNames()) {
    featureOut.fields.set(field, featureIn.fields.get(field))
  }
  layerOut.features.add(featureOut)
}

datasetOut.close()
bertday commented 1 year ago

Thanks so much for the code @mmomtchev! That's super helpful.

One thing I have a question about — you mentioned

GDALDriver::createCopy works only for raster datasets.

I was able to createCopy against vector data in other formats, for instance writing GeoJSON to SHP:

import gdal from 'gdal-async';

const datasetIn = gdal.open('/path/to/some.geojson', 'r');
const gpkgDriver = gdal.drivers.get('ESRI Shapefile');

const datasetOut = gpkgDriver.createCopy('test.shp', datasetIn);

datasetOut.close();

and that worked OK.

Perhaps my question is — my understanding was that this library wrapped ogr2ogr, and with ogr2ogr this would be a one-liner:

ogr2ogr test.geopkg test.shp

Is there any way to invoke ogr2ogr as such with node-gdal-async? Totally understand if this is not the design or intent of the library, just wanted to clear up my own confusion about how it works 😄 Thank you!

mmomtchev commented 1 year ago

Yes, it is available as gdal.vectorTranslate/gdal.vectorTranslateAsync