2
* The Python Imaging Library.
7
* 1996-11-04 fl Added to PIL (incomplete)
8
* 1996-11-05 fl Added sequence semantics
9
* 1997-02-28 fl Fixed getbbox
10
* 1997-06-12 fl Added id attribute
11
* 1997-06-14 fl Added slicing and setitem
12
* 1998-12-29 fl Improved sequence handling (from Richard Jones)
13
* 1999-01-10 fl Fixed IndexError test for 1.5 (from Fred Drake)
14
* 2000-10-12 fl Added special cases for tuples and lists
15
* 2002-10-27 fl Added clipping boilerplate
16
* 2004-09-19 fl Added tolist(flat) variant
17
* 2005-05-06 fl Added buffer interface support to path constructor
20
* FIXME: fill in remaining slots in the sequence api
22
* Copyright (c) 1997-2005 by Secret Labs AB
23
* Copyright (c) 1997-2005 by Fredrik Lundh
25
* See the README file for information on usage and redistribution.
33
#if PY_VERSION_HEX < 0x01060000
34
#define PyObject_New PyObject_NEW
35
#define PyObject_Del PyMem_DEL
38
#if PY_VERSION_HEX < 0x02050000
39
#define Py_ssize_t int
40
#define lenfunc inquiry
41
#define ssizeargfunc intargfunc
42
#define ssizessizeargfunc intintargfunc
43
#define ssizeobjargproc intobjargproc
44
#define ssizessizeobjargproc intintobjargproc
47
/* compatibility wrappers (defined in _imaging.c) */
48
extern int PyImaging_CheckBuffer(PyObject* buffer);
49
extern int PyImaging_ReadBuffer(PyObject* buffer, const void** ptr);
51
/* -------------------------------------------------------------------- */
53
/* -------------------------------------------------------------------- */
59
int index; /* temporary use, e.g. in decimate */
62
staticforward PyTypeObject PyPathType;
65
alloc_array(int count)
72
xy = malloc(2 * count * sizeof(double) + 1);
79
path_new(Py_ssize_t count, double* xy, int duplicate)
85
double* p = alloc_array(count);
88
memcpy(p, xy, count * 2 * sizeof(double));
92
path = PyObject_New(PyPathObject, &PyPathType);
103
path_dealloc(PyPathObject* path)
109
/* -------------------------------------------------------------------- */
111
/* -------------------------------------------------------------------- */
113
#define PyPath_Check(op) ((op)->ob_type == &PyPathType)
116
PyPath_Flatten(PyObject* data, double **pxy)
121
if (PyPath_Check(data)) {
122
/* This was another path object. */
123
PyPathObject *path = (PyPathObject*) data;
124
xy = alloc_array(path->count);
127
memcpy(xy, path->xy, 2 * path->count * sizeof(double));
132
if (PyImaging_CheckBuffer(data)) {
133
/* Assume the buffer contains floats */
135
int n = PyImaging_ReadBuffer(data, (const void**) &ptr);
136
n /= 2 * sizeof(float);
140
for (i = 0; i < n+n; i++)
146
if (!PySequence_Check(data)) {
147
PyErr_SetString(PyExc_TypeError, "argument must be sequence");
152
n = PyObject_Length(data);
153
/* Just in case __len__ breaks (or doesn't exist) */
154
if (PyErr_Occurred())
157
/* Allocate for worst case */
162
/* Copy table to path array */
163
if (PyList_Check(data)) {
164
for (i = 0; i < n; i++) {
166
PyObject *op = PyList_GET_ITEM(data, i);
167
if (PyFloat_Check(op))
168
xy[j++] = PyFloat_AS_DOUBLE(op);
169
else if (PyInt_Check(op))
170
xy[j++] = (float) PyInt_AS_LONG(op);
171
else if (PyNumber_Check(op))
172
xy[j++] = PyFloat_AsDouble(op);
173
else if (PyArg_ParseTuple(op, "dd", &x, &y)) {
181
} else if (PyTuple_Check(data)) {
182
for (i = 0; i < n; i++) {
184
PyObject *op = PyTuple_GET_ITEM(data, i);
185
if (PyFloat_Check(op))
186
xy[j++] = PyFloat_AS_DOUBLE(op);
187
else if (PyInt_Check(op))
188
xy[j++] = (float) PyInt_AS_LONG(op);
189
else if (PyNumber_Check(op))
190
xy[j++] = PyFloat_AsDouble(op);
191
else if (PyArg_ParseTuple(op, "dd", &x, &y)) {
200
for (i = 0; i < n; i++) {
202
PyObject *op = PySequence_GetItem(data, i);
204
/* treat IndexError as end of sequence */
205
if (PyErr_Occurred() &&
206
PyErr_ExceptionMatches(PyExc_IndexError)) {
214
if (PyFloat_Check(op))
215
xy[j++] = PyFloat_AS_DOUBLE(op);
216
else if (PyInt_Check(op))
217
xy[j++] = (float) PyInt_AS_LONG(op);
218
else if (PyNumber_Check(op))
219
xy[j++] = PyFloat_AsDouble(op);
220
else if (PyArg_ParseTuple(op, "dd", &x, &y)) {
233
PyErr_SetString(PyExc_ValueError, "wrong number of coordinates");
243
/* -------------------------------------------------------------------- */
245
/* -------------------------------------------------------------------- */
248
PyPath_Create(PyObject* self, PyObject* args)
254
if (PyArg_ParseTuple(args, "i:Path", &count)) {
256
/* number of vertices */
257
xy = alloc_array(count);
263
/* sequence or other path */
265
if (!PyArg_ParseTuple(args, "O", &data))
268
count = PyPath_Flatten(data, &xy);
273
return (PyObject*) path_new(count, xy, 0);
277
/* -------------------------------------------------------------------- */
279
/* -------------------------------------------------------------------- */
282
path_compact(PyPathObject* self, PyObject* args)
284
/* Simple-minded method to shorten path. A point is removed if
285
the city block distance to the previous point is less than the
290
double cityblock = 2.0;
292
if (!PyArg_ParseTuple(args, "|d:compact", &cityblock))
297
/* remove bogus vertices */
298
for (i = j = 1; i < self->count; i++) {
299
if (fabs(xy[j+j-2]-xy[i+i]) + fabs(xy[j+j-1]-xy[i+i+1]) >= cityblock) {
301
xy[j+j+1] = xy[i+i+1];
309
/* shrink coordinate array */
310
self->xy = realloc(self->xy, 2 * self->count * sizeof(double));
312
return Py_BuildValue("i", i); /* number of removed vertices */
316
path_clip_polygon(PyPathObject* self, PyObject* args)
318
/* Clip path representing a single polygon */
319
PyErr_SetString(PyExc_RuntimeError, "not yet implemented");
324
path_clip_polyline(PyPathObject* self, PyObject* args)
326
/* Clip path representing a single polyline (outline) */
327
PyErr_SetString(PyExc_RuntimeError, "not yet implemented");
332
path_getbbox(PyPathObject* self, PyObject* args)
334
/* Find bounding box */
337
double x0, y0, x1, y1;
339
if (!PyArg_ParseTuple(args, ":getbbox"))
347
for (i = 1; i < self->count; i++) {
358
return Py_BuildValue("dddd", x0, y0, x1, y1);
362
path_getitem(PyPathObject* self, int i)
364
if (i < 0 || i >= self->count) {
365
PyErr_SetString(PyExc_IndexError, "path index out of range");
369
return Py_BuildValue("dd", self->xy[i+i], self->xy[i+i+1]);
373
path_getslice(PyPathObject* self, Py_ssize_t ilow, Py_ssize_t ihigh)
375
/* adjust arguments */
378
else if (ilow >= self->count)
384
else if (ihigh > self->count)
387
return (PyObject*) path_new(ihigh - ilow, self->xy + ilow * 2, 1);
391
path_len(PyPathObject* self)
397
path_map(PyPathObject* self, PyObject* args)
399
/* Map coordinate set through function */
404
if (!PyArg_ParseTuple(args, "O:map", &function))
409
/* apply function to coordinate set */
410
for (i = 0; i < self->count; i++) {
412
double y = xy[i+i+1];
413
PyObject* item = PyObject_CallFunction(function, "dd", x, y);
414
if (!item || !PyArg_ParseTuple(item, "dd", &x, &y)) {
428
path_setitem(PyPathObject* self, int i, PyObject* op)
432
if (i < 0 || i >= self->count) {
433
PyErr_SetString(PyExc_IndexError,
434
"path assignment index out of range");
439
PyErr_SetString(PyExc_TypeError,
440
"cannot delete from path");
446
if (!PyArg_ParseTuple(op, "dd", &xy[0], &xy[1]))
453
path_tolist(PyPathObject* self, PyObject* args)
459
if (!PyArg_ParseTuple(args, "|i:tolist", &flat))
463
list = PyList_New(self->count*2);
464
for (i = 0; i < self->count*2; i++) {
466
item = PyFloat_FromDouble(self->xy[i]);
469
PyList_SetItem(list, i, item);
472
list = PyList_New(self->count);
473
for (i = 0; i < self->count; i++) {
475
item = Py_BuildValue("dd", self->xy[i+i], self->xy[i+i+1]);
478
PyList_SetItem(list, i, item);
490
path_transform(PyPathObject* self, PyObject* args)
492
/* Apply affine transform to coordinate set */
495
double a, b, c, d, e, f;
499
if (!PyArg_ParseTuple(args, "(dddddd)|d:transform",
500
&a, &b, &c, &d, &e, &f,
506
/* transform the coordinate set */
507
if (b == 0.0 && d == 0.0)
509
for (i = 0; i < self->count; i++) {
510
xy[i+i] = a*xy[i+i]+c;
511
xy[i+i+1] = e*xy[i+i+1]+f;
514
/* affine transform */
515
for (i = 0; i < self->count; i++) {
517
double y = xy[i+i+1];
519
xy[i+i+1] = d*x+e*y+f;
522
/* special treatment of geographical map data */
524
for (i = 0; i < self->count; i++)
525
xy[i+i] = fmod(xy[i+i], wrap);
531
static struct PyMethodDef methods[] = {
532
{"getbbox", (PyCFunction)path_getbbox, 1},
533
{"tolist", (PyCFunction)path_tolist, 1},
534
{"clip_polygon", (PyCFunction)path_clip_polygon, 1},
535
{"clip_polyline", (PyCFunction)path_clip_polyline, 1},
536
{"compact", (PyCFunction)path_compact, 1},
537
{"map", (PyCFunction)path_map, 1},
538
{"transform", (PyCFunction)path_transform, 1},
539
{NULL, NULL} /* sentinel */
543
path_getattr(PyPathObject* self, char* name)
547
res = Py_FindMethod(methods, (PyObject*) self, name);
553
if (strcmp(name, "id") == 0)
554
return Py_BuildValue("l", (long) self->xy);
556
PyErr_SetString(PyExc_AttributeError, name);
560
static PySequenceMethods path_as_sequence = {
561
(lenfunc)path_len, /*sq_length*/
562
(binaryfunc)0, /*sq_concat*/
563
(ssizeargfunc)0, /*sq_repeat*/
564
(ssizeargfunc)path_getitem, /*sq_item*/
565
(ssizessizeargfunc)path_getslice, /*sq_slice*/
566
(ssizeobjargproc)path_setitem, /*sq_ass_item*/
567
(ssizessizeobjargproc)0, /*sq_ass_slice*/
570
statichere PyTypeObject PyPathType = {
571
PyObject_HEAD_INIT(NULL)
574
sizeof(PyPathObject), /*tp_size*/
577
(destructor)path_dealloc, /*tp_dealloc*/
579
(getattrfunc)path_getattr, /*tp_getattr*/
584
&path_as_sequence, /*tp_as_sequence */
585
0, /*tp_as_mapping */