diff options
Diffstat (limited to 'plug-ins/pygimp/pygimp-tile.c')
-rw-r--r-- | plug-ins/pygimp/pygimp-tile.c | 1046 |
1 files changed, 1046 insertions, 0 deletions
diff --git a/plug-ins/pygimp/pygimp-tile.c b/plug-ins/pygimp/pygimp-tile.c new file mode 100644 index 0000000..b4f3722 --- /dev/null +++ b/plug-ins/pygimp/pygimp-tile.c @@ -0,0 +1,1046 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * Gimp-Python - allows the writing of Gimp plugins in Python. + * Copyright (C) 1997-2002 James Henstridge <james@daa.com.au> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define GIMP_DISABLE_DEPRECATION_WARNINGS + +#include "pygimp.h" + +#define NO_IMPORT_PYGIMPCOLOR +#include "pygimpcolor-api.h" + +#include <structmember.h> + +static PyObject * +tile_flush(PyGimpTile *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":flush")) + return NULL; + + gimp_tile_flush(self->tile); + + Py_INCREF(Py_None); + return Py_None; +} + + +static PyMethodDef tile_methods[] = { + {"flush", (PyCFunction)tile_flush, METH_VARARGS}, + {NULL, NULL} /* sentinel */ +}; + +/* ---------- */ + + +PyObject * +pygimp_tile_new(GimpTile *t, PyGimpDrawable *drw) +{ + PyGimpTile *self; + + self = PyObject_NEW(PyGimpTile, &PyGimpTile_Type); + + if (self == NULL) + return NULL; + + gimp_tile_ref(t); + + self->tile = t; + + Py_INCREF(drw); + self->drawable = drw; + + return (PyObject *)self; +} + + +static void +tile_dealloc(PyGimpTile *self) +{ + gimp_tile_unref(self->tile, FALSE); + + Py_DECREF(self->drawable); + PyObject_DEL(self); +} + +static PyObject * +tile_get_uint_field(PyGimpTile *self, void *closure) +{ + gint offset = GPOINTER_TO_INT(closure); + guint value; + gchar *addr; + + addr = (gchar *)self->tile; + addr += offset; + value = *(guint *)addr; + + return PyInt_FromLong(value); +} + +static PyObject * +tile_get_dirty(PyGimpTile *self, void *closure) +{ + return PyBool_FromLong(self->tile->dirty); +} + +static PyObject * +tile_get_shadow(PyGimpTile *self, void *closure) +{ + return PyBool_FromLong(self->tile->shadow); +} + +static PyObject * +tile_get_drawable(PyGimpTile *self, void *closure) +{ + return pygimp_drawable_new(self->tile->drawable, 0); +} + + +#define OFF(x) GINT_TO_POINTER(offsetof(GimpTile, x)) +static PyGetSetDef tile_getsets[] = { + { "ewidth", (getter)tile_get_uint_field, 0, NULL, OFF(ewidth) }, + { "eheight", (getter)tile_get_uint_field, 0, NULL, OFF(eheight) }, + { "bpp", (getter)tile_get_uint_field, 0, NULL, OFF(bpp) }, + { "tile_num", (getter)tile_get_uint_field, 0, NULL, OFF(tile_num) }, + { "dirty", (getter)tile_get_dirty, 0, NULL }, + { "shadow", (getter)tile_get_shadow, 0, NULL }, + { "drawable", (getter)tile_get_drawable, 0, NULL }, + { NULL, (getter)0, (setter)0 } +}; +#undef OFF + +static PyObject * +tile_repr(PyGimpTile *self) +{ + PyObject *s; + gchar *name; + + name = gimp_item_get_name(self->tile->drawable->drawable_id); + + if (self->tile->shadow) + s = PyString_FromFormat("<gimp.Tile for drawable '%s' (shadow)>", name); + else + s = PyString_FromFormat("<gimp.Tile for drawable '%s'>", name); + + g_free(name); + + return s; +} + +static Py_ssize_t +tile_length(PyObject *self) +{ + return ((PyGimpTile*)self)->tile->ewidth * ((PyGimpTile*)self)->tile->eheight; +} + +static PyObject * +tile_subscript(PyGimpTile *self, PyObject *sub) +{ + GimpTile *tile = self->tile; + int bpp = tile->bpp; + long x, y; + + if (PyInt_Check(sub)) { + x = PyInt_AsLong(sub); + + if (x < 0 || x >= tile->ewidth * tile->eheight) { + PyErr_SetString(PyExc_IndexError, "index out of range"); + return NULL; + } + + return PyString_FromStringAndSize + ((char *)tile->data + bpp * x, bpp); + } + + if (PyTuple_Check(sub)) { + if (!PyArg_ParseTuple(sub, "ll", &x, &y)) + return NULL; + + if (x < 0 || y < 0 || x >= tile->ewidth || y>=tile->eheight) { + PyErr_SetString(PyExc_IndexError, "index out of range"); + return NULL; + } + + return PyString_FromStringAndSize + ((char *)tile->data + bpp * (x + y * tile->ewidth), bpp); + } + + PyErr_SetString(PyExc_TypeError, "tile subscript not int or 2-tuple"); + return NULL; +} + +static int +tile_ass_sub(PyGimpTile *self, PyObject *v, PyObject *w) +{ + GimpTile *tile = self->tile; + int bpp = tile->bpp, i; + long x, y; + guchar *pix, *data; + + if (w == NULL) { + PyErr_SetString(PyExc_TypeError, + "can not delete pixels in tile"); + return -1; + } + + if (!PyString_Check(w) && PyString_Size(w) == bpp) { + PyErr_SetString(PyExc_TypeError, "invalid subscript"); + return -1; + } + + pix = (guchar *)PyString_AsString(w); + + if (PyInt_Check(v)) { + x = PyInt_AsLong(v); + + if (x < 0 || x >= tile->ewidth * tile->eheight) { + PyErr_SetString(PyExc_IndexError, "index out of range"); + return -1; + } + + data = tile->data + x * bpp; + + for (i = 0; i < bpp; i++) + data[i] = pix[i]; + + tile->dirty = TRUE; + + return 0; + } + + if (PyTuple_Check(v)) { + if (!PyArg_ParseTuple(v, "ll", &x, &y)) + return -1; + + if (x < 0 || y < 0 || x >= tile->ewidth || y>=tile->eheight) { + PyErr_SetString(PyExc_IndexError, "index out of range"); + return -1; + } + + data = tile->data + bpp * (x + y * tile->ewidth); + + for (i = 0; i < bpp; i++) + data[i] = pix[i]; + + tile->dirty = TRUE; + + return 0; + } + + PyErr_SetString(PyExc_TypeError, "tile subscript not int or 2-tuple"); + return -1; +} + +static PyMappingMethods tile_as_mapping = { + tile_length, /*length*/ + (binaryfunc)tile_subscript, /*subscript*/ + (objobjargproc)tile_ass_sub, /*ass_sub*/ +}; + +PyTypeObject PyGimpTile_Type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "gimp.Tile", /* tp_name */ + sizeof(PyGimpTile), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)tile_dealloc, /* tp_dealloc */ + (printfunc)0, /* tp_print */ + (getattrfunc)0, /* tp_getattr */ + (setattrfunc)0, /* tp_setattr */ + (cmpfunc)0, /* tp_compare */ + (reprfunc)tile_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + &tile_as_mapping, /* tp_as_mapping */ + (hashfunc)0, /* tp_hash */ + (ternaryfunc)0, /* tp_call */ + (reprfunc)0, /* tp_str */ + (getattrofunc)0, /* tp_getattro */ + (setattrofunc)0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + NULL, /* Documentation string */ + (traverseproc)0, /* tp_traverse */ + (inquiry)0, /* tp_clear */ + (richcmpfunc)0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + (getiterfunc)0, /* tp_iter */ + (iternextfunc)0, /* tp_iternext */ + tile_methods, /* tp_methods */ + 0, /* tp_members */ + tile_getsets, /* tp_getset */ + (PyTypeObject *)0, /* tp_base */ + (PyObject *)0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)0, /* tp_init */ + (allocfunc)0, /* tp_alloc */ + (newfunc)0, /* tp_new */ +}; + +/* End of code for Tile objects */ +/* -------------------------------------------------------- */ + + +static PyObject * +pr_resize(PyGimpPixelRgn *self, PyObject *args) +{ + int x, y, w, h; + + if (!PyArg_ParseTuple(args, "iiii:resize", &x, &y, &w, &h)) + return NULL; + + gimp_pixel_rgn_resize(&(self->pr), x, y, w, h); + + Py_INCREF(Py_None); + return Py_None; +} + + + +static PyMethodDef pr_methods[] = { + {"resize", (PyCFunction)pr_resize, METH_VARARGS}, + + {NULL, NULL} /* sentinel */ +}; + +/* ---------- */ + + +PyObject * +pygimp_pixel_rgn_new(PyGimpDrawable *drawable, int x, int y, + int width, int height, int dirty, int shadow) +{ + PyGimpPixelRgn *self; + int drw_width; + int drw_height; + + self = PyObject_NEW(PyGimpPixelRgn, &PyGimpPixelRgn_Type); + + if (self == NULL || drawable == NULL) + return NULL; + + drw_width = gimp_drawable_width(drawable->ID); + drw_height = gimp_drawable_height(drawable->ID); + + if(x < 0) x = 0; + if(y < 0) y = 0; + if(width < 0) width = drw_width - x; + if(height < 0) height = drw_height - y; + if(x >= drw_width) x = drw_width - 1; + if(y >= drw_height) y = drw_height - 1; + if(x + width > drw_width) width = drw_width - x; + if(y + height > drw_height) height = drw_height - y; + + gimp_pixel_rgn_init(&(self->pr), drawable->drawable, x, y, width, height, + dirty, shadow); + + self->drawable = drawable; + Py_INCREF(drawable); + + return (PyObject *)self; +} + + +static void +pr_dealloc(PyGimpPixelRgn *self) +{ + Py_DECREF(self->drawable); + PyObject_DEL(self); +} + +/* Code to access pr objects as mappings */ + +static Py_ssize_t +pr_length(PyObject *self) +{ + PyErr_SetString(pygimp_error, "Can't get size of pixel region"); + return -1; +} + +static PyObject * +pr_subscript(PyGimpPixelRgn *self, PyObject *key) +{ + GimpPixelRgn *pr = &(self->pr); + PyObject *x, *y; + Py_ssize_t x1, y1, x2, y2, xs, ys; + PyObject *ret; + + if (!PyTuple_Check(key) || PyTuple_Size(key) != 2) { + PyErr_SetString(PyExc_TypeError, "subscript must be a 2-tuple"); + return NULL; + } + + if (!PyArg_ParseTuple(key, "OO", &x, &y)) + return NULL; + + if (PyInt_Check(x)) { + x1 = PyInt_AsSsize_t(x); + + if (x1 < pr->x || x1 >= pr->x + pr->w) { + PyErr_SetString(PyExc_IndexError, "x subscript out of range"); + return NULL; + } + + if (PyInt_Check(y)) { + y1 = PyInt_AsSsize_t(y); + + if (y1 < pr->y || y1 >= pr->y + pr->h) { + PyErr_SetString(PyExc_IndexError, "y subscript out of range"); + return NULL; + } + + ret = PyString_FromStringAndSize(NULL, pr->bpp); + gimp_pixel_rgn_get_pixel(pr, (guchar*)PyString_AS_STRING(ret), + x1, y1); + + } else if (PySlice_Check(y)) { + if (PySlice_GetIndices((PySliceObject*)y, pr->y + pr->h, + &y1, &y2, &ys) || + y1 >= y2 || ys != 1) { + PyErr_SetString(PyExc_IndexError, "invalid y slice"); + return NULL; + } + + if(y1 == 0) + y1 = pr->y; + + if(y1 < pr->y || y2 < pr->y) { + PyErr_SetString(PyExc_IndexError, "y subscript out of range"); + return NULL; + } + + ret = PyString_FromStringAndSize(NULL, pr->bpp * (y2 - y1)); + gimp_pixel_rgn_get_col(pr, (guchar*)PyString_AS_STRING(ret), + x1, y1, y2-y1); + } + else { + PyErr_SetString(PyExc_TypeError, "invalid y subscript"); + return NULL; + } + } else if (PySlice_Check(x)) { + if (PySlice_GetIndices((PySliceObject *)x, pr->x + pr->w, + &x1, &x2, &xs) || + x1 >= x2 || xs != 1) { + PyErr_SetString(PyExc_IndexError, "invalid x slice"); + return NULL; + } + if (x1 == 0) + x1 = pr->x; + if(x1 < pr->x || x2 < pr->x) { + PyErr_SetString(PyExc_IndexError, "x subscript out of range"); + return NULL; + } + + if (PyInt_Check(y)) { + y1 = PyInt_AsSsize_t(y); + if (y1 < pr->y || y1 >= pr->y + pr->h) { + PyErr_SetString(PyExc_IndexError, "y subscript out of range"); + return NULL; + } + ret = PyString_FromStringAndSize(NULL, pr->bpp * (x2 - x1)); + gimp_pixel_rgn_get_row(pr, (guchar*)PyString_AS_STRING(ret), + x1, y1, x2 - x1); + + } else if (PySlice_Check(y)) { + if (PySlice_GetIndices((PySliceObject*)y, pr->y + pr->h, + &y1, &y2, &ys) || + y1 >= y2 || ys != 1) { + PyErr_SetString(PyExc_IndexError, "invalid y slice"); + return NULL; + } + + if(y1 == 0) + y1 = pr->y; + if(y1 < pr->y || y2 < pr->y) { + PyErr_SetString(PyExc_IndexError, "y subscript out of range"); + return NULL; + } + + ret = PyString_FromStringAndSize(NULL, + pr->bpp * (x2 - x1) * (y2 - y1)); + gimp_pixel_rgn_get_rect(pr, (guchar*)PyString_AS_STRING(ret), + x1, y1, x2 - x1, y2 - y1); + } + else { + PyErr_SetString(PyExc_TypeError, "invalid y subscript"); + return NULL; + } + + } else { + PyErr_SetString(PyExc_TypeError, "invalid x subscript"); + return NULL; + } + return ret; +} + +static int +pr_ass_sub(PyGimpPixelRgn *self, PyObject *v, PyObject *w) +{ + GimpPixelRgn *pr = &(self->pr); + PyObject *x, *y; + const guchar *buf; + Py_ssize_t len, x1, x2, xs, y1, y2, ys; + + if (w == NULL) { + PyErr_SetString(PyExc_TypeError, "can't delete subscripts"); + return -1; + } + + if (!PyString_Check(w)) { + PyErr_SetString(PyExc_TypeError, "must assign string to subscript"); + return -1; + } + + if (!PyTuple_Check(v) || PyTuple_Size(v) != 2) { + PyErr_SetString(PyExc_TypeError, "subscript must be a 2-tuple"); + return -1; + } + + if (!PyArg_ParseTuple(v, "OO", &x, &y)) + return -1; + + buf = (const guchar *)PyString_AsString(w); + len = PyString_Size(w); + if (!buf || len > INT_MAX) { + return -1; + } + + if (PyInt_Check(x)) { + x1 = PyInt_AsSsize_t(x); + if (x1 < pr->x || x1 >= pr->x + pr->w) { + PyErr_SetString(PyExc_IndexError, "x subscript out of range"); + return -1; + } + + if (PyInt_Check(y)) { + y1 = PyInt_AsSsize_t(y); + + if (y1 < pr->y || y1 >= pr->y + pr->h) { + PyErr_SetString(PyExc_IndexError, "y subscript out of range"); + return -1; + } + + if (len != pr->bpp) { + PyErr_SetString(PyExc_TypeError, "string is wrong length"); + return -1; + } + gimp_pixel_rgn_set_pixel(pr, buf, x1, y1); + + } else if (PySlice_Check(y)) { + if (PySlice_GetIndices((PySliceObject *)y, pr->y + pr->h, + &y1, &y2, &ys) || + y1 >= y2 || ys != 1) { + PyErr_SetString(PyExc_IndexError, "invalid y slice"); + return -1; + } + if (y1 == 0) + y1 = pr->y; + + if(y1 < pr->y || y2 < pr->y) { + PyErr_SetString(PyExc_IndexError, "y subscript out of range"); + return -1; + } + if (len != pr->bpp * (y2 - y1)) { + PyErr_SetString(PyExc_TypeError, "string is wrong length"); + return -1; + } + gimp_pixel_rgn_set_col(pr, buf, x1, y1, y2 - y1); + + } else { + PyErr_SetString(PyExc_IndexError,"invalid y subscript"); + return -1; + } + } else if (PySlice_Check(x)) { + if (PySlice_GetIndices((PySliceObject *)x, pr->x + pr->w, + &x1, &x2, &xs) || + x1 >= x2 || xs != 1) { + PyErr_SetString(PyExc_IndexError, "invalid x slice"); + return -1; + } + if(x1 == 0) + x1 = pr->x; + + if(x1 < pr->x || x2 < pr->x) { + PyErr_SetString(PyExc_IndexError, "x subscript out of range"); + return -1; + } + + if (PyInt_Check(y)) { + y1 = PyInt_AsSsize_t(y); + + if (y1 < pr->y || y1 >= pr->y + pr->h) { + PyErr_SetString(PyExc_IndexError, "y subscript out of range"); + return -1; + } + + if (len != pr->bpp * (x2 - x1)) { + PyErr_SetString(PyExc_TypeError, "string is wrong length"); + return -1; + } + gimp_pixel_rgn_set_row(pr, buf, x1, y1, x2 - x1); + + } else if (PySlice_Check(y)) { + if (PySlice_GetIndices((PySliceObject *)y, pr->y + pr->h, + &y1, &y2, &ys) || + y1 >= y2 || ys != 1) { + PyErr_SetString(PyExc_IndexError, "invalid y slice"); + return -1; + } + if (y1 == 0) + y1 = pr->y; + + if(y1 < pr->y || y2 < pr->y) { + PyErr_SetString(PyExc_IndexError, "y subscript out of range"); + return -1; + } + if (len != pr->bpp * (x2 - x1) * (y2 - y1)) { + PyErr_SetString(PyExc_TypeError, "string is wrong length"); + return -1; + } + gimp_pixel_rgn_set_rect(pr, buf, x1, y1, x2 - x1, y2 - y1); + + } else { + PyErr_SetString(PyExc_IndexError,"invalid y subscript"); + return -1; + } + } else { + PyErr_SetString(PyExc_TypeError, "invalid x subscript"); + return -1; + } + return 0; +} + +static PyMappingMethods pr_as_mapping = { + pr_length, /*mp_length*/ + (binaryfunc)pr_subscript, /*mp_subscript*/ + (objobjargproc)pr_ass_sub, /*mp_ass_subscript*/ +}; + +/* -------------------------------------------------------- */ + +static PyObject * +pr_get_drawable(PyGimpPixelRgn *self, void *closure) +{ + return pygimp_drawable_new(self->pr.drawable, 0); +} + +static PyObject * +pr_get_uint_field(PyGimpPixelRgn *self, void *closure) +{ + gint offset = GPOINTER_TO_INT(closure); + guint value; + gchar *addr; + + addr = (gchar *)&self->pr; + addr += offset; + value = *(guint *)addr; + + return PyInt_FromLong(value); +} + +static PyObject * +pr_get_dirty(PyGimpPixelRgn *self, void *closure) +{ + return PyBool_FromLong(self->pr.dirty); +} + +static PyObject * +pr_get_shadow(PyGimpPixelRgn *self, void *closure) +{ + return PyBool_FromLong(self->pr.shadow); +} + +#define OFF(x) GINT_TO_POINTER(offsetof(GimpPixelRgn, x)) +static PyGetSetDef pr_getsets[] = { + { "drawable", (getter)pr_get_drawable, 0, NULL }, + { "bpp", (getter)pr_get_uint_field, 0, NULL, OFF(bpp) }, + { "rowstride", (getter)pr_get_uint_field, 0, NULL, OFF(rowstride) }, + { "x", (getter)pr_get_uint_field, 0, NULL, OFF(x) }, + { "y", (getter)pr_get_uint_field, 0, NULL, OFF(y) }, + { "w", (getter)pr_get_uint_field, 0, NULL, OFF(w) }, + { "h", (getter)pr_get_uint_field, 0, NULL, OFF(h) }, + { "dirty", (getter)pr_get_dirty, 0, NULL }, + { "shadow", (getter)pr_get_shadow, 0, NULL }, + { NULL, (getter)0, (setter)0 }, +}; +#undef OFF + +static PyObject * +pr_repr(PyGimpPixelRgn *self) +{ + PyObject *s; + gchar *name; + + name = gimp_item_get_name(self->drawable->drawable->drawable_id); + s = PyString_FromFormat("<gimp.PixelRgn for drawable '%s'>", name); + g_free(name); + + return s; +} + +PyTypeObject PyGimpPixelRgn_Type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "gimp.PixelRgn", /* tp_name */ + sizeof(PyGimpPixelRgn), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)pr_dealloc, /* tp_dealloc */ + (printfunc)0, /* tp_print */ + (getattrfunc)0, /* tp_getattr */ + (setattrfunc)0, /* tp_setattr */ + (cmpfunc)0, /* tp_compare */ + (reprfunc)pr_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + &pr_as_mapping, /* tp_as_mapping */ + (hashfunc)0, /* tp_hash */ + (ternaryfunc)0, /* tp_call */ + (reprfunc)0, /* tp_str */ + (getattrofunc)0, /* tp_getattro */ + (setattrofunc)0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + NULL, /* Documentation string */ + (traverseproc)0, /* tp_traverse */ + (inquiry)0, /* tp_clear */ + (richcmpfunc)0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + (getiterfunc)0, /* tp_iter */ + (iternextfunc)0, /* tp_iternext */ + pr_methods, /* tp_methods */ + 0, /* tp_members */ + pr_getsets, /* tp_getset */ + (PyTypeObject *)0, /* tp_base */ + (PyObject *)0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)0, /* tp_init */ + (allocfunc)0, /* tp_alloc */ + (newfunc)0, /* tp_new */ +}; + +static PyObject * +pf_get_pixel(PyGimpPixelFetcher *self, PyObject *args, PyObject *kwargs) +{ + int x, y; + guchar pixel[4]; + static char *kwlist[] = { "x", "y", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "ii:get_pixel", kwlist, + &x, &y)) + return NULL; + + gimp_pixel_fetcher_get_pixel(self->pf, x, y, pixel); + + return PyString_FromStringAndSize((char *)pixel, self->bpp); +} + +static PyObject * +pf_put_pixel(PyGimpPixelFetcher *self, PyObject *args, PyObject *kwargs) +{ + int x, y, len; + guchar *pixel; + static char *kwlist[] = { "x", "y", "pixel", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "iis#:put_pixel", kwlist, + &x, &y, &pixel, &len)) + return NULL; + + if (len != self->bpp) { + PyErr_Format(PyExc_TypeError, "pixel must be %d bpp", self->bpp); + return NULL; + } + + gimp_pixel_fetcher_put_pixel(self->pf, x, y, pixel); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef pf_methods[] = { + {"get_pixel", (PyCFunction)pf_get_pixel, METH_VARARGS | METH_KEYWORDS}, + {"put_pixel", (PyCFunction)pf_put_pixel, METH_VARARGS | METH_KEYWORDS}, + {NULL, NULL} +}; + +static int +pf_length(PyGimpPixelFetcher *self) +{ + PyErr_SetString(pygimp_error, "Can't get size of pixel fetcher"); + return -1; +} + +static PyObject * +pf_subscript(PyGimpPixelFetcher *self, PyObject *key) +{ + PyObject *py_x, *py_y; + int x, y; + guchar pixel[4]; + + if (!PyTuple_Check(key) || PyTuple_Size(key) != 2) { + PyErr_SetString(PyExc_TypeError, "subscript must be a 2-tuple"); + return NULL; + } + + if (!PyArg_ParseTuple(key, "OO", &py_x, &py_y)) + return NULL; + + if (PyInt_Check(py_x)) { + if (PyInt_Check(py_y)) { + x = PyInt_AsLong(py_x); + y = PyInt_AsLong(py_y); + + gimp_pixel_fetcher_get_pixel(self->pf, x, y, pixel); + return PyString_FromStringAndSize((char *)pixel, self->bpp); + } else { + PyErr_SetString(PyExc_TypeError, "invalid y subscript"); + return NULL; + } + } else { + PyErr_SetString(PyExc_TypeError, "invalid x subscript"); + return NULL; + } +} + +static int +pf_ass_sub(PyGimpPixelFetcher *self, PyObject *v, PyObject *w) +{ + PyObject *py_x, *py_y; + int x, y, len; + guchar *pixel; + + if (w == NULL) { + PyErr_SetString(PyExc_TypeError, "can't delete subscripts"); + return -1; + } + + if (!PyString_Check(w)) { + PyErr_SetString(PyExc_TypeError, "must assign string to subscript"); + return -1; + } + + if (!PyTuple_Check(v) || PyTuple_Size(v) != 2) { + PyErr_SetString(PyExc_TypeError, "subscript must be a 2-tuple"); + return -1; + } + + if (!PyArg_ParseTuple(v, "OO", &py_x, &py_y)) + return -1; + + pixel = (guchar *)PyString_AsString(w); + len = PyString_Size(w); + + if (len != self->bpp) { + PyErr_Format(PyExc_TypeError, "pixel must be %d bpp", self->bpp); + return -1; + } + + if (PyInt_Check(py_x)) { + if (PyInt_Check(py_y)) { + x = PyInt_AsLong(py_x); + y = PyInt_AsLong(py_y); + + gimp_pixel_fetcher_put_pixel(self->pf, x, y, pixel); + return 0; + } else { + PyErr_SetString(PyExc_TypeError, "invalid y subscript"); + return -1; + } + } else { + PyErr_SetString(PyExc_TypeError, "invalid x subscript"); + return -1; + } +} + +static PyMappingMethods pf_as_mapping = { + (lenfunc)pf_length, + (binaryfunc)pf_subscript, + (objobjargproc)pf_ass_sub, +}; + +static PyObject * +pf_get_bg_color(PyGimpPixelFetcher *self, void *closure) +{ + return pygimp_rgb_new(&self->bg_color); +} + +static int +pf_set_bg_color(PyGimpPixelFetcher *self, PyObject *value, void *closure) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "cannot delete bg_color"); + return -1; + } + + if (!pygimp_rgb_from_pyobject(value, &self->bg_color)) + return -1; + + gimp_pixel_fetcher_set_bg_color(self->pf, &self->bg_color); + + return 0; +} + +static PyObject * +pf_get_edge_mode(PyGimpPixelFetcher *self, void *closure) +{ + return PyInt_FromLong(self->edge_mode); +} + +static int +pf_set_edge_mode(PyGimpPixelFetcher *self, PyObject *value, void *closure) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "cannot delete edge_mode"); + return -1; + } + + if (!PyInt_Check(value)) { + PyErr_SetString(PyExc_TypeError, "type mismatch"); + return -1; + } + + self->edge_mode = PyInt_AsLong(value); + + gimp_pixel_fetcher_set_edge_mode(self->pf, self->edge_mode); + + return 0; +} + +static PyGetSetDef pf_getsets[] = { + { "bg_color", (getter)pf_get_bg_color, (setter)pf_set_bg_color }, + { "edge_mode", (getter)pf_get_edge_mode, (setter)pf_set_edge_mode }, + { NULL, (getter)0, (setter)0 } +}; + +static void +pf_dealloc(PyGimpPixelFetcher *self) +{ + gimp_pixel_fetcher_destroy(self->pf); + + Py_XDECREF(self->drawable); + + PyObject_DEL(self); +} + +static PyObject * +pf_repr(PyGimpPixelFetcher *self) +{ + PyObject *s; + char *name; + + name = gimp_item_get_name(self->drawable->drawable->drawable_id); + + if (self->shadow) + s = PyString_FromFormat("<gimp.PixelFetcher for drawable '%s' (shadow)>", name); + else + s = PyString_FromFormat("<gimp.PixelFetcher for drawable '%s'>", name); + + g_free(name); + + return s; +} + +static int +pf_init(PyGimpPixelFetcher *self, PyObject *args, PyObject *kwargs) +{ + PyGimpDrawable *drw; + gboolean shadow = FALSE; + GimpRGB bg_color = { 0.0, 0.0, 0.0, 1.0 }; + GimpPixelFetcherEdgeMode edge_mode = GIMP_PIXEL_FETCHER_EDGE_NONE; + static char *kwlist[] = { "drawable", "shadow", "bg_color", "edge_mode", + NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "O!|iO&i:gimp.PixelFetcher.__init__", + kwlist, + &PyGimpDrawable_Type, &drw, &shadow, + pygimp_rgb_from_pyobject, &bg_color, + &edge_mode)) + return -1; + + if(!drw->drawable) + drw->drawable = gimp_drawable_get(drw->ID); + + self->pf = gimp_pixel_fetcher_new(drw->drawable, shadow); + + Py_INCREF(drw); + self->drawable = drw; + + self->shadow = shadow; + self->bg_color = bg_color; + self->edge_mode = edge_mode; + + self->bpp = gimp_drawable_bpp(drw->drawable->drawable_id); + + gimp_pixel_fetcher_set_bg_color(self->pf, &bg_color); + gimp_pixel_fetcher_set_edge_mode(self->pf, edge_mode); + + return 0; +} + +PyTypeObject PyGimpPixelFetcher_Type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "gimp.PixelFetcher", /* tp_name */ + sizeof(PyGimpPixelFetcher), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)pf_dealloc, /* tp_dealloc */ + (printfunc)0, /* tp_print */ + (getattrfunc)0, /* tp_getattr */ + (setattrfunc)0, /* tp_setattr */ + (cmpfunc)0, /* tp_compare */ + (reprfunc)pf_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + &pf_as_mapping, /* tp_as_mapping */ + (hashfunc)0, /* tp_hash */ + (ternaryfunc)0, /* tp_call */ + (reprfunc)0, /* tp_str */ + (getattrofunc)0, /* tp_getattro */ + (setattrofunc)0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + NULL, /* Documentation string */ + (traverseproc)0, /* tp_traverse */ + (inquiry)0, /* tp_clear */ + (richcmpfunc)0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + (getiterfunc)0, /* tp_iter */ + (iternextfunc)0, /* tp_iternext */ + pf_methods, /* tp_methods */ + 0, /* tp_members */ + pf_getsets, /* tp_getset */ + (PyTypeObject *)0, /* tp_base */ + (PyObject *)0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)pf_init, /* tp_init */ + (allocfunc)0, /* tp_alloc */ + (newfunc)0, /* tp_new */ +}; |