0

Here is my question: How do I loop through the stuff pointed by an IntPtr in C#? I have C# code calling C++ code. The C++ code returns a pointer to a piece of image buffer. The interface between C# and C++ is an IntPtr variable declared in C# So here is my C# code:

private IntPtr _maskData;

public void LoadMask(string maskName)
{            
     _maskData = Marshal.AllocHGlobal(_imgWidth * _imgHeight * 1);
     ReadImage(maskName, ref _maskData);
}

[DllImport(@"D:\Projects\ImageStatistics\ImageStatisticsEllipse\Debug\DiskIO.dll", EntryPoint = "ReadImage")]
        private static extern int ReadImage([MarshalAs(UnmanagedType.LPWStr)]string path, ref IntPtr outputBuffer);

Here is my C++ code:

DllExport_ThorDiskIO ReadImage(char *selectedFileName, char* &outputBuffer)
{
    TIFF* image;
    tsize_t stripSize;
    unsigned long imageOffset, result;
    int stripMax, stripCount;
    unsigned long bufferSize;
    wchar_t * path = (wchar_t*)selectedFileName;
    bool status;

    // Open the TIFF image
    if((image = tiffDll->TIFFOpenW(path, "r")) == NULL){
        //      logDll->TLTraceEvent(VERBOSE_EVENT,1,L"Could not open incoming image");

    }

    // Read in the possibly multiple strips
    stripSize = tiffDll->TIFFStripSize(image);
    stripMax = tiffDll->TIFFNumberOfStrips (image);
    imageOffset = 0;

    bufferSize = tiffDll->TIFFNumberOfStrips (image) * stripSize;

    for (stripCount = 0; stripCount < stripMax; stripCount++)
    {
        if((result = tiffDll->TIFFReadEncodedStrip (image, stripCount, outputBuffer + imageOffset, stripSize)) == -1)
        {
            //logDll->TLTraceEvent(VERBOSE_EVENT,1,L"Read error on input strip number");
        }
        imageOffset += result;
    }

    // Close the TIFF image
    tiffDll->TIFFClose(image);

    if(outputBuffer > 0)
    {
        //logDll->TLTraceEvent(VERBOSE_EVENT,1,L"inside output buffer: TRUE");
        status = TRUE;
    }
    else
    {
        //logDll->TLTraceEvent(VERBOSE_EVENT,1,L"inside output buffer: FALSE");
        status = FALSE;
    }   
    return status;  
}

So right now I think I can get the IntPtr successfully, but the question really is: How do I use it? How do I loop through each pixel in the image buffer, something like (pseudo code):

for (int y = 0; y < imgHeight; y++)
    for (int x = 0; x < imgWidth; x++)
    {
        int pixVal = IntPtr[y * imgWidth + x ];

        // do something to process the pixel value here....

    }
Nick Tsui
  • 524
  • 2
  • 9
  • 29
  • An `IntPtr` is not a buffer, it’s a memory address (in this case, pointing to the beginning of a buffer). You cannot “loop through” a memory address. You can, however, use unsafe code to loop over the buffer via pointer arithmetic on an unsafe pointer. – Konrad Rudolph Mar 21 '13 at 14:53
  • [`Marshal.PtrToStructure`](http://msdn.microsoft.com/en-us/library/4ca6d5z7.aspx) – Dustin Kingen Mar 21 '13 at 14:53
  • @Romoku: What if I have a piece of buffer of char*? Or a byte*? In general 8-bit data structure? Seems IntPtr only has .ToInt32() and .ToInt64(), and it seems I cannot retrieve my value from my buffer correctly. – Nick Tsui Mar 21 '13 at 15:42
  • @KonradRudolph: An example perhaps? – Nick Tsui Mar 21 '13 at 15:44
  • @KonradRudolph: I used unsafe code, it works. Thanks. So if you post your comments as an answer in 2 days, I will accept it. Thanks. – Nick Tsui Mar 21 '13 at 18:15
  • @Romoku: I tried this PtrToStructure() method, did not figure it out eventually. I guess pointer arithmetic just makes more sense to me, thanks tho. – Nick Tsui Mar 21 '13 at 18:16
  • What does the `_maskData` Data Structure look like? – Dustin Kingen Mar 21 '13 at 18:18
  • @Romoku: private IntPtr _maskData; _maskData = Marshal.AllocHGlobal(_imgWidth * _imgHeight * 1); in C#, and char* &outputBuffer in C++; It seems it is clearly shown in the original thread? – Nick Tsui Mar 21 '13 at 18:31
  • It looks like a byte array from what I can tell. Would it be equivalent to `byte[,]` in C#? – Dustin Kingen Mar 21 '13 at 18:55
  • @Romoku: I think you are right. I did use the byte array as well in the unsafe code. something like this: byte* pMask = (byte*)_maskData.ToPointer(); Then it will be pointer arithmetic like in C++; – Nick Tsui Mar 21 '13 at 18:59
  • I'm gonna drive home. Take a look at [IntPtr to Byte Array and Back](http://stackoverflow.com/questions/4389598/intptr-to-byte-array-and-back). – Dustin Kingen Mar 21 '13 at 19:08
  • @Romoku: I am wondering if the unsafe processing is easy and fast, what is the point of doing this PtrToStructure(), and so many other operations in C#? – Nick Tsui Mar 21 '13 at 19:22

1 Answers1

2

This is how to loop through an image pointed to using an IntPtr (pointer to native memory)

//assume this actually points to something (not zero!!)
IntPtr pNative = IntPtr.Zero;

//assume these are you image dimensions
int w=640; //width
int h=480; //height
int ch =3; //channels

//image loop
//use unsafe
//this is very fast!! 
unsafe
{
    for (int r = 0; r < h; r++)
    {
        byte* pI = (byte*)pNative.ToPointer() + r*w*ch; //pointer to start of row
        for (int c = 0; c < w; c++)
        {
            pI[c * ch]      = 0; //red
            pI[c * ch+1]    = 0; //green
            pI[c * ch+2]    = 0; //blue

//also equivalent to *(pI + c*ch)  = 0 - i.e. using pointer arythmetic;
        }
    }
}
morishuz
  • 2,302
  • 4
  • 21
  • 21