/****************************************************************** Copyright 2000 by Object Craft P/L, Melbourne, Australia. All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of Object Craft is not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. OBJECT CRAFT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL OBJECT CRAFT BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************/ #include "paint.h" static char image_fill__doc__[] = "fill(path, color)\n" "\n" "Fill the path with the specified color"; static PyObject *image_fill(ImageObj *self, PyObject *args) { PathObj *path_obj; art_u32 color; ArtSVP *svp; if (!PyArg_ParseTuple(args, "O!i", &PathType, (PyObject*)&path_obj, &color)) return NULL; svp = art_svp_from_vpath(path_obj->vpath); art_rgb_svp_alpha(svp, 0, 0, self->width, self->height, color, self->buf, self->width * 3, NULL); art_svp_free(svp); Py_INCREF(Py_None); return Py_None; } static char image_stroke__doc__[] = "stroke(path, color, line_width, join = JOIN_MITER, cap = CAP_BUTT, miter_limit = 4, flatness = 0.25)\n" "\n" "Draw the path in the color, line width, and other constraints"; static PyObject *image_stroke(ImageObj *self, PyObject *args) { PathObj *path_obj; art_u32 color; ArtPathStrokeJoinType join = ART_PATH_STROKE_JOIN_MITER; ArtPathStrokeCapType cap = ART_PATH_STROKE_CAP_BUTT; double line_width, miter_limit = 4, flatness = 0.25; ArtSVP *svp; if (!PyArg_ParseTuple(args, "O!id|iidd", &PathType, (PyObject*)&path_obj, &color, &line_width, &join, &cap, &miter_limit, &flatness)) return NULL; svp = art_svp_vpath_stroke(path_obj->vpath, join, cap, line_width, miter_limit, flatness); art_rgb_svp_alpha(svp, 0, 0, self->width, self->height, color, self->buf, self->width * 3, NULL); art_svp_free(svp); Py_INCREF(Py_None); return Py_None; } char image_text__doc__[] = "render(font, x, y, textcolor, text)\n" "\n" "Render the text in the supplied font at the specified location"; PyObject *image_text(ImageObj *self, PyObject *args) { return font_draw_text(self, args); } static char image_write_png__doc__[] = "write_png(file_name)\n" "\n" "Save the image in the named file in PNG format"; static PyObject *image_write_png(ImageObj *self, PyObject *args) { char *file_name; FILE *fp; png_structp png_ptr; png_infop info_ptr; png_bytep *row_pointers; png_uint_32 row; if (!PyArg_ParseTuple(args, "s", &file_name)) return NULL; row_pointers = malloc(self->height * sizeof(*row_pointers)); for (row = 0; row < self->height; row++) row_pointers[row] = self->buf + row * self->width * 3; fp = fopen(file_name, "wb"); if (fp == NULL) { set_error(PyExc_IOError, "could not open file"); return NULL; } png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { fclose(fp); set_error(PyExc_RuntimeError, "could not create write struct"); return NULL; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { fclose(fp); png_destroy_write_struct(&png_ptr, (png_infopp)NULL); set_error(PyExc_RuntimeError, "could not create info struct"); return NULL; } if (setjmp(png_ptr->jmpbuf)) { fclose(fp); png_destroy_write_struct(&png_ptr, (png_infopp)NULL); set_error(PyExc_RuntimeError, "error building image"); return NULL; } png_init_io(png_ptr, fp); png_set_IHDR(png_ptr, info_ptr, self->width, self->height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_write_info(png_ptr, info_ptr); png_write_image(png_ptr, row_pointers); free(row_pointers); png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, (png_infopp)NULL); fclose(fp); Py_INCREF(Py_None); return Py_None; } typedef struct { unsigned char *data; int had_error; int alloc_size; int image_size; } AsPngBuf; #define ALLOC_INC (32 * 1024) static void as_png_write(png_structp png_ptr, png_bytep data, png_size_t length) { AsPngBuf *buf; buf = png_get_io_ptr(png_ptr); if (buf->had_error) return; if (buf->image_size + length > buf->alloc_size) { buf->alloc_size = ((buf->image_size + length) / ALLOC_INC + 1) * ALLOC_INC; if (buf->data == NULL) buf->data = malloc(buf->alloc_size); else { unsigned char *old_data; old_data = buf->data; buf->data = realloc(buf->data, buf->alloc_size); if (buf->data == NULL) free(old_data); } if (buf->data == NULL) { buf->had_error = 1; return; } } memmove(buf->data + buf->image_size, data, length); buf->image_size += length; } static char image_as_png__doc__[] = "as_png()\n" "\n" "Return the image as data in PNG format"; static PyObject *image_as_png(ImageObj *self, PyObject *args) { png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_bytep *row_pointers = NULL; AsPngBuf *buf = NULL; PyObject *image = NULL; png_uint_32 row; if (!PyArg_ParseTuple(args, "")) return NULL; buf = malloc(sizeof(*buf)); if (buf == NULL) return PyErr_NoMemory(); memset(buf, 0, sizeof(*buf)); row_pointers = malloc(self->height * sizeof(*row_pointers)); if (row_pointers == NULL) { PyErr_NoMemory(); goto error; } for (row = 0; row < self->height; row++) row_pointers[row] = self->buf + row * self->width * 3; png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { set_error(PyExc_RuntimeError, "could not create write struct"); goto error; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { set_error(PyExc_RuntimeError, "could not create info struct"); goto error; } if (setjmp(png_ptr->jmpbuf)) { set_error(PyExc_RuntimeError, "error building image"); goto error; } png_set_write_fn(png_ptr, buf, as_png_write, NULL); png_set_IHDR(png_ptr, info_ptr, self->width, self->height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_write_info(png_ptr, info_ptr); png_write_image(png_ptr, row_pointers); png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, (png_infopp)NULL); info_ptr = NULL; png_ptr = NULL; if (!buf->had_error && buf->data != NULL) image = PyString_FromStringAndSize(buf->data, buf->image_size); if (image == NULL) PyErr_NoMemory(); error: if (buf != NULL) { if (buf->data != NULL) free(buf->data); free(buf); } if (info_ptr != NULL) png_write_end(png_ptr, info_ptr); if (png_ptr != NULL) png_destroy_write_struct(&png_ptr, (png_infopp)NULL); if (row_pointers != NULL) free(row_pointers); return image; } static struct PyMethodDef image_methods[] = { { "fill", (PyCFunction)image_fill, METH_VARARGS, image_fill__doc__ }, { "stroke", (PyCFunction)image_stroke, METH_VARARGS, image_stroke__doc__ }, { "text", (PyCFunction)image_text, METH_VARARGS, image_text__doc__ }, { "write_png", (PyCFunction)image_write_png, METH_VARARGS, image_write_png__doc__ }, { "as_png", (PyCFunction)image_as_png, METH_VARARGS, image_as_png__doc__ }, { NULL, NULL } /* sentinel */ }; /* ---------- */ static ImageObj *new_ImageObj(int width, int height, int color) { ImageObj *self; ArtVpath vpath[6]; ArtSVP *svp; self = PyObject_NEW(ImageObj, &ImageType); if (self == NULL) return NULL; self->width = width; self->height = height; self->buf = malloc(width * height * 3); /* RGB */ make_rect_vpath(vpath, 0, 0, width, height); svp = art_svp_from_vpath(vpath); art_rgb_svp_alpha(svp, 0, 0, width, height, color, self->buf, width * 3, NULL); art_svp_free(svp); return self; } static void dealloc_ImageObj(ImageObj *self) { if (self->buf != NULL) free(self->buf); PyMem_DEL(self); } static PyObject *image_getattr(ImageObj *self, char *name) { if (strcmp(name, "width") == 0) return PyInt_FromLong(self->width); if (strcmp(name, "height") == 0) return PyInt_FromLong(self->height); return Py_FindMethod(image_methods, (PyObject *)self, name); } static char ImageType__doc__[] = ""; PyTypeObject ImageType = { PyObject_HEAD_INIT(0) 0, /*ob_size*/ "image", /*tp_name*/ sizeof(ImageObj), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor)dealloc_ImageObj, /*tp_dealloc*/ (printfunc)0, /*tp_print*/ (getattrfunc)image_getattr, /*tp_getattr*/ (setattrfunc)0, /*tp_setattr*/ (cmpfunc)0, /*tp_compare*/ (reprfunc)0, /*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*/ /* Space for future expansion */ 0L, 0L, 0L, 0L, ImageType__doc__ /* Documentation string */ }; PyObject *image_new(PyObject *args) { int width, height, color = 0xffffffff; if (!PyArg_ParseTuple(args, "ii|i", &width, &height, &color)) return NULL; color |= 0xff; return (PyObject*)new_ImageObj(width, height, color); }