From: Robin Dunn <robin@alldunn.com>
Date: Tue, 22 Aug 2006 17:27:42 +0000 (+0000)
Subject: Added wx.BitmapFromBuffer and wx.BitmapFromBufferRGBA factory functions.
X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/238ba802f1a9f79cde6e3ebd44e5c4ab78af2055

Added wx.BitmapFromBuffer and wx.BitmapFromBufferRGBA factory functions.


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@40748 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---

diff --git a/wxPython/docs/CHANGES.txt b/wxPython/docs/CHANGES.txt
index 991c9a76b8..3704a9283a 100644
--- a/wxPython/docs/CHANGES.txt
+++ b/wxPython/docs/CHANGES.txt
@@ -190,6 +190,11 @@ IDs.
 
 Added wx.lib.combotreebox from Frank Niessink
 
+Added wx.ImageFromBuffer, wx.BitmapFromBuffer and
+wx.BitmapFromBufferRGBA factory functions.  They enable loading of am
+image or bitmap directly from a Python object that implements the
+buffer interface, such as strings, arrays, etc.
+
 
 
 
diff --git a/wxPython/include/wx/wxPython/wxPython_int.h b/wxPython/include/wx/wxPython/wxPython_int.h
index 4ca0e75196..4af26ea1fc 100644
--- a/wxPython/include/wx/wxPython/wxPython_int.h
+++ b/wxPython/include/wx/wxPython/wxPython_int.h
@@ -103,7 +103,9 @@ public:
 #endif
 
 //---------------------------------------------------------------------------
-typedef unsigned char byte;
+typedef unsigned char  byte;
+typedef unsigned char* buffer;
+
 typedef wxPoint2DDouble wxPoint2D;    
 
 #ifndef SWIG_TYPE_TABLE
diff --git a/wxPython/src/_bitmap.i b/wxPython/src/_bitmap.i
index 93fa2a2b93..8aa329e133 100644
--- a/wxPython/src/_bitmap.i
+++ b/wxPython/src/_bitmap.i
@@ -12,6 +12,9 @@
 
 // Not a %module
 
+%{
+#include <wx/rawbmp.h>
+%}
 
 //---------------------------------------------------------------------------
 
@@ -62,6 +65,10 @@ converted to a wx.Bitmap, so any image file format supported by
 
 :todo: Find a way to do very efficient PIL Image <--> wx.Bitmap
        converstions.
+
+:see: `wx.EmptyBitmap`, `wx.BitmapFromIcon`, `wx.BitmapFromImage`,
+      `wx.BitmapFromXPMData`, `wx.BitmapFromBits`, `wx.BitmapFromBuffer`,
+      `wx.BitmapFromBufferRGBA`, `wx.Image`
 ");
 
 
@@ -126,35 +133,36 @@ that a colour reduction may have to take place.", "",
 
     
     %extend {
-        DocStr(wxBitmap(PyObject* listOfStrings),
-               "Construct a Bitmap from a list of strings formatted as XPM data.", "");
-        
-        %RenameCtor(BitmapFromXPMData, wxBitmap(PyObject* listOfStrings))
-        {
-            char**    cArray = NULL;
-            wxBitmap* bmp;
-
-            cArray = ConvertListOfStrings(listOfStrings);
-            if (! cArray)
-                return NULL;
-            bmp = new wxBitmap(cArray);
-            delete [] cArray;
-            return bmp;
-        }
-
-        DocStr(wxBitmap(PyObject* bits, int width, int height, int depth=1 ),
-               "Creates a bitmap from an array of bits.  You should only use this
+        %RenameDocCtor(
+            BitmapFromXPMData,
+            "Construct a Bitmap from a list of strings formatted as XPM data.", "",
+            wxBitmap(PyObject* listOfStrings))
+            {
+                char**    cArray = NULL;
+                wxBitmap* bmp;
+
+                cArray = ConvertListOfStrings(listOfStrings);
+                if (! cArray)
+                    return NULL;
+                bmp = new wxBitmap(cArray);
+                delete [] cArray;
+                return bmp;
+            }
+
+       
+        %RenameDocCtor(
+            BitmapFromBits,
+            "Creates a bitmap from an array of bits.  You should only use this
 function for monochrome bitmaps (depth 1) in portable programs: in
 this case the bits parameter should contain an XBM image.  For other
-bit depths, the behaviour is platform dependent.", "");
-        
-        %RenameCtor(BitmapFromBits, wxBitmap(PyObject* bits, int width, int height, int depth=1 ))
-        {
-            char*      buf;
-            Py_ssize_t length;
-            PyString_AsStringAndSize(bits, &buf, &length);
-            return new wxBitmap(buf, width, height, depth);
-        }
+bit depths, the behaviour is platform dependent.", "",
+            wxBitmap(PyObject* bits, int width, int height, int depth=1 ))
+            {
+                char*      buf;
+                Py_ssize_t length;
+                PyString_AsStringAndSize(bits, &buf, &length);
+                return new wxBitmap(buf, width, height, depth);
+            }
     }    
 
     
@@ -304,6 +312,181 @@ the ``type`` parameter.", "");
 };
 
 
+//---------------------------------------------------------------------------
+// Factory functions for creating wxBitmaps from Python buffer objects.  They
+// use the Abstract Pixel API to be able to set RGB and A bytes directly into
+// the wxBitmap's pixel buffer.
+
+%newobject _BitmapFromBufferAlpha;
+%newobject _BitmapFromBuffer;
+%inline %{
+    wxBitmap* _BitmapFromBufferAlpha(int width, int height,
+                                    buffer data, int DATASIZE,
+                                    buffer alpha, int ALPHASIZE)
+    {
+        if (DATASIZE != width*height*3) {
+            wxPyErr_SetString(PyExc_ValueError, "Invalid data buffer size.");
+            return NULL;
+        }
+
+        if (ALPHASIZE != width*height) {
+            wxPyErr_SetString(PyExc_ValueError, "Invalid alpha buffer size.");
+            return NULL;
+        }
+
+        wxBitmap* bmp = new wxBitmap(width, height, 32);
+        wxAlphaPixelData pixels(*bmp, wxPoint(0,0), wxSize(width,height));
+        if (! pixels) {
+            // raise an exception...
+            wxPyErr_SetString(PyExc_RuntimeError,
+                              "Failed to gain raw access to bitmap data.");
+            return NULL;
+        }
+                
+        pixels.UseAlpha();
+        wxAlphaPixelData::Iterator p(pixels);
+        for (int y=0; y<height; y++) {
+            wxAlphaPixelData::Iterator rowStart = p;
+            for (int x=0; x<width; x++) {
+                p.Red()   = *(data++);
+                p.Green() = *(data++);
+                p.Blue()  = *(data++);
+                p.Alpha() = *(alpha++);
+                ++p; 
+            }
+            p = rowStart;
+            p.OffsetY(pixels, 1);
+        }
+        return bmp;
+    }        
+        
+    wxBitmap* _BitmapFromBuffer(int width, int height, buffer data, int DATASIZE)
+    {
+        if (DATASIZE != width*height*3) {
+            wxPyErr_SetString(PyExc_ValueError, "Invalid data buffer size.");
+            return NULL;
+        }
+
+        wxBitmap* bmp = new wxBitmap(width, height, 24);
+        wxNativePixelData pixels(*bmp, wxPoint(0,0), wxSize(width,height));
+        if (! pixels) {
+            // raise an exception...
+            wxPyErr_SetString(PyExc_RuntimeError,
+                              "Failed to gain raw access to bitmap data.");
+            return NULL;
+        }
+                
+        wxNativePixelData::Iterator p(pixels);
+        for (int y=0; y<height; y++) {
+            wxNativePixelData::Iterator rowStart = p;
+            for (int x=0; x<width; x++) {
+                p.Red()   = *(data++);
+                p.Green() = *(data++);
+                p.Blue()  = *(data++);
+                ++p; 
+            }
+            p = rowStart;
+            p.OffsetY(pixels, 1);
+        }
+        return bmp;
+    }
+%}    
+
+
+%pythoncode {
+def BitmapFromBuffer(width, height, dataBuffer, alphaBuffer=None):
+    """
+    Creates a `wx.Bitmap` from the data in dataBuffer.  The dataBuffer
+    parameter must be a Python object that implements the buffer interface, or
+    is convertable to a buffer object, such as a string, array, etc.  The
+    dataBuffer object is expected to contain a series of RGB bytes and be
+    width*height*3 bytes long.  A buffer object can optionally be supplied for
+    the image's alpha channel data, and it is expected to be width*height
+    bytes long.
+
+    Unlike `wx.ImageFromBuffer` the bitmap created with this function does not
+    share the memory buffer with the buffer object.  This is because the
+    native pixel buffer format varies on different platforms, and so instead
+    an efficient as possible copy of the data is made from the buffer objects
+    to the bitmap's native pixel buffer.  For direct access to a bitmap's
+    pixel buffer see `wx.NativePixelData` and `wx.AlphaPixelData`.
+
+    :see: `wx.Bitmap`, `wx.BitmapFromBufferRGBA`, `wx.NativePixelData`,
+          `wx.AlphaPixelData`, `wx.ImageFromBuffer`
+    """
+    if not isinstance(dataBuffer, buffer):
+        dataBuffer = buffer(dataBuffer)
+    if alphaBuffer is not None and not isinstance(alphaBuffer, buffer):
+        alphaBuffer = buffer(alphaBuffer)
+    if alphaBuffer is not None:
+        return _gdi_._BitmapFromBufferAlpha(width, height, dataBuffer, alphaBuffer)
+    else:
+        return _gdi_._BitmapFromBuffer(width, height, dataBuffer)
+}
+
+
+
+%newobject _BitmapFromBufferRGBA;
+%inline %{
+    wxBitmap* _BitmapFromBufferRGBA(int width, int height, buffer data, int DATASIZE)                                   
+    {
+        if (DATASIZE != width*height*4) {
+            wxPyErr_SetString(PyExc_ValueError, "Invalid data buffer size.");
+            return NULL;
+        }
+
+        wxBitmap* bmp = new wxBitmap(width, height, 32);
+        wxAlphaPixelData pixels(*bmp, wxPoint(0,0), wxSize(width,height));
+        if (! pixels) {
+            // raise an exception...
+            wxPyErr_SetString(PyExc_RuntimeError,
+                              "Failed to gain raw access to bitmap data.");
+            return NULL;
+        }
+                
+        pixels.UseAlpha();
+        wxAlphaPixelData::Iterator p(pixels);
+        for (int y=0; y<height; y++) {
+            wxAlphaPixelData::Iterator rowStart = p;
+            for (int x=0; x<width; x++) {
+                p.Red()   = *(data++);
+                p.Green() = *(data++);
+                p.Blue()  = *(data++);
+                p.Alpha() = *(data++);
+                ++p; 
+            }
+            p = rowStart;
+            p.OffsetY(pixels, 1);
+        }
+        return bmp;
+    }        
+%}
+
+%pythoncode {
+def BitmapFromBufferRGBA(width, height, dataBuffer):
+    """
+    Creates a `wx.Bitmap` from the data in dataBuffer.  The dataBuffer
+    parameter must be a Python object that implements the buffer interface, or
+    is convertable to a buffer object, such as a string, array, etc.  The
+    dataBuffer object is expected to contain a series of RGBA bytes (red,
+    gree, blue and alpha) and be width*height*4 bytes long.  
+
+    Unlike `wx.ImageFromBuffer` the bitmap created with this function does not
+    share the memory buffer with the buffer object.  This is because the
+    native pixel buffer format varies on different platforms, and so instead
+    an efficient as possible copy of the data is made from the buffer object
+    to the bitmap's native pixel buffer.  For direct access to a bitmap's
+    pixel buffer see `wx.NativePixelData` and `wx.AlphaPixelData`.
+
+    :see: `wx.Bitmap`, `wx.BitmapFromBuffer`, `wx.NativePixelData`,
+          `wx.AlphaPixelData`, `wx.ImageFromBuffer`
+    """
+    if not isinstance(dataBuffer, buffer):
+        dataBuffer = buffer(dataBuffer)
+    return _gdi_._BitmapFromBufferRGBA(width, height, dataBuffer)
+}
+
+
 //---------------------------------------------------------------------------
 
 DocStr(wxMask,
diff --git a/wxPython/src/my_typemaps.i b/wxPython/src/my_typemaps.i
index 08a2c9c09b..5c8474ef2b 100644
--- a/wxPython/src/my_typemaps.i
+++ b/wxPython/src/my_typemaps.i
@@ -315,6 +315,21 @@ MAKE_INT_ARRAY_TYPEMAPS(styles, styles_field)
 }
 
 
+//---------------------------------------------------------------------------
+// Typemaps for loading a image or bitmap from an object that implements the
+// buffer interface
+
+
+%typemap(in) (buffer data, int DATASIZE)
+{ if ($input != Py_None) {
+        if (!PyArg_Parse($input, "t#", &$1, &$2)) SWIG_fail;
+}}
+
+%typemap(in) (buffer alpha, int ALPHASIZE)
+{ if ($input != Py_None) {
+        if (!PyArg_Parse($input, "t#", &$1, &$2)) SWIG_fail;
+}}
+
 //---------------------------------------------------------------------------
 // Typemaps to convert return values that are base class pointers
 // to the real derived type, if possible.  See wxPyMake_wxObject in