// 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 "_transforms.h" #include "agg_pixfmt_rgba.h" #include "util/agg_color_conv_rgb8.h" #include #include #include // forward declarations static wxImage *convert_agg2image(RendererAgg *aggRenderer, Bbox *clipbox); static wxBitmap *convert_agg2bitmap(RendererAgg *aggRenderer, Bbox *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()); Bbox *clipbox = NULL; if (args[1].ptr() != Py_None) clipbox = static_cast(args[1].ptr()); // 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()); Bbox *clipbox = NULL; if (args[1].ptr() != Py_None) clipbox = static_cast(args[1].ptr()); // 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, Bbox *clipbox) { int srcWidth = 1; int srcHeight = 1; int srcStride = 1; bool deleteSrcBuffer = false; agg::int8u *srcBuffer = NULL; if (clipbox == NULL) { // 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 double l = clipbox->ll_api()->x_api()->val() ; double b = clipbox->ll_api()->y_api()->val(); double r = clipbox->ur_api()->x_api()->val() ; double t = clipbox->ur_api()->y_api()->val() ; 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, Bbox *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 unused warning by creating in two lines static _wxagg_module* _wxagg = NULL; _wxagg = new _wxagg_module; };