[Gdal-dev] C# Bindings
Simon Perkins
sy at perkins.net
Fri Nov 3 17:05:23 EST 2006
Tamas Szekeres wrote:
>>
>> Fair enough. My initial thought was to suggest a signature like:
>>
>> public void ReadRaster(int xOff, int yOff, int xSize, int ySize, byte*
>> buffer, int bufXSize, int bufYSize, int pixelSpace, int lineSpace)
>>
>> and similarly for other data types (short, ushort, int, uint, long,
>> ulong, float, double). Using a pointer rather than an array for the
>> buffer allows the method to be used to fill Bitmaps without having to
>> copy into an intermediate array.
>>
>
> I'm afraid we will not be able to map pointers to the C# interface
> easily.
Is this a SWIG limitation? Pointers are a valid C# type though, aren't they?
> I couldn't understand exactly your problem about the need of the
> double copy of the arrays. Would you
> post a sample that suffers from this issue?
Let's say you want to do the simplest thing: use GDAL to read RGB data
from a file, stick it into an image and then display that image. Off the
top of my head, one way of doing this (starting with a GDAL dataset
object) would look something like:
{
...
// Get the GDAL Band objects from the Dataset
Gdal.Band redBand = dataset.GetRasterBand(1);
Gdal.Band greenBand = dataset.GetRasterBand(2);
Gdal.Band blueBand = dataset.GetRasterBand(3);
// Get the width and height of the Dataset
int width = dataset.RasterXSize;
int height = dataset.RasterYSize;
// Create a Bitmap to store the GDAL image in
Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format24bppRgb);
// Use GDAL raster reading methods to read the image data directly
into the Bitmap
BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, width,
height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
try {
int stride = bitmapData.Stride;
byte* buf = (byte*)bitmapData.Scan0.ToPointer();
// ReadRaster() here takes a byte* argument for the data pointer
redBand.ReadRaster(0, 0, width, height, buf, width, height, 3, stride);
greenBand.ReadRaster(0, 0, width, height, buf+1, width, height, 3,
stride);
blueBand.ReadRaster(0, 0, width, height, buf+2, width, height, 3,
stride);
}
finally {
bitmap.UnlockBits(bitmapData);
}
// Display the image by putting it into a PictureBox
pictureBox.Image = bitmap;
...
}
If ReadRaster() took a byte[] rather than a byte* as an argument, then
you would have to use GDAL to copy the band data first into a byte[]
array, and then from there use InteropServices.Marshal.Copy() to copy
the data into the Bitmap, which is inefficient in time and memory.
If you do want to read into an array, then you can do something like:
byte[] buffer = new byte[width * height];
fixed (byte* ptr = buffer) {
band.ReadRaster(0, 0, width, height, ptr, width, height, 1, width);
}
However, if the functions are setup to read directly into arrays, then
I'm not sure how one could read data from GDAL directly into a Bitmap,
where the buffer is only accessible via a pointer.
As a compromise, how about we have a high and a low level interface? So
you can have type safe versions with byte[], int[] etc, and low level
versions that use an IntPtr and an argument specifying the data type. We
could call the lower level version RasterIO to correspond to the C
function in GDAL.
> I have no problem about the number of the overloads. It would be more
> important to keep
> the interface obvious and clear.
> We have no one by one mapping between the C++ and C# blittable types.
> For a mapping table see for example the blittable types section at:
> http://www.mono-project.com/Interop_with_Native_Libraries
OK. FWIW, I imagine that 99.9% of people's needs can be addressed by
overloads for the data types byte, short, ushort, int, uint and float.
>>
>> How does that sound? Maybe at some point in the future when generics are
>> the norm, we can add templated versions to get a modicum of type safety
>> and avoid having to specify a data type explicitly.
>>
>
> How could we restrict the usage of the templates to the array of the
> simple blittable types?
> However in the future it might be an option but now it's supported
> only by MS.NET FW 2.0 AFAIK.
In order to work with the underlying GDAL code you would need to turn
the type into a GDAL type flag, so you could throw a runtime exception
if an invalid type is used.
But, if you're happy with many overloads, then let's go with that.
Cheers,
Sy
More information about the Gdal-dev
mailing list