diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:30:19 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:30:19 +0000 |
commit | 5c1676dfe6d2f3c837a5e074117b45613fd29a72 (patch) | |
tree | cbffb45144febf451e54061db2b21395faf94bfe /plug-ins/pygimp/pygimp-drawable.c | |
parent | Initial commit. (diff) | |
download | gimp-upstream/2.10.34.tar.xz gimp-upstream/2.10.34.zip |
Adding upstream version 2.10.34.upstream/2.10.34upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'plug-ins/pygimp/pygimp-drawable.c')
-rw-r--r-- | plug-ins/pygimp/pygimp-drawable.c | 2459 |
1 files changed, 2459 insertions, 0 deletions
diff --git a/plug-ins/pygimp/pygimp-drawable.c b/plug-ins/pygimp/pygimp-drawable.c new file mode 100644 index 0000000..9134d9b --- /dev/null +++ b/plug-ins/pygimp/pygimp-drawable.c @@ -0,0 +1,2459 @@ +/* -*- 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 NO_IMPORT_PYGOBJECT +#include <pygobject.h> + +#define GIMP_DISABLE_DEPRECATION_WARNINGS +#include "pygimp.h" + +#define NO_IMPORT_PYGIMPCOLOR +#include "pygimpcolor-api.h" + +#include <glib-object.h> + +#include <gegl.h> + +static void +ensure_drawable(PyGimpDrawable *self) +{ + if (!self->drawable) + self->drawable = gimp_drawable_get(self->ID); +} + +static PyObject * +drw_flush(PyGimpDrawable *self) +{ + ensure_drawable(self); + + gimp_drawable_flush(self->drawable); + + Py_INCREF(Py_None); + return Py_None; +} + + +static PyObject * +drw_update(PyGimpDrawable *self, PyObject *args) +{ + int x, y; + unsigned int w, h; + + if (!PyArg_ParseTuple(args, "iiii:update", &x, &y, &w, &h)) + return NULL; + + if (!gimp_drawable_update(self->ID, x, y, w, h)) { + PyErr_Format(pygimp_error, + "could not update drawable (ID %d): " + "x=%d, y=%d, w=%d, h=%d", + self->ID, x, y, (int)w, (int)h); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + + +static PyObject * +drw_merge_shadow(PyGimpDrawable *self, PyObject *args, PyObject *kwargs) +{ + gboolean undo = FALSE; + + static char *kwlist[] = { "undo", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:merge_shadow", kwlist, + &undo)) + return NULL; + + if (!gimp_drawable_merge_shadow(self->ID, undo)) { + PyErr_Format(pygimp_error, + "could not merge the shadow buffer on drawable (ID %d)", + self->ID); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +drw_free_shadow(PyGimpDrawable *self) +{ + if (!gimp_drawable_free_shadow(self->ID)) { + PyErr_Format(pygimp_error, "could not free shadow tiles on drawable (ID %d)", + self->ID); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +drw_fill(PyGimpDrawable *self, PyObject *args, PyObject *kwargs) +{ + int fill = GIMP_FILL_FOREGROUND; + + static char *kwlist[] = { "fill", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:fill", kwlist, &fill)) + return NULL; + + if (!gimp_drawable_fill(self->ID, fill)) { + PyErr_Format(pygimp_error, + "could not fill drawable (ID %d) with fill mode %d", + self->ID, fill); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + + +static PyObject * +drw_get_tile(PyGimpDrawable *self, PyObject *args, PyObject *kwargs) +{ + GimpTile *t; + int shadow, row, col; + + static char *kwlist[] = { "shadow", "row", "col", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iii:get_tile", kwlist, + &shadow, &row, &col)) + return NULL; + + ensure_drawable(self); + + if(row < 0 || row >= self->drawable->ntile_rows || + col < 0 || col >= self->drawable->ntile_cols) { + Py_INCREF(Py_None); + return Py_None; + } + + t = gimp_drawable_get_tile(self->drawable, shadow, row, col); + return pygimp_tile_new(t, self); +} + +static PyObject * +drw_get_tile2(PyGimpDrawable *self, PyObject *args, PyObject *kwargs) +{ + GimpTile *t; + int shadow, x, y, row, col; + + static char *kwlist[] = { "shadow", "x", "y", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iii:get_tile2", kwlist, + &shadow, &x ,&y)) + return NULL; + + ensure_drawable(self); + if(x < 0 || x >= self->drawable->width || + y < 0 || y >= self->drawable->height) { + Py_INCREF(Py_None); + return Py_None; + } + + col = x / gimp_tile_width (); + row = y / gimp_tile_height (); + + t = gimp_drawable_get_tile(self->drawable, shadow, row, col); + return pygimp_tile_new(t, self); +} + +static PyObject * +drw_get_pixel_rgn(PyGimpDrawable *self, PyObject *args, PyObject *kwargs) +{ + int x, y, width, height, dirty = 1, shadow = 0; + + static char *kwlist[] = { "x", "y", "width", "height", "dirty", "shadow", + NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "iiii|ii:get_pixel_rgn", kwlist, + &x, &y, &width, &height, &dirty, &shadow)) + return NULL; + + ensure_drawable(self); + + return pygimp_pixel_rgn_new(self, x, y, width, height, dirty, shadow); +} + +static PyObject * +drw_offset(PyGimpDrawable *self, PyObject *args, PyObject *kwargs) +{ + int wrap_around; + GimpOffsetType fill_type; + int offset_x, offset_y; + + static char *kwlist[] = { "wrap_around", "fill_type", + "offset_x", "offset_y", + NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iiii:offset", kwlist, + &wrap_around, &fill_type, + &offset_x, &offset_y)) + return NULL; + + if (!gimp_drawable_offset(self->ID, wrap_around, fill_type, + offset_x, offset_y)) { + PyErr_Format(pygimp_error, + "could not offset drawable (ID %d) by x: %d, y: %d", + self->ID, offset_x, offset_y); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +drw_parasite_find(PyGimpDrawable *self, PyObject *args) +{ + char *name; + + if (!PyArg_ParseTuple(args, "s:parasite_find", &name)) + return NULL; + + return pygimp_parasite_new(gimp_item_get_parasite(self->ID, name)); +} + +static PyObject * +drw_parasite_attach(PyGimpDrawable *self, PyObject *args) +{ + PyGimpParasite *parasite; + + if (!PyArg_ParseTuple(args, "O!:parasite_attach", &PyGimpParasite_Type, + ¶site)) + return NULL; + + if (!gimp_item_attach_parasite(self->ID, parasite->para)) { + PyErr_Format(pygimp_error, + "could not attach parasite '%s' on drawable (ID %d)", + gimp_parasite_name(parasite->para), self->ID); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +drw_attach_new_parasite(PyGimpDrawable *self, PyObject *args, PyObject *kwargs) +{ + char *name; + int flags, size; + guint8 *data; + GimpParasite *parasite; + gboolean success; + + static char *kwlist[] = { "name", "flags", "data", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "sis#:attach_new_parasite", kwlist, + &name, &flags, &data, &size)) + return NULL; + + parasite = gimp_parasite_new (name, + flags, size + 1, data); + success = gimp_item_attach_parasite (self->ID, parasite); + gimp_parasite_free (parasite); + + if (!success) { + PyErr_Format(pygimp_error, + "could not attach new parasite '%s' to drawable (ID %d)", + name, self->ID); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +drw_parasite_detach(PyGimpDrawable *self, PyObject *args) +{ + char *name; + if (!PyArg_ParseTuple(args, "s:detach_parasite", &name)) + return NULL; + + if (!gimp_item_detach_parasite(self->ID, name)) { + PyErr_Format(pygimp_error, + "could not detach parasite '%s' from drawable (ID %d)", + name, self->ID); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +drw_parasite_list(PyGimpDrawable *self) +{ + gint num_parasites; + gchar **parasites; + PyObject *ret; + gint i; + + parasites = gimp_item_get_parasite_list(self->ID, &num_parasites); + + ret = PyTuple_New(num_parasites); + + for (i = 0; i < num_parasites; i++) + PyTuple_SetItem(ret, i, PyString_FromString(parasites[i])); + + g_strfreev(parasites); + return ret; +} + +static PyObject * +drw_get_pixel(PyGimpDrawable *self, PyObject *args) +{ + int x, y; + int num_channels, i; + guint8 *pixel; + PyObject *ret; + + if (!PyArg_ParseTuple(args, "(ii):get_pixel", &x, &y)) { + PyErr_Clear(); + if (!PyArg_ParseTuple(args, "ii:get_pixel", &x, &y)) + return NULL; + } + + pixel = gimp_drawable_get_pixel(self->ID, x, y, &num_channels); + + if (!pixel) { + PyErr_Format(pygimp_error, + "could not get pixel (%d, %d) on drawable (ID %d)", + x, y, self->ID); + return NULL; + } + + ret = PyTuple_New(num_channels); + + for (i = 0; i < num_channels; i++) + PyTuple_SetItem(ret, i, PyInt_FromLong(pixel[i])); + + g_free(pixel); + + return ret; +} + +static PyObject * +drw_set_pixel(PyGimpDrawable *self, PyObject *args) +{ + int x, y; + int num_channels, i, val; + guint8 *pixel; + PyObject *seq, *item; + gboolean is_string, error = TRUE; + + if (!PyArg_ParseTuple(args, "(ii)O:set_pixel", &x, &y, &seq)) { + PyErr_Clear(); + if (!PyArg_ParseTuple(args, "iiO:set_pixel", &x, &y, &seq)) + return NULL; + } + + if (!PyString_Check(seq)) { + if (!PySequence_Check(seq)) { + PyErr_SetString(PyExc_TypeError, + "pixel values must be a sequence"); + return NULL; + } + + is_string = FALSE; + + num_channels = PySequence_Length(seq); + pixel = g_new(guint8, num_channels); + + for (i = 0; i < num_channels; i++) { + item = PySequence_GetItem(seq, i); + + if (!PyInt_Check(item)) { + PyErr_SetString(PyExc_TypeError, + "pixel values must be a sequence of ints"); + goto out; + } + + val = PyInt_AsLong(item); + + if (val < 0 || val > 255) { + PyErr_SetString(PyExc_TypeError, + "pixel values must be between 0 and 255"); + goto out; + } + + pixel[i] = val; + } + } else { + is_string = TRUE; + + num_channels = PyString_Size(seq); + pixel = (guint8 *)PyString_AsString(seq); + } + + error = !gimp_drawable_set_pixel(self->ID, x, y, num_channels, pixel); + + if (error) + PyErr_Format(pygimp_error, + "could not set %d-element pixel (%d, %d) on " + "drawable (ID %d)", + num_channels, x, y, self->ID); + +out: + if (!is_string) + g_free(pixel); + + if (!error) { + Py_INCREF(Py_None); + return Py_None; + } else + return NULL; +} + +static PyObject * +drw_mask_intersect(PyGimpDrawable *self) +{ + int x, y, width, height; + + if (!gimp_drawable_mask_intersect(self->ID, &x, &y, &width, &height)) { + PyErr_Format(pygimp_error, + "could not get selection bounds of drawable (ID %d)", + self->ID); + return NULL; + } + + return Py_BuildValue("(iiii)", x, y, width, height); +} + +static PyObject * +transform_result(PyGimpDrawable *self, gint32 id, const char *err_desc) +{ + if (id == self->ID) { + Py_INCREF(self); + return (PyObject *)self; + } else if (id != -1) { + return pygimp_drawable_new(NULL, id); + } else { + PyErr_Format(pygimp_error, "could not %s drawable (ID %d)", + err_desc, self->ID); + return NULL; + } +} + +static PyObject * +drw_transform_flip(PyGimpDrawable *self, PyObject *args, PyObject *kwargs) +{ + double x0, y0, x1, y1; + int transform_direction, interpolation, recursion_level = 3; + gboolean supersample = FALSE, clip_result = FALSE; + gint32 id; + + static char *kwlist[] = { "x0", "y0", "x1", "y1", + "transform_direction", "interpolation", + "supersample", "recursion_level", + "clip_result", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "ddddii|iii:transform_flip", kwlist, + &x0, &y0, &x1, &y1, &transform_direction, + &interpolation, &supersample, + &recursion_level, &clip_result)) + return NULL; + + gimp_context_push (); + gimp_context_set_transform_direction (transform_direction); + gimp_context_set_interpolation (interpolation); + gimp_context_set_transform_resize (clip_result); + + id = gimp_item_transform_flip (self->ID, x0, y0, x1, y1); + + gimp_context_pop (); + + return transform_result(self, id, "flip"); +} + +static PyObject * +drw_transform_flip_simple(PyGimpDrawable *self, PyObject *args, PyObject *kwargs) +{ + int flip_type; + gboolean auto_center, clip_result = FALSE; + double axis; + gint32 id; + + static char *kwlist[] = { "flip_type", "auto_center", "axis", + "clip_result", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "iid|i:transform_flip_simple", kwlist, + &flip_type, &auto_center, &axis, + &clip_result)) + return NULL; + + gimp_context_push (); + gimp_context_set_transform_resize (clip_result); + + id = gimp_item_transform_flip_simple (self->ID, flip_type, + auto_center, axis); + + gimp_context_pop (); + + return transform_result(self, id, "flip"); +} + +static PyObject * +drw_transform_flip_default(PyGimpDrawable *self, PyObject *args, PyObject *kwargs) +{ + double x0, y0, x1, y1; + gboolean interpolate = FALSE, clip_result = FALSE; + gint32 id; + + static char *kwlist[] = { "x0", "y0", "x1", "y1", "interpolate", + "clip_result", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "dddd|ii:transform_flip_default", kwlist, + &x0, &y0, &x1, &y1, &interpolate, + &clip_result)) + return NULL; + + gimp_context_push (); + if (! interpolate) + gimp_context_set_interpolation (GIMP_INTERPOLATION_NONE); + gimp_context_set_transform_resize (clip_result); + + id = gimp_item_transform_flip (self->ID, x0, y0, x1, y1); + + gimp_context_pop (); + + return transform_result(self, id, "flip"); +} + +static PyObject * +drw_transform_perspective(PyGimpDrawable *self, PyObject *args, PyObject *kwargs) +{ + double x0, y0, x1, y1, x2, y2, x3, y3; + int transform_direction, interpolation, recursion_level = 3; + gboolean supersample = FALSE, clip_result = FALSE; + gint32 id; + + static char *kwlist[] = { "x0", "y0", "x1", "y1", "x2", "y2", "x3", "y3", + "transform_direction", "interpolation", + "supersample", "recursion_level", + "clip_result", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "ddddddddii|iii:transform_perspective", + kwlist, + &x0, &y0, &x1, &y1, &x2, &y2, &x3, &y3, + &transform_direction, &interpolation, + &supersample, &recursion_level, + &clip_result)) + return NULL; + + gimp_context_push (); + gimp_context_set_transform_direction (transform_direction); + gimp_context_set_interpolation (interpolation); + gimp_context_set_transform_resize (clip_result); + + id = gimp_item_transform_perspective (self->ID, + x0, y0, x1, y1, x2, y2, x3, y3); + + gimp_context_pop (); + + return transform_result(self, id, "apply perspective transform to"); +} + +static PyObject * +drw_transform_perspective_default(PyGimpDrawable *self, PyObject *args, PyObject *kwargs) +{ + double x0, y0, x1, y1, x2, y2, x3, y3; + gboolean interpolate = FALSE, clip_result = FALSE; + gint32 id; + + static char *kwlist[] = { "x0", "y0", "x1", "y1", "x2", "y2", "x3", "y3", + "interpolate", "clip_result", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "dddddddd|ii:transform_perspective_default", + kwlist, + &x0, &y0, &x1, &y1, &x2, &y2, &x3, &y3, + &interpolate, &clip_result)) + return NULL; + + gimp_context_push (); + if (! interpolate) + gimp_context_set_interpolation (GIMP_INTERPOLATION_NONE); + gimp_context_set_transform_resize (clip_result); + + id = gimp_item_transform_perspective (self->ID, + x0, y0, x1, y1, x2, y2, x3, y3); + + gimp_context_pop (); + + return transform_result(self, id, "apply perspective transform to"); +} + +static PyObject * +drw_transform_rotate(PyGimpDrawable *self, PyObject *args, PyObject *kwargs) +{ + double angle; + gboolean auto_center, supersample = FALSE, clip_result = FALSE; + int center_x, center_y, transform_direction, interpolation, + recursion_level = 3; + gint32 id; + + static char *kwlist[] = { "angle", "auto_center", "center_x", "center_y", + "transform_direction", "interpolation", + "supersample", "recursion_level", + "clip_result", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "diiiii|iii:transform_rotate", kwlist, + &angle, &auto_center, ¢er_x, ¢er_y, + &transform_direction, &interpolation, + &supersample, &recursion_level, + &clip_result)) + return NULL; + + gimp_context_push (); + gimp_context_set_transform_direction (transform_direction); + gimp_context_set_interpolation (interpolation); + gimp_context_set_transform_resize (clip_result); + + id = gimp_item_transform_rotate (self->ID, angle, auto_center, + center_x, center_y); + + gimp_context_pop (); + + return transform_result(self, id, "rotate"); +} + +static PyObject * +drw_transform_rotate_simple(PyGimpDrawable *self, PyObject *args, PyObject *kwargs) +{ + int rotate_type, center_x, center_y; + gboolean auto_center, clip_result = FALSE; + gint32 id; + + static char *kwlist[] = { "rotate_type", "auto_center", + "center_x", "center_y", + "clip_result", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "iiii|i:transform_rotate_simple", kwlist, + &rotate_type, &auto_center, + ¢er_x, ¢er_y, + &clip_result)) + return NULL; + + gimp_context_push (); + gimp_context_set_transform_resize (clip_result); + + id = gimp_item_transform_rotate_simple (self->ID, rotate_type, + auto_center, + center_x, center_y); + + gimp_context_pop (); + + return transform_result(self, id, "rotate"); +} + +static PyObject * +drw_transform_rotate_default(PyGimpDrawable *self, PyObject *args, PyObject *kwargs) +{ + double angle; + gboolean auto_center, interpolate = FALSE, clip_result = FALSE; + int center_x, center_y; + gint32 id; + + static char *kwlist[] = { "angle", "auto_center", "center_x", "center_y", + "interpolate", "clip_result", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "dddd|ii:transform_rotate_default", kwlist, + &angle, &auto_center, ¢er_x, ¢er_y, + &interpolate, &clip_result)) + return NULL; + + gimp_context_push (); + if (! interpolate) + gimp_context_set_interpolation (GIMP_INTERPOLATION_NONE); + gimp_context_set_transform_resize (clip_result); + + id = gimp_item_transform_rotate (self->ID, angle, auto_center, + center_x, center_y); + + gimp_context_pop (); + + return transform_result(self, id, "rotate"); +} + +static PyObject * +drw_transform_scale(PyGimpDrawable *self, PyObject *args, PyObject *kwargs) +{ + double x0, y0, x1, y1; + int transform_direction, interpolation, recursion_level = 3; + gboolean supersample = FALSE, clip_result = FALSE; + gint32 id; + + static char *kwlist[] = { "x0", "y0", "x1", "y1", + "transform_direction", "interpolation", + "supersample", "recursion_level", + "clip_result", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "ddddii|iii:transform_scale", kwlist, + &x0, &y0, &x1, &y1, &transform_direction, + &interpolation, &supersample, + &recursion_level, &clip_result)) + return NULL; + + gimp_context_push (); + gimp_context_set_transform_direction (transform_direction); + gimp_context_set_interpolation (interpolation); + gimp_context_set_transform_resize (clip_result); + + id = gimp_item_transform_scale (self->ID, x0, y0, x1, y1); + + gimp_context_pop (); + + return transform_result(self, id, "scale"); +} + +static PyObject * +drw_transform_scale_default(PyGimpDrawable *self, PyObject *args, PyObject *kwargs) +{ + double x0, y0, x1, y1; + gboolean interpolate = FALSE, clip_result = FALSE; + gint32 id; + + static char *kwlist[] = { "x0", "y0", "x1", "y1", "interpolate", + "clip_result", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "dddd|ii:transform_scale_default", kwlist, + &x0, &y0, &x1, &y1, &interpolate, + &clip_result)) + return NULL; + + gimp_context_push (); + if (! interpolate) + gimp_context_set_interpolation (GIMP_INTERPOLATION_NONE); + gimp_context_set_transform_resize (clip_result); + + id = gimp_item_transform_scale (self->ID, x0, y0, x1, y1); + + gimp_context_pop (); + + return transform_result(self, id, "scale"); +} + +static PyObject * +drw_transform_shear(PyGimpDrawable *self, PyObject *args, PyObject *kwargs) +{ + int shear_type, transform_direction, interpolation, recursion_level = 3; + double magnitude; + gboolean supersample = FALSE, clip_result = FALSE; + gint32 id; + + static char *kwlist[] = { "shear_type", "magnitude", + "transform_direction", "interpolation", + "supersample", "recursion_level", + "clip_result", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "idii|iii:transform_shear", kwlist, + &shear_type, &magnitude, + &transform_direction, &interpolation, + &supersample, &recursion_level, + &clip_result)) + return NULL; + + gimp_context_push (); + gimp_context_set_transform_direction (transform_direction); + gimp_context_set_interpolation (interpolation); + gimp_context_set_transform_resize (clip_result); + + id = gimp_item_transform_shear (self->ID, shear_type, magnitude); + + gimp_context_pop (); + + return transform_result(self, id, "shear"); +} + +static PyObject * +drw_transform_shear_default(PyGimpDrawable *self, PyObject *args, PyObject *kwargs) +{ + int shear_type; + double magnitude; + gboolean interpolate = FALSE, clip_result = FALSE; + gint32 id; + + static char *kwlist[] = { "shear_type", "magnitude", "interpolate", + "clip_result", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "id|ii:transform_shear_default", kwlist, + &shear_type, &magnitude, &interpolate, + &clip_result)) + return NULL; + + gimp_context_push (); + if (! interpolate) + gimp_context_set_interpolation (GIMP_INTERPOLATION_NONE); + gimp_context_set_transform_resize (clip_result); + + id = gimp_item_transform_shear (self->ID, shear_type, magnitude); + + gimp_context_pop (); + + return transform_result(self, id, "shear"); +} + +static PyObject * +drw_transform_2d(PyGimpDrawable *self, PyObject *args, PyObject *kwargs) +{ + double source_x, source_y, scale_x, scale_y, angle, dest_x, dest_y; + int transform_direction, interpolation, recursion_level = 3; + gboolean supersample = FALSE, clip_result = FALSE; + gint32 id; + + static char *kwlist[] = { "source_x", "source_y", "scale_x", "scale_y", + "angle", "dest_x", "dest_y", + "transform_direction", "interpolation", + "supersample", "recursion_level", + "clip_result", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "dddddddii|iii:transform_2d", kwlist, + &source_x, &source_y, &scale_x, &scale_y, + &angle, &dest_x, &dest_y, + &transform_direction, &interpolation, + &supersample, &recursion_level, + &clip_result)) + return NULL; + + gimp_context_push (); + gimp_context_set_transform_direction (transform_direction); + gimp_context_set_interpolation (interpolation); + gimp_context_set_transform_resize (clip_result); + + id = gimp_item_transform_2d (self->ID, source_x, source_y, + scale_x, scale_y, angle, dest_x, dest_y); + + gimp_context_pop (); + + return transform_result(self, id, "apply 2d transform to"); +} + +static PyObject * +drw_transform_2d_default(PyGimpDrawable *self, PyObject *args, PyObject *kwargs) +{ + double source_x, source_y, scale_x, scale_y, angle, dest_x, dest_y; + gboolean interpolate = FALSE, clip_result = FALSE; + gint32 id; + + static char *kwlist[] = { "source_x", "source_y", "scale_x", "scale_y", + "angle", "dest_x", "dest_y", "interpolate", + "clip_result", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "ddddddd|ii:transform_2d_default", kwlist, + &source_x, &source_y, &scale_x, &scale_y, + &angle, &dest_x, &dest_y, &interpolate, + &clip_result)) + return NULL; + + gimp_context_push (); + if (! interpolate) + gimp_context_set_interpolation (GIMP_INTERPOLATION_NONE); + gimp_context_set_transform_resize (clip_result); + + id = gimp_item_transform_2d (self->ID, source_x, source_y, + scale_x, scale_y, angle, dest_x, dest_y); + + gimp_context_pop (); + + return transform_result(self, id, "apply 2d transform to"); +} + +static PyObject * +drw_transform_matrix(PyGimpDrawable *self, PyObject *args, PyObject *kwargs) +{ + double coeff_0_0, coeff_0_1, coeff_0_2, + coeff_1_0, coeff_1_1, coeff_1_2, + coeff_2_0, coeff_2_1, coeff_2_2; + int transform_direction, interpolation, recursion_level = 3; + gboolean supersample = FALSE, clip_result = FALSE; + gint32 id; + + static char *kwlist[] = { "coeff_0_0", "coeff_0_1", "coeff_0_2", + "coeff_1_0", "coeff_1_1", "coeff_1_2", + "coeff_2_0", "coeff_2_1", "coeff_2_2", + "transform_direction", "interpolation", + "supersample", "recursion_level", + "clip_result", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "dddddddddii|iii:transform_matrix", kwlist, + &coeff_0_0, &coeff_0_1, &coeff_0_2, + &coeff_1_0, &coeff_1_1, &coeff_1_2, + &coeff_2_0, &coeff_2_1, &coeff_2_2, + &transform_direction, &interpolation, + &supersample, &recursion_level, + &clip_result)) + return NULL; + + gimp_context_push (); + gimp_context_set_transform_direction (transform_direction); + gimp_context_set_interpolation (interpolation); + gimp_context_set_transform_resize (clip_result); + + id = gimp_item_transform_matrix (self->ID, + coeff_0_0, coeff_0_1, coeff_0_2, + coeff_1_0, coeff_1_1, coeff_1_2, + coeff_2_0, coeff_2_1, coeff_2_2); + + gimp_context_pop (); + + return transform_result(self, id, "apply 2d matrix transform to"); +} + +static PyObject * +drw_transform_matrix_default(PyGimpDrawable *self, PyObject *args, PyObject *kwargs) +{ + double coeff_0_0, coeff_0_1, coeff_0_2, + coeff_1_0, coeff_1_1, coeff_1_2, + coeff_2_0, coeff_2_1, coeff_2_2; + gboolean interpolate = FALSE, clip_result = FALSE; + gint32 id; + + static char *kwlist[] = { "coeff_0_0", "coeff_0_1", "coeff_0_2", + "coeff_1_0", "coeff_1_1", "coeff_1_2", + "coeff_2_0", "coeff_2_1", "coeff_2_2", + "interpolate", "clip_result", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "ddddddddd|ii:transform_matrix_default", + kwlist, + &coeff_0_0, &coeff_0_1, &coeff_0_2, + &coeff_1_0, &coeff_1_1, &coeff_1_2, + &coeff_2_0, &coeff_2_1, &coeff_2_2, + &interpolate, &clip_result)) + return NULL; + + gimp_context_push (); + if (! interpolate) + gimp_context_set_interpolation (GIMP_INTERPOLATION_NONE); + gimp_context_set_transform_resize (clip_result); + + id = gimp_item_transform_matrix (self->ID, + coeff_0_0, coeff_0_1, coeff_0_2, + coeff_1_0, coeff_1_1, coeff_1_2, + coeff_2_0, coeff_2_1, coeff_2_2); + + gimp_context_pop (); + + return transform_result(self, id, "apply 2d matrix transform to"); +} + +static PyObject * +drw_get_data(PyGimpDrawable *self, PyObject *args, PyObject *kwargs) +{ + static char *kwlist[] = { "format", NULL }; + gchar *format = "RGBA float"; + const Babl *bbl_format; + void *output_buffer; + GeglBuffer *buffer; + int bpp; + Py_ssize_t size; + PyObject *buffer_data, *ret; + PyObject *array_module; + PyObject *array_type; + char array_data_type; + + if (!PyArg_ParseTupleAndKeywords (args, kwargs, + "|s:get_data", + kwlist, &format + )) + return NULL; + + if (g_str_has_suffix (format, "double")) { + array_data_type = 'd'; + } else if (g_str_has_suffix (format, "float")) { + array_data_type = 'f'; + } + else if (g_str_has_suffix (format, "u16")) { + array_data_type = 'H'; + } else if (g_str_has_suffix (format, "u8")) { + array_data_type = 'B'; + } else { + PyErr_Warn (PyExc_Warning, + "Could not find appropriate data format - returning raw bytes"); + array_data_type = 'B'; + } + + bbl_format = babl_format (format); + bpp = babl_format_get_bytes_per_pixel (bbl_format); + ensure_drawable(self); + buffer = gimp_drawable_get_buffer (self->ID); + size = bpp * self->drawable->width * self->drawable->height; + output_buffer = g_malloc ((gsize) size); + if (output_buffer == NULL) { + return PyErr_NoMemory(); + } + gegl_buffer_get (buffer, + GEGL_RECTANGLE (0, 0, self->drawable->width, self->drawable->height), + 1.0, + bbl_format, + output_buffer, + GEGL_AUTO_ROWSTRIDE, + GEGL_ABYSS_NONE); + buffer_data = PyString_FromStringAndSize (output_buffer, size); + + array_module = PyImport_ImportModule ("array"); + if (!array_module) { + PyErr_SetString (pygimp_error, "could not import array module"); + return NULL; + } + + array_type = PyObject_GetAttrString (array_module, "array"); + Py_DECREF(array_module); + if (!array_type) { + PyErr_SetString (pygimp_error, "could not get array.array type"); + return NULL; + } + + ret = PyObject_CallFunction (array_type, "cO", array_data_type, buffer_data); + if (!ret) { + PyErr_SetString (pygimp_error, "could not create array object"); + return NULL; + } + + Py_DECREF (buffer_data); + g_free (output_buffer); + + return ret; +} + + +/* for inclusion with the methods of layer and channel objects */ +static PyMethodDef drw_methods[] = { + {"flush", (PyCFunction)drw_flush, METH_NOARGS}, + {"update", (PyCFunction)drw_update, METH_VARARGS}, + {"merge_shadow", (PyCFunction)drw_merge_shadow, METH_VARARGS | METH_KEYWORDS}, + {"free_shadow", (PyCFunction)drw_free_shadow, METH_NOARGS}, + {"fill", (PyCFunction)drw_fill, METH_VARARGS | METH_KEYWORDS}, + {"get_tile", (PyCFunction)drw_get_tile, METH_VARARGS | METH_KEYWORDS}, + {"get_tile2", (PyCFunction)drw_get_tile2, METH_VARARGS | METH_KEYWORDS}, + {"get_pixel_rgn", (PyCFunction)drw_get_pixel_rgn, METH_VARARGS | METH_KEYWORDS}, + {"get_data", (PyCFunction)drw_get_data, METH_VARARGS | METH_KEYWORDS, + "Takes a BABL format string, returns a Python array.array object"}, + {"offset", (PyCFunction)drw_offset, METH_VARARGS | METH_KEYWORDS}, + {"parasite_find", (PyCFunction)drw_parasite_find, METH_VARARGS}, + {"parasite_attach", (PyCFunction)drw_parasite_attach, METH_VARARGS}, + {"attach_new_parasite",(PyCFunction)drw_attach_new_parasite,METH_VARARGS | METH_KEYWORDS}, + {"parasite_detach", (PyCFunction)drw_parasite_detach, METH_VARARGS}, + {"parasite_list", (PyCFunction)drw_parasite_list, METH_VARARGS}, + {"get_pixel", (PyCFunction)drw_get_pixel, METH_VARARGS}, + {"set_pixel", (PyCFunction)drw_set_pixel, METH_VARARGS}, + {"mask_intersect", (PyCFunction)drw_mask_intersect, METH_NOARGS}, + {"transform_flip", (PyCFunction)drw_transform_flip, METH_VARARGS | METH_KEYWORDS}, + {"transform_flip_simple", (PyCFunction)drw_transform_flip_simple, METH_VARARGS | METH_KEYWORDS}, + {"transform_flip_default", (PyCFunction)drw_transform_flip_default, METH_VARARGS | METH_KEYWORDS}, + {"transform_perspective", (PyCFunction)drw_transform_perspective, METH_VARARGS | METH_KEYWORDS}, + {"transform_perspective_default", (PyCFunction)drw_transform_perspective_default, METH_VARARGS | METH_KEYWORDS}, + {"transform_rotate", (PyCFunction)drw_transform_rotate, METH_VARARGS | METH_KEYWORDS}, + {"transform_rotate_simple", (PyCFunction)drw_transform_rotate_simple, METH_VARARGS | METH_KEYWORDS}, + {"transform_rotate_default", (PyCFunction)drw_transform_rotate_default, METH_VARARGS | METH_KEYWORDS}, + {"transform_scale", (PyCFunction)drw_transform_scale, METH_VARARGS | METH_KEYWORDS}, + {"transform_scale_default", (PyCFunction)drw_transform_scale_default, METH_VARARGS | METH_KEYWORDS}, + {"transform_shear", (PyCFunction)drw_transform_shear, METH_VARARGS | METH_KEYWORDS}, + {"transform_shear_default", (PyCFunction)drw_transform_shear_default, METH_VARARGS | METH_KEYWORDS}, + {"transform_2d", (PyCFunction)drw_transform_2d, METH_VARARGS | METH_KEYWORDS}, + {"transform_2d_default", (PyCFunction)drw_transform_2d_default, METH_VARARGS | METH_KEYWORDS}, + {"transform_matrix", (PyCFunction)drw_transform_matrix, METH_VARARGS | METH_KEYWORDS}, + {"transform_matrix_default", (PyCFunction)drw_transform_matrix_default, METH_VARARGS | METH_KEYWORDS}, + {NULL, NULL, 0} +}; + +static PyObject * +drw_get_ID(PyGimpDrawable *self, void *closure) +{ + return PyInt_FromLong(self->ID); +} + +static PyObject * +drw_get_name(PyGimpDrawable *self, void *closure) +{ + return PyString_FromString(gimp_item_get_name(self->ID)); +} + +static int +drw_set_name(PyGimpDrawable *self, PyObject *value, void *closure) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "cannot delete name"); + return -1; + } + + if (!PyString_Check(value) && !PyUnicode_Check(value)) { + PyErr_SetString(PyExc_TypeError, "type mismatch"); + return -1; + } + + gimp_item_set_name(self->ID, PyString_AsString(value)); + + return 0; +} + +static PyObject * +drw_get_bpp(PyGimpDrawable *self, void *closure) +{ + return PyInt_FromLong(gimp_drawable_bpp(self->ID)); +} + +static PyObject * +drw_get_has_alpha(PyGimpDrawable *self, void *closure) +{ + return PyBool_FromLong(gimp_drawable_has_alpha(self->ID)); +} + +static PyObject * +drw_get_height(PyGimpDrawable *self, void *closure) +{ + return PyInt_FromLong(gimp_drawable_height(self->ID)); +} + +static PyObject * +drw_get_image(PyGimpDrawable *self, void *closure) +{ + return pygimp_image_new(gimp_item_get_image(self->ID)); +} + +static PyObject * +drw_get_is_rgb(PyGimpDrawable *self, void *closure) +{ + return PyBool_FromLong(gimp_drawable_is_rgb(self->ID)); +} + +static PyObject * +drw_get_is_gray(PyGimpDrawable *self, void *closure) +{ + return PyBool_FromLong(gimp_drawable_is_gray(self->ID)); +} + +static PyObject * +drw_get_is_indexed(PyGimpDrawable *self, void *closure) +{ + return PyBool_FromLong(gimp_drawable_is_indexed(self->ID)); +} + +static PyObject * +drw_get_is_layer_mask(PyGimpDrawable *self, void *closure) +{ + return PyBool_FromLong(gimp_item_is_layer_mask(self->ID)); +} + +static PyObject * +drw_get_mask_bounds(PyGimpDrawable *self, void *closure) +{ + gint x1, y1, x2, y2; + + gimp_drawable_mask_bounds(self->ID, &x1, &y1, &x2, &y2); + return Py_BuildValue("(iiii)", x1, y1, x2, y2); +} + +static PyObject * +drw_get_mask_intersect(PyGimpDrawable *self, void *closure) +{ + gint x, y, w, h; + + if(!gimp_drawable_mask_intersect(self->ID, &x, &y, &w, &h)) + return Py_BuildValue(""); + return Py_BuildValue("(iiii)", x, y, w, h); +} + +static PyObject * +drw_get_offsets(PyGimpDrawable *self, void *closure) +{ + gint x, y; + + gimp_drawable_offsets(self->ID, &x, &y); + + return Py_BuildValue("(ii)", x, y); +} + +static PyObject * +drw_get_type(PyGimpDrawable *self, void *closure) +{ + return PyInt_FromLong(gimp_drawable_type(self->ID)); +} + +static PyObject * +drw_get_type_with_alpha(PyGimpDrawable *self, void *closure) +{ + return PyInt_FromLong(gimp_drawable_type_with_alpha(self->ID)); +} + +static PyObject * +drw_get_width(PyGimpDrawable *self, void *closure) +{ + return PyInt_FromLong(gimp_drawable_width(self->ID)); +} + +static PyObject * +drw_get_linked(PyGimpDrawable *self, void *closure) +{ + return PyBool_FromLong(gimp_item_get_linked(self->ID)); +} + +static int +drw_set_linked(PyGimpDrawable *self, PyObject *value, void *closure) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "cannot delete linked"); + return -1; + } + + if (!PyInt_Check(value)) { + PyErr_SetString(PyExc_TypeError, "type mismatch"); + return -1; + } + + gimp_item_set_linked(self->ID, PyInt_AsLong(value)); + + return 0; +} + +static PyObject * +drw_get_tattoo(PyGimpDrawable *self, void *closure) +{ + return PyInt_FromLong(gimp_item_get_tattoo(self->ID)); +} + +static int +drw_set_tattoo(PyGimpDrawable *self, PyObject *value, void *closure) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "cannot delete tattoo"); + return -1; + } + + if (!PyInt_Check(value)) { + PyErr_SetString(PyExc_TypeError, "type mismatch"); + return -1; + } + + gimp_item_set_tattoo(self->ID, PyInt_AsLong(value)); + + return 0; +} + +static PyObject * +drw_get_visible(PyGimpDrawable *self, void *closure) +{ + return PyBool_FromLong(gimp_item_get_visible(self->ID)); +} + +static int +drw_set_visible(PyGimpDrawable *self, PyObject *value, void *closure) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "cannot delete visible"); + return -1; + } + + if (!PyInt_Check(value)) { + PyErr_SetString(PyExc_TypeError, "type mismatch"); + return -1; + } + + gimp_item_set_visible(self->ID, PyInt_AsLong(value)); + + return 0; +} + +static PyGetSetDef drw_getsets[] = { + { "ID", (getter)drw_get_ID, (setter)0 }, + { "name", (getter)drw_get_name, (setter)drw_set_name }, + { "bpp", (getter)drw_get_bpp, (setter)0 }, + { "has_alpha", (getter)drw_get_has_alpha, (setter)0 }, + { "height", (getter)drw_get_height, (setter)0 }, + { "image", (getter)drw_get_image, (setter)0 }, + { "is_rgb", (getter)drw_get_is_rgb, (setter)0 }, + { "is_gray", (getter)drw_get_is_gray, (setter)0 }, + { "is_grey", (getter)drw_get_is_gray, (setter)0 }, + { "is_indexed", (getter)drw_get_is_indexed, (setter)0 }, + { "is_layer_mask", (getter)drw_get_is_layer_mask, (setter)0 }, + { "mask_bounds", (getter)drw_get_mask_bounds, (setter)0 }, + { "mask_intersect", (getter)drw_get_mask_intersect, (setter)0 }, + { "offsets", (getter)drw_get_offsets, (setter)0 }, + { "type", (getter)drw_get_type, (setter)0 }, + { "type_with_alpha", (getter)drw_get_type_with_alpha, (setter)0 }, + { "width", (getter)drw_get_width, (setter)0 }, + { "linked", (getter)drw_get_linked, (setter)drw_set_linked }, + { "tattoo", (getter)drw_get_tattoo, (setter)drw_set_tattoo }, + { "visible", (getter)drw_get_visible, (setter)drw_set_visible }, + { NULL, (getter)0, (setter)0 } +}; + +static void +drw_dealloc(PyGimpDrawable *self) +{ + if (self->drawable) + gimp_drawable_detach(self->drawable); + + PyObject_DEL(self); +} + +static PyObject * +drw_repr(PyGimpDrawable *self) +{ + PyObject *s; + gchar *name; + + name = gimp_item_get_name(self->ID); + s = PyString_FromFormat("<gimp.Drawable '%s'>", name ? name : "(null)"); + g_free(name); + + return s; +} + +static int +drw_cmp(PyGimpDrawable *self, PyGimpDrawable *other) +{ + if (self->ID == other->ID) + return 0; + if (self->ID > other->ID) + return -1; + return 1; +} + +PyTypeObject PyGimpDrawable_Type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "gimp.Drawable", /* tp_name */ + sizeof(PyGimpDrawable), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)drw_dealloc, /* tp_dealloc */ + (printfunc)0, /* tp_print */ + (getattrfunc)0, /* tp_getattr */ + (setattrfunc)0, /* tp_setattr */ + (cmpfunc)drw_cmp, /* tp_compare */ + (reprfunc)drw_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* 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 */ + drw_methods, /* tp_methods */ + 0, /* tp_members */ + drw_getsets, /* tp_getset */ + &PyGimpItem_Type, /* 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 */ +}; + + +PyObject * +pygimp_drawable_new(GimpDrawable *drawable, gint32 ID) +{ + PyObject *self; + + if (drawable != NULL) + ID = drawable->drawable_id; + + if (!gimp_item_is_valid(ID)) { + Py_INCREF(Py_None); + return Py_None; + } + + /* create the appropriate object type */ + if (gimp_item_is_layer(ID)) + self = pygimp_layer_new(ID); + else + self = pygimp_channel_new(ID); + + if (self == NULL) + return NULL; + + if (PyObject_TypeCheck(self, &PyGimpDrawable_Type)) + ((PyGimpDrawable *)self)->drawable = drawable; + + return self; +} + +/* End of code for Drawable objects */ +/* -------------------------------------------------------- */ + + +static PyObject * +lay_copy(PyGimpLayer *self, PyObject *args, PyObject *kwargs) +{ + int nreturn_vals; + GimpParam *return_vals; + gboolean add_alpha = FALSE; + gint32 id = -1; + + static char *kwlist[] = { "add_alpha", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:copy", kwlist, + &add_alpha)) + return NULL; + + return_vals = gimp_run_procedure("gimp-layer-copy", + &nreturn_vals, + GIMP_PDB_LAYER, self->ID, + GIMP_PDB_INT32, add_alpha, + GIMP_PDB_END); + + if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS) + id = return_vals[1].data.d_layer; + else + PyErr_Format(pygimp_error, + "could not create new layer copy from layer (ID %d)", + self->ID); + + gimp_destroy_params(return_vals, nreturn_vals); + + return id != -1 ? pygimp_layer_new(id) : NULL; +} + + +static PyObject * +lay_add_alpha(PyGimpLayer *self) +{ + if (!gimp_layer_add_alpha(self->ID)) { + PyErr_Format(pygimp_error, "could not add alpha to layer (ID %d)", + self->ID); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + + +static PyObject * +lay_add_mask(PyGimpLayer *self, PyObject *args) +{ + PyGimpChannel *mask; + + if (!PyArg_ParseTuple(args, "O!:add_mask", &PyGimpChannel_Type, &mask)) + return NULL; + + if (!gimp_layer_add_mask(self->ID, mask->ID)) { + PyErr_Format(pygimp_error, + "could not add mask (ID %d) to layer (ID %d)", + mask->ID, self->ID); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +lay_create_mask(PyGimpLayer *self, PyObject *args) +{ + int type; + gint32 id; + + if (!PyArg_ParseTuple(args, "i:create_mask", &type)) + return NULL; + + id = gimp_layer_create_mask(self->ID, type); + + if (id == -1) { + PyErr_Format(pygimp_error, + "could not create mask of type %d on layer (ID %d)", + type, self->ID); + return NULL; + } + + return pygimp_channel_new(id); +} + +static PyObject * +lay_remove_mask(PyGimpLayer *self, PyObject *args) +{ + int mode; + + if (!PyArg_ParseTuple(args, "i:remove_mask", &mode)) + return NULL; + + if (!gimp_layer_remove_mask(self->ID, mode)) { + PyErr_Format(pygimp_error, + "could not remove mask from layer (ID %d) with mode %d", + self->ID, mode); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + + +static PyObject * +lay_resize(PyGimpLayer *self, PyObject *args, PyObject *kwargs) +{ + unsigned int new_h, new_w; + int offs_x = 0, offs_y = 0; + + static char *kwlist[] = { "width", "height", "offset_x", "offset_y", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii|ii:resize", kwlist, + &new_w, &new_h, &offs_x, &offs_y)) + return NULL; + + if (!gimp_layer_resize(self->ID, new_w, new_h, offs_x, offs_y)) { + PyErr_Format(pygimp_error, + "could not resize layer (ID %d) to size %dx%d " + "(offset %d, %d)", + self->ID, new_w, new_h, offs_x, offs_y); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +lay_resize_to_image_size(PyGimpLayer *self) +{ + if (!gimp_layer_resize_to_image_size(self->ID)) { + PyErr_Format(pygimp_error, + "could not resize layer (ID %d) to image size", + self->ID); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +lay_scale(PyGimpLayer *self, PyObject *args, PyObject *kwargs) +{ + int new_width, new_height; + int interpolation = -1; + gboolean local_origin = FALSE; + + static char *kwlist[] = { "width", "height", "local_origin", + "interpolation", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii|ii:scale", kwlist, + &new_width, &new_height, + &local_origin, &interpolation)) + return NULL; + + if (interpolation != -1) { + gimp_context_push(); + gimp_context_set_interpolation(interpolation); + } + + if (!gimp_layer_scale(self->ID, new_width, new_height, local_origin)) { + PyErr_Format(pygimp_error, + "could not scale layer (ID %d) to size %dx%d", + self->ID, new_width, new_height); + if (interpolation != -1) { + gimp_context_pop(); + } + return NULL; + } + + if (interpolation != -1) { + gimp_context_pop(); + } + + Py_INCREF(Py_None); + return Py_None; +} + + +static PyObject * +lay_translate(PyGimpLayer *self, PyObject *args, PyObject *kwargs) +{ + int offs_x, offs_y; + + static char *kwlist[] = { "offset_x", "offset_y", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii:translate", kwlist, + &offs_x, &offs_y)) + return NULL; + + if (!gimp_item_transform_translate(self->ID, offs_x, offs_y)) { + PyErr_Format(pygimp_error, + "could not translate layer (ID %d) to offset %d, %d", + self->ID, offs_x, offs_y); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + + +static PyObject * +lay_set_offsets(PyGimpLayer *self, PyObject *args, PyObject *kwargs) +{ + int offs_x, offs_y; + + static char *kwlist[] = { "offset_x", "offset_y", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii:set_offsets", kwlist, + &offs_x, &offs_y)) + return NULL; + + if (!gimp_layer_set_offsets(self->ID, offs_x, offs_y)) { + PyErr_Format(pygimp_error, + "could not set offset %d, %d on layer (ID %d)", + offs_x, offs_y, self->ID); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef lay_methods[] = { + {"copy", (PyCFunction)lay_copy, METH_VARARGS | METH_KEYWORDS}, + {"add_alpha", (PyCFunction)lay_add_alpha, METH_NOARGS}, + {"add_mask", (PyCFunction)lay_add_mask, METH_VARARGS}, + {"create_mask", (PyCFunction)lay_create_mask, METH_VARARGS}, + {"remove_mask", (PyCFunction)lay_remove_mask, METH_VARARGS}, + {"resize", (PyCFunction)lay_resize, METH_VARARGS | METH_KEYWORDS}, + {"resize_to_image_size", (PyCFunction)lay_resize_to_image_size, METH_NOARGS}, + {"scale", (PyCFunction)lay_scale, METH_VARARGS | METH_KEYWORDS}, + {"translate", (PyCFunction)lay_translate, METH_VARARGS | METH_KEYWORDS}, + {"set_offsets", (PyCFunction)lay_set_offsets, METH_VARARGS | METH_KEYWORDS}, + {NULL, NULL} /* sentinel */ +}; + +static PyObject * +lay_get_is_floating_sel(PyGimpLayer *self, void *closure) +{ + return PyBool_FromLong(gimp_layer_is_floating_sel(self->ID)); +} + +static PyObject * +lay_get_mask(PyGimpLayer *self, void *closure) +{ + gint32 id = gimp_layer_get_mask(self->ID); + + if (id == -1) { + Py_INCREF(Py_None); + return Py_None; + } + + return pygimp_channel_new(id); +} + +static PyObject * +lay_get_apply_mask(PyGimpLayer *self, void *closure) +{ + return PyBool_FromLong(gimp_layer_get_apply_mask(self->ID)); +} + +static int +lay_set_apply_mask(PyGimpLayer *self, PyObject *value, void *closure) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "cannot delete apply_mask"); + return -1; + } + + if (!PyInt_Check(value)) { + PyErr_SetString(PyExc_TypeError, "type mismatch"); + return -1; + } + + if (!gimp_layer_set_apply_mask(self->ID, PyInt_AsLong(value))) { + PyErr_Format(pygimp_error, + "could not set layer mask on layer (ID %d)", + self->ID); + return -1; + } + + return 0; +} + +static PyObject * +lay_get_edit_mask(PyGimpLayer *self, void *closure) +{ + return PyBool_FromLong(gimp_layer_get_edit_mask(self->ID)); +} + +static int +lay_set_edit_mask(PyGimpLayer *self, PyObject *value, void *closure) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "cannot delete edit_mask"); + return -1; + } + + if (!PyInt_Check(value)) { + PyErr_SetString(PyExc_TypeError, "type mismatch"); + return -1; + } + + if (!gimp_layer_set_edit_mask(self->ID, PyInt_AsLong(value))) { + PyErr_Format(pygimp_error, + "could not set layer mask active on layer (ID %d)", + self->ID); + return -1; + } + + return 0; +} + +static PyObject * +lay_get_mode(PyGimpLayer *self, void *closure) +{ + return PyInt_FromLong(gimp_layer_get_mode(self->ID)); +} + +static int +lay_set_mode(PyGimpLayer *self, PyObject *value, void *closure) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "cannot delete mode"); + return -1; + } + + if (!PyInt_Check(value)) { + PyErr_SetString(PyExc_TypeError, "type mismatch"); + return -1; + } + + if (!gimp_layer_set_mode(self->ID, PyInt_AsLong(value))) { + PyErr_Format(pygimp_error, "could not set mode on layer (ID %d)", + self->ID); + return -1; + } + + return 0; +} + +static PyObject * +lay_get_opacity(PyGimpLayer *self, void *closure) +{ + return PyFloat_FromDouble(gimp_layer_get_opacity(self->ID)); +} + +static int +lay_set_opacity(PyGimpLayer *self, PyObject *value, void *closure) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "cannot delete opacity"); + return -1; + } + + if (!PyFloat_Check(value)) { + PyErr_SetString(PyExc_TypeError, "type mismatch"); + return -1; + } + + if (!gimp_layer_set_opacity(self->ID, PyFloat_AsDouble(value))) { + PyErr_Format(pygimp_error, "could not set opacity on layer (ID %d)", + self->ID); + return -1; + } + + return 0; +} + +static PyObject * +lay_get_lock_alpha(PyGimpLayer *self, void *closure) +{ + return PyBool_FromLong(gimp_layer_get_lock_alpha(self->ID)); +} + +static int +lay_set_lock_alpha(PyGimpLayer *self, PyObject *value, void *closure) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, + "cannot delete lock_alpha"); + return -1; + } + + if (!PyInt_Check(value)) { + PyErr_SetString(PyExc_TypeError, "type mismatch"); + return -1; + } + + if (!gimp_layer_set_lock_alpha(self->ID, PyInt_AsLong(value))) { + PyErr_Format(pygimp_error, + "could not set lock alpha setting on layer (ID %d)", + self->ID); + return -1; + } + + return 0; +} + +static PyObject * +lay_get_show_mask(PyGimpLayer *self, void *closure) +{ + return PyBool_FromLong(gimp_layer_get_show_mask(self->ID)); +} + +static int +lay_set_show_mask(PyGimpLayer *self, PyObject *value, void *closure) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "cannot delete show_mask"); + return -1; + } + + if (!PyInt_Check(value)) { + PyErr_SetString(PyExc_TypeError, "type mismatch"); + return -1; + } + + if (!gimp_layer_set_show_mask(self->ID, PyInt_AsLong(value))) { + PyErr_Format(pygimp_error, + "could not set mask visibility on layer (ID %d)", + self->ID); + return -1; + } + + return 0; +} + +static PyObject * +lay_get_preserve_trans(PyGimpLayer *self, void *closure) +{ + if (PyErr_Warn(PyExc_DeprecationWarning, "use lock_alpha attribute") < 0) + return NULL; + + return lay_get_lock_alpha(self, closure); +} + +static int +lay_set_preserve_trans(PyGimpLayer *self, PyObject *value, void *closure) +{ + if (PyErr_Warn(PyExc_DeprecationWarning, "use lock_alpha attribute") < 0) + return -1; + + return lay_set_lock_alpha(self, value, closure); +} + +static PyGetSetDef lay_getsets[] = { + { "is_floating_sel", (getter)lay_get_is_floating_sel, (setter)0 }, + { "mask", (getter)lay_get_mask, (setter)0 }, + { "apply_mask", (getter)lay_get_apply_mask, (setter)lay_set_apply_mask }, + { "edit_mask", (getter)lay_get_edit_mask, (setter)lay_set_edit_mask }, + { "mode", (getter)lay_get_mode, (setter)lay_set_mode }, + { "opacity", (getter)lay_get_opacity, (setter)lay_set_opacity }, + { "lock_alpha", (getter)lay_get_lock_alpha, (setter)lay_set_lock_alpha }, + { "show_mask", (getter)lay_get_show_mask, (setter)lay_set_show_mask }, + { "preserve_trans", (getter)lay_get_preserve_trans, + (setter)lay_set_preserve_trans }, + { NULL, (getter)0, (setter)0 } +}; + +static PyObject * +lay_repr(PyGimpLayer *self) +{ + PyObject *s; + gchar *name; + + name = gimp_item_get_name(self->ID); + s = PyString_FromFormat("<gimp.Layer '%s'>", name ? name : "(null)"); + g_free(name); + + return s; +} + +static int +lay_init(PyGimpLayer *self, PyObject *args, PyObject *kwargs) +{ + PyGimpImage *img; + char *name; + unsigned int width, height; + GimpImageType type = GIMP_RGB_IMAGE; + double opacity = 100.0; + GimpLayerMode mode = GIMP_LAYER_MODE_NORMAL; + + + if (!PyArg_ParseTuple(args, "O!sii|idi:gimp.Layer.__init__", + &PyGimpImage_Type, &img, &name, &width, &height, + &type, &opacity, &mode)) + return -1; + + self->ID = gimp_layer_new(img->ID, name, width, height, + type, opacity, mode); + + self->drawable = NULL; + + if (self->ID < 0) { + PyErr_Format(pygimp_error, + "could not create %dx%d layer '%s' of type %d on " + "image (ID %d)", + width, height, name, type, img->ID); + return -1; + } + + return 0; +} + +PyTypeObject PyGimpLayer_Type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "gimp.Layer", /* tp_name */ + sizeof(PyGimpLayer), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)drw_dealloc, /* tp_dealloc */ + (printfunc)0, /* tp_print */ + (getattrfunc)0, /* tp_getattr */ + (setattrfunc)0, /* tp_setattr */ + (cmpfunc)drw_cmp, /* tp_compare */ + (reprfunc)lay_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* 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 */ + lay_methods, /* tp_methods */ + 0, /* tp_members */ + lay_getsets, /* tp_getset */ + &PyGimpDrawable_Type, /* tp_base */ + (PyObject *)0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)lay_init, /* tp_init */ + (allocfunc)0, /* tp_alloc */ + (newfunc)0, /* tp_new */ +}; + +PyObject * +pygimp_layer_new(gint32 ID) +{ + PyGimpLayer *self; + + if (!gimp_item_is_valid(ID) || !gimp_item_is_layer(ID)) { + Py_INCREF(Py_None); + return Py_None; + } + + + if (gimp_item_is_group(ID)) { + self = PyObject_NEW(PyGimpGroupLayer, &PyGimpGroupLayer_Type); + } + else { + self = PyObject_NEW(PyGimpLayer, &PyGimpLayer_Type); + } + + if (self == NULL) + return NULL; + + self->ID = ID; + self->drawable = NULL; + + return (PyObject *)self; +} + +/* End of code for Layer objects */ +/* -------------------------------------------------------- */ + +/* Since this help will primarily be seen from within + * GIMP's Python console, we should make it fit in that + * window's default size. + */ + +#define GROUPLAYER_DOC "" \ +"gimp.GroupLayer(img, name="", opacity=100.0, " \ +"mode=gimp.LAYER_MODE_NORMAL)\n" \ +"\n" \ +" Creates a new GroupLayer object that has to be \n" \ +"subsequently added to an image. Use Image.add_layer \n" \ +"or pdb.gimp_image_insert_layer calls to do that. \n" \ + +static PyMethodDef grouplay_methods[] = { + {NULL, NULL} /* sentinel */ +}; + +static PyObject * +grouplay_get_layers(PyGimpGroupLayer *self, void *closure) +{ + gint32 *layers; + gint n_layers, i; + PyObject *ret; + + layers = gimp_item_get_children(self->ID, &n_layers); + + ret = PyList_New(n_layers); + + for (i = 0; i < n_layers; i++) + PyList_SetItem(ret, i, pygimp_group_layer_new(layers[i])); + + g_free(layers); + + return ret; +} + +static PyGetSetDef grouplay_getsets[] = { + { "layers", (getter)grouplay_get_layers, (setter)0 }, + { NULL, (getter)0, (setter)0 } +}; + +static PyObject * +grouplay_repr(PyGimpLayer *self) +{ + PyObject *s; + gchar *name; + + name = gimp_item_get_name(self->ID); + s = PyString_FromFormat("<gimp.GroupLayer '%s'>", name ? name : "(null)"); + g_free(name); + + return s; +} + +static int +grouplay_init(PyGimpLayer *self, PyObject *args, PyObject *kwargs) +{ + PyGimpImage *img; + char *name = "Layer Group"; + GimpImageType type = GIMP_RGB_IMAGE; + double opacity = 100.0; + GimpLayerMode mode = GIMP_LAYER_MODE_NORMAL; + + + if (!PyArg_ParseTuple(args, "O!|sdi:gimp.Layer.__init__", + &PyGimpImage_Type, &img, &name, + &opacity, &mode)) + return -1; + + self->ID = gimp_layer_group_new(img->ID); + + self->drawable = NULL; + + if (self->ID < 0) { + PyErr_Format(pygimp_error, + "could not create layer group '%s' of type %d on " + "image (ID %d)", + name, type, img->ID); + return -1; + } + + gimp_layer_set_opacity(self->ID, opacity); + gimp_layer_set_mode(self->ID, mode); + + gimp_item_set_name(self->ID, name); + + return 0; +} + +PyTypeObject PyGimpGroupLayer_Type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "gimp.GroupLayer", /* tp_name */ + sizeof(PyGimpGroupLayer), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)drw_dealloc, /* tp_dealloc */ + (printfunc)0, /* tp_print */ + (getattrfunc)0, /* tp_getattr */ + (setattrfunc)0, /* tp_setattr */ + (cmpfunc)drw_cmp, /* tp_compare */ + (reprfunc)grouplay_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* 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 */ + GROUPLAYER_DOC, /* 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 */ + grouplay_methods, /* tp_methods */ + 0, /* tp_members */ + grouplay_getsets, /* tp_getset */ + &PyGimpLayer_Type, /* tp_base */ + (PyObject *)0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)grouplay_init, /* tp_init */ + (allocfunc)0, /* tp_alloc */ + (newfunc)0, /* tp_new */ +}; + +PyObject * +pygimp_group_layer_new(gint32 ID) +{ + PyGimpGroupLayer *self; + + if (!gimp_item_is_valid(ID) || !gimp_item_is_layer(ID)) { + Py_INCREF(Py_None); + return Py_None; + } + + if (!gimp_item_is_group(ID)) { + return pygimp_layer_new(ID); + } + + self = PyObject_NEW(PyGimpGroupLayer, &PyGimpGroupLayer_Type); + + if (self == NULL) + return NULL; + + self->ID = ID; + self->drawable = NULL; + + return (PyObject *)self; +} + +/* End of code for GroupLayer objects */ +/* -------------------------------------------------------- */ + + +static PyObject * +chn_copy(PyGimpChannel *self) +{ + gint32 id; + + id = gimp_channel_copy(self->ID); + + if (id == -1) { + PyErr_Format(pygimp_error, + "could not create new channel copy from channel (ID %d)", + self->ID); + return NULL; + } + + return pygimp_channel_new(id); +} + +static PyObject * +chn_combine_masks(PyGimpChannel *self, PyObject *args, PyObject *kwargs) +{ + PyGimpChannel *channel2; + GimpChannelOps operation; + int offx = 0, offy = 0; + + static char *kwlist[] = { "channel", "operation", "offset_x", "offset_y", + NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!i|ii:combine_masks", + kwlist, + &PyGimpChannel_Type, &channel2, + &operation, &offx, &offy)) + return NULL; + + if (!gimp_channel_combine_masks(self->ID, channel2->ID, operation, + offx, offy)) { + PyErr_Format(pygimp_error, + "could not combine masks with channels (ID %d and ID %d) " + "with operation %d, offset %d, %d", + self->ID, channel2->ID, operation, offx, offy); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef chn_methods[] = { + {"copy", (PyCFunction)chn_copy, METH_NOARGS}, + {"combine_masks", (PyCFunction)chn_combine_masks, METH_VARARGS}, + {NULL, NULL} /* sentinel */ +}; + +static PyObject * +chn_get_color(PyGimpChannel *self, void *closure) +{ + GimpRGB rgb; + + if (!gimp_channel_get_color(self->ID, &rgb)) { + PyErr_Format(pygimp_error, + "could not get compositing color of channel (ID %d)", + self->ID); + return NULL; + } + + return pygimp_rgb_new(&rgb); +} + +static int +chn_set_color(PyGimpChannel *self, PyObject *value, void *closure) +{ + guchar r, g, b; + GimpRGB tmprgb, *rgb; + + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "cannot delete color"); + return -1; + } + + if (pygimp_rgb_check(value)) { + rgb = pyg_boxed_get(value, GimpRGB); + } else if (PyTuple_Check(value) && + PyArg_ParseTuple(value, "(BBB)", &r, &g, &b)) { + gimp_rgb_set_uchar(&tmprgb, r, g, b); + rgb = &tmprgb; + } else { + PyErr_Clear(); + PyErr_SetString(PyExc_TypeError, "type mismatch"); + return -1; + } + + if (!gimp_channel_set_color(self->ID, rgb)) { + PyErr_Format(pygimp_error, + "could not set compositing color on channel (ID %d)", + self->ID); + return -1; + } + + return 0; +} + +static PyObject * +chn_get_opacity(PyGimpLayer *self, void *closure) +{ + return PyFloat_FromDouble(gimp_channel_get_opacity(self->ID)); +} + +static int +chn_set_opacity(PyGimpLayer *self, PyObject *value, void *closure) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "cannot delete opacity"); + return -1; + } + + if (!PyFloat_Check(value)) { + PyErr_SetString(PyExc_TypeError, "type mismatch"); + return -1; + } + + if (!gimp_channel_set_opacity(self->ID, PyFloat_AsDouble(value))) { + PyErr_Format(pygimp_error, + "could not set opacity on channel (ID %d)", + self->ID); + return -1; + } + + return 0; +} + +static PyObject * +chn_get_show_masked(PyGimpLayer *self, void *closure) +{ + return PyBool_FromLong(gimp_channel_get_show_masked(self->ID)); +} + +static int +chn_set_show_masked(PyGimpLayer *self, PyObject *value, void *closure) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "cannot delete show_masked"); + return -1; + } + + if (!PyInt_Check(value)) { + PyErr_SetString(PyExc_TypeError, "type mismatch"); + return -1; + } + + if (!gimp_channel_set_show_masked(self->ID, PyInt_AsLong(value))) { + PyErr_Format(pygimp_error, + "could not set composite method on channel (ID %d)", + self->ID); + return -1; + } + + return 0; +} + +static PyGetSetDef chn_getsets[] = { + { "color", (getter)chn_get_color, (setter)chn_set_color }, + { "colour", (getter)chn_get_color, (setter)chn_set_color }, + { "opacity", (getter)chn_get_opacity, (setter)chn_set_opacity }, + { "show_masked", (getter)chn_get_show_masked, (setter)chn_set_show_masked}, + { NULL, (getter)0, (setter)0 } +}; + +static PyObject * +chn_repr(PyGimpChannel *self) +{ + PyObject *s; + gchar *name; + + name = gimp_item_get_name(self->ID); + s = PyString_FromFormat("<gimp.Channel '%s'>", name ? name : "(null)"); + g_free(name); + + return s; +} + +static int +chn_init(PyGimpChannel *self, PyObject *args, PyObject *kwargs) +{ + PyGimpImage *img; + PyObject *color; + char *name; + unsigned int width, height, r, g, b; + double opacity; + GimpRGB tmprgb, *rgb; + + if (!PyArg_ParseTuple(args, "O!siidO:gimp.Channel.__init__", + &PyGimpImage_Type, &img, &name, &width, + &height, &opacity, &color)) + return -1; + + if (pygimp_rgb_check(color)) { + rgb = pyg_boxed_get(color, GimpRGB); + } else if (PyTuple_Check(color) && + PyArg_ParseTuple(color, "(BBB)", &r, &g, &b)) { + gimp_rgb_set_uchar(&tmprgb, r, g, b); + rgb = &tmprgb; + } else { + PyErr_Clear(); + PyErr_SetString(PyExc_TypeError, "type mismatch"); + return -1; + } + + self->ID = gimp_channel_new(img->ID, name, width, height, opacity, rgb); + + self->drawable = NULL; + + if (self->ID < 0) { + PyErr_Format(pygimp_error, + "could not create %dx%d channel '%s' on image (ID %d)", + width, height, name, img->ID); + return -1; + } + + return 0; +} + +PyTypeObject PyGimpChannel_Type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "gimp.Channel", /* tp_name */ + sizeof(PyGimpChannel), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)drw_dealloc, /* tp_dealloc */ + (printfunc)0, /* tp_print */ + (getattrfunc)0, /* tp_getattr */ + (setattrfunc)0, /* tp_setattr */ + (cmpfunc)drw_cmp, /* tp_compare */ + (reprfunc)chn_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* 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 */ + chn_methods, /* tp_methods */ + 0, /* tp_members */ + chn_getsets, /* tp_getset */ + &PyGimpDrawable_Type, /* tp_base */ + (PyObject *)0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)chn_init, /* tp_init */ + (allocfunc)0, /* tp_alloc */ + (newfunc)0, /* tp_new */ +}; + +PyObject * +pygimp_channel_new(gint32 ID) +{ + PyGimpChannel *self; + + if (!gimp_item_is_valid(ID) || !gimp_item_is_channel(ID)) { + Py_INCREF(Py_None); + return Py_None; + } + + self = PyObject_NEW(PyGimpChannel, &PyGimpChannel_Type); + + if (self == NULL) + return NULL; + + self->ID = ID; + self->drawable = NULL; + + return (PyObject *)self; +} |