[IronPython] Convert between python array and .NET Array

Marcel marcel.vandendungen at gmail.com
Wed Jun 16 02:43:12 CEST 2010


Thanks Dino, the ctypes.memmove does work!

I wasn't aware that ctypes could be used in IronPython. Do they
marshal to unmanaged code under the hood?

Let me know if you want me to file a bug against the Marshal.Copy
overload behavior.

Thanks,
-- Marcel

On Jun 15, 11:42 am, Dino Viehland <di... at microsoft.com> wrote:
> Can I make a different recommendation?  Rather than doing a Marshal.Copy
> you could use ctypes.memmove.  That would look like:
>
> import ctypes
> ctypes.memmove(bmData.Scan0, bytes.buffer_info()[0], total_bytes)
>
> If Scan0 is actually an IntPtr youa may need to do a .ToInt32() or .ToInt64()
> on it (I don't remember if we support IntPtr's when marshalling to ctypes -
> we probably should).
>
> Even better still would be to use a ctypes array:
>
> bytes_type = (ctypes.c_int8* total_bytes)
> bytes = bytes_type()
> ctypes.memmove(0, bytes, total_bytes)
>
>
>
> > -----Original Message-----
> > From: users-boun... at lists.ironpython.com [mailto:users-
> > boun... at lists.ironpython.com] On Behalf Of Marcel
> > Sent: Monday, June 14, 2010 6:21 PM
> > To: us... at lists.ironpython.com
> > Subject: Re: [IronPython] Convert between python array and .NET Array
>
> > Hi Curt,
>
> > I did try that overload but I get this quite amusing error message:
> > TypeError: Copy() takes at least 2147483647 arguments (4 given)
>
> > Without the explicit overload selection, I get:
> > TypeError: expected IntPtr, got int
>
> > Did the example work for you with the overload you suggested?
>
> > The reason I chose array('B') was twofold. The pixel generation is
> > done in a pure Python library and I sometimes need to swap the byes
> > (depending on the endianness of the system), which the Python array
> > conveniently provides.
>
> > Thanks,
> > -- Marcel
>
> > On Jun 14, 7:05 am, Curt Hagenlocher <c... at hagenlocher.org> wrote:
> > > Ah, I'm clearly not familiar with how the array type was implemented. The
> > > first member of the buffer_info() tuple is an IntPtr, so you probably want
> > > the [IntPtr, int, IntPtr, int] overload of Marshal.Copy. In fact, if you use
> > > the buffer_info() approach, you may be able to avoid manually specifying the
> > > overload. (Though there's something to be said for the types as a form of
> > > documentation -- particularly given the opacity of the call to
> > > buffer_info()).
>
> > > Personally, my rule of thumb is to use the Python standard library for
> > > portable and "mostly Pythonic" code, but to use .NET types when doing
> > > "mostly .NET". In this case, I think I would have created an Array[Byte]
> > > instead of an array('B') as it's a bit more self-documenting.
>
> > > On Sun, Jun 13, 2010 at 3:51 PM, Marcel
> > <marcel.vandendun... at gmail.com>wrote:
>
> > > > Hi Curt,
>
> > > > Your suggestion gives me:
> > > > TypeError: expected Array[Byte], got array
>
> > > > bytes is a Python array. I tried:
> > > > Marshal.Copy.Overloads[Array[Byte], int, IntPtr, int]
> > > > (bytes.buffer_info()[0], 0, bmData.Scan0, total_bytes)
>
> > > > but that gave the error:
> > > > TypeError: expected Array[Byte], got int
>
> > > > This small sample application demonstrates the issue:
>
> > > > import array
> > > > import struct
> > > > import StringIO
>
> > > > import clr
> > > > clr.AddReference("System.Windows.Forms")
> > > > clr.AddReference("System.Drawing")
>
> > > > from System import Array, Byte, Char, IntPtr
> > > > from System.Windows.Forms import Application, Form, PictureBox
> > > > from System.Drawing import Size, Point, Bitmap, Color, Rectangle
> > > > from System.Drawing.Imaging import PixelFormat, ImageLockMode
> > > > from System.Runtime.InteropServices import Marshal
>
> > > > class IForm(Form):
>
> > > >    def __init__(self):
> > > >        bytes = array.array('B')
>
> > > >        width  = 25
> > > >        height = 20
>
> > > >        for i in range(width * height):
> > > >            bytes.append(i % 256) # R
> > > >            bytes.append(i % 256) # G
> > > >            bytes.append(i % 256) # B
>
> > > >        bitmap = Bitmap(width, height, PixelFormat.Format24bppRgb)
>
> > > >        bmData = bitmap.LockBits(Rectangle(0, 0, bitmap.Width,
> > > > bitmap.Height),
> > > >          ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb)
>
> > > >        total_bytes = (bmData.Stride) * bmData.Height
>
> > > >        Marshal.Copy.Overloads[Array[Byte], int, IntPtr, int](
> > > >          bytes.buffer_info()[0], 0, bmData.Scan0, total_bytes)
> > > >        bitmap.UnlockBits(bmData)
>
> > > > ##        for x in range(width):
> > > > ##            for y in range(height):
> > > > ##                i = y * width + x
> > > > ##                bitmap.SetPixel(x, y, Color.FromArgb(bytes[i],
> > > > bytes[i+1], bytes[i+2]))
>
> > > >        pb = PictureBox()
> > > >        pb.Size = Size(bitmap.Width, bitmap.Height)
> > > >        pb.Location = Point(2, 2)
> > > >        pb.Image = bitmap
> > > >        pb.Parent = self
>
> > > >        self.Size = Size(bitmap.Width + 20, bitmap.Height + 45)
> > > >        self.CenterToScreen()
>
> > > > Application.Run(IForm())
>
> > > > Using bitmap.SetPixel works, but I cannot find how to make it work
> > > > using the LockBits and Marshal.Copy.
>
> > > > Thanks,
> > > > -- Marcel
>
> > > > On Jun 12, 10:27 pm, Curt Hagenlocher <c... at hagenlocher.org> wrote:
> > > > > It looks like the automatic overload resolution may be failing -- at
> > > > least,
> > > > > it's worth trying to resolve the overload manually. This would be
> > > > something
> > > > > like
>
> > > > > from System import Array, Byte, IntPtr
> > > > > Marshal.Copy.Overloads[Array[Byte], int, IntPtr, int](bytes, 0,
> > > > > bmData.Scan0, total_bytes)
>
> > > > > On Sat, Jun 12, 2010 at 10:07 PM, Marcel <marcel.vandendun... at gmail.com
> > > > >wrote:
>
> > > > > > I think I simplified my example a little too far. I'm trying to
> > > > > > display a Bitmap from bytes generated in Python code.
>
> > > > > >        bytes = array.array('c') # tried 'B' also
> > > > > >        # generate bitmap bytes ...
>
> > > > > >        bitmap = Bitmap(width, height, PixelFormat.Format24bppRgb)
>
> > > > > >        bmData = bitmap.LockBits(Rectangle(0, 0, bitmap.Width,
> > > > > > bitmap.Height),
> > > > > >          ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb)
>
> > > > > >        total_bytes = (bmData.Stride) * bmData.Height
>
> > > > > >        Marshal.Copy(bytes, 0, bmData.Scan0, total_bytes);
>
> > > > > >        bitmap.UnlockBits(bmData)
>
> > > > > > The IronPython exception I'm getting is:
> > > > > > TypeError: expected IntPtr, got array
>
> > > > > > Casting the bytes array to IntPtr changed the error into:
> > > > > > TypeError: expected int, got array
>
> > > > > > I'm using IronPython 2.6 (2.6.10920.0) on .NET 2.0.50727.4927
>
> > > > > > Any idea?
>
> > > > > > Thanks,
> > > > > > -- Marcel
>
> > > > > > On Jun 11, 11:27 pm, David Escobar <davidesco... at ieee.org> wrote:
> > > > > > > This worked for me (based on the code you provided):
>
> > > > > > > import clr
> > > > > > > from System import Array
>
> > > > > > > dest = Array[str](bytes)
>
> > > > > > > On Fri, Jun 11, 2010 at 9:51 PM, Marcel <
> > > > marcel.vandendun... at gmail.com
> > > > > > >wrote:
>
> > > > > > > > I have a python method that returns a Python byte
> > array.array('c').
>
> > > > > > > > Now, I want to copy this array using
> > > > > > > > System.Runtime.InteropServices.Marshal.Copy. This method however
> > > > > > > > expects a .NET Array.
>
> > > > > > > > import array
> > > > > > > > from System.Runtime.InteropServices import Marshal
>
> > > > > > > > bytes = array.array('c')
> > > > > > > > bytes.append('a')
> > > > > > > > bytes.append('b')
> > > > > > > > bytes.append('c')
> > > > > > > > Marshal.Copy(bytes, dest, 0, 3)
>
> > > > > > > > Is there a way to make this work without copying the data? If not,
> > > > how
> > > > > > > > do I convert the data in the Python array to the .NET array?
>
> > > > > > > > Thanks,
> > > > > > > > -- Marcel
> > > > > > > > _______________________________________________
> > > > > > > > Users mailing list
> > > > > > > > Us... at lists.ironpython.com
> > > > > > > >http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
>
> > > > > > > _______________________________________________
> > > > > > > Users mailing list
> > > > > > > Us... at lists.ironpython.comhttp://
> > > > > > lists.ironpython.com/listinfo.cgi/users-ironpython.com
> > > > > > _______________________________________________
> > > > > > Users mailing list
> > > > > > Us... at lists.ironpython.com
> > > > > >http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
>
> > > > > _______________________________________________
> > > > > Users mailing list
> > > > > Us... at lists.ironpython.comhttp://
> > > > lists.ironpython.com/listinfo.cgi/users-ironpython.com
> > > > _______________________________________________
> > > > Users mailing list
> > > > Us... at lists.ironpython.com
> > > >http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
>
> > > _______________________________________________
> > > Users mailing list
> > > Us... at lists.ironpython.comhttp://lists.ironpython.com/listinfo.cgi/users-
> > ironpython.com
> > _______________________________________________
> > Users mailing list
> > Us... at lists.ironpython.com
> >http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
>
> _______________________________________________
> Users mailing list
> Us... at lists.ironpython.comhttp://lists.ironpython.com/listinfo.cgi/users-ironpython.com



More information about the Ironpython-users mailing list