[gdal-dev] GDAL C# bindings, read from /vsimem/

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view

[gdal-dev] GDAL C# bindings, read from /vsimem/

Atle Frenvik Sveen-3
Hi list, first time poster here.

I'm using the GDAL C# bindings in .net core via the Gdal.Core Nuget package (https://www.nuget.org/packages/Gdal.Core/)

Everyting seems to work fine, apart from the fact that I have to touch the file system in order to get my created GeoTiff as a memory stream

Sample code:

var outputRasterFileName = $"{Path.GetTempPath()}{Guid.NewGuid()}.tiff";

var driver = Gdal.GetDriverByName("GTiff");
var ds = driver.Create(outputRasterFileName, resolution.X, resolution.Y, 1, DataType.GDT_Byte, null);

SetSrsFromLayer(ds, layer);
var arg = new[] { envelope.MinX, pixelSize, 0, envelope.MinY, 0, pixelSize };
var band = ds.GetRasterBand(1);
var rasterizeOptions = new[] { "ALL_TOUCHED=TRUE" };

Gdal.RasterizeLayer(ds, 1, new[] { 1 }, layer, IntPtr.Zero, IntPtr.Zero, 1, new[] { 10.0 }, rasterizeOptions, null, null);

var destination = new MemoryStream();

using (var source = File.Open(outputRasterFileName, FileMode.Open))
    destination.Position = 0;
    return destination;

This works, but I do not like the idea of writing to disk when I don't have to. I then found these threads:

Which says I can use the memory file system handler, and the python sample code provided by Even seems easy enough to translate:

# Read /vsimem/output.png
f = gdal.VSIFOpenL('/vsimem/output.png', 'rb')
gdal.VSIFSeekL(f, 0, 2) # seek to end
size = gdal.VSIFTellL(f)
gdal.VSIFSeekL(f, 0, 0) # seek to beginning
data = gdal.VSIFReadL(1, size, f)
# Cleanup

However, the C# bindings does not seem to include VSIFReadL, although Maksim Sestic seems to indicate that they are.

Is this an issue with the Nuget-package?

I then tried using C# Marshal.Copy, but this fails:

            var bufPtr = Gdal.VSIFOpenL(outputRasterFileName, "rb"); //outputRasterFileName is now "/vsimem/file.tiff"
            Gdal.VSIFSeekL(bufPtr, 0, 2); // seek to end
            var size = Gdal.VSIFTellL(bufPtr);
            Gdal.VSIFSeekL(bufPtr, 0, 0); // seek to beginning
            var data = new byte[size];
            Marshal.Copy(bufPtr, data, 0, size);          

I am by no means a C# expert, but I cannot see any reason this should fail? Given a memory pointer and size, read bytes, right?

As a last alternative I've tried to use the examples provided here: https://trac.osgeo.org/gdal/browser/trunk/gdal/swig/csharp/apps/GDALReadDirect.cs

This lets me read the bitmap of my raster, but all geotiff-metadata is lost. This also seems a bit overkill, as the actual GeoTiff is created and exists in memory!

So, to sum up a large mail:

1. Should Gdal.VSIFReadL be available in the C# bindings? If so, how do I get them?
2. If not 1, Should I be able to use Marshal.Copy in the manner described above? Or are there any other ways of getting these bytes?
3. If not 2, is using the sample code in https://trac.osgeo.org/gdal/browser/trunk/gdal/swig/csharp/apps/GDALReadDirect.cs a feasible way to create a stream of a geotiff-file`?

Thanks in advance for your replies, and thanks for a great library!


  Atle Frenvik Sveen
  [hidden email]
gdal-dev mailing list
[hidden email]