mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-11-10 19:56:47 +03:00
RF: run-time loading of Tcl / Tk functions
Discover Tcl / Tk functions at run-time by looking in libs loaded by Tkinter Python module. Use header excerpts from Tcl / Tk so we don't need an installed Tcl / Tk to build.
This commit is contained in:
parent
2af16a7b58
commit
659e294676
146
Tk/_tkmini.h
Normal file
146
Tk/_tkmini.h
Normal file
|
@ -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
|
316
Tk/tkImaging.c
316
Tk/tkImaging.c
|
@ -42,17 +42,23 @@
|
||||||
* See the README file for information on usage and redistribution.
|
* 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 "Imaging.h"
|
||||||
#include "tk.h"
|
#include "_tkmini.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
static Imaging
|
||||||
ImagingFind(const char* name)
|
ImagingFind(const char* name)
|
||||||
|
@ -81,15 +87,15 @@ PyImagingPhotoPut(ClientData clientdata, Tcl_Interp* interp,
|
||||||
Tk_PhotoImageBlock block;
|
Tk_PhotoImageBlock block;
|
||||||
|
|
||||||
if (argc != 3) {
|
if (argc != 3) {
|
||||||
Tcl_AppendResult(interp, "usage: ", argv[0],
|
TCL_APPEND_RESULT(interp, "usage: ", argv[0],
|
||||||
" destPhoto srcImage", (char *) NULL);
|
" destPhoto srcImage", (char *) NULL);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get Tcl PhotoImage handle */
|
/* get Tcl PhotoImage handle */
|
||||||
photo = Tk_FindPhoto(interp, argv[1]);
|
photo = TK_FIND_PHOTO(interp, argv[1]);
|
||||||
if (photo == NULL) {
|
if (photo == NULL) {
|
||||||
Tcl_AppendResult(
|
TCL_APPEND_RESULT(
|
||||||
interp, "destination photo must exist", (char *) NULL
|
interp, "destination photo must exist", (char *) NULL
|
||||||
);
|
);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
|
@ -98,12 +104,12 @@ PyImagingPhotoPut(ClientData clientdata, Tcl_Interp* interp,
|
||||||
/* get PIL Image handle */
|
/* get PIL Image handle */
|
||||||
im = ImagingFind(argv[2]);
|
im = ImagingFind(argv[2]);
|
||||||
if (!im) {
|
if (!im) {
|
||||||
Tcl_AppendResult(interp, "bad name", (char*) NULL);
|
TCL_APPEND_RESULT(interp, "bad name", (char*) NULL);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
if (!im->block) {
|
if (!im->block) {
|
||||||
Tcl_AppendResult(interp, "bad display memory", (char*) NULL);
|
TCL_APPEND_RESULT(interp, "bad display memory", (char*) NULL);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Active region */
|
/* Active region */
|
||||||
|
@ -133,7 +139,7 @@ PyImagingPhotoPut(ClientData clientdata, Tcl_Interp* interp,
|
||||||
else
|
else
|
||||||
block.offset[3] = 0; /* no alpha */
|
block.offset[3] = 0; /* no alpha */
|
||||||
} else {
|
} else {
|
||||||
Tcl_AppendResult(interp, "Bad mode", (char*) NULL);
|
TCL_APPEND_RESULT(interp, "Bad mode", (char*) NULL);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,17 +153,18 @@ PyImagingPhotoPut(ClientData clientdata, Tcl_Interp* interp,
|
||||||
src_xoffset * im->pixelsize;
|
src_xoffset * im->pixelsize;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if TK < 85 /* Tk 8.4 */
|
if (TK_LT_85) { /* Tk 8.4 */
|
||||||
Tk_PhotoPutBlock(photo, &block, 0, 0, block.width, block.height,
|
TK_PHOTO_PUT_BLOCK_84(photo, &block, 0, 0, block.width, block.height,
|
||||||
TK_PHOTO_COMPOSITE_SET);
|
TK_PHOTO_COMPOSITE_SET);
|
||||||
if (strcmp(im->mode, "RGBA") == 0)
|
if (strcmp(im->mode, "RGBA") == 0)
|
||||||
/* Tk workaround: we need apply ToggleComplexAlphaIfNeeded */
|
/* Tk workaround: we need apply ToggleComplexAlphaIfNeeded */
|
||||||
/* (fixed in Tk 8.5a3) */
|
/* (fixed in Tk 8.5a3) */
|
||||||
Tk_PhotoSetSize(photo, block.width, block.height);
|
TK_PHOTO_SET_SIZE_84(photo, block.width, block.height);
|
||||||
#else /* Tk 8.5 */
|
} else {
|
||||||
Tk_PhotoPutBlock(interp, photo, &block, 0, 0, block.width, block.height,
|
/* Tk >=8.5 */
|
||||||
TK_PHOTO_COMPOSITE_SET);
|
TK_PHOTO_PUT_BLOCK_85(interp, photo, &block, 0, 0, block.width,
|
||||||
#endif
|
block.height, TK_PHOTO_COMPOSITE_SET);
|
||||||
|
}
|
||||||
|
|
||||||
return TCL_OK;
|
return TCL_OK;
|
||||||
}
|
}
|
||||||
|
@ -171,21 +178,21 @@ PyImagingPhotoGet(ClientData clientdata, Tcl_Interp* interp,
|
||||||
Tk_PhotoImageBlock block;
|
Tk_PhotoImageBlock block;
|
||||||
|
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
Tcl_AppendResult(interp, "usage: ", argv[0],
|
TCL_APPEND_RESULT(interp, "usage: ", argv[0],
|
||||||
" srcPhoto", (char *) NULL);
|
" srcPhoto", (char *) NULL);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get Tcl PhotoImage handle */
|
/* get Tcl PhotoImage handle */
|
||||||
photo = Tk_FindPhoto(interp, argv[1]);
|
photo = TK_FIND_PHOTO(interp, argv[1]);
|
||||||
if (photo == NULL) {
|
if (photo == NULL) {
|
||||||
Tcl_AppendResult(
|
TCL_APPEND_RESULT(
|
||||||
interp, "source photo must exist", (char *) NULL
|
interp, "source photo must exist", (char *) NULL
|
||||||
);
|
);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tk_PhotoGetImage(photo, &block);
|
TK_PHOTO_GET_IMAGE(photo, &block);
|
||||||
|
|
||||||
printf("pixelPtr = %p\n", block.pixelPtr);
|
printf("pixelPtr = %p\n", block.pixelPtr);
|
||||||
printf("width = %d\n", block.width);
|
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],
|
printf("offset = %d %d %d %d\n", block.offset[0], block.offset[1],
|
||||||
block.offset[2], block.offset[3]);
|
block.offset[2], block.offset[3]);
|
||||||
|
|
||||||
Tcl_AppendResult(
|
TCL_APPEND_RESULT(
|
||||||
interp, "this function is not yet supported", (char *) NULL
|
interp, "this function is not yet supported", (char *) NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -206,8 +213,251 @@ PyImagingPhotoGet(ClientData clientdata, Tcl_Interp* interp,
|
||||||
void
|
void
|
||||||
TkImaging_Init(Tcl_Interp* interp)
|
TkImaging_Init(Tcl_Interp* interp)
|
||||||
{
|
{
|
||||||
Tcl_CreateCommand(interp, "PyImagingPhoto", PyImagingPhotoPut,
|
TCL_CREATE_COMMAND(interp, "PyImagingPhoto", PyImagingPhotoPut,
|
||||||
(ClientData) 0, (Tcl_CmdDeleteProc*) NULL);
|
(ClientData) 0, (Tcl_CmdDeleteProc*) NULL);
|
||||||
Tcl_CreateCommand(interp, "PyImagingPhotoGet", PyImagingPhotoGet,
|
TCL_CREATE_COMMAND(interp, "PyImagingPhotoGet", PyImagingPhotoGet,
|
||||||
(ClientData) 0, (Tcl_CmdDeleteProc*) NULL);
|
(ClientData) 0, (Tcl_CmdDeleteProc*) NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* 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_VERSION_HEX >= 0x03000000
|
||||||
|
#define TKINTER_PKG "tkinter"
|
||||||
|
#define TKINTER_MOD "_tkinter"
|
||||||
|
/* From module __file__ attribute to char *string for dlopen. */
|
||||||
|
char *fname2char(PyObject *fname)
|
||||||
|
{
|
||||||
|
PyObject *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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 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, *pSubmodule = NULL, *pString = NULL;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
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(pSubmodule);
|
||||||
|
Py_XDECREF(pString);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif /* end not Windows */
|
||||||
|
|
|
@ -16,10 +16,11 @@
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
#include "Imaging.h"
|
#include "Imaging.h"
|
||||||
|
|
||||||
#include "tk.h"
|
#include "_tkmini.h"
|
||||||
|
|
||||||
/* must link with Tk/tkImaging.c */
|
/* must link with Tk/tkImaging.c */
|
||||||
extern void TkImaging_Init(Tcl_Interp* interp);
|
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
|
/* 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
|
versions, we use _tkinter's interpaddr hook instead, and all older
|
||||||
|
@ -73,14 +74,16 @@ PyInit__imagingtk(void) {
|
||||||
-1, /* m_size */
|
-1, /* m_size */
|
||||||
functions, /* m_methods */
|
functions, /* m_methods */
|
||||||
};
|
};
|
||||||
|
PyObject *m;
|
||||||
return PyModule_Create(&module_def);
|
m = PyModule_Create(&module_def);
|
||||||
|
return (load_tkinter_funcs() == 0) ? m : NULL;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
PyMODINIT_FUNC
|
PyMODINIT_FUNC
|
||||||
init_imagingtk(void)
|
init_imagingtk(void)
|
||||||
{
|
{
|
||||||
Py_InitModule("_imagingtk", functions);
|
Py_InitModule("_imagingtk", functions);
|
||||||
|
load_tkinter_funcs();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
112
setup.py
112
setup.py
|
@ -111,7 +111,6 @@ except (ImportError, OSError):
|
||||||
|
|
||||||
NAME = 'Pillow'
|
NAME = 'Pillow'
|
||||||
PILLOW_VERSION = '3.3.0.dev0'
|
PILLOW_VERSION = '3.3.0.dev0'
|
||||||
TCL_ROOT = None
|
|
||||||
JPEG_ROOT = None
|
JPEG_ROOT = None
|
||||||
JPEG2K_ROOT = None
|
JPEG2K_ROOT = None
|
||||||
ZLIB_ROOT = None
|
ZLIB_ROOT = None
|
||||||
|
@ -123,8 +122,8 @@ LCMS_ROOT = None
|
||||||
|
|
||||||
class pil_build_ext(build_ext):
|
class pil_build_ext(build_ext):
|
||||||
class feature:
|
class feature:
|
||||||
features = ['zlib', 'jpeg', 'tiff', 'freetype', 'tcl', 'tk', 'lcms',
|
features = ['zlib', 'jpeg', 'tiff', 'freetype', 'lcms', 'webp',
|
||||||
'webp', 'webpmux', 'jpeg2000', 'imagequant']
|
'webpmux', 'jpeg2000', 'imagequant']
|
||||||
|
|
||||||
required = set(['jpeg', 'zlib'])
|
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
|
('enable-%s' % x, None, 'Enable support for %s' % x) for x in feature
|
||||||
] + [
|
] + [
|
||||||
('disable-platform-guessing', None, 'Disable platform guessing on Linux'),
|
('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')
|
('debug', None, 'Debug logging')
|
||||||
]
|
]
|
||||||
|
|
||||||
def initialize_options(self):
|
def initialize_options(self):
|
||||||
self.disable_platform_guessing = None
|
self.disable_platform_guessing = None
|
||||||
self.disable_osx_tcltk_framework = None
|
|
||||||
build_ext.initialize_options(self)
|
build_ext.initialize_options(self)
|
||||||
for x in self.feature:
|
for x in self.feature:
|
||||||
setattr(self, 'disable_%s' % x, None)
|
setattr(self, 'disable_%s' % x, None)
|
||||||
|
@ -183,8 +179,6 @@ class pil_build_ext(build_ext):
|
||||||
|
|
||||||
def build_extensions(self):
|
def build_extensions(self):
|
||||||
|
|
||||||
global TCL_ROOT
|
|
||||||
|
|
||||||
library_dirs = []
|
library_dirs = []
|
||||||
include_dirs = []
|
include_dirs = []
|
||||||
|
|
||||||
|
@ -193,7 +187,7 @@ class pil_build_ext(build_ext):
|
||||||
#
|
#
|
||||||
# add configured kits
|
# 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):
|
FREETYPE_ROOT, LCMS_ROOT, IMAGEQUANT_ROOT):
|
||||||
if isinstance(root, type(())):
|
if isinstance(root, type(())):
|
||||||
lib_root, include_root = root
|
lib_root, include_root = root
|
||||||
|
@ -351,53 +345,6 @@ class pil_build_ext(build_ext):
|
||||||
|
|
||||||
# FIXME: check /opt/stuff directories here?
|
# 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
|
# standard locations
|
||||||
if not self.disable_platform_guessing:
|
if not self.disable_platform_guessing:
|
||||||
_add_directory(library_dirs, "/usr/local/lib")
|
_add_directory(library_dirs, "/usr/local/lib")
|
||||||
|
@ -543,22 +490,6 @@ class pil_build_ext(build_ext):
|
||||||
# alternate Windows name.
|
# alternate Windows name.
|
||||||
feature.lcms = "lcms2_static"
|
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'):
|
if feature.want('webp'):
|
||||||
_dbg('Looking for webp')
|
_dbg('Looking for webp')
|
||||||
if (_find_include_file(self, "webp/encode.h") and
|
if (_find_include_file(self, "webp/encode.h") and
|
||||||
|
@ -658,34 +589,11 @@ class pil_build_ext(build_ext):
|
||||||
libraries=libs,
|
libraries=libs,
|
||||||
define_macros=defs))
|
define_macros=defs))
|
||||||
|
|
||||||
if feature.tcl and feature.tk:
|
tk_libs = ['psapi'] if sys.platform == 'win32' else []
|
||||||
if sys.platform == "darwin" and not self.disable_osx_tcltk_framework:
|
exts.append(Extension("PIL._imagingtk",
|
||||||
# locate Tcl/Tk frameworks
|
["_imagingtk.c", "Tk/tkImaging.c"],
|
||||||
frameworks = []
|
include_dirs=['Tk'],
|
||||||
framework_roots = [
|
libraries=tk_libs))
|
||||||
"/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]))
|
|
||||||
|
|
||||||
exts.append(Extension("PIL._imagingmath", ["_imagingmath.c"]))
|
exts.append(Extension("PIL._imagingmath", ["_imagingmath.c"]))
|
||||||
exts.append(Extension("PIL._imagingmorph", ["_imagingmorph.c"]))
|
exts.append(Extension("PIL._imagingmorph", ["_imagingmorph.c"]))
|
||||||
|
@ -717,7 +625,6 @@ class pil_build_ext(build_ext):
|
||||||
print("-" * 68)
|
print("-" * 68)
|
||||||
|
|
||||||
options = [
|
options = [
|
||||||
(feature.tcl and feature.tk, "TKINTER"),
|
|
||||||
(feature.jpeg, "JPEG"),
|
(feature.jpeg, "JPEG"),
|
||||||
(feature.jpeg2000, "OPENJPEG (JPEG2000)",
|
(feature.jpeg2000, "OPENJPEG (JPEG2000)",
|
||||||
feature.openjpeg_version),
|
feature.openjpeg_version),
|
||||||
|
@ -739,9 +646,6 @@ class pil_build_ext(build_ext):
|
||||||
print("--- %s support available%s" % (option[1], version))
|
print("--- %s support available%s" % (option[1], version))
|
||||||
else:
|
else:
|
||||||
print("*** %s support not available" % option[1])
|
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
|
all = 0
|
||||||
|
|
||||||
if feature.zlib and unsafe_zlib:
|
if feature.zlib and unsafe_zlib:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user