wx.Bitmap CopyFromBuffer issues

I am writing a program that creates and displays an image based upon a
numpy array. Ideally I would like to have a 32bit int (0xAARRGGBB) in
each element of the array, and convert that to a bitmap. To get
familiar with drawing to the screen I followed an example and came up
with the following code. I'm trying to do a trivial example of drawing
a 1x1 bitmap and drawing (blitting?) that to the DC. It's turning out
not to be so trivial however as the MakeCustomBitmap function in the
below code doesn't work.

The wx.Bitmap documentation isn't helping me out to much on this issue
as:
1) I don't know how 'A simple sequence of RGB bytes' is
represented.
2) Any 'Sequence of 32-bit values' seems to be giving me a black
pixel.

Any suggestions?

···

===
CopyFromBuffer(self, data, format=BitmapBufferFormat_RGB, stride=-1)

Copy data from a buffer object to replace the bitmap pixel data.
Default format is plain RGB, but other formats are now supported as
well. The following symbols are used to specify the format of the
bytes in the buffer:

    ============================= ================================
    wx.BitmapBufferFormat_RGB A simple sequence of RGB bytes
    wx.BitmapBufferFormat_RGBA A simple sequence of RGBA bytes
    wx.BitmapBufferFormat_ARGB32 A sequence of 32-bit values in
native
                                   endian order, with alpha in the
upper
                                   8 bits, followed by red, green, and
                                   blue.
    wx.BitmapBufferFormat_RGB32 Same as above but the alpha byte
                                   is ignored.
    ============================= ================================

=================================
import wx
import array

class SketchFrame(wx.Frame):
    def __init__(self, parent):

        wx.Frame.__init__(self, parent, -1, "Sketch Frame",size=
(350,350))
        self.sketch = ScrolledCanvas(self, -1)

class ScrolledCanvas(wx.ScrolledWindow):
    def __init__(self, parent, id = -1, size = wx.DefaultSize):
  wx.ScrolledWindow.__init__(self, parent, id, (0, 0), size=size,
style=wx.SUNKEN_BORDER)

  self.maxWidth = 100
  self.maxHeight = 100

  self.SetBackgroundColour("WHITE")
  self.SetVirtualSize((self.maxWidth, self.maxHeight))
  self.SetScrollRate(20,20)

  self.bmp = None

  # Initialize the buffer bitmap. No real DC is needed at this point.
  self.buffer = wx.EmptyBitmap(self.maxWidth, self.maxHeight)
  dc = wx.BufferedDC(None, self.buffer)
  dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
  dc.Clear()
  self.bmp = self.MakeCustomBitmap()
  self.DoDrawing(dc)

  self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBack)

    def MakeCustomBitmap(self):
  """
  Make a bitmap with a single pixel
  """
  bmp = wx.EmptyBitmap(1, 1)
  yellow = array.array('I', [255, 255, 000])
  yellow2 = '255255000'
  yellow3 = 'FFFF00'
  # This throws a runtime exception:
  # 'RuntimeError: Failed to gain raw access to bitmap data.'
  #bmp.CopyFromBuffer(yellow, wx.BitmapBufferFormat_RGB32)

  # This gives me a bitmap, but the one pixel is black on the screen =
(
  bmp.CopyFromBuffer(yellow, wx.BitmapBufferFormat_RGB32)

  return bmp

    def OnEraseBack(self, event):
        pass # do nothing to avoid flicker

    def OnPaint(self, event):
  # Create a buffered paint DC. It will create the real
  # wx.PaintDC and then blit the bitmap to it when dc is
  # deleted. Since we don't need to draw anything else
  # here that's all there is to it.
  dc = wx.BufferedPaintDC(self, self.buffer, wx.BUFFER_VIRTUAL_AREA)

    def DoDrawing(self, dc, printing=False):
  dc.BeginDrawing()
  dc.DrawBitmap(self.bmp, 0, 0, False)
  dc.EndDrawing()

if __name__=='__main__':
    app=wx.PySimpleApp()
    frame=SketchFrame(None)
    frame.Show(True)
    app.MainLoop()

I am writing a program that creates and displays an image based upon a
numpy array. Ideally I would like to have a 32bit int (0xAARRGGBB) in
each element of the array, and convert that to a bitmap. To get
familiar with drawing to the screen I followed an example and came up
with the following code. I'm trying to do a trivial example of drawing
a 1x1 bitmap and drawing (blitting?) that to the DC. It's turning out
not to be so trivial however as the MakeCustomBitmap function in the
below code doesn't work.

The wx.Bitmap documentation isn't helping me out to much on this issue
as:
1) I don't know how 'A simple sequence of RGB bytes' is
represented.

A string or buffer of 8-bit binary byte values where each set of three represent the red green and blue components of a single pixel.

2) Any 'Sequence of 32-bit values' seems to be giving me a black
pixel.

Those two formats should use a data buffer containing a series of 32-bit integers in native endian byte order. In other words, instead of a sequence of 8-bit bytes where they are grouped in sets of 3 or 4 for the RGB or RGBA of a single pixel, there is a single 32-bit integer for each pixel, and the physical order of the RGBA bytes within that integer is dependent on the system's architecture and matches the order used for an integer on that platform.

Any suggestions?

===
CopyFromBuffer(self, data, format=BitmapBufferFormat_RGB, stride=-1)

Copy data from a buffer object to replace the bitmap pixel data.
Default format is plain RGB, but other formats are now supported as
well. The following symbols are used to specify the format of the
bytes in the buffer:

     ============================= ================================
     wx.BitmapBufferFormat_RGB A simple sequence of RGB bytes
     wx.BitmapBufferFormat_RGBA A simple sequence of RGBA bytes
     wx.BitmapBufferFormat_ARGB32 A sequence of 32-bit values in
native
                                    endian order, with alpha in the
upper
                                    8 bits, followed by red, green, and
                                    blue.
     wx.BitmapBufferFormat_RGB32 Same as above but the alpha byte
                                    is ignored.
     ============================= ================================

     def MakeCustomBitmap(self):
  """
  Make a bitmap with a single pixel
  """
  bmp = wx.EmptyBitmap(1, 1)

It would probably be a good idea to explicitly set the bit depth of the bitmap so it matches the data you will be using. So you should pass either 24 or 32 for the 3rd parameter.

  yellow = array.array('I', [255, 255, 000])

You're actually creating an array of 3 unsigned integers, not one with a single 32-bit value like I think you are intending to do. Try [0x00ffff00] instead.

Or, if you want to use a sequence of RGB bytes, then use array.array('b', [255, 255, 000]) instead, and also set the bitdepth of the bitmap to 24.

  yellow2 = '255255000'
  yellow3 = 'FFFF00'

These two string presentations are wrong. You've got 9 or 6 bytes where only three are needed, and you are using string representations of the byte values instead of actual binary byte values. This should work: "\xff\xff\x00" and use wx.BitmapBufferFormat_RGB.

  # This throws a runtime exception:
  # 'RuntimeError: Failed to gain raw access to bitmap data.'
  #bmp.CopyFromBuffer(yellow, wx.BitmapBufferFormat_RGB32)

Probably because it is expecting a bitmap with a bitdepth of 32 because of the passed format, but bmp is only 24.

···

On 12/28/09 11:12 PM, beissemj wrote:

  # This gives me a bitmap, but the one pixel is black on the screen =
(
  bmp.CopyFromBuffer(yellow, wx.BitmapBufferFormat_RGB32)

--
Robin Dunn
Software Craftsman

Robin Dunn wrote:

Or, if you want to use a sequence of RGB bytes, then use array.array('b', [255, 255, 000]) instead, and also set the bitdepth of the bitmap to 24.

or:
array.array('b', [255, 255, 000, 255])

and set bitmap to 32, if you want alpha.

also:
>> I am writing a program that creates and displays an image based upon >> a numpy array.

but you are using a std lib array in the example. numpy arrays do work well for this, in which case, you want:

w = 1, h = 1
np.array((255, 255, 000, 255), dtype=uint8).reshape(w, h, 4)

(similarly if you don't want alpha)

the w and h are for when you want a more than 1 pixel sized image. (it may be h,w, I don't recall at the moment)

you now have an array where:

img[i,j,0] is the red component of the i,j pixel
img[i,j,1] is the green component of the i,j pixel

etc.

-Chris

···

On 12/28/09 11:12 PM, beissemj wrote:

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

Thank you both for the great explanations. I finally got my trivial
example working with a numpy array. I decided that going with
wx.BitmapBufferFormat_RGB for the bitmaps will make my life easier for
cross platforms.

def MakeCustomBitmap(self):
    """
    Make a bitmap with a single pixel
    """
    w = 1
    h = 1
    foo = numpy.array((255, 255, 000), dtype=numpy.uint8).reshape(w,
h, 3)
    bmp = wx.EmptyBitmap(w, h, 24)
    bmp.CopyFromBuffer(foo.tostring(), wx.BitmapBufferFormat_RGB)