Opened 10 years ago

Closed 10 years ago

#3073 closed defect (fixed)

[PATCH - C#] Dataset.ReadRaster()/WriteRaster() doesn't work on multi-band datasets

Reported by: Even Rouault Owned by: tamas
Priority: normal Milestone: 1.6.2
Component: CSharpBindings Version: 1.6.1
Severity: normal Keywords:
Cc: amanda.m.henneke@…

Description

Tamas,

The Marshal.AllocHGlobal and Marshal.Copy calls in Dataset.ReadRaster?()/WriteRaster?() mainly forget to multiply the pixel count by the number of bands, thus only the data for the first band is correctly read/written for pixel-interleaved buffers. Attached a patch that fixes the issue (adapted from gdal_java.i). I've also better taken into account the pixelSpace, lineSpace and bandSpace parameters to compute the number of elements to copy, as done in BandRasterIO_Validate and DatasetRasterIO_Validate in gdal_java.i. Currently, this wouldn't work with exotic values of spacings.

With that patch, the following code snippet does produce a pink image :

using System;
using OSGeo.GDAL;

class test
{
    public static void Main(string[] args) 
    {
        Gdal.AllRegister();
        Driver drv = Gdal.GetDriverByName("GTiff");
        int iWidth = 100;
        int iHeight = 100;
        Dataset ds_new = drv.Create("testrgb.tif", iWidth, iHeight, 3, DataType.GDT_Byte, new string[] { });
        byte[] buffers = new byte[(iHeight * iWidth) * 3];
        int i, j;
        for(i=0;i<iHeight;i++)
        {
            for(j=0;j<iWidth;j++)
            {
                buffers[(i*iWidth+j)] = 255;
                buffers[100*100+(i*iWidth+j)] = 0;
                buffers[2*100*100+(i*iWidth+j)] = 255;
            }
        }
        int[] iBandMap = { 1, 2, 3 };
        ds_new.WriteRaster(0, 0, iWidth, iHeight, buffers, iWidth, iHeight, 3, iBandMap, 0, 0, 0);
        ds_new = null;
    }
}

Attachments (1)

patch_3073.patch (8.2 KB) - added by Even Rouault 10 years ago.

Download all attachments as: .zip

Change History (5)

Changed 10 years ago by Even Rouault

Attachment: patch_3073.patch added

comment:1 Changed 10 years ago by tamas

Status: newassigned

Even,

Thank you for showing this up. I'd wonder if that count estimation would be done somewhere at gdal level as it looks like we implement something similar at the target languages. I'm still working on fixing this issue by using a direct copy on GC pinned arrays instead of doing the double copy like now. If the GC pinned array approach doesn't work on all systems (MS.NET/MONO) then I'll apply your patch to fix this issue.

Tamas

comment:2 Changed 10 years ago by Even Rouault

yes, it would be good if the count estimation could be moved in something common to all bindings. Would be usefull for C# and Java bindings. Python bindings don't need it as they don't provide the spacing parameters. Not sure about other bindings.

comment:3 Changed 10 years ago by tamas

I've applied a fix to use GC pinned arrays instead of the double copy in r17453, which should make the IO faster and fix this problem as well. If the change seems OK than I'll backport it into the stable branch.

comment:4 Changed 10 years ago by Even Rouault

Milestone: 1.6.2
Resolution: fixed
Status: assignedclosed

It has been backported in branches/1.6 in r17475. So the issue is closed.

I've also moved code used in the Java bindigns to check that the buffer provided by the user is large enough taking into account the buffer width and height and the spacing parameters. This could be used now by the C# bindings. See r17455 and the ComputeBandRasterIOSize() / ComputeDatasetRasterIOSize() methods

Note: See TracTickets for help on using tickets.