[IronPython] Convert between python array and .NET Array

Dino Viehland dinov at microsoft.com
Tue Jun 15 20:42:34 CEST 2010


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-bounces at lists.ironpython.com [mailto:users-
> bounces at lists.ironpython.com] On Behalf Of Marcel
> Sent: Monday, June 14, 2010 6:21 PM
> To: users 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
> Users at lists.ironpython.com
> http://lists.ironpython.com/listinfo.cgi/users-ironpython.com



More information about the Ironpython-users mailing list