diff options
author | shumkovnd <shumkovnd@yandex-team.com> | 2023-11-10 14:39:34 +0300 |
---|---|---|
committer | shumkovnd <shumkovnd@yandex-team.com> | 2023-11-10 16:42:24 +0300 |
commit | 77eb2d3fdcec5c978c64e025ced2764c57c00285 (patch) | |
tree | c51edb0748ca8d4a08d7c7323312c27ba1a8b79a /contrib/python/matplotlib/py2/src/_tkagg.cpp | |
parent | dd6d20cadb65582270ac23f4b3b14ae189704b9d (diff) | |
download | ydb-77eb2d3fdcec5c978c64e025ced2764c57c00285.tar.gz |
KIKIMR-19287: add task_stats_drawing script
Diffstat (limited to 'contrib/python/matplotlib/py2/src/_tkagg.cpp')
-rw-r--r-- | contrib/python/matplotlib/py2/src/_tkagg.cpp | 475 |
1 files changed, 475 insertions, 0 deletions
diff --git a/contrib/python/matplotlib/py2/src/_tkagg.cpp b/contrib/python/matplotlib/py2/src/_tkagg.cpp new file mode 100644 index 0000000000..ad5289b3d6 --- /dev/null +++ b/contrib/python/matplotlib/py2/src/_tkagg.cpp @@ -0,0 +1,475 @@ +/* -*- mode: c++; c-basic-offset: 4 -*- */ + +/* + * This code is derived from The Python Imaging Library and is covered + * by the PIL license. + * + * See LICENSE/LICENSE.PIL for details. + * + */ + +#include <Python.h> +#include <cstdlib> +#include <cstdio> +#include <sstream> + +#include <agg_basics.h> // agg:int8u + +// Include our own excerpts from the Tcl / Tk headers +#include "_tkmini.h" + +#if defined(_MSC_VER) +# define IMG_FORMAT "%d %d %Iu" +#else +# define IMG_FORMAT "%d %d %zu" +#endif +#define BBOX_FORMAT "%f %f %f %f" + +typedef struct +{ + PyObject_HEAD + Tcl_Interp *interp; +} TkappObject; + +// Global vars for Tcl / Tk functions. We load these symbols from the tkinter +// extension module or loaded Tcl / Tk libraries at run-time. +static Tcl_CreateCommand_t TCL_CREATE_COMMAND; +static Tcl_AppendResult_t TCL_APPEND_RESULT; +static Tk_MainWindow_t TK_MAIN_WINDOW; +static Tk_FindPhoto_t TK_FIND_PHOTO; +static Tk_PhotoPutBlock_NoComposite_t TK_PHOTO_PUT_BLOCK_NO_COMPOSITE; +static Tk_PhotoBlank_t TK_PHOTO_BLANK; + +static int PyAggImagePhoto(ClientData clientdata, Tcl_Interp *interp, int + argc, char **argv) +{ + Tk_PhotoHandle photo; + Tk_PhotoImageBlock block; + + // vars for blitting + + size_t pdata; + int wdata, hdata, bbox_parse; + float x1, x2, y1, y2; + bool has_bbox; + agg::int8u *destbuffer, *buffer; + int destx, desty, destwidth, destheight, deststride; + + long mode; + long nval; + if (TK_MAIN_WINDOW(interp) == NULL) { + // Will throw a _tkinter.TclError with "this isn't a Tk application" + return TCL_ERROR; + } + + if (argc != 5) { + TCL_APPEND_RESULT(interp, "usage: ", argv[0], " destPhoto srcImage", (char *)NULL); + return TCL_ERROR; + } + + /* get Tcl PhotoImage handle */ + photo = TK_FIND_PHOTO(interp, argv[1]); + if (photo == NULL) { + TCL_APPEND_RESULT(interp, "destination photo must exist", (char *)NULL); + return TCL_ERROR; + } + /* get buffer from str which is "height width ptr" */ + if (sscanf(argv[2], IMG_FORMAT, &hdata, &wdata, &pdata) != 3) { + TCL_APPEND_RESULT(interp, + "error reading data, expected height width ptr", + (char *)NULL); + return TCL_ERROR; + } + buffer = (agg::int8u*)pdata; + + /* get array mode (0=mono, 1=rgb, 2=rgba) */ + mode = atol(argv[3]); + if ((mode != 0) && (mode != 1) && (mode != 2)) { + TCL_APPEND_RESULT(interp, "illegal image mode", (char *)NULL); + return TCL_ERROR; + } + + /* check for bbox/blitting */ + 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; + } + + 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]; + if (destbuffer == NULL) { + TCL_APPEND_RESULT(interp, "could not allocate memory", (char *)NULL); + return TCL_ERROR; + } + + for (int i = 0; i < destheight; ++i) { + memcpy(destbuffer + (deststride * i), + &buffer[(i + desty) * srcstride + (destx * 4)], + deststride); + } + } else { + destbuffer = NULL; + destx = desty = destwidth = destheight = deststride = 0; + } + + /* setup tkblock */ + block.pixelSize = 1; + if (mode == 0) { + block.offset[0] = block.offset[1] = block.offset[2] = 0; + nval = 1; + } else { + block.offset[0] = 0; + block.offset[1] = 1; + block.offset[2] = 2; + if (mode == 1) { + block.offset[3] = 0; + block.pixelSize = 3; + nval = 3; + } else { + block.offset[3] = 3; + block.pixelSize = 4; + nval = 4; + } + } + + if (has_bbox) { + block.width = destwidth; + block.height = destheight; + block.pitch = deststride; + block.pixelPtr = destbuffer; + + TK_PHOTO_PUT_BLOCK_NO_COMPOSITE(photo, &block, destx, desty, + destwidth, destheight); + delete[] destbuffer; + + } else { + block.width = wdata; + block.height = hdata; + block.pitch = (int)block.width * nval; + block.pixelPtr = buffer; + + /* Clear current contents */ + TK_PHOTO_BLANK(photo); + /* Copy opaque block to photo image, and leave the rest to TK */ + TK_PHOTO_PUT_BLOCK_NO_COMPOSITE(photo, &block, 0, 0, block.width, + block.height); + } + + return TCL_OK; +} + +static PyObject *_tkinit(PyObject *self, PyObject *args) +{ + Tcl_Interp *interp; + TkappObject *app; + + PyObject *arg; + int is_interp; + if (!PyArg_ParseTuple(args, "Oi", &arg, &is_interp)) { + return NULL; + } + + if (is_interp) { + interp = (Tcl_Interp *)PyLong_AsVoidPtr(arg); + } else { + /* Do it the hard way. This will break if the TkappObject + layout changes */ + app = (TkappObject *)arg; + interp = app->interp; + } + + /* This will bomb if interp is invalid... */ + + TCL_CREATE_COMMAND(interp, + "PyAggImagePhoto", + (Tcl_CmdProc *)PyAggImagePhoto, + (ClientData)0, + (Tcl_CmdDeleteProc *)NULL); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef functions[] = { + /* Tkinter interface stuff */ + { "tkinit", (PyCFunction)_tkinit, 1 }, + { NULL, NULL } /* sentinel */ +}; + +// Functions to fill global TCL / Tk function pointers by dynamic loading +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) + +/* + * On Windows, we can't load the tkinter module to get the TCL or Tk symbols, + * because Windows does not load symbols into the library name-space of + * importing modules. So, knowing that tkinter has already been imported by + * Python, we scan all modules in the running process for the TCL and Tk + * function names. + */ +#include <windows.h> +#define PSAPI_VERSION 1 +#include <psapi.h> +// Must be linked with 'psapi' library + +FARPROC _dfunc(HMODULE lib_handle, const char *func_name) +{ + // Load function `func_name` from `lib_handle`. + // Set Python exception if we can't find `func_name` in `lib_handle`. + // Returns function pointer or NULL if not present. + + char message[100]; + + FARPROC func = GetProcAddress(lib_handle, func_name); + if (func == NULL) { + sprintf(message, "Cannot load function %s", func_name); + PyErr_SetString(PyExc_RuntimeError, message); + } + return func; +} + +int get_tcl(HMODULE hMod) +{ + // Try to fill TCL global vars with function pointers. Return 0 for no + // functions found, 1 for all functions found, -1 for some but not all + // functions found. + TCL_CREATE_COMMAND = (Tcl_CreateCommand_t) + GetProcAddress(hMod, "Tcl_CreateCommand"); + if (TCL_CREATE_COMMAND == NULL) { // Maybe not TCL module + return 0; + } + TCL_APPEND_RESULT = (Tcl_AppendResult_t) _dfunc(hMod, + "Tcl_AppendResult"); + return (TCL_APPEND_RESULT == NULL) ? -1 : 1; +} + +int get_tk(HMODULE hMod) +{ + // Try to fill Tk global vars with function pointers. Return 0 for no + // functions found, 1 for all functions found, -1 for some but not all + // functions found. + TK_MAIN_WINDOW = (Tk_MainWindow_t) + GetProcAddress(hMod, "Tk_MainWindow"); + if (TK_MAIN_WINDOW == NULL) { // Maybe not Tk module + return 0; + } + return ( // -1 if any remaining symbols are NULL + ((TK_FIND_PHOTO = (Tk_FindPhoto_t) + _dfunc(hMod, "Tk_FindPhoto")) == NULL) || + ((TK_PHOTO_PUT_BLOCK_NO_COMPOSITE = (Tk_PhotoPutBlock_NoComposite_t) + _dfunc(hMod, "Tk_PhotoPutBlock_NoComposite")) == NULL) || + ((TK_PHOTO_BLANK = (Tk_PhotoBlank_t) + _dfunc(hMod, "Tk_PhotoBlank")) == NULL)) + ? -1 : 1; +} + +int load_tkinter_funcs(void) +{ + // Load TCL and Tk functions by searching all modules in current process. + // Return 0 for success, non-zero for failure. + + HMODULE hMods[1024]; + HANDLE hProcess; + DWORD cbNeeded; + unsigned int i; + int found_tcl = 0; + int found_tk = 0; + + // Returns pseudo-handle that does not need to be closed + hProcess = GetCurrentProcess(); + + // Iterate through modules in this process looking for TCL / Tk names + if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) { + for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) { + if (!found_tcl) { + found_tcl = get_tcl(hMods[i]); + if (found_tcl == -1) { + return 1; + } + } + if (!found_tk) { + found_tk = get_tk(hMods[i]); + if (found_tk == -1) { + return 1; + } + } + if (found_tcl && found_tk) { + return 0; + } + } + } + + if (found_tcl == 0) { + PyErr_SetString(PyExc_RuntimeError, "Could not find TCL routines"); + } else { + PyErr_SetString(PyExc_RuntimeError, "Could not find Tk routines"); + } + return 1; +} + +#else // not Windows + +/* + * On Unix, we can get the TCL and Tk synbols from the tkinter module, because + * tkinter uses these symbols, and the symbols are therefore visible in the + * tkinter dynamic library (module). + */ +#if PY_MAJOR_VERSION >= 3 +#define TKINTER_PKG "tkinter" +#define TKINTER_MOD "_tkinter" +// From module __file__ attribute to char *string for dlopen. +char *fname2char(PyObject *fname) +{ + PyObject* bytes; + bytes = PyUnicode_EncodeFSDefault(fname); + if (bytes == NULL) { + return NULL; + } + return PyBytes_AsString(bytes); +} +#else +#define TKINTER_PKG "Tkinter" +#define TKINTER_MOD "tkinter" +// From module __file__ attribute to char *string for dlopen +#define fname2char(s) (PyString_AsString(s)) +#endif + +#include <dlfcn.h> + +void *_dfunc(void *lib_handle, const char *func_name) +{ + // Load function `func_name` from `lib_handle`. + // Set Python exception if we can't find `func_name` in `lib_handle`. + // Returns function pointer or NULL if not present. + + void* func; + // Reset errors. + dlerror(); + func = dlsym(lib_handle, func_name); + if (func == NULL) { + const char *error = dlerror(); + PyErr_SetString(PyExc_RuntimeError, error); + } + return func; +} + +int _func_loader(void *lib) +{ + // Fill global function pointers from dynamic lib. + // Return 1 if any pointer is NULL, 0 otherwise. + return ( + ((TCL_CREATE_COMMAND = (Tcl_CreateCommand_t) + _dfunc(lib, "Tcl_CreateCommand")) == NULL) || + ((TCL_APPEND_RESULT = (Tcl_AppendResult_t) + _dfunc(lib, "Tcl_AppendResult")) == NULL) || + ((TK_MAIN_WINDOW = (Tk_MainWindow_t) + _dfunc(lib, "Tk_MainWindow")) == NULL) || + ((TK_FIND_PHOTO = (Tk_FindPhoto_t) + _dfunc(lib, "Tk_FindPhoto")) == NULL) || + ((TK_PHOTO_PUT_BLOCK_NO_COMPOSITE = (Tk_PhotoPutBlock_NoComposite_t) + _dfunc(lib, "Tk_PhotoPutBlock_NoComposite")) == NULL) || + ((TK_PHOTO_BLANK = (Tk_PhotoBlank_t) + _dfunc(lib, "Tk_PhotoBlank")) == NULL)); +} + +int load_tkinter_funcs(void) +{ + // Load tkinter global funcs from tkinter compiled module. + // Return 0 for success, non-zero for failure. + int ret = -1; + void *main_program, *tkinter_lib; + char *tkinter_libname; + PyObject *pModule = NULL, *pSubmodule = NULL, *pString = NULL; + + // Try loading from the main program namespace first + main_program = dlopen(NULL, RTLD_LAZY); + if (_func_loader(main_program) == 0) { + return 0; + } + // Clear exception triggered when we didn't find symbols above. + PyErr_Clear(); + + // Now try finding the tkinter compiled module + pModule = PyImport_ImportModule(TKINTER_PKG); + if (pModule == NULL) { + goto exit; + } + pSubmodule = PyObject_GetAttrString(pModule, TKINTER_MOD); + if (pSubmodule == NULL) { + goto exit; + } + pString = PyObject_GetAttrString(pSubmodule, "__file__"); + if (pString == NULL) { + goto exit; + } + tkinter_libname = fname2char(pString); + if (tkinter_libname == NULL) { + goto exit; + } + tkinter_lib = dlopen(tkinter_libname, RTLD_LAZY); + if (tkinter_lib == NULL) { + /* 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); + Py_XDECREF(pString); + return ret; +} +#endif // end not Windows + +#if PY_MAJOR_VERSION >= 3 +static PyModuleDef _tkagg_module = { PyModuleDef_HEAD_INIT, "_tkagg", "", -1, functions, + NULL, NULL, NULL, NULL }; + +PyMODINIT_FUNC PyInit__tkagg(void) +{ + PyObject *m; + + m = PyModule_Create(&_tkagg_module); + + return (load_tkinter_funcs() == 0) ? m : NULL; +} +#else +PyMODINIT_FUNC init_tkagg(void) +{ + Py_InitModule("_tkagg", functions); + + load_tkinter_funcs(); +} +#endif |