/****************************************************************** Copyright 1995 Richard Jones, Bureau of Meteorology Australia. richard@bofh.asn.au Current maintainer is Chris Gonnerman Please direct all questions and problems to me. This module is a python wrapper for the GD library (version 1.8.3) version 0.51 Revised 09/24/2003 by Chris Gonnerman -- fixed memory management bug reported by Jack Diederich. version 0.50 Revised 09/13/2003 by Chris Gonnerman -- documentation change only: the GD library must be version 2.0.8 or higher (or you must choose version 0.40 or earlier of this module, which supports GD 1.8.3 or higher). version 0.42 Revised 06/10/2003 by Chris Gonnerman -- implemented patch by Gregory P. Smith to support writing to arbitrary objects, superceding the patch in 0.41 from Andreas Rottman. gddemo.py contains Rottman's example (which works with Smith's patched version) as well as an example (by me) of reading an image from a URL. The documentation was updated to reflect these changes. version 0.41 Revised 05/29/2003 by Chris Gonnerman -- implemented big patch by Andreas Rottmann to support writing images to memory via StringIO/CStringIO. Currently the only documentation is an example in gddemo.py. -- implemented patch by Bob Galloway to remove the "specialness" of negative coordinates in the string_ttf/string_ft methods. -- implemented patch by Nathan Robertson to enable MacOSX fink builds. -- fixed bugs in the proxy class with regard to passing of _gd.image types. version 0.40 Revised 09/18/2002 by Chris Gonnerman -- updated to deal with incomplete library installs version 0.30 Revised 06/12/2002 by Chris Gonnerman -- initial conversion to two-tier design version 0.26 Revised 12/10/2001 by Chris Gonnerman -- made unicode optional via define Py_UNICODEOBJECT_H version 0.25 Revised 09/15/2001 by Chris Gonnerman -- implemented patch by Mike Romberg: adds additional public functions, available only if GD 2.0.1+ is installed. version 0.24 Revised 08/08/2001 by Chris Gonnerman -- implemented patch by Mike Romberg: supports GCC 3.0 and GD 2.0.1 adds public C function makeGDImage() It allows C or C++ code which uses the gd library directly to make an imageobject instance. version 0.23 Revised 11/22/2000 by Chris Gonnerman -- included the patch from Tanimoto Osamu -- updated support to GD version 1.8.3 -- cleaned up code, added ANSI prototypes ******************************************************************/ #include #include #include #include #include #include #include #include #include #ifdef HAVE_LIBTTF #define HAVE_LIBFREETYPE #endif /* missing from gd.h */ gdImagePtr gdImageCreateFromXpm(char *filename); static PyObject *ErrorObject; extern int errno; /* ** Declarations for objects of type image */ typedef struct i_o { PyObject_HEAD gdImagePtr imagedata; int multiplier_x,origin_x; int multiplier_y,origin_y; struct i_o *current_brush; struct i_o *current_tile; } imageobject; typedef struct { char *name; gdFontPtr data; } fontstruct; extern gdFont gdFontTinyRep; extern gdFont gdFontSmallRep; extern gdFont gdFontMediumBoldRep; extern gdFont gdFontLargeRep; extern gdFont gdFontGiantRep; static fontstruct fonts[] = {{"gdFontTiny",&gdFontTinyRep}, {"gdFontSmall",&gdFontSmallRep}, {"gdFontMediumBold",&gdFontMediumBoldRep}, {"gdFontLarge",&gdFontLargeRep}, {"gdFontGiant",&gdFontGiantRep}, {NULL,NULL}}; staticforward PyTypeObject Imagetype; #define is_imageobject(v) ((v)->ob_type == &Imagetype) #define MIN(x,y) ((x)<(y)?(x):(y)) #define X(x) ((x)*self->multiplier_x+self->origin_x) #define Y(y) ((y)*self->multiplier_y+self->origin_y) #define W(x) ((x)*self->multiplier_x) #define H(y) ((y)*self->multiplier_y) static imageobject *newimageobject(PyObject *args); /* ** Support Functions */ static PyObject *write_file(imageobject *img, PyObject *args, char fmt) { char *filename; PyObject *fileobj; FILE *fp = NULL; int closeme = 0, use_fileobj_write = 0; int arg1 = -1, arg2 = -1; int filesize = 0; void *filedata = NULL; if(PyArg_ParseTuple(args, "O!|ii", &PyFile_Type, &fileobj, &arg1, &arg2)) { fp = PyFile_AsFile(fileobj); } else if(PyErr_Clear(), PyArg_ParseTuple(args, "z|ii", &filename, &arg1, &arg2)) { if((fp = fopen(filename, "wb"))) { closeme = 1; } else { PyErr_SetFromErrno(PyExc_IOError); return NULL; } } else if (PyErr_Clear(), PyArg_ParseTuple(args, "O|ii", &fileobj, &arg1, &arg2)) { /* if we're passed a random object that has a write method we will * attempt to call object.write(filedata) */ if (!PyObject_HasAttrString(fileobj, "write")) { PyErr_SetString(ErrorObject, "first argument must be a file, string or object with a write method"); return NULL; } use_fileobj_write = 1; } else return NULL; switch(fmt) { case 'p' : /* png */ #ifdef HAVE_LIBPNG if (use_fileobj_write) { filedata = gdImagePngPtr(img->imagedata, &filesize); } else { gdImagePng(img->imagedata, fp); } #else PyErr_SetString(PyExc_NotImplementedError, "PNG Support Not Available"); return NULL; #endif break; case 'j' : /* jpeg */ #ifdef HAVE_LIBJPEG if (use_fileobj_write) { filedata = gdImageJpegPtr(img->imagedata, &filesize, arg1); } else { gdImageJpeg(img->imagedata, fp, arg1); } #else PyErr_SetString(PyExc_NotImplementedError, "PNG Support Not Available"); return NULL; #endif break; case 'g' : /* gd */ if (use_fileobj_write) { filedata = gdImageGdPtr(img->imagedata, &filesize); } else { gdImageGd(img->imagedata, fp); } break; case 'G' : /* gd2 */ if(arg1 == -1) arg1 = 0; if(arg2 != GD2_FMT_RAW && arg2 != GD2_FMT_COMPRESSED) arg2 = GD2_FMT_COMPRESSED; if (use_fileobj_write) { filedata = gdImageGd2Ptr(img->imagedata, arg1, arg2, &filesize); } else { gdImageGd2(img->imagedata, fp, arg1, arg2); } break; case 'w' : /* wbmp */ if(arg1 == -1) arg1 = 0; if (use_fileobj_write) { filedata = gdImageWBMPPtr(img->imagedata, &filesize, arg1); } else { gdImageWBMP(img->imagedata, arg1, fp); } break; } if (use_fileobj_write || filedata) { PyObject *noerr; noerr = PyObject_CallMethod(fileobj, "write", "s#", filedata, filesize); gdFree(filedata); if (noerr == NULL) return NULL; } else if (closeme) { fclose(fp); } Py_INCREF(Py_None); return Py_None; } /* ** Methods for the image type */ imageobject *makeGDImage(gdImagePtr imagedata) { gdImagePtr newimg = gdImageCreate(gdImageSX(imagedata), gdImageSY(imagedata)); imageobject *rval = 0; gdImageCopy(newimg, imagedata, 0, 0, 0, 0, gdImageSX(imagedata), gdImageSY(imagedata)); if (!(rval = PyObject_NEW(imageobject, &Imagetype))) return NULL; rval->current_tile = rval->current_brush = NULL; rval->origin_x = rval->origin_y = 0; rval->multiplier_x = rval->multiplier_y = 1; rval->imagedata = newimg; return rval; } /*** I/O Methods ***/ static PyObject *image_writepng(imageobject *self, PyObject *args) { return write_file(self, args, 'p'); } static PyObject *image_writejpeg(imageobject *self, PyObject *args) { return write_file(self, args, 'j'); } static PyObject *image_writegd(imageobject *self, PyObject *args) { return write_file(self, args, 'g'); } static PyObject *image_writegd2(imageobject *self, PyObject *args) { return write_file(self, args, 'G'); } static PyObject *image_writewbmp(imageobject *self, PyObject *args) { return write_file(self, args, 'w'); } /*** Drawing Methods ***/ static PyObject *image_setpixel(imageobject *self, PyObject *args) { int x,y,color; if(!PyArg_ParseTuple(args, "(ii)i", &x, &y, &color)) return NULL; gdImageSetPixel(self->imagedata, X(x), Y(y), color); Py_INCREF(Py_None); return Py_None; } static PyObject *image_line(imageobject *self, PyObject *args) { int sx,sy,ex,ey,color; if(!PyArg_ParseTuple(args, "(ii)(ii)i", &sx, &sy, &ex, &ey, &color)) return NULL; gdImageLine(self->imagedata, X(sx), Y(sy), X(ex), Y(ey), color); Py_INCREF(Py_None); return Py_None; } static PyObject *image_polygon(imageobject *self, PyObject *args) { PyObject *point, *points; gdPointPtr gdpoints; int size, color, i, fillcolor=-1; if(!PyArg_ParseTuple(args, "O!i|i", &PyTuple_Type, &points, &color, &fillcolor)) { PyErr_Clear(); if(PyArg_ParseTuple(args, "O!i|i", &PyList_Type, &points, &color, &fillcolor)) points=PyList_AsTuple(points); else return NULL; } size = PyTuple_Size(points); gdpoints = (gdPointPtr)calloc(size,sizeof(gdPoint)); for(i=0; iimagedata, gdpoints, size, color); gdImagePolygon(self->imagedata, gdpoints, size, color); free(gdpoints); Py_INCREF(Py_None); return Py_None; } static PyObject *image_rectangle(imageobject *self, PyObject *args) { int tx,ty,bx,by,t,color,fillcolor,fill=0; if(PyArg_ParseTuple(args, "(ii)(ii)ii", &tx, &ty, &bx, &by, &color, &fillcolor)) fill=1; else if(PyErr_Clear(), !PyArg_ParseTuple(args, "(ii)(ii)i", &tx, &ty, &bx, &by, &color)) return NULL; tx = X(tx); ty = Y(ty); bx = X(bx); by = Y(by); if(tx > bx) { t = tx; tx = bx; bx = t; } if(ty > by) { t = ty; ty = by; by = t; } if(fill) gdImageFilledRectangle(self->imagedata, tx, ty, bx, by, fillcolor); gdImageRectangle(self->imagedata, tx, ty, bx, by, color); Py_INCREF(Py_None); return Py_None; } static PyObject *image_filledpolygon(imageobject *self, PyObject *args) { PyObject *point, *points; gdPointPtr gdpoints; int size, color, i; if(!PyArg_ParseTuple(args, "O!i", &PyTuple_Type, &points, &color)) { PyErr_Clear(); if(PyArg_ParseTuple(args, "O!i", &PyList_Type, &points, &color)) points=PyList_AsTuple(points); else return NULL; } size = PyTuple_Size(points); gdpoints = (gdPointPtr)calloc(size,sizeof(gdPoint)); for(i = 0; i < size; i++) { point = PyTuple_GET_ITEM(points,i); gdpoints[i].x = X(PyInt_AS_LONG((PyIntObject *)PyTuple_GET_ITEM(point,0))); gdpoints[i].y = Y(PyInt_AS_LONG((PyIntObject *)PyTuple_GET_ITEM(point,1))); } gdImageFilledPolygon(self->imagedata, gdpoints, size, color); free(gdpoints); Py_INCREF(Py_None); return Py_None; } static PyObject *image_filledrectangle(imageobject *self, PyObject *args) { int tx,ty,bx,by,t,color; if(!PyArg_ParseTuple(args, "(ii)(ii)i", &tx, &ty, &bx, &by, &color)) return NULL; tx = X(tx); ty = Y(ty); bx = X(bx); by = Y(by); if(tx > bx) {t=tx;tx=bx;bx=t;} if(ty > by) {t=ty;ty=by;by=t;} gdImageFilledRectangle(self->imagedata, tx, ty, bx, by, color); Py_INCREF(Py_None); return Py_None; } static PyObject *image_arc(imageobject *self, PyObject *args) { int cx, cy, w, h, s, e, color, i; if(!PyArg_ParseTuple(args, "(ii)(ii)iii", &cx, &cy, &w, &h, &s, &e, &color)) return NULL; if(eimagedata, X(cx), Y(cy), W(w), H(h), s, e, color); Py_INCREF(Py_None); return Py_None; } static PyObject *image_filledarc(imageobject *self, PyObject *args) { #if GD2_VERS <= 1 PyErr_SetString(PyExc_NotImplementedError, "filledArc() requires gd 2.0 or later"); return NULL; #else int cx, cy, w, h, s, e, color, i, style; if(!PyArg_ParseTuple(args, "(ii)(ii)iiii", &cx, &cy, &w, &h, &s, &e, &color, &style)) return NULL; if(eimagedata, X(cx), Y(cy), W(w), H(h), s, e, color, style); Py_INCREF(Py_None); return Py_None; #endif } static PyObject *image_filledellipse(imageobject *self, PyObject *args) { #if GD2_VERS <= 1 PyErr_SetString(PyExc_NotImplementedError, "filledEllipse() requires gd 2.0 or later"); return NULL; #else int cx, cy, w, h, color; if(!PyArg_ParseTuple(args, "(ii)(ii)i", &cx, &cy, &w, &h, &color)) return NULL; gdImageFilledEllipse(self->imagedata, X(cx), Y(cy), W(w), H(h), color); Py_INCREF(Py_None); return Py_None; #endif } static PyObject *image_filltoborder(imageobject *self, PyObject *args) { int x,y,border,color; if(!PyArg_ParseTuple(args, "(ii)ii", &x,&y,&border,&color)) return NULL; gdImageFillToBorder(self->imagedata, X(x),Y(y),border,color); Py_INCREF(Py_None); return Py_None; } static PyObject *image_fill(imageobject *self, PyObject *args) { int x,y,color; if(!PyArg_ParseTuple(args, "(ii)i", &x,&y,&color)) return NULL; gdImageFill(self->imagedata, X(x),Y(y),color); Py_INCREF(Py_None); return Py_None; } static PyObject *image_setbrush(imageobject *self, PyObject *args) { imageobject *brush; char *filename, *type; /* dummies */ if(PyArg_ParseTuple(args, "z|z", &filename, &type)) brush = (imageobject *)newimageobject(args); else if(PyErr_Clear(), PyArg_ParseTuple(args, "O!", &Imagetype, &brush)) Py_INCREF(brush); else return NULL; if(self->current_brush){ Py_DECREF(self->current_brush); } self->current_brush = brush; gdImageSetBrush(self->imagedata, brush->imagedata); Py_INCREF(Py_None); return Py_None; } static PyObject *image_setantialiased(imageobject *self, PyObject *args) { int c; if(!PyArg_ParseTuple(args, "i", &c)) return NULL; gdImageSetAntiAliased(self->imagedata, c); Py_INCREF(Py_None); return Py_None; } static PyObject *image_setclip(imageobject *self, PyObject *args) { int tx,ty,bx,by,t; if(!PyArg_ParseTuple(args, "(ii)(ii)", &tx, &ty, &bx, &by)) return NULL; tx = X(tx); ty = Y(ty); bx = X(bx); by = Y(by); if(tx > bx) { t = tx; tx = bx; bx = t; } if(ty > by) { t = ty; ty = by; by = t; } gdImageSetClip(self->imagedata, tx, ty, bx, by); Py_INCREF(Py_None); return Py_None; } static PyObject *image_settile(imageobject *self, PyObject *args) { imageobject *tile; char *filename, *type; /* dummies */ if(PyArg_ParseTuple(args, "z|z", &filename, &type)) tile = (imageobject *)newimageobject(args); else if(PyErr_Clear(), PyArg_ParseTuple(args, "O!", &Imagetype, &tile)) Py_INCREF(tile); else return NULL; if(self->current_tile) { Py_DECREF(self->current_tile); } self->current_tile = tile; gdImageSetBrush(self->imagedata, tile->imagedata); Py_INCREF(Py_None); return Py_None; } static PyObject *image_setstyle(imageobject *self, PyObject *args) { PyObject *style; int size, i, *stylearray; if(!PyArg_ParseTuple(args, "O!", &PyTuple_Type, &style)) { PyErr_Clear(); if(PyArg_ParseTuple(args, "O!", &PyList_Type, &style)) style=PyList_AsTuple(style); else return NULL; } size = PyTuple_Size(style); stylearray = (int *)calloc(size,sizeof(int)); for(i=0; iimagedata, stylearray, size); free(stylearray); Py_INCREF(Py_None); return Py_None; } static PyObject *image_setthickness(imageobject *self, PyObject *args) { #if GD2_VERS <= 1 PyErr_SetString(PyExc_NotImplementedError, "setThickness() requires gd 2.0 or later"); return NULL; #else int t; if(!PyArg_ParseTuple(args, "i", &t)) return NULL; gdImageSetThickness(self->imagedata, t); Py_INCREF(Py_None); return Py_None; #endif } static PyObject *image_alphablending(imageobject *self, PyObject *args) { #if GD2_VERS <= 1 PyErr_SetString(PyExc_NotImplementedError, "alphaBlending() requires gd 2.0 or later"); return NULL; #else int blending; if(!PyArg_ParseTuple(args, "i", &blending)) return NULL; gdImageAlphaBlending(self->imagedata, blending); Py_INCREF(Py_None); return Py_None; #endif } static PyObject *image_alpha(imageobject *self, PyObject *args) { #if GD2_VERS <= 1 PyErr_SetString(PyExc_NotImplementedError, "alpha() requires gd 2.0 or later"); return NULL; #else int color; if(!PyArg_ParseTuple(args, "i", &color)) return NULL; return Py_BuildValue("i", gdImageAlpha(self->imagedata, color)); #endif } static PyObject *image_getpixel(imageobject *self, PyObject *args) { int x,y; if(!PyArg_ParseTuple(args, "(ii)", &x,&y)) return NULL; return Py_BuildValue("i",gdImageGetPixel(self->imagedata, X(x),Y(y))); } static PyObject *image_boundssafe(imageobject *self, PyObject *args) { int x,y; if(!PyArg_ParseTuple(args, "(ii)", &x,&y)) return NULL; return Py_BuildValue("i",gdImageBoundsSafe(self->imagedata, X(x),Y(y))); } static PyObject *image_blue(imageobject *self, PyObject *args) { int c; if(!PyArg_ParseTuple(args, "i", &c)) return NULL; return Py_BuildValue("i",gdImageBlue(self->imagedata,c)); } static PyObject *image_green(imageobject *self, PyObject *args) { int c; if(!PyArg_ParseTuple(args, "i", &c)) return NULL; return Py_BuildValue("i",gdImageGreen(self->imagedata,c)); } static PyObject *image_red(imageobject *self, PyObject *args) { int c; if(!PyArg_ParseTuple(args, "i", &c)) return NULL; return Py_BuildValue("i",gdImageRed(self->imagedata,c)); } static PyObject *image_size(imageobject *self) { return Py_BuildValue("(ii)",gdImageSX(self->imagedata),gdImageSY(self->imagedata)); } static PyObject *image_char(imageobject *self, PyObject *args) { int x,y,font,color; char c; if(!PyArg_ParseTuple(args, "i(ii)ii", &font,&x,&y,&c,&color)) return NULL; gdImageChar(self->imagedata, fonts[font].data, X(x), Y(y), c, color); Py_INCREF(Py_None); return Py_None; } static PyObject *image_charup(imageobject *self, PyObject *args) { int x,y,font,color; char c; if(!PyArg_ParseTuple(args, "i(ii)si", &font,&x,&y,&c,&color)) return NULL; gdImageCharUp(self->imagedata, fonts[font].data, X(x), Y(y), c, color); Py_INCREF(Py_None); return Py_None; } static PyObject *image_get_bounding_rect(imageobject *self, PyObject *args) { #ifndef HAVE_LIBFREETYPE PyErr_SetString(PyExc_NotImplementedError, "Freetype Support Not Available"); return NULL; #else double ptsize, angle; char *fontname, *str, *rc; int x, y, brect[8]; if(!PyArg_ParseTuple(args, "sdd(ii)s", &fontname, &ptsize, &angle, &x, &y, &str)) return NULL; rc = gdImageStringTTF(NULL, brect, 0, fontname, ptsize, angle, x, y, str); if(rc != NULL){ PyErr_SetString(PyExc_ValueError, rc); return NULL; } return Py_BuildValue("(iiiiiiii)",brect[0],brect[1],brect[2],brect[3], brect[4],brect[5],brect[6],brect[7]); #endif } static PyObject *image_string_ft(imageobject *self, PyObject *args) { #ifndef HAVE_LIBFREETYPE PyErr_SetString(PyExc_NotImplementedError, "Freetype Support Not Available"); return NULL; #else #if GD2_VERS <= 1 PyErr_SetString(PyExc_NotImplementedError, "string_ft() requires gd 2.0 or later"); return NULL; #else int x,y,fg; double ptsize,angle; char *fontname,*str,*rc; int brect[8]; if(!PyArg_ParseTuple(args, "sdd(ii)si", &fontname, &ptsize, &angle, &x,&y,&str,&fg)) return NULL; rc = gdImageStringFT(NULL, brect, 0, fontname, ptsize, angle, 0, 0, str); /* calculate the bounding rect */ if(rc != NULL){ PyErr_SetString(PyExc_ValueError, rc); return NULL; } rc = gdImageStringTTF(self->imagedata, brect, fg, fontname, ptsize, angle, x, y, str); if(rc != NULL){ PyErr_SetString(PyExc_ValueError, rc); return NULL; } return Py_BuildValue("(iiiiiiii)", brect[0], brect[1], brect[2], brect[3], brect[4], brect[5], brect[6], brect[7]); #endif #endif } static PyObject *image_string_ttf(imageobject *self, PyObject *args) { #ifndef HAVE_LIBFREETYPE PyErr_SetString(PyExc_NotImplementedError, "Freetype Support Not Available"); return NULL; #else int x,y,fg; double ptsize,angle; char *fontname,*str,*rc; int brect[8]; if(!PyArg_ParseTuple(args, "sdd(ii)si", &fontname, &ptsize, &angle, &x,&y,&str,&fg)) return NULL; rc = gdImageStringTTF(NULL, brect, 0, fontname, ptsize, angle, 0, 0, str); /* calculate the bounding rect */ if(rc != NULL){ PyErr_SetString(PyExc_ValueError, rc); return NULL; } rc = gdImageStringTTF(self->imagedata, brect, fg, fontname, ptsize, angle, x, y, str); if(rc != NULL){ PyErr_SetString(PyExc_ValueError, rc); return NULL; } return Py_BuildValue("(iiiiiiii)", brect[0], brect[1], brect[2], brect[3], brect[4], brect[5], brect[6], brect[7]); #endif } static PyObject *image_string(imageobject *self, PyObject *args) { int x,y,font,color; char *str; if(!PyArg_ParseTuple(args, "i(ii)si", &font,&x,&y,&str,&color)) return NULL; gdImageString(self->imagedata, fonts[font].data, X(x), Y(y), str, color); Py_INCREF(Py_None); return Py_None; } #ifdef Py_UNICODEOBJECT_H static PyObject *image_string16(imageobject *self, PyObject *args) { int x,y,font,color; Py_UNICODE *ustr; if(!PyArg_ParseTuple(args, "i(ii)ui", &font,&x,&y,&ustr,&color)) return NULL; gdImageString16(self->imagedata, fonts[font].data, X(x), Y(y), ustr, color); Py_INCREF(Py_None); return Py_None; } #endif static PyObject *image_stringup(imageobject *self, PyObject *args) { int x,y,font,color; char *str; if(!PyArg_ParseTuple(args, "i(ii)si", &font,&x,&y,&str,&color)) return NULL; gdImageStringUp(self->imagedata, fonts[font].data, X(x), Y(y), str, color); Py_INCREF(Py_None); return Py_None; } #ifdef Py_UNICODEOBJECT_H static PyObject *image_stringup16(imageobject *self, PyObject *args) { int x,y,font,color; Py_UNICODE *ustr; if(!PyArg_ParseTuple(args, "i(ii)ui", &font,&x,&y,&ustr,&color)) return NULL; gdImageStringUp16(self->imagedata, fonts[font].data, X(x), Y(y), ustr, color); Py_INCREF(Py_None); return Py_None; } #endif static PyObject *image_colorallocate(imageobject *self, PyObject *args) { int r,g,b; if(!PyArg_ParseTuple(args, "(iii)", &r, &g, &b)) return NULL; return(Py_BuildValue("i",gdImageColorAllocate(self->imagedata, r, g, b))); } static PyObject *image_colorallocatealpha(imageobject *self, PyObject *args) { #if GD2_VERS <= 1 PyErr_SetString(PyExc_NotImplementedError, "colorAllocateAlpha() requires gd 2.0 or later"); return NULL; #else int r,g,b,a; if(!PyArg_ParseTuple(args, "(iiii)", &r, &g, &b, &a)) return NULL; return(Py_BuildValue("i",gdImageColorAllocateAlpha(self->imagedata, r, g, b, a))); #endif } static PyObject *image_colorclosest(imageobject *self, PyObject *args) { int r,g,b; if(!PyArg_ParseTuple(args, "(iii)", &r, &g, &b)) return NULL; return(Py_BuildValue("i",gdImageColorClosest(self->imagedata, r, g, b))); } static PyObject *image_colorclosestalpha(imageobject *self, PyObject *args) { #if GD2_VERS <= 1 PyErr_SetString(PyExc_NotImplementedError, "colorClosestAlpha() requires gd 2.0 or later"); return NULL; #else int r,g,b,a; if(!PyArg_ParseTuple(args, "(iiii)", &r, &g, &b, &a)) return NULL; return(Py_BuildValue("i",gdImageColorClosestAlpha(self->imagedata, r, g, b, a))); #endif } static PyObject *image_colorclosestHWB(imageobject *self, PyObject *args) { #if GD2_VERS <= 1 PyErr_SetString(PyExc_NotImplementedError, "colorClosestHWB() requires gd 2.0 or later"); return NULL; #else int r,g,b; if(!PyArg_ParseTuple(args, "(iii)", &r, &g, &b)) return NULL; return(Py_BuildValue("i",gdImageColorClosestHWB(self->imagedata, r, g, b))); #endif } static PyObject *image_colorexact(imageobject *self, PyObject *args) { int r,g,b; if(!PyArg_ParseTuple(args, "(iii)", &r, &g, &b)) return NULL; return(Py_BuildValue("i",gdImageColorExact(self->imagedata, r, g, b))); } static PyObject *image_colorresolve(imageobject *self, PyObject *args) { #if GD2_VERS <= 1 PyErr_SetString(PyExc_NotImplementedError, "colorResolve() requires gd 2.0 or later"); return NULL; #else int r,g,b; if(!PyArg_ParseTuple(args, "(iii)", &r, &g, &b)) return NULL; return(Py_BuildValue("i",gdImageColorResolve(self->imagedata, r, g, b))); #endif } static PyObject *image_colorresolvealpha(imageobject *self, PyObject *args) { #if GD2_VERS <= 1 PyErr_SetString(PyExc_NotImplementedError, "colorResolveAlpha() requires gd 2.0 or later"); return NULL; #else int r,g,b,a; if(!PyArg_ParseTuple(args, "(iiii)", &r, &g, &b, &a)) return NULL; return(Py_BuildValue("i",gdImageColorResolveAlpha(self->imagedata, r, g, b, a))); #endif } static PyObject *image_colorstotal(imageobject *self) { return Py_BuildValue("i",gdImageColorsTotal(self->imagedata)); } static PyObject *image_colorcomponents(imageobject *self, PyObject *args) { int c,r,g,b; if(!PyArg_ParseTuple(args, "i", &c)) return NULL; r=gdImageRed(self->imagedata,c); g=gdImageGreen(self->imagedata,c); b=gdImageBlue(self->imagedata,c); return Py_BuildValue("(iii)",r,g,b); } static PyObject *image_getinterlaced(imageobject *self) { return Py_BuildValue("i",gdImageGetInterlaced(self->imagedata)); } static PyObject *image_gettransparent(imageobject *self) { return Py_BuildValue("i",gdImageGetTransparent(self->imagedata)); } static PyObject *image_colordeallocate(imageobject *self, PyObject *args) { int c; if(!PyArg_ParseTuple(args, "i", &c)) return NULL; gdImageColorDeallocate(self->imagedata, c); Py_INCREF(Py_None); return Py_None; } static PyObject *image_colortransparent(imageobject *self, PyObject *args) { int c; if(!PyArg_ParseTuple(args, "i", &c)) return NULL; gdImageColorTransparent(self->imagedata, c); Py_INCREF(Py_None); return Py_None; } static PyObject *image_copyto(imageobject *self, PyObject *args) { imageobject *dest; int dx,dy,sx,sy,w,h,dw,dh; dx=dy=sx=sy=0; w = gdImageSX(self->imagedata); h = gdImageSY(self->imagedata); if(!PyArg_ParseTuple(args, "O!|(ii)(ii)(ii)", &Imagetype, &dest, &dx, &dy, &sx, &sy, &w, &h)) return NULL; dw = gdImageSX(dest->imagedata); dh = gdImageSY(dest->imagedata); gdImageCopy(dest->imagedata, self->imagedata, X(dx), Y(dy), X(sx), Y(sy), W(w), H(h)); Py_INCREF(Py_None); return Py_None; } static PyObject *image_copyresizedto(imageobject *self, PyObject *args) { imageobject *dest; int dx,dy,sx,sy,dw,dh,sw,sh; dx=dy=sx=sy=0; sw = gdImageSX(self->imagedata); sh = gdImageSY(self->imagedata); if(PyArg_ParseTuple(args, "O!|(ii)(ii)", &Imagetype, &dest, &dx, &dy, &sx, &sy)) { dw = gdImageSX(dest->imagedata); dh = gdImageSY(dest->imagedata); } else if(PyErr_Clear(), !PyArg_ParseTuple(args, "O!|(ii)(ii)(ii)(ii)", &Imagetype, &dest, &dx, &dy, &sx, &sy, &dw, &dh, &sw, &sh)) return NULL; gdImageCopyResized(dest->imagedata, self->imagedata, X(dx), Y(dy), X(sx), Y(sy), W(dw), H(dh), W(sw), H(sh)); Py_INCREF(Py_None); return Py_None; } static PyObject *image_copyresampledto(imageobject *self, PyObject *args) { #if GD2_VERS <= 1 PyErr_SetString(PyExc_NotImplementedError, "copyResampledTo() requires gd 2.0 or later"); return NULL; #else imageobject *dest; int dx,dy,sx,sy,dw,dh,sw,sh; dx=dy=sx=sy=0; sw = gdImageSX(self->imagedata); sh = gdImageSY(self->imagedata); if(PyArg_ParseTuple(args, "O!|(ii)(ii)", &Imagetype, &dest, &dx, &dy, &sx, &sy)) { dw = gdImageSX(dest->imagedata); dh = gdImageSY(dest->imagedata); } else if(PyErr_Clear(), !PyArg_ParseTuple(args, "O!|(ii)(ii)(ii)(ii)", &Imagetype, &dest, &dx, &dy, &sx, &sy, &dw, &dh, &sw, &sh)) return NULL; gdImageCopyResampled(dest->imagedata, self->imagedata, X(dx), Y(dy), X(sx), Y(sy), W(dw), H(dh), W(sw), H(sh)); Py_INCREF(Py_None); return Py_None; #endif } static PyObject *image_copymergeto(imageobject *self, PyObject *args) { #if GD2_VERS <= 1 PyErr_SetString(PyExc_NotImplementedError, "copyMergeTo() requires gd 2.0 or later"); return NULL; #else imageobject *dest; int dx,dy,sx,sy,w,h,dw,dh,pct; dx=dy=sx=sy=0; w = gdImageSX(self->imagedata); h = gdImageSY(self->imagedata); pct = 100; if(!PyArg_ParseTuple(args, "O!|(ii)(ii)(ii)i", &Imagetype, &dest, &dx, &dy, &sx, &sy, &w, &h, &pct)) return NULL; dw = gdImageSX(dest->imagedata); dh = gdImageSY(dest->imagedata); gdImageCopyMerge(dest->imagedata, self->imagedata, X(dx), Y(dy), X(sx), Y(sy), W(w), H(h), pct); Py_INCREF(Py_None); return Py_None; #endif } static PyObject *image_copymergegrayto(imageobject *self, PyObject *args) { #if GD2_VERS <= 1 PyErr_SetString(PyExc_NotImplementedError, "copyMergeGrayTo() requires gd 2.0 or later"); return NULL; #else imageobject *dest; int dx,dy,sx,sy,w,h,dw,dh,pct; dx=dy=sx=sy=0; w = gdImageSX(self->imagedata); h = gdImageSY(self->imagedata); pct = 100; if(!PyArg_ParseTuple(args, "O!|(ii)(ii)(ii)i", &Imagetype, &dest, &dx, &dy, &sx, &sy, &w, &h, &pct)) return NULL; dw = gdImageSX(dest->imagedata); dh = gdImageSY(dest->imagedata); gdImageCopyMergeGray(dest->imagedata, self->imagedata, X(dx), Y(dy), X(sx), Y(sy), W(w), H(h), pct); Py_INCREF(Py_None); return Py_None; #endif } static PyObject *image_copypaletteto(imageobject *self, PyObject *args) { #if GD2_VERS <= 1 PyErr_SetString(PyExc_NotImplementedError, "copyPaletteTo() requires gd 2.0 or later"); return NULL; #else imageobject *dest; if(!PyArg_ParseTuple(args, "O!", &Imagetype, &dest)) return NULL; gdImagePaletteCopy(dest->imagedata, self->imagedata); Py_INCREF(Py_None); return Py_None; #endif } static PyObject *image_compare(imageobject *self, PyObject *args) { #if GD2_VERS <= 1 PyErr_SetString(PyExc_NotImplementedError, "compare() requires gd 2.0 or later"); return NULL; #else imageobject *dest; if(!PyArg_ParseTuple(args, "O!", &Imagetype, &dest)) return NULL; return Py_BuildValue("i", gdImageCompare(dest->imagedata, self->imagedata)); #endif } static PyObject *image_interlace(imageobject *self, PyObject *args) { int i; if(!PyArg_ParseTuple(args, "i", &i)) return NULL; gdImageInterlace(self->imagedata, i); Py_INCREF(Py_None); return Py_None; } static PyObject *image_origin(imageobject *self, PyObject *args) { if(!PyArg_ParseTuple(args, "(ii)|ii",&self->origin_x,&self->origin_y, &self->multiplier_x,&self->multiplier_y)) return NULL; Py_INCREF(Py_None); return Py_None; } static PyObject *image_getorigin(imageobject *self) { return Py_BuildValue("((ii)ii)",self->origin_x,self->origin_y,self->multiplier_x,self->multiplier_y); } static struct PyMethodDef image_methods[] = { {"writePng", (PyCFunction)image_writepng, 1, "writePng(f)\n" "write the image to f as a PNG, where f is either an open file object or a\n" "file name."}, {"writeJpeg", (PyCFunction)image_writejpeg, 1, "writeJpeg(f,quality)\n" "write the image to f as a JPEG, where f is either an open file object or a\n" "file name. quality is an optional integer value giving the JPEG quality from\n" "0 to 95%; leave out for default quality."}, {"writeWbmp", (PyCFunction)image_writewbmp, 1, "writeWbmp(f,fg)\n" "write the image to f as a WBMP, where f is either an open file object or a\n" "file name. fg is a foreground color index which will be set in the output\n" "file; see the gd documentation for a further explanation of this value."}, {"writeGd", (PyCFunction)image_writegd, 1, "writeGd(f)\n" "write the image to f as a GD file, where f is either an open file object\n" "or a file name."}, {"writeGd2", (PyCFunction)image_writegd2, 1, "writeGd(f,chunksize,fmt)\n" "write the image to f as a GD2 file, where f is either an open file object\n" "or a file name. see the gd documentation for an explanation of the chunksize\n" "and fmt arguments. defaults will be used if not given."}, {"setPixel", (PyCFunction)image_setpixel, 1, "setPixel((x,y), color)\n" "set the pixel at (x,y) to color"}, {"line", (PyCFunction)image_line, 1, "line((x1,y1), (x2,y2), color)\n" "draw a line from (x1,y1) to (x2,y2) in color"}, {"polygon", (PyCFunction)image_polygon, 1, "polygon(((x1,y1), (x2,y2), ..., (xn, yn)), color[, fillcolor])\n" "draw a polygon using the list or tuple of points (minimum 3) in color,\n" "optionally filled with fillcolor"}, {"rectangle", (PyCFunction)image_rectangle, 1, "rectangle((x1,y1), (x2,y2), color[, fillcolor])\n" "draw a rectangle with upper corner (x1,y1), lower corner (x2,y2) in color,\n" "optionally filled with fillcolor"}, {"filledPolygon", (PyCFunction)image_filledpolygon, 1, "filledPolygon(((x1,y1), (x2,y2), ..., (xn, yn)), color)\n" "draw a filled polygon using the list or tuple of points (minimum 3) in color"}, {"filledRectangle", (PyCFunction)image_filledrectangle, 1, "filledRectangle((x1,y1), (x2,y2), color)\n" "draw a rectangle with upper corner (x1,y1), lower corner (x2,y2) in color"}, {"arc", (PyCFunction)image_arc, 1, "arc((x,y), (w,h), start, end, color)\n" "draw an ellipse centered at (x,y) with width w, height h from start\n" "degrees to end degrees in color."}, {"filledArc", (PyCFunction)image_filledarc, 1, "filledArc((x,y), (w,h), start, end, color, style)\n" "draw an ellipse centered at (x,y) with width w, height h from start\n" "degrees to end degrees in color. The style argument is a bitwise OR\n" "of the following (gdArc, gdChord, gdPie, gdNoFill, gdEdged)."}, {"filledEllipse", (PyCFunction)image_filledellipse, 1, "filledEllipse((x,y), (w,h), color)\n" "draw a filled ellipse centered at (x,y) with width w,\n" "height h in color."}, {"fillToBorder", (PyCFunction)image_filltoborder, 1, "fillToBorder((x,y), border, color)\n" "flood from point (x,y) to border color in color"}, {"fill", (PyCFunction)image_fill, 1, "fill((x,y), color)\n" "flood from point (x,y) in color for those pixels with the same color\n" "as the starting point"}, {"setBrush", (PyCFunction)image_setbrush, 1, "setBrush(image)\n" "set the drawing brush to (use gdBrushed when drawing)"}, {"setAntiAliased", (PyCFunction)image_setantialiased, 1, "setAntiAliased(color)\n" "Set the foreground color to be used when drawing antialiased lines. Use the gdAntiAliased in place of the color when drawing"}, {"setClip", (PyCFunction)image_setclip, 1, "setClip((x1,y1), (x2,y2))\n" "Set the image clipping rectangle"}, {"setTile", (PyCFunction)image_settile, 1, "setTile(image)\n" "set the fill tile to (use gdTiled when filling)"}, {"setStyle", (PyCFunction)image_setstyle, 1, "setStyle(tuple)\n" "set the line bit-style to tuple of colors (use gdStyled when drawing)"}, {"setThickness", (PyCFunction)image_setthickness, 1, "setThickness(thickness)\n" "set the width of lines, polyons, and arcs."}, {"alphaBlending", (PyCFunction)image_alphablending, 1, "alphaBlending(blending)\n" "toggles alpha channel blending for trucolor images."}, {"alpha", (PyCFunction)image_alpha, 1, "alpha(color)\n" "returns the alpha component of the specified color."}, {"blue", (PyCFunction)image_blue, 1, "blue(color)\n" "returns the blue component of the specified color."}, {"green", (PyCFunction)image_green, 1, "green(color)\n" "returns the green component of the specified color."}, {"red", (PyCFunction)image_red, 1, "red(color)\n" "returns the red component of the specified color."}, {"getPixel", (PyCFunction)image_getpixel, 1, "getPixel((x,y))\n" "color index of image at (x,y)"}, {"boundsSafe", (PyCFunction)image_boundssafe, 1, "boundsSafe((x,y))\n" "returns true if(x,y) is within image"}, {"size", (PyCFunction)image_size, 1, "size()\n" "return the 2-tuple size of image"}, {"char", (PyCFunction)image_char,1, "char(font, (x,y), c, color)\n" "draw string c at (x,y) using one of the pre-defined gdmodule fonts (gdFont*)"}, {"charUp", (PyCFunction)image_charup,1, "charUp(font, (x,y), c, color)\n" "vertically draw string c at (x,y) using one of the pre-defined gdmodule\n" "fonts (gdFont*)"}, {"get_bounding_rect", (PyCFunction)image_get_bounding_rect,1, "get_bounding_rect(font, ptsize, angle,(x,y), s)\n" "get bounding rect of string s using the truetype font"}, {"string_ttf", (PyCFunction)image_string_ttf,1, "string_ttf(font, ptsize, angle, (x,y), s, color)\n" "draw string s at (x,y) using the truetype font"}, {"string_ft", (PyCFunction)image_string_ft,1, "string_ft(font, ptsize, angle, (x,y), s, color)\n" "draw string s at (x,y) using the truetype font"}, {"string", (PyCFunction)image_string,1, "string(font, (x,y), s, color)\n" "draw string s at (x,y) using one of the pre-defined gdmodule fonts (gdFont*)"}, #ifdef Py_UNICODEOBJECT_H {"string16", (PyCFunction)image_string16,1, "string(font, (x,y), s, color)\n" "draw unicode string s at (x,y) using one of the pre-defined gdmodule fonts (gdFont*)"}, #endif {"stringUp", (PyCFunction)image_stringup,1, "stringUp(font, (x,y), s, color)\n" "vertically draw string s at (x,y) using one of the pre-defined gdmodule\n" "fonts (gdFont*)"}, #ifdef Py_UNICODEOBJECT_H {"stringUp16", (PyCFunction)image_stringup16,1, "stringUp16(font, (x,y), s, color)\n" "vertically draw unicode string s at (x,y) using one of the pre-defined gdmodule\n" "fonts (gdFont*)"}, #endif {"colorAllocate", (PyCFunction)image_colorallocate,1, "colorAllocate((r,g,b))\n" "allocate a color index to (r,g,b) (returns -1 if unable to)"}, {"colorAllocateAlpha", (PyCFunction)image_colorallocatealpha,1, "colorAllocateAlpha((r,g,b,a))\n" "allocate a color index to (r,g,b,a) (returns -1 if unable to)"}, {"colorClosest", (PyCFunction)image_colorclosest, 1, "colorClosest((r,g,b))\n" "return the color index closest to (r,g,b) (returns -1 if unable to)"}, {"colorClosestAlpha", (PyCFunction)image_colorclosestalpha, 1, "colorClosestAlpha((r,g,b,a))\n" "return the color index closest to (r,g,b,a) (returns -1 if unable to)"}, {"colorClosestHWB", (PyCFunction)image_colorclosestHWB, 1, "colorClosestHWB((r,g,b))\n" "return the color index closest in hue whiteness and blackness to (r,g,b) (returns -1 if unable to)"}, {"colorExact", (PyCFunction)image_colorexact, 1, "colorExact((r,g,b))\n" "return an exact color index match for (r,g,b) (returns -1 if unable to)"}, {"colorResolve", (PyCFunction)image_colorresolve, 1, "colorResolve((r,g,b))\n" "returns the exact color (after possibly allocating) or the closes match."}, {"colorResolveAlpha", (PyCFunction)image_colorresolvealpha, 1, "colorResolve((r,g,b,a))\n" "returns the exact color (after possibly allocating) or the closes match."}, {"colorsTotal", (PyCFunction)image_colorstotal, 1, "colorsTotal()\n" "returns the number of colors currently allocated"}, {"colorComponents", (PyCFunction)image_colorcomponents, 1, "colorComponents(color)\n" "returns a 3-tulple of the (r,g,b) components of color"}, {"getInterlaced", (PyCFunction)image_getinterlaced, 1, "getInterlaced()\n" "returns true if the image is interlaced"}, {"getTransparent", (PyCFunction)image_gettransparent, 1, "getTransparent()\n" "returns transparent color index or -1"}, {"colorDeallocate", (PyCFunction)image_colordeallocate, 1, "colorDeallocate(color)\n" "deallocate color from the image palette"}, {"colorTransparent", (PyCFunction)image_colortransparent, 1, "colorTransparent(color)\n" "set the transparent color to color"}, {"copyTo", (PyCFunction)image_copyto, 1, "copyTo(image[, (dx,dy)[, (sx,sy)[, (w,h)]]])\n" "copy from (sx,sy), width sw and height sh to destination image (dx,dy)"}, {"copyResizedTo", (PyCFunction)image_copyresizedto,1, "copyResizedTocopyTo(image[, (dx,dy)[, (sx,sy)[, (dw,dh)[, (sw,sh)]]]])\n" "copy from (sx,sy), width sw and height sh to destination image (dx,dy), \n" "width dw and height dh"}, {"copyResampledTo", (PyCFunction)image_copyresampledto,1, "copyResampledTo(image[, (dx,dy)[, (sx,sy)[, (dw,dh)[, (sw,sh)]]]])\n" "copy from (sx,sy), width sw and height sh to destination image (dx,dy), \n" "width dw and height dh using smooth pixel interpolation."}, {"copyMergeTo", (PyCFunction)image_copymergeto, 1, "copyMergeTo(image[, (dx,dy)[, (sx,sy)[, (w,h)]], pct])\n" "copy from (sx,sy), width sw and height sh to destination image (dx,dy)\n" "If pct is 100 then this is equivalent to copyTo(). If pct is less\n" "than 100 the images are merged." }, {"copyMergeGrayTo", (PyCFunction)image_copymergegrayto, 1, "copyMergeGrayTo(image[, (dx,dy)[, (sx,sy)[, (w,h)]], pct])\n" "copy from (sx,sy), width sw and height sh to destination image (dx,dy)\n" "If pct is 100 then this is equivalent to copyTo(). If pct is less\n" "than 100 the images are merged. The hue is preserved by first\n" "converting the destination pixels to gray." }, {"copyPaletteTo", (PyCFunction)image_copypaletteto, 1, "copyPaletteTo(image)\n" "copy the palette from one image to another."}, {"compare", (PyCFunction)image_compare, 1, "compare(image)\n" "compares this image with another. Returns a bitmask whose values\n" "are composed of CMP_IMAGE, CMP_NUM_COLORS, CMP_COLOR, CMP_SIZE_X,\n" "CMP_SIZE_Y, CMP_TRANSPARENT, CMP_BACKGROUND, CMP_INTERLACE, CMP_TRUECOLOR"}, {"interlace", (PyCFunction)image_interlace, 1, "interlace()\n" "set the interlace bit"}, {"origin", (PyCFunction)image_origin, 1, "origin((x,y)[,xmult,ymult])\n" "set the origin of the image to (x,y) and multiply all x, y, width and\n" "height factors by xmult and ymult (typically either 1 or -1)"}, {"getOrigin", (PyCFunction)image_getorigin, 1, "getOrigin()\n" "returns the origin parameters ((x,y),xmult,ymult)"}, {NULL, NULL} /* sentinel */ }; /* ** Table of file types understood to gd "constructors" */ static struct { char *ext; gdImagePtr (*func)(FILE*); } ext_table[] = { #ifdef HAVE_LIBPNG {"png", gdImageCreateFromPng}, #endif #ifdef HAVE_LIBJPEG {"jpeg", gdImageCreateFromJpeg}, {"jpg", gdImageCreateFromJpeg}, {"jfif", gdImageCreateFromJpeg}, #endif {"gd", gdImageCreateFromGd}, {"gd2", gdImageCreateFromGd2}, {"xbm", gdImageCreateFromXbm}, /* this is internal to gd */ {NULL, NULL} }; static struct { char *ext; gdImagePtr (*func)(gdIOCtxPtr); } ext_table_ctx[] = { #ifdef HAVE_LIBPNG {"png", gdImageCreateFromPngCtx}, #endif #ifdef HAVE_LIBJPEG {"jpeg", gdImageCreateFromJpegCtx}, {"jpg", gdImageCreateFromJpegCtx}, {"jfif", gdImageCreateFromJpegCtx}, #endif {"gd", gdImageCreateFromGdCtx}, {"gd2", gdImageCreateFromGd2Ctx}, {NULL, NULL} }; /* ** Code to act as a gdIOCtx wrapper for a python file object ** (read-only; write support would not be difficult to add) */ struct PyFileIfaceObj_gdIOCtx { gdIOCtx ctx; PyObject *fileIfaceObj; PyObject *strObj; // our reference to the data string we're currently }; int PyFileIfaceObj_IOCtx_GetC(gdIOCtx *ctx) { struct PyFileIfaceObj_gdIOCtx *pctx = (struct PyFileIfaceObj_gdIOCtx *)ctx; if (pctx->strObj) { Py_DECREF(pctx->strObj); pctx->strObj = NULL; } pctx->strObj = PyObject_CallMethod(pctx->fileIfaceObj, "read", "i", 1); if (!pctx->strObj || !PyString_Check(pctx->strObj)) { return EOF; } if (PyString_GET_SIZE(pctx->strObj) == 1) { return (int)(unsigned char)PyString_AS_STRING(pctx->strObj)[0]; } return EOF; } int PyFileIfaceObj_IOCtx_GetBuf(gdIOCtx *ctx, void *data, int size) { int err; char *value; struct PyFileIfaceObj_gdIOCtx *pctx = (struct PyFileIfaceObj_gdIOCtx *)ctx; if (pctx->strObj) { Py_DECREF(pctx->strObj); pctx->strObj = NULL; } pctx->strObj = PyObject_CallMethod(pctx->fileIfaceObj, "read", "i", size); if (!pctx->strObj) { return 0; } err = PyString_AsStringAndSize(pctx->strObj, &value, &size); if (err < 0) { /* this throws away the python exception since the gd library * won't pass it up properly. gdmodule should create its own * since the "file" couldn't be read properly. */ PyErr_Clear(); return 0; } memcpy(data, value, size); return size; } void PyFileIfaceObj_IOCtx_Free(gdIOCtx *ctx) { struct PyFileIfaceObj_gdIOCtx *pctx = (struct PyFileIfaceObj_gdIOCtx *)ctx; if (pctx->strObj) { Py_DECREF(pctx->strObj); pctx->strObj = NULL; } if (pctx->fileIfaceObj) { Py_DECREF(pctx->fileIfaceObj); pctx->fileIfaceObj = NULL; } /* NOTE: we leave deallocation of the ctx structure itself to outside * code for memory allocation symmetry. This function is safe to * call multiple times (gd should call it + we call it to be safe). */ } struct PyFileIfaceObj_gdIOCtx * alloc_PyFileIfaceObj_IOCtx(PyObject *fileIfaceObj) { struct PyFileIfaceObj_gdIOCtx *pctx; pctx = calloc(1, sizeof(struct PyFileIfaceObj_gdIOCtx)); if (!pctx) return NULL; pctx->ctx.getC = PyFileIfaceObj_IOCtx_GetC; pctx->ctx.getBuf = PyFileIfaceObj_IOCtx_GetBuf; pctx->ctx.gd_free = PyFileIfaceObj_IOCtx_Free; Py_INCREF(fileIfaceObj); pctx->fileIfaceObj = fileIfaceObj; return pctx; } void free_PyFileIfaceObj_IOCtx(struct PyFileIfaceObj_gdIOCtx *pctx) { if (!pctx) return; assert(pctx->ctx.gd_free != NULL); pctx->ctx.gd_free((gdIOCtxPtr)pctx); // free its internal resources free(pctx); } /* ** Code to create the imageobject */ static imageobject *newimageobject(PyObject *args) { imageobject *self, *srcimage; int xdim=0, ydim=0, i, trueColor=0; char *filename,*ext=0; FILE *fp; PyObject *readObj; if(!(self = PyObject_NEW(imageobject, &Imagetype))) return NULL; self->current_tile = self->current_brush = NULL; self->origin_x = self->origin_y = 0; self->multiplier_x = self->multiplier_y = 1; self->imagedata = NULL; if(PyArg_ParseTuple(args, "")) { PyErr_SetString(PyExc_ValueError, "image size or source filename required"); Py_DECREF(self); return NULL; } else if(PyErr_Clear(), PyArg_ParseTuple(args, "O!|(ii)i", &Imagetype, &srcimage, &xdim, &ydim, &trueColor)) { if(!xdim) xdim = gdImageSX(srcimage->imagedata); if(!ydim) ydim = gdImageSY(srcimage->imagedata); #if GD2_VERS <= 1 trueColor = 0; #endif if (!trueColor){ if(!(self->imagedata = gdImageCreate(xdim,ydim))) { Py_DECREF(self); return NULL; } } #if GD2_VERS > 1 else if(!(self->imagedata = gdImageCreateTrueColor(xdim,ydim))) { Py_DECREF(self); return NULL; } #endif if(xdim == gdImageSX(srcimage->imagedata) && ydim == gdImageSY(srcimage->imagedata)) gdImageCopy(self->imagedata,srcimage->imagedata,0,0,0,0,xdim,ydim); else gdImageCopyResized(self->imagedata,srcimage->imagedata, 0,0,0,0,xdim,ydim,gdImageSX(srcimage->imagedata), gdImageSY(srcimage->imagedata)); } else if(PyErr_Clear(), PyArg_ParseTuple(args, "(ii)|i", &xdim, &ydim, &trueColor)) { if(!xdim || !ydim) { PyErr_SetString(PyExc_ValueError, "dimensions cannot be 0"); Py_DECREF(self); return NULL; } #if GD2_VERS <= 1 trueColor = 0; #endif if (!trueColor){ if(!(self->imagedata = gdImageCreate(xdim,ydim))) { Py_DECREF(self); return NULL; } } #if GD2_VERS > 1 else if(!(self->imagedata = gdImageCreateTrueColor(xdim,ydim))) { Py_DECREF(self); return NULL; } #endif } else if(PyErr_Clear(), PyArg_ParseTuple(args, "s|s", &filename, &ext)) { if(!ext) { if(!(ext = strrchr(filename,'.'))) { PyErr_SetString(PyExc_IOError, "need an extension to determine file type (.png|.jpeg|.jpg|.gd|.gd2|.xpm|.xbm)"); Py_DECREF(self); return NULL; } ext++; } if(strcmp(ext, "xpm") == 0) { #ifndef HAVE_LIBXPM PyErr_SetString(PyExc_NotImplementedError, "XPM Support Not Available"); Py_DECREF(self); return NULL; #else /* gdImageCreateFromXpm takes a filename rather than a FILE * */ if(!(self->imagedata = gdImageCreateFromXpm(filename))) { PyErr_SetString(PyExc_IOError, "corrupt or invalid image file"); Py_DECREF(self); return(NULL); } return self; #endif } if(!(fp = fopen(filename,"rb"))) { PyErr_SetFromErrno(PyExc_IOError); Py_DECREF(self); return(NULL); } for(i = 0; ext_table[i].ext != NULL; i++) { if(strcmp(ext, ext_table[i].ext) == 0) { if(!(self->imagedata = ext_table[i].func(fp))) { fclose(fp); PyErr_SetString(PyExc_IOError, "corrupt or invalid image file (may be unsupported)"); Py_DECREF(self); return(NULL); } fclose(fp); return self; } } /* if we fall out, we didn't find the file type */ PyErr_SetString(PyExc_IOError, "unsupported file type (only .png|.jpeg|.jpg|.gd|.gd2|.xbm|.xpm accepted)"); Py_DECREF(self); return(NULL); } else if(PyErr_Clear(), PyArg_ParseTuple(args, "Oz", &readObj, &ext)) { struct PyFileIfaceObj_gdIOCtx *ourIOCtx = NULL; if (!PyObject_HasAttrString(readObj, "read")) { PyErr_SetString(ErrorObject, "non-Image objects must have a read() method"); Py_DECREF(self); return NULL; } ourIOCtx = alloc_PyFileIfaceObj_IOCtx(readObj); if (!ourIOCtx) { PyErr_NoMemory(); Py_DECREF(self); return(NULL); } for(i = 0; ext_table_ctx[i].ext != NULL; i++) { if(strcmp(ext, ext_table_ctx[i].ext) == 0) { if(!(self->imagedata = ext_table_ctx[i].func((gdIOCtxPtr)ourIOCtx))) { free_PyFileIfaceObj_IOCtx(ourIOCtx); PyErr_SetString(PyExc_IOError, "corrupt or invalid image data (may be unsupported)"); Py_DECREF(self); return(NULL); } free_PyFileIfaceObj_IOCtx(ourIOCtx); return self; } } /* if we fall out, we didn't find the file type */ PyErr_SetString(PyExc_IOError, "unsupported file type (only png, jpeg, gd, & gd2 can be read from an object)"); free_PyFileIfaceObj_IOCtx(ourIOCtx); Py_DECREF(self); return(NULL); } else { PyErr_SetString(PyExc_ValueError, "invalid argument list"); Py_DECREF(self); return(NULL); } return self; } static void image_dealloc(imageobject *self) { if(self->current_brush) { Py_DECREF(self->current_brush); } if(self->current_tile) { Py_DECREF(self->current_tile); } if(self->imagedata) gdImageDestroy(self->imagedata); } static PyObject *image_getattr(PyObject *self, char *name) { return Py_FindMethod(image_methods, self, name); } static PyObject *image_print(PyObject *self, FILE *fp, int flags) { gdImagePtr im; im = ((imageobject *)self)->imagedata; fprintf(fp,"<%dx%d image object at 0x%lx>",gdImageSX(im),gdImageSY(im), (unsigned long)self); return 0; } static PyTypeObject Imagetype = { PyObject_HEAD_INIT(&PyType_Type) 0, /*ob_size*/ "image", /*tp_name*/ sizeof(imageobject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor)image_dealloc, /*tp_dealloc*/ (printfunc)image_print, /*tp_print*/ (getattrfunc)image_getattr, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call */ 0, /*tp_str */ 0,0,0,0, /*tp_xxx1-4 */ }; static PyObject *gd_image(PyObject *self, PyObject *args) { return (PyObject *)newimageobject(args); } static PyObject *gd_fontSSize(PyObject *self, PyObject *args) { int font; char *str; int len; if(!PyArg_ParseTuple(args, "is", &font, &str)) return NULL; if(font < 0 && font >= (sizeof(fonts)-1)) { PyErr_SetString(PyExc_ValueError, "Font value not valid"); return NULL; } len = strlen(str); return Py_BuildValue("(ii)", len*(fonts[font].data->w), fonts[font].data->h); } /* ** List of methods defined in the module */ static struct PyMethodDef gd_methods[] = { {"image", gd_image, 1, "image(image[,(w,h)] | file | file,type | (w,h))\n" "create GD image from file of type png, jpeg, gd, gd, gd2, xbm, or xpm.\n" "the existing image, optionally resized to width w and height h\n" "or blank with width w and height h"}, {"fontstrsize", gd_fontSSize, 1, "fontstrsize(font, string)\n" "return a tuple containing the size in pixels of the given string in the\n" "given font"}, {NULL, NULL} /* sentinel */ }; /* Initialization function for the module (*must* be called init_gd) */ void init_gd(void) { PyObject *m, *d, *v; int i=0; /* Create the module and add the functions */ m = Py_InitModule("_gd", gd_methods); /* Add some symbolic constants to the module */ d = PyModule_GetDict(m); ErrorObject = PyString_FromString("gd.error"); PyDict_SetItemString(d, "error", ErrorObject); /* add in the two font constants */ while(fonts[i].name) { v = Py_BuildValue("i", i); PyDict_SetItemString(d, fonts[i++].name, v); } /* and the standard gd constants */ v = Py_BuildValue("i", gdAntiAliased); PyDict_SetItemString(d, "gdAntiAliased", v); v = Py_BuildValue("i", gdBrushed); PyDict_SetItemString(d, "gdBrushed", v); v = Py_BuildValue("i", gdMaxColors); PyDict_SetItemString(d, "gdMaxColors", v); v = Py_BuildValue("i", gdMaxColors); PyDict_SetItemString(d, "gdMaxColors", v); v = Py_BuildValue("i", gdStyled); PyDict_SetItemString(d, "gdStyled", v); v = Py_BuildValue("i", gdStyledBrushed); PyDict_SetItemString(d, "gdStyledBrushed", v); v = Py_BuildValue("i", gdDashSize); PyDict_SetItemString(d, "gdDashSize", v); v = Py_BuildValue("i", gdTiled); PyDict_SetItemString(d, "gdTiled", v); v = Py_BuildValue("i", gdTransparent); PyDict_SetItemString(d, "gdTransparent", v); #if GD2_VERS > 1 v = Py_BuildValue("i", gdArc); PyDict_SetItemString(d, "gdArc", v); v = Py_BuildValue("i", gdChord); PyDict_SetItemString(d, "gdChord", v); v = Py_BuildValue("i", gdPie); PyDict_SetItemString(d, "gdPie", v); v = Py_BuildValue("i", gdNoFill); PyDict_SetItemString(d, "gdNoFill", v); v = Py_BuildValue("i", gdEdged); PyDict_SetItemString(d, "gdEdged", v); v = Py_BuildValue("i", GD_CMP_IMAGE); PyDict_SetItemString(d, "CMP_IMAGE", v); v = Py_BuildValue("i", GD_CMP_NUM_COLORS); PyDict_SetItemString(d, "CMP_NUM_COLORS", v); v = Py_BuildValue("i", GD_CMP_COLOR); PyDict_SetItemString(d, "CMP_COLOR", v); v = Py_BuildValue("i", GD_CMP_SIZE_X); PyDict_SetItemString(d, "CMP_SIZE_X", v); v = Py_BuildValue("i", GD_CMP_SIZE_Y); PyDict_SetItemString(d, "CMP_SIZE_Y", v); v = Py_BuildValue("i", GD_CMP_TRANSPARENT); PyDict_SetItemString(d, "CMP_TRANSPARENT", v); v = Py_BuildValue("i", GD_CMP_BACKGROUND); PyDict_SetItemString(d, "CMP_BACKGROUND", v); v = Py_BuildValue("i", GD_CMP_INTERLACE); PyDict_SetItemString(d, "CMP_INTERLACE", v); v = Py_BuildValue("i", GD_CMP_TRUECOLOR); PyDict_SetItemString(d, "CMP_TRUECOLOR", v); #endif /* Check for errors */ if(PyErr_Occurred()) Py_FatalError("can't initialize module gd"); } /* end of file. */