diff --git a/PIL/_tkinter_finder.py b/PIL/_tkinter_finder.py new file mode 100644 index 000000000..df4159193 --- /dev/null +++ b/PIL/_tkinter_finder.py @@ -0,0 +1,20 @@ +""" Find compiled module linking to Tcl / Tk libraries +""" +import sys + +if sys.version_info[0] > 2: + from tkinter import _tkinter as tk +else: + from Tkinter import tkinter as tk + +if hasattr(sys, 'pypy_find_executable'): + # Tested with packages at https://bitbucket.org/pypy/pypy/downloads. + # PyPies 1.6, 2.0 do not have tkinter built in. PyPy3-2.3.1 gives an + # OSError trying to import tkinter. Otherwise: + try: # PyPy 5.1, 4.0.0, 2.6.1, 2.6.0 + TKINTER_LIB = tk.tklib_cffi.__file__ + except AttributeError: + # PyPy3 2.4, 2.1-beta1; PyPy 2.5.1, 2.5.0, 2.4.0, 2.3, 2.2, 2.1 + TKINTER_LIB = tk.tkffi.verifier.modulefilename +else: + TKINTER_LIB = tk.__file__ diff --git a/Tk/_tkmini.h b/Tk/_tkmini.h new file mode 100644 index 000000000..348425e41 --- /dev/null +++ b/Tk/_tkmini.h @@ -0,0 +1,146 @@ +/* Small excerpts from the Tcl / Tk 8.6 headers + * + * License terms copied from: + * http://www.tcl.tk/software/tcltk/license.html + * as of 20 May 2016. + * + * Copyright (c) 1987-1994 The Regents of the University of California. + * Copyright (c) 1993-1996 Lucent Technologies. + * Copyright (c) 1994-1998 Sun Microsystems, Inc. + * Copyright (c) 1998-2000 by Scriptics Corporation. + * Copyright (c) 2002 by Kevin B. Kenny. All rights reserved. + * + * This software is copyrighted by the Regents of the University + * of California, Sun Microsystems, Inc., Scriptics Corporation, + * and other parties. The following terms apply to all files + * associated with the software unless explicitly disclaimed in + * individual files. + * + * The authors hereby grant permission to use, copy, modify, + * distribute, and license this software and its documentation + * for any purpose, provided that existing copyright notices are + * retained in all copies and that this notice is included + * verbatim in any distributions. No written agreement, license, + * or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their + * authors and need not follow the licensing terms described + * here, provided that the new terms are clearly indicated on + * the first page of each file where they apply. + * + * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO + * ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS + * SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN + * IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON + * AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO + * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, + * ENHANCEMENTS, OR MODIFICATIONS. + * + * GOVERNMENT USE: If you are acquiring this software on behalf + * of the U.S. government, the Government shall have only + * "Restricted Rights" in the software and related documentation + * as defined in the Federal Acquisition Regulations (FARs) in + * Clause 52.227.19 (c) (2). If you are acquiring the software + * on behalf of the Department of Defense, the software shall be + * classified as "Commercial Computer Software" and the + * Government shall have only "Restricted Rights" as defined in + * Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the + * foregoing, the authors grant the U.S. Government and others + * acting in its behalf permission to use and distribute the + * software in accordance with the terms specified in this + * license + */ + +/* + * Unless otherwise noted, these definitions are stable from Tcl / Tk 8.4 + * through Tck / Tk master as of 21 May 2016 + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Tcl header excerpts */ +#define TCL_OK 0 +#define TCL_ERROR 1 + +/* + * Users of versions of Tcl >= 8.6 encouraged to treat Tcl_Interp as an opaque + * pointer. The following definition results when TCL_NO_DEPRECATED defined. + */ +typedef struct Tcl_Interp Tcl_Interp; + +typedef struct Tcl_Command_ *Tcl_Command; +typedef void *ClientData; + +typedef int (Tcl_CmdProc) (ClientData clientData, Tcl_Interp + *interp, int argc, const char *argv[]); +typedef void (Tcl_CmdDeleteProc) (ClientData clientData); + +/* Typedefs derived from function signatures in Tcl header */ +/* Tcl_CreateCommand */ +typedef Tcl_Command (*Tcl_CreateCommand_t)(Tcl_Interp *interp, + const char *cmdName, Tcl_CmdProc *proc, + ClientData clientData, + Tcl_CmdDeleteProc *deleteProc); +/* Tcl_AppendResult */ +typedef void (*Tcl_AppendResult_t) (Tcl_Interp *interp, ...); + +/* Tk header excerpts */ + +/* + * The following values control how blocks are combined into photo + * images when the alpha component of a pixel is not 255, a.k.a. the + * compositing rule. + */ + +#define TK_PHOTO_COMPOSITE_OVERLAY 0 +#define TK_PHOTO_COMPOSITE_SET 1 + +typedef struct Tk_Window_ *Tk_Window; + +typedef void *Tk_PhotoHandle; + +typedef struct Tk_PhotoImageBlock +{ + unsigned char *pixelPtr; + int width; + int height; + int pitch; + int pixelSize; + int offset[4]; +} Tk_PhotoImageBlock; + +/* Typedefs derived from function signatures in Tk header */ +/* Tk_PhotoPutBlock for Tk <= 8.4 */ +typedef void (*Tk_PhotoPutBlock_84_t) (Tk_PhotoHandle handle, + Tk_PhotoImageBlock *blockPtr, int x, int y, + int width, int height, int compRule); +/* Tk_PhotoPutBlock for Tk >= 8.5 */ +typedef int (*Tk_PhotoPutBlock_85_t) (Tcl_Interp * interp, + Tk_PhotoHandle handle, + Tk_PhotoImageBlock * blockPtr, int x, int y, + int width, int height, int compRule); +/* Tk_PhotoSetSize for Tk <= 8.4 */ +typedef void (*Tk_PhotoSetSize_84_t) (Tk_PhotoHandle handle, + int width, int height); +/* Tk_FindPhoto */ +typedef Tk_PhotoHandle (*Tk_FindPhoto_t) (Tcl_Interp *interp, + const char *imageName); +/* Tk_PhotoGetImage */ +typedef int (*Tk_PhotoGetImage_t) (Tk_PhotoHandle handle, + Tk_PhotoImageBlock * blockPtr); + +/* + * end block for C++ + */ + +#ifdef __cplusplus +} +#endif diff --git a/Tk/tkImaging.c b/Tk/tkImaging.c index f82fc2007..9e9365d66 100644 --- a/Tk/tkImaging.c +++ b/Tk/tkImaging.c @@ -42,17 +42,23 @@ * See the README file for information on usage and redistribution. */ -#define TK (TK_MAJOR_VERSION*10 + TK_MINOR_VERSION) - -/* This is needed for (at least) Tk 8.4.6 and later, to avoid warnings - for the Tcl_CreateCommand command. */ -#define USE_COMPAT_CONST - #include "Imaging.h" -#include "tk.h" +#include "_tkmini.h" #include +/* + * Global vars for Tcl / Tk functions. We load these symbols from the tkinter + * extension module or loaded Tcl / Tk libraries at run-time. + */ +static int TK_LT_85 = 0; +static Tcl_CreateCommand_t TCL_CREATE_COMMAND; +static Tcl_AppendResult_t TCL_APPEND_RESULT; +static Tk_FindPhoto_t TK_FIND_PHOTO; +static Tk_PhotoGetImage_t TK_PHOTO_GET_IMAGE; +static Tk_PhotoPutBlock_84_t TK_PHOTO_PUT_BLOCK_84; +static Tk_PhotoSetSize_84_t TK_PHOTO_SET_SIZE_84; +static Tk_PhotoPutBlock_85_t TK_PHOTO_PUT_BLOCK_85; static Imaging ImagingFind(const char* name) @@ -81,15 +87,15 @@ PyImagingPhotoPut(ClientData clientdata, Tcl_Interp* interp, Tk_PhotoImageBlock block; if (argc != 3) { - Tcl_AppendResult(interp, "usage: ", argv[0], + TCL_APPEND_RESULT(interp, "usage: ", argv[0], " destPhoto srcImage", (char *) NULL); return TCL_ERROR; } /* get Tcl PhotoImage handle */ - photo = Tk_FindPhoto(interp, argv[1]); + photo = TK_FIND_PHOTO(interp, argv[1]); if (photo == NULL) { - Tcl_AppendResult( + TCL_APPEND_RESULT( interp, "destination photo must exist", (char *) NULL ); return TCL_ERROR; @@ -98,12 +104,12 @@ PyImagingPhotoPut(ClientData clientdata, Tcl_Interp* interp, /* get PIL Image handle */ im = ImagingFind(argv[2]); if (!im) { - Tcl_AppendResult(interp, "bad name", (char*) NULL); - return TCL_ERROR; + TCL_APPEND_RESULT(interp, "bad name", (char*) NULL); + return TCL_ERROR; } if (!im->block) { - Tcl_AppendResult(interp, "bad display memory", (char*) NULL); - return TCL_ERROR; + TCL_APPEND_RESULT(interp, "bad display memory", (char*) NULL); + return TCL_ERROR; } /* Active region */ @@ -133,7 +139,7 @@ PyImagingPhotoPut(ClientData clientdata, Tcl_Interp* interp, else block.offset[3] = 0; /* no alpha */ } else { - Tcl_AppendResult(interp, "Bad mode", (char*) NULL); + TCL_APPEND_RESULT(interp, "Bad mode", (char*) NULL); return TCL_ERROR; } @@ -147,17 +153,18 @@ PyImagingPhotoPut(ClientData clientdata, Tcl_Interp* interp, src_xoffset * im->pixelsize; #endif -#if TK < 85 /* Tk 8.4 */ - Tk_PhotoPutBlock(photo, &block, 0, 0, block.width, block.height, - TK_PHOTO_COMPOSITE_SET); - if (strcmp(im->mode, "RGBA") == 0) - /* Tk workaround: we need apply ToggleComplexAlphaIfNeeded */ - /* (fixed in Tk 8.5a3) */ - Tk_PhotoSetSize(photo, block.width, block.height); -#else /* Tk 8.5 */ - Tk_PhotoPutBlock(interp, photo, &block, 0, 0, block.width, block.height, - TK_PHOTO_COMPOSITE_SET); -#endif + if (TK_LT_85) { /* Tk 8.4 */ + TK_PHOTO_PUT_BLOCK_84(photo, &block, 0, 0, block.width, block.height, + TK_PHOTO_COMPOSITE_SET); + if (strcmp(im->mode, "RGBA") == 0) + /* Tk workaround: we need apply ToggleComplexAlphaIfNeeded */ + /* (fixed in Tk 8.5a3) */ + TK_PHOTO_SET_SIZE_84(photo, block.width, block.height); + } else { + /* Tk >=8.5 */ + TK_PHOTO_PUT_BLOCK_85(interp, photo, &block, 0, 0, block.width, + block.height, TK_PHOTO_COMPOSITE_SET); + } return TCL_OK; } @@ -171,21 +178,21 @@ PyImagingPhotoGet(ClientData clientdata, Tcl_Interp* interp, Tk_PhotoImageBlock block; if (argc != 2) { - Tcl_AppendResult(interp, "usage: ", argv[0], + TCL_APPEND_RESULT(interp, "usage: ", argv[0], " srcPhoto", (char *) NULL); return TCL_ERROR; } /* get Tcl PhotoImage handle */ - photo = Tk_FindPhoto(interp, argv[1]); + photo = TK_FIND_PHOTO(interp, argv[1]); if (photo == NULL) { - Tcl_AppendResult( + TCL_APPEND_RESULT( interp, "source photo must exist", (char *) NULL ); return TCL_ERROR; } - Tk_PhotoGetImage(photo, &block); + TK_PHOTO_GET_IMAGE(photo, &block); printf("pixelPtr = %p\n", block.pixelPtr); printf("width = %d\n", block.width); @@ -195,7 +202,7 @@ PyImagingPhotoGet(ClientData clientdata, Tcl_Interp* interp, printf("offset = %d %d %d %d\n", block.offset[0], block.offset[1], block.offset[2], block.offset[3]); - Tcl_AppendResult( + TCL_APPEND_RESULT( interp, "this function is not yet supported", (char *) NULL ); @@ -206,8 +213,257 @@ PyImagingPhotoGet(ClientData clientdata, Tcl_Interp* interp, void TkImaging_Init(Tcl_Interp* interp) { - Tcl_CreateCommand(interp, "PyImagingPhoto", PyImagingPhotoPut, + TCL_CREATE_COMMAND(interp, "PyImagingPhoto", PyImagingPhotoPut, (ClientData) 0, (Tcl_CmdDeleteProc*) NULL); - Tcl_CreateCommand(interp, "PyImagingPhotoGet", PyImagingPhotoGet, + TCL_CREATE_COMMAND(interp, "PyImagingPhotoGet", PyImagingPhotoGet, (ClientData) 0, (Tcl_CmdDeleteProc*) NULL); } + +/* + * Functions to fill global Tcl / Tk function pointers by dynamic loading + */ + +#define TKINTER_FINDER "PIL._tkinter_finder" + +#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 +#define PSAPI_VERSION 1 +#include +/* Must be linked with 'psapi' library */ + +#if PY_VERSION_HEX >= 0x03000000 +#define TKINTER_PKG "tkinter" +#else +#define TKINTER_PKG "Tkinter" +#endif + +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. + */ + + if ((TCL_CREATE_COMMAND = (Tcl_CreateCommand_t) + GetProcAddress(hMod, "Tcl_CreateCommand")) == NULL) { + return 0; /* Maybe not Tcl module */ + } + return ((TCL_APPEND_RESULT = (Tcl_AppendResult_t) _dfunc(hMod, + "Tcl_AppendResult")) == 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. + */ + + FARPROC func = GetProcAddress(hMod, "Tk_PhotoPutBlock"); + if (func == NULL) { /* Maybe not Tk module */ + return 0; + } + if ((TK_PHOTO_GET_IMAGE = (Tk_PhotoGetImage_t) + _dfunc(hMod, "Tk_PhotoGetImage")) == NULL) { return -1; }; + if ((TK_FIND_PHOTO = (Tk_FindPhoto_t) + _dfunc(hMod, "Tk_FindPhoto")) == NULL) { return -1; }; + TK_LT_85 = GetProcAddress(hMod, "Tk_PhotoPutBlock_Panic") == NULL; + /* Tk_PhotoPutBlock_Panic defined as of 8.5.0 */ + if (TK_LT_85) { + TK_PHOTO_PUT_BLOCK_84 = (Tk_PhotoPutBlock_84_t) func; + return ((TK_PHOTO_SET_SIZE_84 = (Tk_PhotoSetSize_84_t) + _dfunc(hMod, "Tk_PhotoSetSize")) == NULL) ? -1 : 1; + } + TK_PHOTO_PUT_BLOCK_85 = (Tk_PhotoPutBlock_85_t) func; + return 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; + + /* First load tkinter module to make sure libraries are loaded */ + PyObject *pModule = PyImport_ImportModule(TKINTER_PKG); + if (pModule == NULL) { + return 1; + } + Py_DECREF(pModule); + + /* 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). + */ + +/* From module __file__ attribute to char *string for dlopen. */ +#if PY_VERSION_HEX >= 0x03000000 +char *fname2char(PyObject *fname) +{ + PyObject *bytes = PyUnicode_EncodeFSDefault(fname); + if (bytes == NULL) { + return NULL; + } + return PyBytes_AsString(bytes); +} +#else +#define fname2char(s) (PyString_AsString(s)) +#endif + +#include + +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. + */ + + /* Reset errors. */ + dlerror(); + void *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. + */ + + if ((TCL_CREATE_COMMAND = (Tcl_CreateCommand_t) + _dfunc(lib, "Tcl_CreateCommand")) == NULL) { return 1; } + if ((TCL_APPEND_RESULT = (Tcl_AppendResult_t) _dfunc(lib, + "Tcl_AppendResult")) == NULL) { return 1; } + if ((TK_PHOTO_GET_IMAGE = (Tk_PhotoGetImage_t) + _dfunc(lib, "Tk_PhotoGetImage")) == NULL) { return 1; } + if ((TK_FIND_PHOTO = (Tk_FindPhoto_t) + _dfunc(lib, "Tk_FindPhoto")) == NULL) { return 1; } + /* Tk_PhotoPutBlock_Panic defined as of 8.5.0 */ + TK_LT_85 = (dlsym(lib, "Tk_PhotoPutBlock_Panic") == NULL); + if (TK_LT_85) { + return (((TK_PHOTO_PUT_BLOCK_84 = (Tk_PhotoPutBlock_84_t) + _dfunc(lib, "Tk_PhotoPutBlock")) == NULL) || + ((TK_PHOTO_SET_SIZE_84 = (Tk_PhotoSetSize_84_t) + _dfunc(lib, "Tk_PhotoSetSize")) == NULL)); + } + return ((TK_PHOTO_PUT_BLOCK_85 = (Tk_PhotoPutBlock_85_t) + _dfunc(lib, "Tk_PhotoPutBlock")) == 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 *tkinter_lib; + char *tkinter_libname; + PyObject *pModule = NULL, *pString = NULL; + + pModule = PyImport_ImportModule(TKINTER_FINDER); + if (pModule == NULL) { + goto exit; + } + pString = PyObject_GetAttrString(pModule, "TKINTER_LIB"); + 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) { + PyErr_SetString(PyExc_RuntimeError, + "Cannot dlopen tkinter module file"); + goto exit; + } + ret = _func_loader(tkinter_lib); + /* dlclose probably safe because tkinter has been imported. */ + dlclose(tkinter_lib); +exit: + Py_XDECREF(pModule); + Py_XDECREF(pString); + return ret; +} +#endif /* end not Windows */ diff --git a/_imagingtk.c b/_imagingtk.c index c379f7dc5..87de36a04 100644 --- a/_imagingtk.c +++ b/_imagingtk.c @@ -16,10 +16,11 @@ #include "Python.h" #include "Imaging.h" -#include "tk.h" +#include "_tkmini.h" /* must link with Tk/tkImaging.c */ extern void TkImaging_Init(Tcl_Interp* interp); +extern int load_tkinter_funcs(void); /* copied from _tkinter.c (this isn't as bad as it may seem: for new versions, we use _tkinter's interpaddr hook instead, and all older @@ -73,14 +74,16 @@ PyInit__imagingtk(void) { -1, /* m_size */ functions, /* m_methods */ }; - - return PyModule_Create(&module_def); + PyObject *m; + m = PyModule_Create(&module_def); + return (load_tkinter_funcs() == 0) ? m : NULL; } #else PyMODINIT_FUNC init_imagingtk(void) { Py_InitModule("_imagingtk", functions); + load_tkinter_funcs(); } #endif diff --git a/setup.py b/setup.py index 511422e7b..cf420debc 100644 --- a/setup.py +++ b/setup.py @@ -111,7 +111,6 @@ except (ImportError, OSError): NAME = 'Pillow' PILLOW_VERSION = '3.3.0.dev0' -TCL_ROOT = None JPEG_ROOT = None JPEG2K_ROOT = None ZLIB_ROOT = None @@ -123,8 +122,8 @@ LCMS_ROOT = None class pil_build_ext(build_ext): class feature: - features = ['zlib', 'jpeg', 'tiff', 'freetype', 'tcl', 'tk', 'lcms', - 'webp', 'webpmux', 'jpeg2000', 'imagequant'] + features = ['zlib', 'jpeg', 'tiff', 'freetype', 'lcms', 'webp', + 'webpmux', 'jpeg2000', 'imagequant'] required = set(['jpeg', 'zlib']) @@ -150,14 +149,11 @@ class pil_build_ext(build_ext): ('enable-%s' % x, None, 'Enable support for %s' % x) for x in feature ] + [ ('disable-platform-guessing', None, 'Disable platform guessing on Linux'), - ('disable-osx-tcltk-framework', None, - 'Disable linking against system tcl/tk frameworks on OSX'), ('debug', None, 'Debug logging') ] def initialize_options(self): self.disable_platform_guessing = None - self.disable_osx_tcltk_framework = None build_ext.initialize_options(self) for x in self.feature: setattr(self, 'disable_%s' % x, None) @@ -183,8 +179,6 @@ class pil_build_ext(build_ext): def build_extensions(self): - global TCL_ROOT - library_dirs = [] include_dirs = [] @@ -193,7 +187,7 @@ class pil_build_ext(build_ext): # # add configured kits - for root in (TCL_ROOT, JPEG_ROOT, JPEG2K_ROOT, TIFF_ROOT, ZLIB_ROOT, + for root in (JPEG_ROOT, JPEG2K_ROOT, TIFF_ROOT, ZLIB_ROOT, FREETYPE_ROOT, LCMS_ROOT, IMAGEQUANT_ROOT): if isinstance(root, type(())): lib_root, include_root = root @@ -351,53 +345,6 @@ class pil_build_ext(build_ext): # FIXME: check /opt/stuff directories here? - # locate tkinter libraries - - if _tkinter: - TCL_VERSION = _tkinter.TCL_VERSION[:3] - _dbg('Tkinter found, will check for Tcl/Tk') - else: - _dbg('Tkinter not found') - - if _tkinter and not TCL_ROOT: - # we have Tkinter but the TCL_ROOT variable was not set; - # try to locate appropriate Tcl/Tk libraries - PYVERSION = sys.version[0] + sys.version[2] - TCLVERSION = TCL_VERSION[0] + TCL_VERSION[2] - roots = [ - # common installation directories, mostly for Windows - # (for Unix-style platforms, we'll check in well-known - # locations later) - os.path.join("/py" + PYVERSION, "Tcl"), - os.path.join("/python" + PYVERSION, "Tcl"), - "/Tcl", - "/Tcl" + TCLVERSION, - "/Tcl" + TCL_VERSION, - os.path.join( - os.environ.get("ProgramFiles", ""), "Tcl"), - ] - for TCL_ROOT in roots: - TCL_ROOT = os.path.abspath(TCL_ROOT) - _dbg('Checking %s for tk.h', TCL_ROOT) - if os.path.isfile(os.path.join(TCL_ROOT, "include", "tk.h")): - # FIXME: use distutils logging (?) - print("--- using Tcl/Tk libraries at", TCL_ROOT) - print("--- using Tcl/Tk version", TCL_VERSION) - TCL_ROOT = _lib_include(TCL_ROOT) - break - else: - TCL_ROOT = None - _dbg('Tcl/tk not found') - - # add standard directories - - # look for tcl specific subdirectory (e.g debian) - if _tkinter: - if not self.disable_platform_guessing: - tcl_dir = "/usr/include/tcl" + TCL_VERSION - if os.path.isfile(os.path.join(tcl_dir, "tk.h")): - _add_directory(include_dirs, tcl_dir) - # standard locations if not self.disable_platform_guessing: _add_directory(library_dirs, "/usr/local/lib") @@ -545,22 +492,6 @@ class pil_build_ext(build_ext): # alternate Windows name. feature.lcms = "lcms2_static" - if _tkinter and _find_include_file(self, "tk.h"): - # the library names may vary somewhat (e.g. tcl85 or tcl8.5) - version = TCL_VERSION[0] + TCL_VERSION[2] - if feature.want('tcl'): - _dbg('Looking for TCL') - if _find_library_file(self, "tcl" + version): - feature.tcl = "tcl" + version - elif _find_library_file(self, "tcl" + TCL_VERSION): - feature.tcl = "tcl" + TCL_VERSION - if feature.want('tk'): - _dbg('Looking for TK') - if _find_library_file(self, "tk" + version): - feature.tk = "tk" + version - elif _find_library_file(self, "tk" + TCL_VERSION): - feature.tk = "tk" + TCL_VERSION - if feature.want('webp'): _dbg('Looking for webp') if (_find_include_file(self, "webp/encode.h") and @@ -660,34 +591,11 @@ class pil_build_ext(build_ext): libraries=libs, define_macros=defs)) - if feature.tcl and feature.tk: - if sys.platform == "darwin" and not self.disable_osx_tcltk_framework: - # locate Tcl/Tk frameworks - frameworks = [] - framework_roots = [ - "/Library/Frameworks", "/System/Library/Frameworks" - ] - _dbg('Looking for TclTk Framework Build') - for root in framework_roots: - root_tcl = os.path.join(root, "Tcl.framework") - root_tk = os.path.join(root, "Tk.framework") - if (os.path.exists(root_tcl) and os.path.exists(root_tk)): - print("--- using frameworks at %s" % root) - frameworks = ["-framework", "Tcl", "-framework", "Tk"] - subdir = os.path.join(root_tcl, "Headers") - _add_directory(self.compiler.include_dirs, subdir, 0) - subdir = os.path.join(root_tk, "Headers") - _add_directory(self.compiler.include_dirs, subdir, 1) - break - if frameworks: - exts.append(Extension("PIL._imagingtk", - ["_imagingtk.c", "Tk/tkImaging.c"], - extra_compile_args=frameworks, - extra_link_args=frameworks)) - else: - exts.append(Extension("PIL._imagingtk", - ["_imagingtk.c", "Tk/tkImaging.c"], - libraries=[feature.tcl, feature.tk])) + tk_libs = ['psapi'] if sys.platform == 'win32' else [] + exts.append(Extension("PIL._imagingtk", + ["_imagingtk.c", "Tk/tkImaging.c"], + include_dirs=['Tk'], + libraries=tk_libs)) exts.append(Extension("PIL._imagingmath", ["_imagingmath.c"])) exts.append(Extension("PIL._imagingmorph", ["_imagingmorph.c"])) @@ -719,7 +627,6 @@ class pil_build_ext(build_ext): print("-" * 68) options = [ - (feature.tcl and feature.tk, "TKINTER"), (feature.jpeg, "JPEG"), (feature.jpeg2000, "OPENJPEG (JPEG2000)", feature.openjpeg_version), @@ -741,9 +648,6 @@ class pil_build_ext(build_ext): print("--- %s support available%s" % (option[1], version)) else: print("*** %s support not available" % option[1]) - if option[1] == "TKINTER" and _tkinter: - version = _tkinter.TCL_VERSION - print("(Tcl/Tk %s libraries needed)" % version) all = 0 if feature.zlib and unsafe_zlib: