[IronPython] Convert between python array and .NET Array

Marcel marcel.vandendungen at gmail.com
Tue Jun 15 03:20:38 CEST 2010


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



More information about the Ironpython-users mailing list