diff --git a/doc/users/next_whats_new/2018_01_10_pypy_tkagg_support.rst b/doc/users/next_whats_new/2018_01_10_pypy_tkagg_support.rst new file mode 100644 index 000000000000..cd4fb18f06c1 --- /dev/null +++ b/doc/users/next_whats_new/2018_01_10_pypy_tkagg_support.rst @@ -0,0 +1,7 @@ +Rework TkAgg backend to support PyPy +------------------------------------ + +PyPy_ can plot using the TkAgg backend, supported on PyPy 5.9 +and greater (both PyPy for python 2.7 and PyPy for python 3.5) + +.. _PyPy: https:/www.pypy.org diff --git a/examples/user_interfaces/embedding_in_tk_sgskip.py b/examples/user_interfaces/embedding_in_tk_sgskip.py index bee6bb050281..f79390d30990 100644 --- a/examples/user_interfaces/embedding_in_tk_sgskip.py +++ b/examples/user_interfaces/embedding_in_tk_sgskip.py @@ -12,6 +12,7 @@ # Implement the default Matplotlib key bindings. from matplotlib.backend_bases import key_press_handler from matplotlib.figure import Figure +from six.moves import tkinter as Tk import numpy as np diff --git a/lib/matplotlib/backends/tkagg.py b/lib/matplotlib/backends/tkagg.py index 060f4726c060..e3b6be68ceb2 100644 --- a/lib/matplotlib/backends/tkagg.py +++ b/lib/matplotlib/backends/tkagg.py @@ -13,23 +13,25 @@ def blit(photoimage, aggimage, bbox=None, colormode=1): if bbox is not None: bbox_array = bbox.__array__() + # x1, x2, y1, y2 + bboxptr = (bbox_array[0, 0], bbox_array[1, 0], + bbox_array[0, 1], bbox_array[1, 1]) else: - bbox_array = None + bboxptr = 0 data = np.asarray(aggimage) + dataptr = (data.ctypes.data, data.shape[0], data.shape[1]) try: tk.call( "PyAggImagePhoto", photoimage, - id(data), colormode, id(bbox_array)) + dataptr, colormode, bboxptr) except Tk.TclError: - try: - try: - _tkagg.tkinit(tk.interpaddr(), 1) - except AttributeError: - _tkagg.tkinit(id(tk), 0) - tk.call("PyAggImagePhoto", photoimage, - id(data), colormode, id(bbox_array)) - except (ImportError, AttributeError, Tk.TclError): - raise + if hasattr(tk, 'interpaddr'): + _tkagg.tkinit(tk.interpaddr(), 1) + else: + # very old python? + _tkagg.tkinit(tk, 0) + tk.call("PyAggImagePhoto", photoimage, + dataptr, colormode, bboxptr) def test(aggimage): r = Tk.Tk() diff --git a/setupext.py b/setupext.py index 508f2b825d45..acef4ba2549f 100644 --- a/setupext.py +++ b/setupext.py @@ -1505,13 +1505,11 @@ def runtime_check(self): def get_extension(self): sources = [ - 'src/py_converters.cpp', 'src/_tkagg.cpp' ] ext = make_extension('matplotlib.backends._tkagg', sources) self.add_flags(ext) - Numpy().add_flags(ext) LibAgg().add_flags(ext, add_sources=False) return ext diff --git a/src/_tkagg.cpp b/src/_tkagg.cpp index 830831400d50..d92d8e7ffc9d 100644 --- a/src/_tkagg.cpp +++ b/src/_tkagg.cpp @@ -13,16 +13,17 @@ #include #include -#include "py_converters.h" +#include // agg:int8u // Include our own excerpts from the Tcl / Tk headers #include "_tkmini.h" #if defined(_MSC_VER) -# define SIZE_T_FORMAT "%Iu" +# define IMG_FORMAT "%Iu %d %d" #else -# define SIZE_T_FORMAT "%zu" +# define IMG_FORMAT "%zu %d %d" #endif +#define BBOX_FORMAT "%f %f %f %f" typedef struct { @@ -44,16 +45,15 @@ static int PyAggImagePhoto(ClientData clientdata, Tcl_Interp *interp, int { Tk_PhotoHandle photo; Tk_PhotoImageBlock block; - PyObject *bufferobj; // vars for blitting - PyObject *bboxo; - size_t aggl, bboxl; + size_t pdata; + int wdata, hdata, bbox_parse; + float x1, x2, y1, y2; bool has_bbox; - uint8_t *destbuffer; + agg::int8u *destbuffer, *buffer; int destx, desty, destwidth, destheight, deststride; - //unsigned long tmp_ptr; long mode; long nval; @@ -73,24 +73,14 @@ static int PyAggImagePhoto(ClientData clientdata, Tcl_Interp *interp, int TCL_APPEND_RESULT(interp, "destination photo must exist", (char *)NULL); return TCL_ERROR; } - /* get array (or object that can be converted to array) pointer */ - if (sscanf(argv[2], SIZE_T_FORMAT, &aggl) != 1) { - TCL_APPEND_RESULT(interp, "error casting pointer", (char *)NULL); + /* get buffer from str which is "ptr height width" */ + if (sscanf(argv[2], IMG_FORMAT, &pdata, &hdata, &wdata) != 3) { + TCL_APPEND_RESULT(interp, + "error reading data, expected ptr height width", + (char *)NULL); return TCL_ERROR; } - bufferobj = (PyObject *)aggl; - - numpy::array_view buffer; - try { - buffer = numpy::array_view(bufferobj); - } catch (...) { - TCL_APPEND_RESULT(interp, "buffer is of wrong type", (char *)NULL); - PyErr_Clear(); - return TCL_ERROR; - } - int srcheight = buffer.dim(0); - - /* XXX insert aggRenderer type check */ + buffer = (agg::int8u*)pdata; /* get array mode (0=mono, 1=rgb, 2=rgba) */ mode = atol(argv[3]); @@ -100,24 +90,23 @@ static int PyAggImagePhoto(ClientData clientdata, Tcl_Interp *interp, int } /* check for bbox/blitting */ - if (sscanf(argv[4], SIZE_T_FORMAT, &bboxl) != 1) { - TCL_APPEND_RESULT(interp, "error casting pointer", (char *)NULL); + bbox_parse = sscanf(argv[4], BBOX_FORMAT, &x1, &x2, &y1, &y2); + if (bbox_parse == 4) { + has_bbox = true; + } + else if ((bbox_parse == 1) && (x1 == 0)){ + has_bbox = false; + } else { + TCL_APPEND_RESULT(interp, "illegal bbox", (char *)NULL); return TCL_ERROR; } - bboxo = (PyObject *)bboxl; - - if (bboxo != NULL && bboxo != Py_None) { - agg::rect_d rect; - if (!convert_rect(bboxo, &rect)) { - return TCL_ERROR; - } - - has_bbox = true; - destx = (int)rect.x1; - desty = srcheight - (int)rect.y2; - destwidth = (int)(rect.x2 - rect.x1); - destheight = (int)(rect.y2 - rect.y1); + if (has_bbox) { + int srcstride = wdata * 4; + destx = (int)x1; + desty = (int)(hdata - y2); + destwidth = (int)(x2 - x1); + destheight = (int)(y2 - y1); deststride = 4 * destwidth; destbuffer = new agg::int8u[deststride * destheight]; @@ -128,11 +117,10 @@ static int PyAggImagePhoto(ClientData clientdata, Tcl_Interp *interp, int for (int i = 0; i < destheight; ++i) { memcpy(destbuffer + (deststride * i), - &buffer(i + desty, destx, 0), + &buffer[(i + desty) * srcstride + (destx * 4)], deststride); } } else { - has_bbox = false; destbuffer = NULL; destx = desty = destwidth = destheight = deststride = 0; } @@ -168,10 +156,10 @@ static int PyAggImagePhoto(ClientData clientdata, Tcl_Interp *interp, int delete[] destbuffer; } else { - block.width = buffer.dim(1); - block.height = buffer.dim(0); + block.width = wdata; + block.height = hdata; block.pitch = (int)block.width * nval; - block.pixelPtr = buffer.data(); + block.pixelPtr = buffer; /* Clear current contents */ TK_PHOTO_BLANK(photo); @@ -199,7 +187,7 @@ static PyObject *_tkinit(PyObject *self, PyObject *args) } else { /* Do it the hard way. This will break if the TkappObject layout changes */ - app = (TkappObject *)PyLong_AsVoidPtr(arg); + app = (TkappObject *)arg; interp = app->interp; } @@ -338,7 +326,7 @@ int load_tkinter_funcs(void) * tkinter uses these symbols, and the symbols are therefore visible in the * tkinter dynamic library (module). */ -#if PY3K +#if PY_MAJOR_VERSION >= 3 #define TKINTER_PKG "tkinter" #define TKINTER_MOD "_tkinter" // From module __file__ attribute to char *string for dlopen. @@ -432,13 +420,31 @@ int load_tkinter_funcs(void) } tkinter_lib = dlopen(tkinter_libname, RTLD_LAZY); if (tkinter_lib == NULL) { - PyErr_SetString(PyExc_RuntimeError, - "Cannot dlopen tkinter module file"); - goto exit; + /* Perhaps it is a cffi module, like in PyPy? */ + pString = PyObject_GetAttrString(pSubmodule, "tklib_cffi"); + if (pString == NULL) { + goto fail; + } + pString = PyObject_GetAttrString(pString, "__file__"); + if (pString == NULL) { + goto fail; + } + tkinter_libname = fname2char(pString); + if (tkinter_libname == NULL) { + goto fail; + } + tkinter_lib = dlopen(tkinter_libname, RTLD_LAZY); + } + if (tkinter_lib == NULL) { + goto fail; } ret = _func_loader(tkinter_lib); // dlclose probably safe because tkinter has been imported. dlclose(tkinter_lib); + goto exit; +fail: + PyErr_SetString(PyExc_RuntimeError, + "Cannot dlopen tkinter module file"); exit: Py_XDECREF(pModule); Py_XDECREF(pSubmodule); @@ -447,7 +453,7 @@ int load_tkinter_funcs(void) } #endif // end not Windows -#if PY3K +#if PY_MAJOR_VERSION >= 3 static PyModuleDef _tkagg_module = { PyModuleDef_HEAD_INIT, "_tkagg", "", -1, functions, NULL, NULL, NULL, NULL }; @@ -457,15 +463,11 @@ PyMODINIT_FUNC PyInit__tkagg(void) m = PyModule_Create(&_tkagg_module); - import_array(); - return (load_tkinter_funcs() == 0) ? m : NULL; } #else PyMODINIT_FUNC init_tkagg(void) { - import_array(); - Py_InitModule("_tkagg", functions); load_tkinter_funcs(); diff --git a/src/file_compat.h b/src/file_compat.h index a8f04eaeddca..42fdd162288c 100644 --- a/src/file_compat.h +++ b/src/file_compat.h @@ -48,7 +48,7 @@ extern "C" { /* * PyFile_* compatibility */ -#if PY3K +#if defined(PY3K) | defined(PYPY_VERSION) /* * Get a FILE* handle to the file represented by the Python object pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy