Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit dc93a74

Browse files
committed
Rewrite the tk C blitting code
... to use the standard Python C-API rather than the tk API. We do not need to support colormodes other than 2 (i.e. RGBA) (previously there was 0 = grayscale, 1 = RGB) so it was simpler to just deprecate the previous function and move everything to a new private one (matplotlib.backends._backend_tk.blit).
1 parent 21c4f9e commit dc93a74

File tree

5 files changed

+92
-19
lines changed

5 files changed

+92
-19
lines changed

lib/matplotlib/backends/_backend_tk.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
1-
from __future__ import (absolute_import, division, print_function,
2-
unicode_literals)
3-
41
import six
52
from six.moves import tkinter as Tk
63

4+
import math
75
import logging
86
import os.path
97
import sys
108

11-
# Paint image to Tk photo blitter extension
12-
import matplotlib.backends.tkagg as tkagg
9+
import numpy as np
1310

11+
from . import _tkagg
1412
from matplotlib.backends.backend_agg import FigureCanvasAgg
1513
import matplotlib.backends.windowing as windowing
1614

@@ -53,6 +51,25 @@ def error_msg_tkpaint(msg, parent=None):
5351
tkMessageBox.showerror("matplotlib", msg)
5452

5553

54+
def blit(photoimage, aggimage, bbox=None):
55+
"""
56+
Blit *aggimage* to *photoimage*.
57+
58+
If *bbox* is passed, it defines the region that gets blitted.
59+
"""
60+
data = np.asarray(aggimage)
61+
height, width = data.shape[:2]
62+
dataptr = (height, width, data.ctypes.data)
63+
if bbox is not None:
64+
(x1, y1), (x2, y2) = bbox.__array__()
65+
bboxptr = (math.floor(x1), math.ceil(x2),
66+
math.floor(y1), math.ceil(y2))
67+
else:
68+
photoimage.blank()
69+
bboxptr = (0, width, 0, height)
70+
_tkagg.blit(photoimage, dataptr, bboxptr)
71+
72+
5673
class TimerTk(TimerBase):
5774
'''
5875
Subclass of :class:`backend_bases.TimerBase` that uses Tk's timer events.

lib/matplotlib/backends/backend_tkagg.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from . import tkagg # Paint image to Tk photo blitter extension.
1+
from . import _backend_tk
22
from .backend_agg import FigureCanvasAgg
33
from ._backend_tk import (
44
_BackendTk, FigureCanvasTk, FigureManagerTk, NavigationToolbar2Tk)
@@ -7,12 +7,12 @@
77
class FigureCanvasTkAgg(FigureCanvasAgg, FigureCanvasTk):
88
def draw(self):
99
super(FigureCanvasTkAgg, self).draw()
10-
tkagg.blit(self._tkphoto, self.renderer._renderer, colormode=2)
10+
_backend_tk.blit(self._tkphoto, self.renderer._renderer)
1111
self._master.update_idletasks()
1212

1313
def blit(self, bbox=None):
14-
tkagg.blit(
15-
self._tkphoto, self.renderer._renderer, bbox=bbox, colormode=2)
14+
_backend_tk.blit(
15+
self._tkphoto, self.renderer._renderer, bbox=bbox)
1616
self._master.update_idletasks()
1717

1818

lib/matplotlib/backends/backend_tkcairo.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import numpy as np
44

5-
from . import tkagg # Paint image to Tk photo blitter extension.
5+
from . import _backend_tk
66
from .backend_cairo import cairo, FigureCanvasCairo, RendererCairo
77
from ._backend_tk import _BackendTk, FigureCanvasTk
88

@@ -22,11 +22,11 @@ def draw(self):
2222
buf = np.reshape(surface.get_data(), (height, width, 4))
2323
# Convert from ARGB32 to RGBA8888. Using .take() instead of directly
2424
# indexing ensures C-contiguity of the result, which is needed by
25-
# tkagg.
25+
# _backend_tk.
2626
buf = buf.take(
2727
[2, 1, 0, 3] if sys.byteorder == "little" else [1, 2, 3, 0],
2828
axis=2)
29-
tkagg.blit(self._tkphoto, buf, colormode=2)
29+
_backend_tk.blit(self._tkphoto, buf)
3030
self._master.update_idletasks()
3131

3232

lib/matplotlib/backends/tkagg.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1-
from __future__ import (absolute_import, division, print_function,
2-
unicode_literals)
3-
4-
import six
5-
from six.moves import tkinter as Tk
1+
import tkinter as Tk
62

73
import numpy as np
84

5+
from matplotlib import cbook
96
from matplotlib.backends import _tkagg
107

8+
9+
cbook.warn_deprecated(
10+
"3.0", "The matplotlib.backends.tkagg module is deprecated.")
11+
12+
1113
def blit(photoimage, aggimage, bbox=None, colormode=1):
1214
tk = photoimage.tk
1315

src/_tkagg.cpp

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,9 +203,62 @@ static PyObject *_tkinit(PyObject *self, PyObject *args)
203203
return Py_None;
204204
}
205205

206+
static PyObject *mpl_tk_blit(PyObject *self, PyObject *args) {
207+
PyObject *py_photo = NULL,
208+
*py_tk = NULL,
209+
*py_interpaddr = NULL,
210+
*py_photo_name = NULL;
211+
int height, width;
212+
unsigned char *data_ptr;
213+
int x1, x2, y1, y2;
214+
Tcl_Interp *interp;
215+
char const *photo_name;
216+
Tk_PhotoHandle photo;
217+
Tk_PhotoImageBlock block;
218+
if (!PyArg_ParseTuple(args, "O(iin)(iiii):blit",
219+
&py_photo,
220+
&height, &width, &data_ptr,
221+
&x1, &x2, &y1, &y2)) {
222+
goto exit;
223+
}
224+
if (!(py_tk = PyObject_GetAttrString(py_photo, "tk")) ||
225+
!(py_interpaddr = PyObject_CallMethod(py_tk, "interpaddr", NULL)) ||
226+
!(interp = (Tcl_Interp *)PyLong_AsVoidPtr(py_interpaddr))) {
227+
goto exit;
228+
}
229+
if (!(py_photo_name = PyObject_Str(py_photo)) ||
230+
!(photo_name = PyUnicode_AsUTF8(py_photo_name)) ||
231+
!(photo = TK_FIND_PHOTO(interp, photo_name))) {
232+
// TK_FIND_PHOTO (obviously) does not set an exception on failure.
233+
PyErr_SetString(PyExc_ValueError, "Failed to extract Tk_PhotoHandle");
234+
goto exit;
235+
}
236+
block.pixelPtr = data_ptr + 4 * ((height - y2) * width + x1);
237+
block.width = x2 - x1;
238+
block.height = y2 - y1;
239+
block.pitch = 4 * width;
240+
block.pixelSize = 4;
241+
block.offset[0] = 0;
242+
block.offset[1] = 1;
243+
block.offset[2] = 2;
244+
block.offset[3] = 3;
245+
TK_PHOTO_PUT_BLOCK_NO_COMPOSITE(
246+
photo, &block, x1, height - y2, x2 - x1, y2 - y1);
247+
exit:
248+
Py_XDECREF(py_tk);
249+
Py_XDECREF(py_interpaddr);
250+
Py_XDECREF(py_photo_name);
251+
if (PyErr_Occurred()) {
252+
return NULL;
253+
} else {
254+
Py_RETURN_NONE;
255+
}
256+
}
257+
206258
static PyMethodDef functions[] = {
207259
/* Tkinter interface stuff */
208260
{ "tkinit", (PyCFunction)_tkinit, 1 },
261+
{ "blit", (PyCFunction)mpl_tk_blit, 1 },
209262
{ NULL, NULL } /* sentinel */
210263
};
211264

@@ -444,8 +497,9 @@ int load_tkinter_funcs(void)
444497
}
445498
#endif // end not Windows
446499

447-
static PyModuleDef _tkagg_module = { PyModuleDef_HEAD_INIT, "_tkagg", "", -1, functions,
448-
NULL, NULL, NULL, NULL };
500+
static PyModuleDef _tkagg_module = {
501+
PyModuleDef_HEAD_INIT, "_tkagg", "", -1, functions, NULL, NULL, NULL, NULL
502+
};
449503

450504
PyMODINIT_FUNC PyInit__tkagg(void)
451505
{

0 commit comments

Comments
 (0)