mirror of
https://github.com/wxWidgets/Phoenix.git
synced 2026-01-06 12:00:13 +01:00
Add buffer related methods and helpers for wxBitmap
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxPython/Phoenix/trunk@71293 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
3
TODO.txt
3
TODO.txt
@@ -107,9 +107,6 @@ WAF Build
|
|||||||
other dev stuff
|
other dev stuff
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
* port all of the wx.Bitmap copy-to and copy-from buffer methods, and
|
|
||||||
raw bitmap access routines from Classic.
|
|
||||||
|
|
||||||
* Come up with some way to implement the MustHaveApp check that
|
* Come up with some way to implement the MustHaveApp check that
|
||||||
Classic does. It should raise an exception when something is
|
Classic does. It should raise an exception when something is
|
||||||
created/used that should not be done before there is an application
|
created/used that should not be done before there is an application
|
||||||
|
|||||||
266
etg/bitmap.py
266
etg/bitmap.py
@@ -18,8 +18,14 @@ DOCSTRING = ""
|
|||||||
|
|
||||||
# The classes and/or the basename of the Doxygen XML files to be processed by
|
# The classes and/or the basename of the Doxygen XML files to be processed by
|
||||||
# this script.
|
# this script.
|
||||||
ITEMS = [ 'wxBitmap', 'wxBitmapHandler', 'wxMask' ]
|
ITEMS = [ 'wxBitmap',
|
||||||
|
'wxBitmapHandler',
|
||||||
|
'wxMask' ]
|
||||||
|
|
||||||
|
OTHERDEPS = [ 'src/bitmap_ex.h',
|
||||||
|
'src/bitmap_ex.cpp', ]
|
||||||
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
def run():
|
def run():
|
||||||
@@ -52,9 +58,36 @@ def run():
|
|||||||
return self->IsOk();
|
return self->IsOk();
|
||||||
""")
|
""")
|
||||||
|
|
||||||
# On MSW the handler classes are different than what is documented, and
|
c.addCppMethod('long', 'GetHandle', '()',
|
||||||
# this causes compile errors. Nobody has needed them from Python thus far,
|
doc='MSW-only method to fetch the windows handle for the bitmap.',
|
||||||
# so just ignore them all for now.
|
body="""\
|
||||||
|
#ifdef __WXMSW__
|
||||||
|
return self->GetHandle();
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
""")
|
||||||
|
|
||||||
|
c.addCppMethod('void', 'SetHandle', '(long handle)',
|
||||||
|
doc='MSW-only method to set the windows handle for the bitmap.',
|
||||||
|
body="""\
|
||||||
|
#ifdef __WXMSW__
|
||||||
|
self->SetHandle((WXHANDLE)handle);
|
||||||
|
#endif
|
||||||
|
""")
|
||||||
|
|
||||||
|
c.addCppMethod('void', 'SetSize', '(const wxSize& size)',
|
||||||
|
doc='Set the bitmap size (does not affect the existing bitmap data).',
|
||||||
|
body="""\
|
||||||
|
self->SetWidth(size->x);
|
||||||
|
self->SetHeight(size->y);
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# On MSW the bitmap handler classes are different than what is
|
||||||
|
# documented, and this causes compile errors. Nobody has needed them from
|
||||||
|
# Python thus far, so just ignore them all for now.
|
||||||
for m in c.find('FindHandler').all():
|
for m in c.find('FindHandler').all():
|
||||||
m.ignore()
|
m.ignore()
|
||||||
c.find('AddHandler').ignore()
|
c.find('AddHandler').ignore()
|
||||||
@@ -70,9 +103,230 @@ def run():
|
|||||||
module.find('wxBitmapHandler').ignore()
|
module.find('wxBitmapHandler').ignore()
|
||||||
#module.addItem(tools.wxListWrapperTemplate('wxList', 'wxBitmapHandler', module))
|
#module.addItem(tools.wxListWrapperTemplate('wxList', 'wxBitmapHandler', module))
|
||||||
|
|
||||||
# TODO: The ctors and methods from Classic for converting to/from
|
|
||||||
# buffer objects with raw bitmap access.
|
|
||||||
|
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Declarations, helpers and methods for converting to/from buffer objects
|
||||||
|
# with raw bitmap access.
|
||||||
|
|
||||||
|
from etgtools import EnumDef, EnumValueDef
|
||||||
|
e = EnumDef(name='wxBitmapBufferFormat')
|
||||||
|
e.items.extend([ EnumValueDef(name='wxBitmapBufferFormat_RGB'),
|
||||||
|
EnumValueDef(name='wxBitmapBufferFormat_RGBA'),
|
||||||
|
EnumValueDef(name='wxBitmapBufferFormat_RGB32'),
|
||||||
|
EnumValueDef(name='wxBitmapBufferFormat_ARGB32'),
|
||||||
|
])
|
||||||
|
module.insertItem(0, e)
|
||||||
|
|
||||||
|
c.includeCppCode('src/bitmap_ex.cpp')
|
||||||
|
module.addHeaderCode('#include "bitmap_ex.h"')
|
||||||
|
|
||||||
|
|
||||||
|
c.addCppMethod('void', 'CopyFromBuffer',
|
||||||
|
'(wxPyBuffer* data, wxBitmapBufferFormat format=wxBitmapBufferFormat_RGB, int stride=-1)',
|
||||||
|
doc="""\
|
||||||
|
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.
|
||||||
|
============================= ================================""",
|
||||||
|
body="""\
|
||||||
|
wxPyCopyBitmapFromBuffer(self, (byte*)data->m_ptr, data->m_len, format, stride);
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
c.addCppMethod('void', 'CopyToBuffer',
|
||||||
|
'(wxPyBuffer* data, wxBitmapBufferFormat format=wxBitmapBufferFormat_RGB, int stride=-1)',
|
||||||
|
doc="""\
|
||||||
|
Copy pixel data to a buffer object. See `CopyFromBuffer` for buffer
|
||||||
|
format details.""",
|
||||||
|
body="""\
|
||||||
|
wxPyCopyBitmapToBuffer(self, (byte*)data->m_ptr, data->m_len, format, stride);
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
# Some bitmap factories added as static methods
|
||||||
|
|
||||||
|
c.addCppMethod('wxBitmap*', 'FromBufferAndAlpha',
|
||||||
|
'(int width, int height, wxPyBuffer* data, wxPyBuffer* alpha)',
|
||||||
|
isStatic=True,
|
||||||
|
factory=True,
|
||||||
|
doc="""\
|
||||||
|
Creates a `wx.Bitmap` from in-memory data. The data and alpha
|
||||||
|
parameters must be a Python object that implements the buffer
|
||||||
|
interface, such as a string, bytearray, etc. The data object
|
||||||
|
is expected to contain a series of RGB bytes and be at least
|
||||||
|
width*height*3 bytes long, while the alpha object is expected
|
||||||
|
to be width*height bytes long and represents the image's alpha
|
||||||
|
channel. On Windows and Mac the RGB values will be
|
||||||
|
'premultiplied' by the alpha values. (The other platforms do
|
||||||
|
the multiplication themselves.)
|
||||||
|
|
||||||
|
Unlike `wx.ImageFromBuffer` the bitmap created with this function
|
||||||
|
does not share the memory block 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.
|
||||||
|
""",
|
||||||
|
body="""\
|
||||||
|
if (!data->checkSize(width*height*3) || !alpha->checkSize(width*height))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
byte* ddata = (byte*)data->m_ptr;
|
||||||
|
byte* adata = (byte*)alpha->m_ptr;
|
||||||
|
wxBitmap* bmp = new wxBitmap(width, height, 32);
|
||||||
|
|
||||||
|
wxAlphaPixelData pixData(*bmp, wxPoint(0,0), wxSize(width,height));
|
||||||
|
if (! pixData) {
|
||||||
|
wxPyErr_SetString(PyExc_RuntimeError, "Failed to gain raw access to bitmap data.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxAlphaPixelData::Iterator p(pixData);
|
||||||
|
for (int y=0; y<height; y++) {
|
||||||
|
wxAlphaPixelData::Iterator rowStart = p;
|
||||||
|
for (int x=0; x<width; x++) {
|
||||||
|
byte a = *(adata++);
|
||||||
|
p.Red() = wxPy_premultiply(*(ddata++), a);
|
||||||
|
p.Green() = wxPy_premultiply(*(ddata++), a);
|
||||||
|
p.Blue() = wxPy_premultiply(*(ddata++), a);
|
||||||
|
p.Alpha() = a;
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
p = rowStart;
|
||||||
|
p.OffsetY(pixData, 1);
|
||||||
|
}
|
||||||
|
return bmp;
|
||||||
|
""")
|
||||||
|
|
||||||
|
c.addCppMethod('wxBitmap*', 'FromBuffer', '(int width, int height, wxPyBuffer* data)',
|
||||||
|
isStatic=True,
|
||||||
|
factory=True,
|
||||||
|
doc="""\
|
||||||
|
Creates a `wx.Bitmap` from in-memory data. The data parameter
|
||||||
|
must be a Python object that implements the buffer interface, such
|
||||||
|
as a string, bytearray, etc. The data object is expected to contain
|
||||||
|
a series of RGB bytes and be at least width*height*3 bytes long.
|
||||||
|
|
||||||
|
Unlike `wx.ImageFromBuffer` the bitmap created with this function
|
||||||
|
does not share the memory block 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.
|
||||||
|
""",
|
||||||
|
body="""\
|
||||||
|
wxBitmap* bmp = new wxBitmap(width, height, 24);
|
||||||
|
wxPyCopyBitmapFromBuffer(bmp, (byte*)data->m_ptr, data->m_len, wxBitmapBufferFormat_RGB);
|
||||||
|
if (PyErr_Occurred()) {
|
||||||
|
delete bmp;
|
||||||
|
bmp = NULL;
|
||||||
|
}
|
||||||
|
return bmp;
|
||||||
|
""")
|
||||||
|
|
||||||
|
module.addPyFunction('BitmapFromBuffer', '(width, height, dataBuffer, alphaBuffer=None)',
|
||||||
|
deprecated=True,
|
||||||
|
doc='A compatibility wrapper for Bitmap.FromBuffer and Bitmap.FromBufferAndAlpha',
|
||||||
|
body="""\
|
||||||
|
if alphaBuffer is not None:
|
||||||
|
return Bitmap.FromBufferAndAlpha(width, height, dataBuffer, alphaBuffer)
|
||||||
|
else:
|
||||||
|
return Bitmap.FromBuffer(width, height, dataBuffer)
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
c.addCppMethod('wxBitmap*', 'FromBufferRGBA', '(int width, int height, wxPyBuffer* data)',
|
||||||
|
isStatic=True,
|
||||||
|
factory=True,
|
||||||
|
doc="""\
|
||||||
|
Creates a `wx.Bitmap` from in-memory data. The data parameter
|
||||||
|
must be a Python object that implements the buffer interface, such
|
||||||
|
as a string, bytearray, etc. The data object is expected to contain
|
||||||
|
a series of RGBA bytes and be at least width*height*4 bytes long.
|
||||||
|
On Windows and Mac the RGB values will be 'premultiplied' by the
|
||||||
|
alpha values. (The other platforms do the multiplication themselves.)
|
||||||
|
|
||||||
|
Unlike `wx.ImageFromBuffer` the bitmap created with this function
|
||||||
|
does not share the memory block 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.
|
||||||
|
""",
|
||||||
|
body="""\
|
||||||
|
wxBitmap* bmp = new wxBitmap(width, height, 32);
|
||||||
|
wxPyCopyBitmapFromBuffer(bmp, (byte*)data->m_ptr, data->m_len, wxBitmapBufferFormat_RGBA);
|
||||||
|
if (PyErr_Occurred()) {
|
||||||
|
delete bmp;
|
||||||
|
bmp = NULL;
|
||||||
|
}
|
||||||
|
return bmp;
|
||||||
|
""")
|
||||||
|
|
||||||
|
module.addPyFunction('BitmapFromBufferRGBA', '(width, height, dataBuffer)',
|
||||||
|
deprecated=True,
|
||||||
|
doc='A compatibility wrapper for Bitmap.FromBufferRGBA',
|
||||||
|
body='return Bitmap.FromBufferRGBA(width, height, dataBuffer)')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
c.addCppMethod('wxBitmap*', 'FromRGBA',
|
||||||
|
'(int width, int height, byte red=0, byte green=0, byte blue=0, byte alpha=0)',
|
||||||
|
isStatic=True,
|
||||||
|
factory=True,
|
||||||
|
doc="""\
|
||||||
|
Creates a new empty 32-bit `wx.Bitmap` where every pixel has been
|
||||||
|
initialized with the given RGBA values.
|
||||||
|
""",
|
||||||
|
body="""\
|
||||||
|
if ( !(width > 0 && height > 0) ) {
|
||||||
|
wxPyErr_SetString(PyExc_ValueError, "Width and height must be greater than zero");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxBitmap* bmp = new wxBitmap(width, height, 32);
|
||||||
|
wxAlphaPixelData pixData(*bmp, wxPoint(0,0), wxSize(width,height));
|
||||||
|
if (! pixData) {
|
||||||
|
wxPyErr_SetString(PyExc_RuntimeError, "Failed to gain raw access to bitmap data.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxAlphaPixelData::Iterator p(pixData);
|
||||||
|
for (int y=0; y<height; y++) {
|
||||||
|
wxAlphaPixelData::Iterator rowStart = p;
|
||||||
|
for (int x=0; x<width; x++) {
|
||||||
|
p.Red() = wxPy_premultiply(red, alpha);
|
||||||
|
p.Green() = wxPy_premultiply(green, alpha);
|
||||||
|
p.Blue() = wxPy_premultiply(blue, alpha);
|
||||||
|
p.Alpha() = alpha;
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
p = rowStart;
|
||||||
|
p.OffsetY(pixData, 1);
|
||||||
|
}
|
||||||
|
return bmp;
|
||||||
|
""")
|
||||||
|
|
||||||
|
module.addPyFunction('EmptyBitmapRGBA', '(width, height, red=0, green=0, blue=0, alpha=0)',
|
||||||
|
deprecated=True,
|
||||||
|
doc='A compatibility wrapper for Bitmap.FromRGBA',
|
||||||
|
body='return Bitmap.FromRGBA(width, height, red, green, blue, alpha)')
|
||||||
|
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
|
||||||
# For compatibility:
|
# For compatibility:
|
||||||
module.addPyFunction('EmptyBitmap', '(width, height, depth=BITMAP_SCREEN_DEPTH)',
|
module.addPyFunction('EmptyBitmap', '(width, height, depth=BITMAP_SCREEN_DEPTH)',
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ def run():
|
|||||||
module.insertItemAfter(td, etgtools.TypedefDef(type='long', name='time_t'))
|
module.insertItemAfter(td, etgtools.TypedefDef(type='long', name='time_t'))
|
||||||
module.insertItemAfter(td, etgtools.TypedefDef(type='long long', name='wxFileOffset'))
|
module.insertItemAfter(td, etgtools.TypedefDef(type='long long', name='wxFileOffset'))
|
||||||
module.insertItemAfter(td, etgtools.TypedefDef(type='SIP_SSIZE_T', name='ssize_t'))
|
module.insertItemAfter(td, etgtools.TypedefDef(type='SIP_SSIZE_T', name='ssize_t'))
|
||||||
|
module.insertItemAfter(td, etgtools.TypedefDef(type='unsigned char', name='byte', pyInt=True))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
105
etg/image.py
105
etg/image.py
@@ -21,6 +21,8 @@ DOCSTRING = ""
|
|||||||
ITEMS = [ 'wxImage',
|
ITEMS = [ 'wxImage',
|
||||||
'wxImageHistogram',
|
'wxImageHistogram',
|
||||||
'wxImageHandler',
|
'wxImageHandler',
|
||||||
|
#'wxQuantize',
|
||||||
|
#'wxPalette',
|
||||||
]
|
]
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
@@ -58,7 +60,7 @@ def run():
|
|||||||
if (! copy)
|
if (! copy)
|
||||||
return NULL;
|
return NULL;
|
||||||
sipCpp = new sipwxImage;
|
sipCpp = new sipwxImage;
|
||||||
sipCpp->Create(width, height, (unsigned char*)copy);
|
sipCpp->Create(width, height, (byte*)copy);
|
||||||
""")
|
""")
|
||||||
|
|
||||||
c.addCppCtor_sip('(int width, int height, wxPyBuffer* data, wxPyBuffer* alpha)',
|
c.addCppCtor_sip('(int width, int height, wxPyBuffer* data, wxPyBuffer* alpha)',
|
||||||
@@ -70,7 +72,7 @@ def run():
|
|||||||
if ((dcopy = data->copy()) == NULL || (acopy = alpha->copy()) == NULL)
|
if ((dcopy = data->copy()) == NULL || (acopy = alpha->copy()) == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
sipCpp = new sipwxImage;
|
sipCpp = new sipwxImage;
|
||||||
sipCpp->Create(width, height, (unsigned char*)dcopy, (unsigned char*)acopy, false);
|
sipCpp->Create(width, height, (byte*)dcopy, (byte*)acopy, false);
|
||||||
""")
|
""")
|
||||||
|
|
||||||
c.addCppCtor_sip('(const wxSize& size, wxPyBuffer* data)',
|
c.addCppCtor_sip('(const wxSize& size, wxPyBuffer* data)',
|
||||||
@@ -82,7 +84,7 @@ def run():
|
|||||||
if (! copy)
|
if (! copy)
|
||||||
return NULL;
|
return NULL;
|
||||||
sipCpp = new sipwxImage;
|
sipCpp = new sipwxImage;
|
||||||
sipCpp->Create(size->x, size->y, (unsigned char*)copy, false);
|
sipCpp->Create(size->x, size->y, (byte*)copy, false);
|
||||||
""")
|
""")
|
||||||
|
|
||||||
c.addCppCtor_sip('(const wxSize& size, wxPyBuffer* data, wxPyBuffer* alpha)',
|
c.addCppCtor_sip('(const wxSize& size, wxPyBuffer* data, wxPyBuffer* alpha)',
|
||||||
@@ -94,7 +96,7 @@ def run():
|
|||||||
if ((dcopy = data->copy()) == NULL || (acopy = alpha->copy()) == NULL)
|
if ((dcopy = data->copy()) == NULL || (acopy = alpha->copy()) == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
sipCpp = new sipwxImage;
|
sipCpp = new sipwxImage;
|
||||||
sipCpp->Create(size->x, size->y, (unsigned char*)dcopy, (unsigned char*)acopy, false);
|
sipCpp->Create(size->x, size->y, (byte*)dcopy, (byte*)acopy, false);
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
|
||||||
@@ -112,7 +114,7 @@ def run():
|
|||||||
void* copy = data->copy();
|
void* copy = data->copy();
|
||||||
if (! copy)
|
if (! copy)
|
||||||
return false;
|
return false;
|
||||||
return self->Create(width, height, (unsigned char*)copy);
|
return self->Create(width, height, (byte*)copy);
|
||||||
""")
|
""")
|
||||||
|
|
||||||
c.addCppMethod('bool', 'Create', '(int width, int height, wxPyBuffer* data, wxPyBuffer* alpha)',
|
c.addCppMethod('bool', 'Create', '(int width, int height, wxPyBuffer* data, wxPyBuffer* alpha)',
|
||||||
@@ -123,7 +125,7 @@ def run():
|
|||||||
return false;
|
return false;
|
||||||
if ((dcopy = data->copy()) == NULL || (acopy = alpha->copy()) == NULL)
|
if ((dcopy = data->copy()) == NULL || (acopy = alpha->copy()) == NULL)
|
||||||
return false;
|
return false;
|
||||||
return self->Create(width, height, (unsigned char*)dcopy, (unsigned char*)acopy);
|
return self->Create(width, height, (byte*)dcopy, (byte*)acopy);
|
||||||
""")
|
""")
|
||||||
|
|
||||||
c.addCppMethod('bool', 'Create', '(const wxSize& size, wxPyBuffer* data)',
|
c.addCppMethod('bool', 'Create', '(const wxSize& size, wxPyBuffer* data)',
|
||||||
@@ -134,7 +136,7 @@ def run():
|
|||||||
void* copy = data->copy();
|
void* copy = data->copy();
|
||||||
if (! copy)
|
if (! copy)
|
||||||
return false;
|
return false;
|
||||||
return self->Create(size->x, size->y, (unsigned char*)copy);
|
return self->Create(size->x, size->y, (byte*)copy);
|
||||||
""")
|
""")
|
||||||
|
|
||||||
c.addCppMethod('bool', 'Create', '(const wxSize& size, wxPyBuffer* data, wxPyBuffer* alpha)',
|
c.addCppMethod('bool', 'Create', '(const wxSize& size, wxPyBuffer* data, wxPyBuffer* alpha)',
|
||||||
@@ -145,7 +147,7 @@ def run():
|
|||||||
return false;
|
return false;
|
||||||
if ((dcopy = data->copy()) == NULL || (acopy = alpha->copy()) == NULL)
|
if ((dcopy = data->copy()) == NULL || (acopy = alpha->copy()) == NULL)
|
||||||
return false;
|
return false;
|
||||||
return self->Create(size->x, size->y, (unsigned char*)dcopy, (unsigned char*)acopy);
|
return self->Create(size->x, size->y, (byte*)dcopy, (byte*)acopy);
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
|
||||||
@@ -160,7 +162,7 @@ def run():
|
|||||||
void* copy = data->copy();
|
void* copy = data->copy();
|
||||||
if (!copy)
|
if (!copy)
|
||||||
return;
|
return;
|
||||||
self->SetData((unsigned char*)copy, false);
|
self->SetData((byte*)copy, false);
|
||||||
""", briefDoc=bd, detailedDoc=dd)
|
""", briefDoc=bd, detailedDoc=dd)
|
||||||
|
|
||||||
c.find('SetData').findOverload('int new_width').ignore()
|
c.find('SetData').findOverload('int new_width').ignore()
|
||||||
@@ -171,7 +173,7 @@ def run():
|
|||||||
void* copy = data->copy();
|
void* copy = data->copy();
|
||||||
if (!copy)
|
if (!copy)
|
||||||
return;
|
return;
|
||||||
self->SetData((unsigned char*)copy, new_width, new_height, false);
|
self->SetData((byte*)copy, new_width, new_height, false);
|
||||||
""")
|
""")
|
||||||
|
|
||||||
m = c.find('SetAlpha').findOverload('unsigned char *alpha')
|
m = c.find('SetAlpha').findOverload('unsigned char *alpha')
|
||||||
@@ -184,7 +186,7 @@ def run():
|
|||||||
void* copy = alpha->copy();
|
void* copy = alpha->copy();
|
||||||
if (!copy)
|
if (!copy)
|
||||||
return;
|
return;
|
||||||
self->SetAlpha((unsigned char*)copy, false);
|
self->SetAlpha((byte*)copy, false);
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
|
||||||
@@ -195,7 +197,7 @@ def run():
|
|||||||
c.addCppMethod('PyObject*', 'GetData', '()',
|
c.addCppMethod('PyObject*', 'GetData', '()',
|
||||||
doc="Returns a copy of the RGB bytes of the image.",
|
doc="Returns a copy of the RGB bytes of the image.",
|
||||||
body="""\
|
body="""\
|
||||||
unsigned char* data = self->GetData();
|
byte* data = self->GetData();
|
||||||
Py_ssize_t len = self->GetWidth() * self->GetHeight() * 3;
|
Py_ssize_t len = self->GetWidth() * self->GetHeight() * 3;
|
||||||
PyObject* rv = NULL;
|
PyObject* rv = NULL;
|
||||||
wxPyBLOCK_THREADS( rv = PyByteArray_FromStringAndSize((const char*)data, len));
|
wxPyBLOCK_THREADS( rv = PyByteArray_FromStringAndSize((const char*)data, len));
|
||||||
@@ -206,7 +208,7 @@ def run():
|
|||||||
c.addCppMethod('PyObject*', 'GetAlpha', '()',
|
c.addCppMethod('PyObject*', 'GetAlpha', '()',
|
||||||
doc="Returns a copy of the Alpha bytes of the image.",
|
doc="Returns a copy of the Alpha bytes of the image.",
|
||||||
body="""\
|
body="""\
|
||||||
unsigned char* data = self->GetAlpha();
|
byte* data = self->GetAlpha();
|
||||||
Py_ssize_t len = self->GetWidth() * self->GetHeight();
|
Py_ssize_t len = self->GetWidth() * self->GetHeight();
|
||||||
PyObject* rv = NULL;
|
PyObject* rv = NULL;
|
||||||
wxPyBLOCK_THREADS( rv = PyByteArray_FromStringAndSize((const char*)data, len));
|
wxPyBLOCK_THREADS( rv = PyByteArray_FromStringAndSize((const char*)data, len));
|
||||||
@@ -223,7 +225,7 @@ def run():
|
|||||||
image data buffer inside the wx.Image. You need to ensure that you do
|
image data buffer inside the wx.Image. You need to ensure that you do
|
||||||
not use this buffer object after the image has been destroyed.""",
|
not use this buffer object after the image has been destroyed.""",
|
||||||
body="""\
|
body="""\
|
||||||
unsigned char* data = self->GetData();
|
byte* data = self->GetData();
|
||||||
Py_ssize_t len = self->GetWidth() * self->GetHeight() * 3;
|
Py_ssize_t len = self->GetWidth() * self->GetHeight() * 3;
|
||||||
PyObject* rv;
|
PyObject* rv;
|
||||||
Py_buffer view;
|
Py_buffer view;
|
||||||
@@ -240,7 +242,7 @@ def run():
|
|||||||
data buffer inside the wx.Image. You need to ensure that you do
|
data buffer inside the wx.Image. You need to ensure that you do
|
||||||
not use this buffer object after the image has been destroyed.""",
|
not use this buffer object after the image has been destroyed.""",
|
||||||
body="""\
|
body="""\
|
||||||
unsigned char* data = self->GetAlpha();
|
byte* data = self->GetAlpha();
|
||||||
Py_ssize_t len = self->GetWidth() * self->GetHeight();
|
Py_ssize_t len = self->GetWidth() * self->GetHeight();
|
||||||
PyObject* rv;
|
PyObject* rv;
|
||||||
Py_buffer view;
|
Py_buffer view;
|
||||||
@@ -263,7 +265,7 @@ def run():
|
|||||||
if (!data->checkSize(self->GetWidth() * self->GetHeight() * 3))
|
if (!data->checkSize(self->GetWidth() * self->GetHeight() * 3))
|
||||||
return;
|
return;
|
||||||
// True means don't free() the pointer
|
// True means don't free() the pointer
|
||||||
self->SetData((unsigned char*)data->m_ptr, true);
|
self->SetData((byte*)data->m_ptr, true);
|
||||||
""")
|
""")
|
||||||
c.addCppMethod('void', 'SetDataBuffer', '(wxPyBuffer* data, int new_width, int new_height)',
|
c.addCppMethod('void', 'SetDataBuffer', '(wxPyBuffer* data, int new_width, int new_height)',
|
||||||
doc="""\
|
doc="""\
|
||||||
@@ -275,7 +277,7 @@ def run():
|
|||||||
if (!data->checkSize(new_width * new_height * 3))
|
if (!data->checkSize(new_width * new_height * 3))
|
||||||
return;
|
return;
|
||||||
// True means don't free() the pointer
|
// True means don't free() the pointer
|
||||||
self->SetData((unsigned char*)data->m_ptr, new_width, new_height, true);
|
self->SetData((byte*)data->m_ptr, new_width, new_height, true);
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
|
||||||
@@ -289,7 +291,7 @@ def run():
|
|||||||
if (!alpha->checkSize(self->GetWidth() * self->GetHeight()))
|
if (!alpha->checkSize(self->GetWidth() * self->GetHeight()))
|
||||||
return;
|
return;
|
||||||
// True means don't free() the pointer
|
// True means don't free() the pointer
|
||||||
self->SetAlpha((unsigned char*)alpha->m_ptr, true);
|
self->SetAlpha((byte*)alpha->m_ptr, true);
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
|
||||||
@@ -387,10 +389,10 @@ def run():
|
|||||||
|
|
||||||
unsigned rgblen = 3 * self->GetWidth() * self->GetHeight();
|
unsigned rgblen = 3 * self->GetWidth() * self->GetHeight();
|
||||||
unsigned alphalen = self->GetWidth() * self->GetHeight();
|
unsigned alphalen = self->GetWidth() * self->GetHeight();
|
||||||
unsigned char* src_data = self->GetData();
|
byte* src_data = self->GetData();
|
||||||
unsigned char* src_alpha = self->GetAlpha();
|
byte* src_alpha = self->GetAlpha();
|
||||||
unsigned char* dst_data = dest->GetData();
|
byte* dst_data = dest->GetData();
|
||||||
unsigned char* dst_alpha = NULL;
|
byte* dst_alpha = NULL;
|
||||||
|
|
||||||
// adjust rgb
|
// adjust rgb
|
||||||
if ( factor_red == 1.0 && factor_green == 1.0 && factor_blue == 1.0)
|
if ( factor_red == 1.0 && factor_green == 1.0 && factor_blue == 1.0)
|
||||||
@@ -403,18 +405,18 @@ def run():
|
|||||||
// rgb pixel for pixel
|
// rgb pixel for pixel
|
||||||
for ( unsigned i = 0; i < rgblen; i= i + 3 )
|
for ( unsigned i = 0; i < rgblen; i= i + 3 )
|
||||||
{
|
{
|
||||||
dst_data[i] = (unsigned char) wxMin( 255, (int) (factor_red * src_data[i]) );
|
dst_data[i] = (byte) wxMin( 255, (int) (factor_red * src_data[i]) );
|
||||||
dst_data[i + 1] = (unsigned char) wxMin( 255, (int) (factor_green * src_data[i + 1]) );
|
dst_data[i + 1] = (byte) wxMin( 255, (int) (factor_green * src_data[i + 1]) );
|
||||||
dst_data[i + 2] = (unsigned char) wxMin( 255, (int) (factor_blue * src_data[i + 2]) );
|
dst_data[i + 2] = (byte) wxMin( 255, (int) (factor_blue * src_data[i + 2]) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// adjust the mask colour
|
// adjust the mask colour
|
||||||
if ( self->HasMask() )
|
if ( self->HasMask() )
|
||||||
{
|
{
|
||||||
dest->SetMaskColour((unsigned char) wxMin( 255, (int) (factor_red * self->GetMaskRed() ) ),
|
dest->SetMaskColour((byte) wxMin( 255, (int) (factor_red * self->GetMaskRed() ) ),
|
||||||
(unsigned char) wxMin( 255, (int) (factor_green * self->GetMaskGreen() ) ),
|
(byte) wxMin( 255, (int) (factor_green * self->GetMaskGreen() ) ),
|
||||||
(unsigned char) wxMin( 255, (int) (factor_blue * self->GetMaskBlue() ) ) );
|
(byte) wxMin( 255, (int) (factor_blue * self->GetMaskBlue() ) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// adjust the alpha channel
|
// adjust the alpha channel
|
||||||
@@ -436,7 +438,7 @@ def run():
|
|||||||
// alpha value for alpha value
|
// alpha value for alpha value
|
||||||
for ( unsigned i = 0; i < alphalen; ++i )
|
for ( unsigned i = 0; i < alphalen; ++i )
|
||||||
{
|
{
|
||||||
dst_alpha[i] = (unsigned char) wxMin( 255, (int) (factor_alpha * src_alpha[i]) );
|
dst_alpha[i] = (byte) wxMin( 255, (int) (factor_alpha * src_alpha[i]) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -450,7 +452,7 @@ def run():
|
|||||||
|
|
||||||
for ( unsigned i = 0; i < alphalen; ++i )
|
for ( unsigned i = 0; i < alphalen; ++i )
|
||||||
{
|
{
|
||||||
dst_alpha[i] = (unsigned char) wxMin( 255, (int) (factor_alpha * 255) );
|
dst_alpha[i] = (byte) wxMin( 255, (int) (factor_alpha * 255) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -458,9 +460,9 @@ def run():
|
|||||||
if ( dst_alpha && dest->HasMask() )
|
if ( dst_alpha && dest->HasMask() )
|
||||||
{
|
{
|
||||||
// make the mask transparent honoring the alpha channel
|
// make the mask transparent honoring the alpha channel
|
||||||
const unsigned char mr = dest->GetMaskRed();
|
const byte mr = dest->GetMaskRed();
|
||||||
const unsigned char mg = dest->GetMaskGreen();
|
const byte mg = dest->GetMaskGreen();
|
||||||
const unsigned char mb = dest->GetMaskBlue();
|
const byte mb = dest->GetMaskBlue();
|
||||||
|
|
||||||
for ( unsigned i = 0; i < alphalen; ++i )
|
for ( unsigned i = 0; i < alphalen; ++i )
|
||||||
{
|
{
|
||||||
@@ -506,7 +508,42 @@ def run():
|
|||||||
doc='Compatibility wrapper for creating an image from RGB and Alpha data',
|
doc='Compatibility wrapper for creating an image from RGB and Alpha data',
|
||||||
body='return Image(width, height, data, alpha)')
|
body='return Image(width, height, data, alpha)')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
module.addPyFunction('ImageFromBuffer', '(width, height, dataBuffer, alphaBuffer=None)',
|
||||||
|
doc="""\
|
||||||
|
Creates a `wx.Image` from the data in dataBuffer. The dataBuffer
|
||||||
|
parameter must be a Python object that implements the buffer interface,
|
||||||
|
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.
|
||||||
|
|
||||||
|
The wx.Image will be created with its data and alpha pointers initialized
|
||||||
|
to the memory address pointed to by the buffer objects, thus saving the
|
||||||
|
time needed to copy the image data from the buffer object to the wx.Image.
|
||||||
|
While this has advantages, it also has the shoot-yourself-in-the-foot
|
||||||
|
risks associated with sharing a C pointer between two objects.
|
||||||
|
|
||||||
|
To help alleviate the risk a reference to the data and alpha buffer
|
||||||
|
objects are kept with the wx.Image, so that they won't get deleted until
|
||||||
|
after the wx.Image is deleted. However please be aware that it is not
|
||||||
|
guaranteed that an object won't move its memory buffer to a new location
|
||||||
|
when it needs to resize its contents. If that happens then the wx.Image
|
||||||
|
will end up referring to an invalid memory location and could cause the
|
||||||
|
application to crash. Therefore care should be taken to not manipulate
|
||||||
|
the objects used for the data and alpha buffers in a way that would cause
|
||||||
|
them to change size.
|
||||||
|
""",
|
||||||
|
body="""\
|
||||||
|
img = Image(width, height)
|
||||||
|
img.SetDataBuffer(dataBuffer)
|
||||||
|
if alphaBuffer:
|
||||||
|
img.SetAlphaBuffer(alphaBuffer)
|
||||||
|
img._buffer = dataBuffer
|
||||||
|
img._alpha = alphaBuffer
|
||||||
|
return img
|
||||||
|
""")
|
||||||
|
|
||||||
#-------------------------------------------------------
|
#-------------------------------------------------------
|
||||||
c = module.find('wxImageHistogram')
|
c = module.find('wxImageHistogram')
|
||||||
|
|||||||
319
src/bitmap_ex.cpp
Normal file
319
src/bitmap_ex.cpp
Normal file
@@ -0,0 +1,319 @@
|
|||||||
|
//--------------------------------------------------------------------------
|
||||||
|
// Name: src/bitmap_ex.h
|
||||||
|
// Purpose: Helper functions and etc. for copying bitmap data to/from
|
||||||
|
// buffer objects. This file is included in etg/bitmap.py and
|
||||||
|
// used in the wxBitmap wrapper.
|
||||||
|
//
|
||||||
|
// Author: Robin Dunn
|
||||||
|
//
|
||||||
|
// Created: 27-Apr-2012
|
||||||
|
// Copyright: (c) 2012 by Total Control Software
|
||||||
|
// Licence: wxWindows license
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
#include <wx/rawbmp.h>
|
||||||
|
|
||||||
|
// TODO: Switch these APIs to use the new wxPyBuffer class
|
||||||
|
|
||||||
|
void wxPyCopyBitmapFromBuffer(wxBitmap* bmp,
|
||||||
|
buffer data, Py_ssize_t DATASIZE,
|
||||||
|
wxBitmapBufferFormat format, int stride)
|
||||||
|
{
|
||||||
|
int height = bmp->GetHeight();
|
||||||
|
int width = bmp->GetWidth();
|
||||||
|
|
||||||
|
switch (format) {
|
||||||
|
// A simple sequence of RGB bytes
|
||||||
|
case wxBitmapBufferFormat_RGB:
|
||||||
|
{
|
||||||
|
if (DATASIZE < width * height * 3) {
|
||||||
|
wxPyErr_SetString(PyExc_ValueError, "Invalid data buffer size.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wxNativePixelData pixData(*bmp, wxPoint(0,0), wxSize(width, height));
|
||||||
|
if (! pixData) {
|
||||||
|
wxPyErr_SetString(PyExc_RuntimeError,
|
||||||
|
"Failed to gain raw access to bitmap data.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxNativePixelData::Iterator p(pixData);
|
||||||
|
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(pixData, 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A simple sequence of RGBA bytes
|
||||||
|
case wxBitmapBufferFormat_RGBA:
|
||||||
|
{
|
||||||
|
if (DATASIZE < width * height * 4) {
|
||||||
|
wxPyErr_SetString(PyExc_ValueError, "Invalid data buffer size.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wxAlphaPixelData pixData(*bmp, wxPoint(0,0), wxSize(width, height));
|
||||||
|
if (! pixData) {
|
||||||
|
wxPyErr_SetString(PyExc_RuntimeError,
|
||||||
|
"Failed to gain raw access to bitmap data.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wxAlphaPixelData::Iterator p(pixData);
|
||||||
|
for (int y=0; y<height; y++) {
|
||||||
|
wxAlphaPixelData::Iterator rowStart = p;
|
||||||
|
for (int x=0; x<width; x++) {
|
||||||
|
byte a = data[3];
|
||||||
|
p.Red() = wxPy_premultiply(*(data++), a);
|
||||||
|
p.Green() = wxPy_premultiply(*(data++), a);
|
||||||
|
p.Blue() = wxPy_premultiply(*(data++), a);
|
||||||
|
p.Alpha() = a; data++;
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
p = rowStart;
|
||||||
|
p.OffsetY(pixData, 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A sequence of 32-bit values in native endian order,
|
||||||
|
// where the alpha is in the upper 8 bits, then red, then
|
||||||
|
// green, then blue. The stride is the distance in bytes
|
||||||
|
// from the beginning of one row of the image data to the
|
||||||
|
// beginning of the next row. This may not be the same as
|
||||||
|
// width*4 if alignment or platform specific optimizations
|
||||||
|
// have been utilized.
|
||||||
|
|
||||||
|
// NOTE: This is normally used with Cairo, which seems to
|
||||||
|
// already have the values premultiplied. Should we have
|
||||||
|
// a way to optionally do it anyway?
|
||||||
|
|
||||||
|
case wxBitmapBufferFormat_RGB32:
|
||||||
|
case wxBitmapBufferFormat_ARGB32:
|
||||||
|
{
|
||||||
|
bool useAlpha = (format == wxBitmapBufferFormat_ARGB32);
|
||||||
|
byte* rowStart = data;
|
||||||
|
wxUint32* bufptr;
|
||||||
|
wxUint32 value;
|
||||||
|
|
||||||
|
if (stride == -1)
|
||||||
|
stride = width * 4;
|
||||||
|
|
||||||
|
if (DATASIZE < stride * height) {
|
||||||
|
wxPyErr_SetString(PyExc_ValueError, "Invalid data buffer size.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxAlphaPixelData pixData(*bmp, wxPoint(0,0), wxSize(width,height));
|
||||||
|
if (! pixData) {
|
||||||
|
wxPyErr_SetString(PyExc_RuntimeError,
|
||||||
|
"Failed to gain raw access to bitmap data.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxAlphaPixelData::Iterator pix(pixData);
|
||||||
|
for (int y=0; y<height; y++) {
|
||||||
|
pix.MoveTo(pixData, 0, y);
|
||||||
|
bufptr = (wxUint32*)rowStart;
|
||||||
|
for (int x=0; x<width; x++) {
|
||||||
|
value = *bufptr;
|
||||||
|
pix.Alpha() = useAlpha ? (value >> 24) & 0xFF : 255;
|
||||||
|
pix.Red() = (value >> 16) & 0xFF;
|
||||||
|
pix.Green() = (value >> 8) & 0xFF;
|
||||||
|
pix.Blue() = (value >> 0) & 0xFF;
|
||||||
|
++pix;
|
||||||
|
++bufptr;
|
||||||
|
}
|
||||||
|
rowStart += stride;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Some helper macros used below to help declutter the code
|
||||||
|
#define MAKE_PIXDATA(type) \
|
||||||
|
type pixData(*bmp, wxPoint(0,0), wxSize(width, height)); \
|
||||||
|
if (! pixData) { \
|
||||||
|
wxPyErr_SetString(PyExc_RuntimeError, "Failed to gain raw access to bitmap data."); \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
|
type::Iterator p(pixData); \
|
||||||
|
type::Iterator rowStart
|
||||||
|
|
||||||
|
#define CHECK_BUFFERSIZE(size_needed) \
|
||||||
|
if (DATASIZE < size_needed) { \
|
||||||
|
wxPyErr_SetString(PyExc_ValueError, "Invalid data buffer size."); \
|
||||||
|
return; \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void wxPyCopyBitmapToBuffer(wxBitmap* bmp,
|
||||||
|
buffer data, Py_ssize_t DATASIZE,
|
||||||
|
wxBitmapBufferFormat format, int stride)
|
||||||
|
{
|
||||||
|
int height = bmp->GetHeight();
|
||||||
|
int width = bmp->GetWidth();
|
||||||
|
int depth = bmp->GetDepth();
|
||||||
|
|
||||||
|
// images loaded from a file may not have set the depth, at least on Mac...
|
||||||
|
if (depth == -1) {
|
||||||
|
if (bmp->HasAlpha())
|
||||||
|
depth = 32;
|
||||||
|
else
|
||||||
|
depth = 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (format) {
|
||||||
|
// A simple sequence of RGB bytes
|
||||||
|
case wxBitmapBufferFormat_RGB:
|
||||||
|
{
|
||||||
|
CHECK_BUFFERSIZE(width * height * 3);
|
||||||
|
if (depth == 24) {
|
||||||
|
MAKE_PIXDATA(wxNativePixelData);
|
||||||
|
|
||||||
|
for (int y=0; y<height; y++) {
|
||||||
|
rowStart = p;
|
||||||
|
for (int x=0; x<width; x++) {
|
||||||
|
*(data++) = p.Red();
|
||||||
|
*(data++) = p.Green();
|
||||||
|
*(data++) = p.Blue();
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
p = rowStart;
|
||||||
|
p.OffsetY(pixData, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (depth == 32) {
|
||||||
|
// Source has alpha, but we won't be using it because the
|
||||||
|
// destination buffer doesn't
|
||||||
|
MAKE_PIXDATA(wxAlphaPixelData);
|
||||||
|
|
||||||
|
for (int y=0; y<height; y++) {
|
||||||
|
rowStart = p;
|
||||||
|
for (int x=0; x<width; x++) {
|
||||||
|
*(data++) = p.Red();
|
||||||
|
*(data++) = p.Green();
|
||||||
|
*(data++) = p.Blue();
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
p = rowStart;
|
||||||
|
p.OffsetY(pixData, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A simple sequence of RGBA bytes
|
||||||
|
case wxBitmapBufferFormat_RGBA:
|
||||||
|
{
|
||||||
|
CHECK_BUFFERSIZE(width * height * 4);
|
||||||
|
if (depth == 24) {
|
||||||
|
MAKE_PIXDATA(wxNativePixelData);
|
||||||
|
for (int y=0; y<height; y++) {
|
||||||
|
rowStart = p;
|
||||||
|
for (int x=0; x<width; x++) {
|
||||||
|
byte a = wxALPHA_OPAQUE;
|
||||||
|
*(data++) = wxPy_unpremultiply(p.Red(), a);
|
||||||
|
*(data++) = wxPy_unpremultiply(p.Green(), a);
|
||||||
|
*(data++) = wxPy_unpremultiply(p.Blue(), a);
|
||||||
|
*(data++) = a;
|
||||||
|
}
|
||||||
|
p = rowStart;
|
||||||
|
p.OffsetY(pixData, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (depth == 32) {
|
||||||
|
MAKE_PIXDATA(wxAlphaPixelData);
|
||||||
|
for (int y=0; y<height; y++) {
|
||||||
|
rowStart = p;
|
||||||
|
for (int x=0; x<width; x++) {
|
||||||
|
byte a = p.Alpha();
|
||||||
|
*(data++) = wxPy_unpremultiply(p.Red(), a);
|
||||||
|
*(data++) = wxPy_unpremultiply(p.Green(), a);
|
||||||
|
*(data++) = wxPy_unpremultiply(p.Blue(), a);
|
||||||
|
*(data++) = a;
|
||||||
|
}
|
||||||
|
p = rowStart;
|
||||||
|
p.OffsetY(pixData, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A sequence of 32-bit values in native endian order,
|
||||||
|
// where the alpha is in the upper 8 bits, then red, then
|
||||||
|
// green, then blue. The stride is the distance in bytes
|
||||||
|
// from the beginning of one row of the image data to the
|
||||||
|
// beginning of the next row. This may not be the same as
|
||||||
|
// width*4 if alignment or platform specific optimizations
|
||||||
|
// have been utilized.
|
||||||
|
|
||||||
|
// NOTE: This is normally used with Cairo, which seems to
|
||||||
|
// already have the values premultiplied. Should we have
|
||||||
|
// a way to optionally do it anyway?
|
||||||
|
|
||||||
|
case wxBitmapBufferFormat_RGB32:
|
||||||
|
case wxBitmapBufferFormat_ARGB32:
|
||||||
|
{
|
||||||
|
bool useAlpha = (format == wxBitmapBufferFormat_ARGB32);
|
||||||
|
byte* dataRow = data;
|
||||||
|
wxUint32* bufptr;
|
||||||
|
wxUint32 value;
|
||||||
|
|
||||||
|
if (stride == -1)
|
||||||
|
stride = width * 4;
|
||||||
|
|
||||||
|
CHECK_BUFFERSIZE(stride * height);
|
||||||
|
|
||||||
|
if (useAlpha && depth == 32) {
|
||||||
|
MAKE_PIXDATA(wxAlphaPixelData);
|
||||||
|
for (int y=0; y<height; y++) {
|
||||||
|
p.MoveTo(pixData, 0, y);
|
||||||
|
bufptr = (wxUint32*)dataRow;
|
||||||
|
for (int x=0; x<width; x++) {
|
||||||
|
value =
|
||||||
|
(p.Alpha() << 24) |
|
||||||
|
(p.Red() << 16) |
|
||||||
|
(p.Green() << 8) |
|
||||||
|
(p.Blue());
|
||||||
|
*bufptr = value;
|
||||||
|
++p;
|
||||||
|
++bufptr;
|
||||||
|
}
|
||||||
|
dataRow += stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // if (!useAlpha /*depth == 24*/)
|
||||||
|
{
|
||||||
|
MAKE_PIXDATA(wxNativePixelData);
|
||||||
|
for (int y=0; y<height; y++) {
|
||||||
|
p.MoveTo(pixData, 0, y);
|
||||||
|
bufptr = (wxUint32*)dataRow;
|
||||||
|
for (int x=0; x<width; x++) {
|
||||||
|
value =
|
||||||
|
(wxALPHA_OPAQUE << 24) |
|
||||||
|
(p.Red() << 16) |
|
||||||
|
(p.Green() << 8) |
|
||||||
|
(p.Blue());
|
||||||
|
*bufptr = value;
|
||||||
|
++p;
|
||||||
|
++bufptr;
|
||||||
|
}
|
||||||
|
dataRow += stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
46
src/bitmap_ex.h
Normal file
46
src/bitmap_ex.h
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
//--------------------------------------------------------------------------
|
||||||
|
// Name: src/bitmap_ex.h
|
||||||
|
// Purpose: Helper functions and etc. for copying bitmap data to/from
|
||||||
|
// buffer objects.
|
||||||
|
//
|
||||||
|
// Author: Robin Dunn
|
||||||
|
//
|
||||||
|
// Created: 27-Apr-2012
|
||||||
|
// Copyright: (c) 2012 by Total Control Software
|
||||||
|
// Licence: wxWindows license
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef BITMAP_EX_H
|
||||||
|
#define BITMAP_EX_H
|
||||||
|
|
||||||
|
|
||||||
|
enum wxBitmapBufferFormat {
|
||||||
|
wxBitmapBufferFormat_RGB,
|
||||||
|
wxBitmapBufferFormat_RGBA,
|
||||||
|
wxBitmapBufferFormat_RGB32,
|
||||||
|
wxBitmapBufferFormat_ARGB32,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// See http://tinyurl.com/e5adr for what premultiplying alpha means. wxMSW and
|
||||||
|
// wxMac want to have the values premultiplied by the alpha value, but the
|
||||||
|
// other platforms don't. These macros help keep the code clean.
|
||||||
|
#if defined(__WXMSW__) || defined(__WXMAC__)
|
||||||
|
#define wxPy_premultiply(p, a) ((p) * (a) / 0xff)
|
||||||
|
#define wxPy_unpremultiply(p, a) ((a) ? ((p) * 0xff / (a)) : (p))
|
||||||
|
#else
|
||||||
|
#define wxPy_premultiply(p, a) (p)
|
||||||
|
#define wxPy_unpremultiply(p, a) (p)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void wxPyCopyBitmapFromBuffer(wxBitmap* bmp,
|
||||||
|
buffer data, Py_ssize_t DATASIZE,
|
||||||
|
wxBitmapBufferFormat format, int stride=-1);
|
||||||
|
|
||||||
|
void wxPyCopyBitmapToBuffer(wxBitmap* bmp,
|
||||||
|
buffer data, Py_ssize_t DATASIZE,
|
||||||
|
wxBitmapBufferFormat format, int stride=-1);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -46,6 +46,8 @@
|
|||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
typedef PyGILState_STATE wxPyBlock_t;
|
typedef PyGILState_STATE wxPyBlock_t;
|
||||||
|
typedef unsigned char byte;
|
||||||
|
typedef unsigned char* buffer;
|
||||||
|
|
||||||
|
|
||||||
// Convert a wxString to a Python string (actually a PyUnicode object).
|
// Convert a wxString to a Python string (actually a PyUnicode object).
|
||||||
|
|||||||
@@ -7,19 +7,35 @@ pngFile = os.path.join(os.path.dirname(__file__), 'toucan.png')
|
|||||||
|
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def makeBuf(w, h, bpp=1, init=0):
|
||||||
|
"Make a simple buffer for testing with"
|
||||||
|
buf = bytearray([init] * (w*h*bpp))
|
||||||
|
return buf
|
||||||
|
|
||||||
|
|
||||||
class BitmapTests(wtc.WidgetTestCase):
|
class BitmapTests(wtc.WidgetTestCase):
|
||||||
|
|
||||||
def test_BitmapCtors(self):
|
def test_BitmapCtor1(self):
|
||||||
b1 = wx.Bitmap()
|
b1 = wx.Bitmap()
|
||||||
self.assertTrue( not b1.IsOk() )
|
self.assertTrue( not b1.IsOk() )
|
||||||
|
|
||||||
|
def test_BitmapCtor2(self):
|
||||||
b2 = wx.Bitmap(5, 10, 32)
|
b2 = wx.Bitmap(5, 10, 32)
|
||||||
self.assertTrue( b2.IsOk() )
|
self.assertTrue( b2.IsOk() )
|
||||||
|
|
||||||
|
def test_BitmapCtor3(self):
|
||||||
b3 = wx.Bitmap(wx.Size(5,10), 32)
|
b3 = wx.Bitmap(wx.Size(5,10), 32)
|
||||||
self.assertTrue( b3.IsOk() )
|
self.assertTrue( b3.IsOk() )
|
||||||
|
|
||||||
|
def test_BitmapCtor4(self):
|
||||||
b4 = wx.Bitmap((5,10), 32)
|
b4 = wx.Bitmap((5,10), 32)
|
||||||
self.assertTrue( b4.IsOk() )
|
self.assertTrue( b4.IsOk() )
|
||||||
|
|
||||||
|
def test_BitmapCtor5(self):
|
||||||
b5 = wx.Bitmap(pngFile)
|
b5 = wx.Bitmap(pngFile)
|
||||||
self.assertTrue( b5.IsOk() )
|
self.assertTrue( b5.IsOk() )
|
||||||
|
|
||||||
|
def test_BitmapCtor6(self):
|
||||||
img = wx.Image(pngFile)
|
img = wx.Image(pngFile)
|
||||||
b6 = wx.Bitmap(img)
|
b6 = wx.Bitmap(img)
|
||||||
self.assertTrue( b6.IsOk() )
|
self.assertTrue( b6.IsOk() )
|
||||||
@@ -76,6 +92,96 @@ class BitmapTests(wtc.WidgetTestCase):
|
|||||||
m = wx.Mask(bmp, wx.Colour(1,2,3))
|
m = wx.Mask(bmp, wx.Colour(1,2,3))
|
||||||
|
|
||||||
|
|
||||||
|
def test_bitmapFormatConstants(self):
|
||||||
|
wx.BitmapBufferFormat_RGB
|
||||||
|
wx.BitmapBufferFormat_RGBA
|
||||||
|
wx.BitmapBufferFormat_RGB32
|
||||||
|
wx.BitmapBufferFormat_ARGB32
|
||||||
|
|
||||||
|
def test_bitmapSetSize(self):
|
||||||
|
b1 = wx.Bitmap(1,1)
|
||||||
|
b1.SetSize((20,30))
|
||||||
|
self.assertTrue(b1.GetSize() == (20,30))
|
||||||
|
self.assertTrue(b1.Size == (20,30))
|
||||||
|
b1.Size = (25,35)
|
||||||
|
self.assertTrue(b1.GetSize() == (25,35))
|
||||||
|
|
||||||
|
def test_bitmapHandle(self):
|
||||||
|
b1 = wx.Bitmap(1,1)
|
||||||
|
b1.Handle
|
||||||
|
b1.GetHandle()
|
||||||
|
|
||||||
|
|
||||||
|
def test_bitmapCopyFromBuffer1(self):
|
||||||
|
w = h = 10
|
||||||
|
buf = makeBuf(w,h,3)
|
||||||
|
bmp = wx.Bitmap(w,h,24)
|
||||||
|
bmp.CopyFromBuffer(buf, wx.BitmapBufferFormat_RGB)
|
||||||
|
|
||||||
|
def test_bitmapCopyFromBuffer2(self):
|
||||||
|
w = h = 10
|
||||||
|
buf = makeBuf(w,h,4)
|
||||||
|
bmp = wx.Bitmap(w,h,32)
|
||||||
|
bmp.CopyFromBuffer(buf, wx.BitmapBufferFormat_RGBA)
|
||||||
|
|
||||||
|
def test_bitmapCopyFromBuffer3(self):
|
||||||
|
w = h = 10
|
||||||
|
buf = makeBuf(w,h,4)
|
||||||
|
bmp = wx.Bitmap(w,h,32)
|
||||||
|
bmp.CopyFromBuffer(buf, wx.BitmapBufferFormat_ARGB32)
|
||||||
|
|
||||||
|
|
||||||
|
def test_bitmapCopyToBuffer1(self):
|
||||||
|
w = h = 10
|
||||||
|
buf = makeBuf(w,h,3)
|
||||||
|
bmp = wx.Bitmap(w,h,24)
|
||||||
|
bmp.CopyToBuffer(buf, wx.BitmapBufferFormat_RGB)
|
||||||
|
|
||||||
|
def test_bitmapCopyToBuffer2(self):
|
||||||
|
w = h = 10
|
||||||
|
buf = makeBuf(w,h,4)
|
||||||
|
bmp = wx.Bitmap(w,h,32)
|
||||||
|
bmp.CopyToBuffer(buf, wx.BitmapBufferFormat_RGBA)
|
||||||
|
|
||||||
|
def test_bitmapCopyToBuffer3(self):
|
||||||
|
w = h = 10
|
||||||
|
buf = makeBuf(w,h,4)
|
||||||
|
bmp = wx.Bitmap(w,h,32)
|
||||||
|
bmp.CopyToBuffer(buf, wx.BitmapBufferFormat_ARGB32)
|
||||||
|
|
||||||
|
|
||||||
|
def test_bitmapBufferFactory1(self):
|
||||||
|
w = h = 10
|
||||||
|
buf = makeBuf(w,h,3, 111)
|
||||||
|
bmp = wx.Bitmap.FromBuffer(w, h, buf)
|
||||||
|
self.assertTrue(bmp.IsOk())
|
||||||
|
|
||||||
|
def test_bitmapBufferFactory2(self):
|
||||||
|
w = h = 10
|
||||||
|
buf = makeBuf(w,h,3, 111)
|
||||||
|
alpha = makeBuf(w,h,1)
|
||||||
|
bmp = wx.Bitmap.FromBufferAndAlpha(w, h, buf, alpha)
|
||||||
|
self.assertTrue(bmp.IsOk())
|
||||||
|
|
||||||
|
def test_bitmapBufferFactory3(self):
|
||||||
|
w = h = 10
|
||||||
|
buf = makeBuf(w,h,4, 111)
|
||||||
|
bmp = wx.Bitmap.FromBufferRGBA(w, h, buf)
|
||||||
|
self.assertTrue(bmp.IsOk())
|
||||||
|
|
||||||
|
|
||||||
|
def test_bitmapEmptyFactory1(self):
|
||||||
|
w = h = 10
|
||||||
|
bmp = wx.Bitmap.FromRGBA(w, h)
|
||||||
|
self.assertTrue(bmp.IsOk())
|
||||||
|
|
||||||
|
def test_bitmapEmptyFactory2(self):
|
||||||
|
w = h = 10
|
||||||
|
bmp = wx.Bitmap.FromRGBA(w, h, 1, 2, 3, 4)
|
||||||
|
self.assertTrue(bmp.IsOk())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,11 +9,6 @@ pngFile = os.path.join(os.path.dirname(__file__), 'toucan.png')
|
|||||||
|
|
||||||
def makeBuf(w, h, bpp=1, init=0):
|
def makeBuf(w, h, bpp=1, init=0):
|
||||||
"Make a simple buffer for testing with"
|
"Make a simple buffer for testing with"
|
||||||
|
|
||||||
# Apparently array objects do not implement the new buffer protocol...
|
|
||||||
#import array
|
|
||||||
#buf = array.array('B', [init] * (w*h*bpp))
|
|
||||||
|
|
||||||
buf = bytearray([init] * (w*h*bpp))
|
buf = bytearray([init] * (w*h*bpp))
|
||||||
return buf
|
return buf
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user