wiki:GdalOgrCsharpRaster

Version 2 (modified by tamas, 17 years ago) ( diff )

--

GDAL CSharp Raster Operations

The GDAL CSharp interface supports transferring the raster data between the C# application and the GDAL library. The various Band.ReadRaster, Band.WriteRaster, Dataset.ReadRaster, Dataset.WriteRaster overloads are involved in transferring raster data between the managed and the unmanaged part of the application. This chapter will summarize the main aspects of the raster data handling related exclusively to the C# interface.

Band class contains the following ReadRaster/WriteRaster overloads:

public CPLErr ReadRaster(int xOff, int yOff, int xSize, int ySize, byte[] buffer, 
    int buf_xSize, int buf_ySize, int pixelSpace, int lineSpace)
public CPLErr WriteRaster(int xOff, int yOff, int xSize, int ySize, byte[] buffer, 
    int buf_xSize, int buf_ySize, int pixelSpace, int lineSpace)
public CPLErr ReadRaster(int xOff, int yOff, int xSize, int ySize, short[] buffer, 
    int buf_xSize, int buf_ySize, int pixelSpace, int lineSpace)
public CPLErr WriteRaster(int xOff, int yOff, int xSize, int ySize, short[] buffer, 
    int buf_xSize, int buf_ySize, int pixelSpace, int lineSpace)
public CPLErr ReadRaster(int xOff, int yOff, int xSize, int ySize, int[] buffer, 
    int buf_xSize, int buf_ySize, int pixelSpace, int lineSpace)
public CPLErr WriteRaster(int xOff, int yOff, int xSize, int ySize, int[] buffer, 
    int buf_xSize, int buf_ySize, int pixelSpace, int lineSpace)
public CPLErr ReadRaster(int xOff, int yOff, int xSize, int ySize, float[] buffer, 
    int buf_xSize, int buf_ySize, int pixelSpace, int lineSpace)
public CPLErr WriteRaster(int xOff, int yOff, int xSize, int ySize, float[] buffer, 
    int buf_xSize, int buf_ySize, int pixelSpace, int lineSpace)
public CPLErr ReadRaster(int xOff, int yOff, int xSize, int ySize, double[] buffer, 
    int buf_xSize, int buf_ySize, int pixelSpace, int lineSpace)
public CPLErr WriteRaster(int xOff, int yOff, int xSize, int ySize, double[] buffer, 
    int buf_xSize, int buf_ySize, int pixelSpace, int lineSpace)
public CPLErr ReadRaster(int xOff, int yOff, int xSize, int ySize, IntPtr buffer, i
    nt buf_xSize, int buf_ySize, DataType buf_type, int pixelSpace, int lineSpace)
public CPLErr WriteRaster(int xOff, int yOff, int xSize, int ySize, IntPtr buffer, 
    int buf_xSize, int buf_ySize, DataType buf_type, int pixelSpace, int lineSpace)

The only difference between these functions is the actual type of the buffer parameter. The last 2 overloads are the generic overloads and the caller should write the proper marshaling code for the buffer holding the raster data. The overloads having C# array as the buffer parameter implement the proper marshaling code for the caller.

Reading the raster image

When reading raster data from the GDAL code the user will probably create a .NET image to hold C# representation of the data. The raster data can be read directly or in a buffered fashion.

Using the buffered read approach

When reading the image this way the C# API will copy the image data between the C and the C# arrays:

// Creating a Bitmap to store the GDAL image in
Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format32bppRgb);
// Creating a C# array to hold the image data
byte[] r = new byte[width * height];
band.ReadRaster(0, 0, width, height, r, width, height, 0, 0);
// Copying the pixels into the C# bitmap
int i, j;
for (i = 0; i< width; i++) 
{
    for (j=0; j<height; j++)
    {
        Color newColor = Color.FromArgb(Convert.ToInt32(r[i+j*width]),Convert.ToInt32(r[i+j*width]), Convert.ToInt32(r[i+j*width]));
				bitmap.SetPixel(i, j, newColor);
    }
}
bitmap.Save(filename);

In this case the interface implementation uses an internally created unmanaged array to transfer the data between the C and C++ part of the code, like:

public CPLErr ReadRaster(int xOff, int yOff, int xSize, int ySize, byte[] buffer, int buf_xSize, int buf_ySize, int pixelSpace, int lineSpace) {
      CPLErr retval;
      IntPtr ptr = Marshal.AllocHGlobal(buf_xSize * buf_ySize * Marshal.SizeOf(buffer[0]));
      try {
          retval = ReadRaster(xOff, yOff, xSize, ySize, ptr, buf_xSize, buf_ySize, DataType.GDT_Byte, pixelSpace, lineSpace);
          Marshal.Copy(ptr, buffer, 0, buf_xSize * buf_ySize);
      } finally {
          Marshal.FreeHGlobal(ptr);
      }
      GC.KeepAlive(this);
      return retval;
 }

Using the direct read approach

The raster data can be read into the C# bitmap directly using the following approach:

// Creating a Bitmap to store the GDAL image in
Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
// Obtaining the bitmap buffer
BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);
try 
{
    int stride = bitmapData.Stride;
    IntPtr buf = bitmapData.Scan0;
    band.ReadRaster(0, 0, width, height, buf, width, height, DataType.GDT_Byte, 1, stride);
}
finally 
{
    bitmap.UnlockBits(bitmapData);
}
bitmap.Save(filename);

This approach is more performant than the previous since there's no need to allocate an intermediary array for transferring the data.

Using /unsafe code and the fixed statement

In the previous examples the programmer could ignore bothering with implementing the marshaling code for the raster arrays. Both of the implementation prevent from relocating the array by the garbage collector during the execution of the P/Invoke call. Without using an intermediary array the programmer can also use the following way to read the raster data:

byte[] buffer = new byte[width * height];
 fixed (byte* ptr = buffer) {
   band.ReadRaster(0, 0, width, height, ptr, width, height, 1, width);
 }

When using this approach the application might be compiled using the /unsafe commandline option.

Note: See TracWiki for help on using the wiki.