// File: _wxagg.cpp // Purpose: Accelerate WXAgg by doing the agg->wxWidgets conversions in C++. // Author: Ken McIvor // // Copyright 2005 Illinois Institute of Technology // Derived from `_gtkagg.cpp', Copyright 2004-2005 John Hunter // // See the file "LICENSE" for information on usage and redistribution // of this file, and for a DISCLAIMER OF ALL WARRANTIES. // TODO: // * Better type checking. // // * Make the `bbox' argument optional. // // * Determine if there are any thread-safety issues with this implementation. // // * Perform some AGG kung-fu to let us slice a region out of a // rendering_buffer and convert it from RGBA to RGB on the fly, rather than // making itermediate copies. This could be of use in _gtkagg and _tkagg as // well. // // * Write an agg_to_wx_bitmap() that works more like agg_to_gtk_drawable(), // drawing directly to a bitmap. // // This was the initial plan, except that I had not idea how to take a // wx.Bitmap Python shadow class and turn it into a wxBitmap pointer. // // It appears that this is the way to do it: // bool success = wxPyConvertSwigPtr(pyBitmap, (void**)&bitmap, // _T("wxBitmap")); // // I'm not sure this will speed things up much, since wxWidgets requires you // to go AGG->wx.Image->wx.Bitmap before you can blit using a MemoryDC. #include #include #include #include #include #include #include #include #include "agg_basics.h" #include "_backend_agg.h" #include "agg_pixfmt_rgba.h" #include "util/agg_color_conv_rgb8.h" #include "agg_py_transforms.h" #include #include #include // forward declarations static wxImage *convert_agg2image(RendererAgg *aggRenderer, Py::Object clipbox); static wxBitmap *convert_agg2bitmap(RendererAgg *aggRenderer, Py::Object clipbox); // the extension module class _wxagg_module : public Py::ExtensionModule<_wxagg_module> { public: _wxagg_module() : Py::ExtensionModule<_wxagg_module>("_wxkagg") { add_varargs_method("convert_agg_to_wx_image", &_wxagg_module::convert_agg_to_wx_image, "Convert the region of the agg buffer bounded by bbox to a wx.Image." " If bbox\nis None, the entire buffer is converted.\n\nNote: agg must" " be a backend_agg.RendererAgg instance."); add_varargs_method("convert_agg_to_wx_bitmap", &_wxagg_module::convert_agg_to_wx_bitmap, "Convert the region of the agg buffer bounded by bbox to a wx.Bitmap." " If bbox\nis None, the entire buffer is converted.\n\nNote: agg must" " be a backend_agg.RendererAgg instance."); initialize("The _wxagg module"); } virtual ~_wxagg_module() {} private: Py::Object convert_agg_to_wx_image(const Py::Tuple &args) { args.verify_length(2); RendererAgg* aggRenderer = static_cast( args[0].getAttr("_renderer").ptr()); Py::Object clipbox = args[1]; // convert the buffer wxImage *image = convert_agg2image(aggRenderer, clipbox); // wrap a wx.Image around the result and return it PyObject *pyWxImage = wxPyConstructObject(image, _T("wxImage"), 1); if (pyWxImage == NULL) { throw Py::MemoryError( "_wxagg.convert_agg_to_wx_image(): could not create the wx.Image"); } return Py::asObject(pyWxImage); } Py::Object convert_agg_to_wx_bitmap(const Py::Tuple &args) { args.verify_length(2); RendererAgg* aggRenderer = static_cast( args[0].getAttr("_renderer").ptr()); Py::Object clipbox = args[1]; // convert the buffer wxBitmap *bitmap = convert_agg2bitmap(aggRenderer, clipbox); // wrap a wx.Bitmap around the result and return it PyObject *pyWxBitmap = wxPyConstructObject(bitmap, _T("wxBitmap"), 1); if (pyWxBitmap == NULL) { throw Py::MemoryError( "_wxagg.convert_agg_to_wx_bitmap(): could not create the wx.Bitmap"); } return Py::asObject(pyWxBitmap); } }; // // Implementation Functions // static wxImage *convert_agg2image(RendererAgg *aggRenderer, Py::Object clipbox) { int srcWidth = 1; int srcHeight = 1; int srcStride = 1; bool deleteSrcBuffer = false; agg::int8u *srcBuffer = NULL; double l, b, r, t; if (!py_convert_bbox(clipbox.ptr(), l, b, r, t)) { // Convert everything: rgba => rgb -> image srcBuffer = aggRenderer->pixBuffer; srcWidth = (int) aggRenderer->get_width(); srcHeight = (int) aggRenderer->get_height(); srcStride = (int) aggRenderer->get_width() * 4; } else { // Convert a region: rgba => clipped rgba => rgb -> image srcWidth = (int)(r - l); srcHeight = (int)(t - b); srcStride = srcWidth * 4; deleteSrcBuffer = true; srcBuffer = new agg::int8u[srcStride*srcHeight]; if (srcBuffer == NULL) { throw Py::MemoryError( "_wxagg::convert_agg2image(): could not allocate `srcBuffer'"); } int h = (int) aggRenderer->get_height(); agg::rect_base region( (int) l, // x1 h - (int) t, // y1 (int) r, // x2 h - (int) b); // y2 agg::rendering_buffer rbuf; rbuf.attach(srcBuffer, srcWidth, srcHeight, srcStride); pixfmt pf(rbuf); renderer_base rndr(pf); rndr.copy_from(aggRenderer->renderingBuffer, ®ion, (int) - l, (int)(t - h)); } // allocate the RGB data array // use malloc(3) because wxImage will use free(3) agg::int8u *destBuffer = (agg::int8u *) malloc( sizeof(agg::int8u) * srcWidth * 3 * srcHeight); if (destBuffer == NULL) { if (deleteSrcBuffer) { delete [] srcBuffer; } throw Py::MemoryError( "_wxagg::convert_agg2image(): could not allocate `destBuffer'"); } // convert from RGBA to RGB agg::rendering_buffer rbSource; rbSource.attach(srcBuffer, srcWidth, srcHeight, srcStride); agg::rendering_buffer rbDest; rbDest.attach(destBuffer, srcWidth, srcHeight, srcWidth*3); agg::color_conv(&rbDest, &rbSource, agg::color_conv_rgba32_to_rgb24()); // Create a wxImage using the RGB data wxImage *image = new wxImage(srcWidth, srcHeight, destBuffer); if (image == NULL) { if (deleteSrcBuffer) { delete [] srcBuffer; } free(destBuffer); throw Py::MemoryError( "_wxagg::convert_agg2image(): could not allocate `image'"); } if (deleteSrcBuffer) { delete [] srcBuffer; } return image; } static wxBitmap *convert_agg2bitmap(RendererAgg *aggRenderer, Py::Object clipbox) { // Convert everything: rgba => rgb -> image => bitmap // Convert a region: rgba => clipped rgba => rgb -> image => bitmap wxImage *image = convert_agg2image(aggRenderer, clipbox); wxBitmap *bitmap = new wxBitmap(*image); image->Destroy(); delete image; if (bitmap == NULL) { throw Py::MemoryError( "_wxagg::convert_agg2bitmap(): could not allocate `bitmap'"); } return bitmap; } // // Module Initialization // extern "C" DL_EXPORT(void) init_wxagg(void) { wxPyCoreAPI_IMPORT(); //suppress an unused variable warning by creating _wxagg_module in two lines static _wxagg_module* _wxagg = NULL; _wxagg = new _wxagg_module; };