[Gdal-dev] C# Bindings

Simon Perkins sy at perkins.net
Sun Nov 5 13:38:19 EST 2006


Tamas Szekeres wrote:
> BTW, how about Dataset.WriteRaster? Is it necessary to implement?

I personally never use it, but it's a reasonable candidate for the 
future. It would allow you to fill the packed format Bitmap buffers 
we've been talking about with a single GDAL call, for instance, since 
you can read multiple bands at once into a buffer.

I would suggest that we nail down the Band.Read/WriteRaster() methods 
first and then see where we are with the Dataset method.

> With this solution the unmanaged memory would be allocated using
> Marshal.AllocHGlobal at the marshaling
> code and released after the call as for example (untested):
>
> IntPtr ptr = Marshal.AllocHGlobal(buffer.length);
> Mashal.Copy(buffer, 0, ptr, buffer.length);
> WriteRasterInternal(xOff, yOff, xSize, ySize, ptr, pixelSpace, 
> lineSpace);
> Marshal.FreeHGlobal(ptr);
>
> or
>
> IntPtr ptr = Marshal.AllocHGlobal(buffer.length);
> ReadRasterInternal(xOff, yOff, xSize, ySize, ptr, pixelSpace, lineSpace);
> Mashal.Copy(ptr, buffer, 0, buffer.length);
> Marshal.FreeHGlobal(ptr);

OK, I see how this would work now. As you might guess, I still don't 
like the extra copying just to use a typesafe version of the method and 
to avoid the /UNSAFE keyword, but that's a personal preference. As long 
as the high performance IntPtr version of Read/WriteRaster() is 
available, I'll be happy...


> Since I am not an expert in the usage of the GDAL part of the
> interface it's much difficult for me
> to think over the most efficient use cases. As you have mentioned
> copying the buffers will produce
> much of overhead during the processing of the image, I would consider
> it was most efficient
> to prolong the lifetime of the "processing" buffer by introducing a
> new class (GDALBuffer for example)
> This class could safely handle an internal unmanaged memory (being
> allocated and freed at the unmanaged
> side by using CPLMalloc and CPLFree). In addition we could use this
> class passing the internal buffer to
> WriteRasterInternal / ReadRasterInternal respectively. This class
> would also contain the GDALDataType that makes up the
> buffer and could reduce the number of overloads mentioned before in 
> this thread.
> We could access the elements of the array using an indexer with a 
> GDALDataType
> compliant C# type.
> How do you like this idea?

Hmmm, I don't think I really like it... :)

We could create this new data structure and read and write data from it 
directly, but I would imagine that (a) indexing into this structure will 
not be as fast as indexing into an array, and (b) you're often going to 
want to copy the data into a proper array anwyay, for interoperability 
with other code that doesn't know anything about GDALBuffers. It just 
doesn't feel right to me...


OK, how's this for a suggestion:

We write Read/WriteRaster() methods for typed arrays that you've 
proposed, that use an intermediate buffer for copying. But in addition, 
we also write FastReadRaster() and FastWriteRaster() methods that use 
the "fixed" keyword to read/write directly to/from array buffers. These 
methods will be declared "unsafe". Code that we don't want to compile 
with /UNSAFE can just use the basic Read/WriteRaster() methods, while 
code that wants to achieve maximum efficiency can use the Fast/usafe 
variants of the method. Note that there's no actual difference in the 
safety of these methods!


Anyway, at the end of the day, as long as I have my IntPtr version that 
I can use for efficient I/O, I don't really mind what other type safe 
versions we put in there...


>> I think this is a pretty low priority. Most C++ apps use RasterIO()
>> directly, which in turn makes calls to ReadBlock() and WriteBlock()
>> (actually IReadBlock() and IWriteBlock()), which are implemented by the
>> author of the particular GDAL driver being used. If people really want
>> to read and write blocks, then can always get the block width and height
>> using GDALGetBlockXSize(), and so forth, and then use RasterIO() with
>> windows of that size.
>>
>
> OK. But the documentation notes that using RasterIO is less efficient, 
> isn't it?

I think the docs only say that RasterIO is _potentially_ less efficient. 
And even that's a bit misleading. Basically, if you use RasterIO() to 
read data using buffers that are the natural block size of your image, 
with no resampling, and that have the same type as  the raw data type of 
the image file, then RasterIO() is just as efficient as ReadBlock(). The 
point is that RasterIO() is a more flexible function that allows you to 
do all kinds of extra stuff, e.g. resampling, data type conversion, that 
take extra computation. So ReadBlock() is not more efficient than 
rasterIO() - it just doesn't permit some of the more complicated slower 
things that RasterIO() can do.


>> Thinking about it some more, I think even for the IntPtr overload of
>> ReadRaster / WriteRaster, it would make sense to add the bufferOffset
>> argument, whenever we use the pixelSpace and lineSpace arguments. This
>> avoids having to use that "new IntPtr(buf.ToInt32() + 1)" stuff. All
>> three args are only really used when dealing with packed pixel format
>> buffers.
>>
>> For convenience, it would be nice to have overloads that assume default
>> values for the last three parameters (bufferOffset, pixelSpace and
>> lineSpace) for the common case where we're not dealing with packed
>> buffers. In these cases, bufferOffset = 0, pixelSpace =
>> sizeof(datatype), and lineSpace = bufXSize * pixelSpace.
>>
>
> Would it be a requirement to access the buffer as a 2D array and specify
> the offset accordingly?

The buffer offset would just be a single starting index into the array.



Cheers,

Sy




More information about the Gdal-dev mailing list