[IronPython] Convert between python array and .NET Array

Curt Hagenlocher curt at hagenlocher.org
Mon Jun 14 16:05:07 CEST 2010


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.vandendungen 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
> Users at lists.ironpython.com
> http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/ironpython-users/attachments/20100614/076897ce/attachment.html>


More information about the Ironpython-users mailing list