/* -*- mode: c++; c-basic-offset: 4 -*- */
/*
* The Python Imaging Library.
* $Id$
*
*/
/* This is needed for (at least) Tk 8.4.1, otherwise the signature of
** Tk_PhotoPutBlock changes.
*/
#define USE_COMPOSITELESS_PHOTO_PUT_BLOCK
#include
#include
#include
#include
#include "py_converters.h"
extern "C"
{
#ifdef __APPLE__
# ifdef TK_FRAMEWORK
# include
# include
# else
# include
# endif
#else
# include
#endif
}
#if defined(_MSC_VER)
# define SIZE_T_FORMAT "%Iu"
#else
# define SIZE_T_FORMAT "%zu"
#endif
typedef struct
{
PyObject_HEAD;
Tcl_Interp *interp;
} TkappObject;
static int PyAggImagePhoto(ClientData clientdata, Tcl_Interp *interp, int argc, char **argv)
{
Tk_PhotoHandle photo;
Tk_PhotoImageBlock block;
PyObject *bufferobj;
// vars for blitting
PyObject *bboxo;
size_t aggl, bboxl;
bool has_bbox;
uint8_t *destbuffer;
int destx, desty, destwidth, destheight, deststride;
//unsigned long tmp_ptr;
long mode;
long nval;
if (Tk_MainWindow(interp) == NULL) {
// Will throw a _tkinter.TclError with "this isn't a Tk application"
return TCL_ERROR;
}
if (argc != 5) {
Tcl_AppendResult(interp, "usage: ", argv[0], " destPhoto srcImage", (char *)NULL);
return TCL_ERROR;
}
/* get Tcl PhotoImage handle */
photo = Tk_FindPhoto(interp, argv[1]);
if (photo == NULL) {
Tcl_AppendResult(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_AppendResult(interp, "error casting pointer", (char *)NULL);
return TCL_ERROR;
}
bufferobj = (PyObject *)aggl;
numpy::array_view buffer;
try {
buffer = numpy::array_view(bufferobj);
} catch (...) {
Tcl_AppendResult(interp, "buffer is of wrong type", (char *)NULL);
PyErr_Clear();
return TCL_ERROR;
}
int srcheight = buffer.dim(0);
/* XXX insert aggRenderer type check */
/* get array mode (0=mono, 1=rgb, 2=rgba) */
mode = atol(argv[3]);
if ((mode != 0) && (mode != 1) && (mode != 2)) {
Tcl_AppendResult(interp, "illegal image mode", (char *)NULL);
return TCL_ERROR;
}
/* check for bbox/blitting */
if (sscanf(argv[4], SIZE_T_FORMAT, &bboxl) != 1) {
Tcl_AppendResult(interp, "error casting pointer", (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);
deststride = 4 * destwidth;
destbuffer = new agg::int8u[deststride * destheight];
if (destbuffer == NULL) {
Tcl_AppendResult(interp, "could not allocate memory", (char *)NULL);
return TCL_ERROR;
}
for (int i = 0; i < destheight; ++i) {
memcpy(destbuffer + (deststride * i),
&buffer(i + desty, destx, 0),
deststride);
}
} else {
has_bbox = false;
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_PhotoPutBlock(photo, &block, destx, desty, destwidth, destheight);
delete[] destbuffer;
} else {
block.width = buffer.dim(1);
block.height = buffer.dim(0);
block.pitch = (int)block.width * nval;
block.pixelPtr = buffer.data();
/* Clear current contents */
Tk_PhotoBlank(photo);
/* Copy opaque block to photo image, and leave the rest to TK */
Tk_PhotoPutBlock(photo, &block, 0, 0, block.width, block.height);
}
return TCL_OK;
}
static PyObject *_pyobj_addr(PyObject *self, PyObject *args)
{
PyObject *pyobj;
if (!PyArg_ParseTuple(args, "O", &pyobj)) {
return NULL;
}
return Py_BuildValue("n", (Py_ssize_t)pyobj);
}
static PyObject *_tkinit(PyObject *self, PyObject *args)
{
Tcl_Interp *interp;
TkappObject *app;
Py_ssize_t arg;
int is_interp;
if (!PyArg_ParseTuple(args, "ni", &arg, &is_interp)) {
return NULL;
}
if (is_interp) {
interp = (Tcl_Interp *)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_CreateCommand(interp,
"PyAggImagePhoto",
(Tcl_CmdProc *)PyAggImagePhoto,
(ClientData)0,
(Tcl_CmdDeleteProc *)NULL);
Py_INCREF(Py_None);
return Py_None;
}
static PyMethodDef functions[] = {
/* Tkinter interface stuff */
{ "_pyobj_addr", (PyCFunction)_pyobj_addr, 1 }, { "tkinit", (PyCFunction)_tkinit, 1 },
{ NULL, NULL } /* sentinel */
};
#if PY3K
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);
import_array();
return m;
}
#else
PyMODINIT_FUNC init_tkagg(void)
{
import_array();
Py_InitModule("_tkagg", functions);
}
#endif