added median advance detection
[swftools.git] / lib / python / primitives.c
1 /* primitives.c
2
3    Python wrapper for librfxswf- primitive objects (implementation)
4
5    Part of the swftools package.
6
7    Copyright (c) 2003 Matthias Kramm <kramm@quiss.org>
8  
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
22
23 #include <Python.h>
24 #undef HAVE_STAT
25 #include "../rfxswf.h"
26 #include "../log.h"
27 #include "./pyutils.h"
28 #include "primitives.h"
29
30 //----------------------------------------------------------------------------
31 typedef struct {
32     PyObject_HEAD
33     RGBA rgba;
34 } ColorObject;
35
36 PyObject* f_Color2(U8 r, U8 g, U8 b, U8 a)
37 {
38     ColorObject* color = PyObject_New(ColorObject, &ColorClass);
39     color->rgba.r = r;
40     color->rgba.g = g;
41     color->rgba.b = b;
42     color->rgba.a = a;
43     return (PyObject*)color;
44 }
45 PyObject* f_Color(PyObject* self, PyObject* args, PyObject* kwargs)
46 {
47     static char *kwlist[] = {"r", "g", "b", "a", NULL};
48     ColorObject* color;
49     int r=0,g=0,b=0,a=255;
50     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iii|i", kwlist, &r,&g,&b,&a)) {
51         char*s= 0;
52         int mya = -1;
53         PyErr_Clear();
54         static char *kwlist[] = {"col", "alpha", NULL};
55         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|i", kwlist, &s, &mya))
56             return NULL;
57         if(mya>=0) a=mya;
58         sscanf(s, "%02x%02x%02x%02x",&r,&g,&b,&a);
59     }
60     color = PyObject_New(ColorObject, &ColorClass);
61     mylog("+%08x(%d) color_new(%d,%d,%d,%d)\n", (int)color, color->ob_refcnt, r,g,b,a);
62     return f_Color2(r,g,b,a);
63 }
64 static PyObject* color_getattr(PyObject * self, char* a)
65 {
66     ColorObject*color = (ColorObject*)self;
67     if(!strcmp(a, "r")) {
68         return Py_BuildValue("i", color->rgba.r);
69     } else if(!strcmp(a, "g")) {
70         return Py_BuildValue("i", color->rgba.g);
71     } else if(!strcmp(a, "b")) {
72         return Py_BuildValue("i", color->rgba.b);
73     } else if(!strcmp(a, "a")) {
74         return Py_BuildValue("i", color->rgba.a);
75     } else if(!strcmp(a, "alpha")) {
76         return Py_BuildValue("i", color->rgba.a);
77     } else if(!strcmp(a, "rgb")) {
78         char text[80];
79         sprintf(text, "%02x%02x%02x", color->rgba.r, color->rgba.g, color->rgba.b);
80         return PyString_FromString(text);
81     } else if(!strcmp(a, "rgba")) {
82         char text[80];
83         sprintf(text, "%02x%02x%02x%02x", color->rgba.r, color->rgba.g, color->rgba.b, color->rgba.a);
84         return PyString_FromString(text);
85     }
86     return PY_ERROR("bad attribute");
87 }
88 static int color_setattr(PyObject * self, char* attr, PyObject* o)
89 {
90     ColorObject*color = (ColorObject*)self;
91     if(!strcmp(attr, "r")) {
92         if (!PyArg_Parse(o, "d", &color->rgba.r)) goto err;
93         return 0;
94     } else if(!strcmp(attr, "g")) {
95         if (!PyArg_Parse(o, "d", &color->rgba.g)) goto err;
96         return 0;
97     } else if(!strcmp(attr, "b")) {
98         if (!PyArg_Parse(o, "d", &color->rgba.b)) goto err;
99         return 0;
100     } else if(!strcmp(attr, "a")) {
101         if (!PyArg_Parse(o, "d", &color->rgba.a)) goto err;
102         return 0;
103     } 
104 err:
105     mylog("swf_setattr %08x(%d) %s = ? (%08x)\n", (int)self, self->ob_refcnt, attr, o);
106     return 1;
107 }
108 RGBA color_getRGBA(PyObject*self)
109 {
110     ColorObject*color = 0;
111     if (!PyArg_Parse(self, "O!", &ColorClass, &color)) {
112         RGBA dummy;
113         memset(&dummy, 0, sizeof(dummy));
114         mylog("Error: wrong type for function color_getRGBA");
115         return dummy;
116     }
117     return color->rgba;
118 }
119 void color_dealloc(PyObject* self)
120 {
121     mylog("-%08x(%d) color_dealloc\n", (int)self, self->ob_refcnt);
122     PyObject_Del(self);
123 }
124 PyTypeObject ColorClass = 
125 {
126     PyObject_HEAD_INIT(NULL)
127     0,
128     tp_name: "Color",
129     tp_basicsize: sizeof(ColorObject),
130     tp_itemsize: 0,
131     tp_dealloc: color_dealloc,
132     tp_print: 0,
133     tp_getattr: color_getattr,
134     tp_setattr: color_setattr,
135 };
136 //----------------------------------------------------------------------------
137 typedef struct {
138     PyObject_HEAD
139     SRECT bbox;
140 } BBoxObject;
141 //void swf_ExpandRect(SRECT*src, SPOINT add);
142 //void swf_ExpandRect2(SRECT*src, SRECT*add);
143
144 PyObject* f_BBox(PyObject* self, PyObject* args, PyObject* kwargs)
145 {
146     static char *kwlist[] = {"xmin", "ymin", "xmax", "ymax", NULL};
147     BBoxObject* bbox;
148     float xmin,ymin,xmax,ymax;
149     if(!kwargs) {
150         if (!PyArg_ParseTuple(args, "ffff", &xmin, &ymin, &xmax, &ymax))
151             return NULL;
152     } else {
153         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ffff", kwlist, &xmin, &ymin, &xmax, &ymax))
154             return NULL;
155     }
156     SRECT box;
157     box.xmin = (int)(xmin*20);
158     box.ymin = (int)(ymin*20);
159     box.xmax = (int)(xmax*20);
160     box.ymax = (int)(ymax*20);
161     mylog("+%08x(%d) bbox_new(%d,%d,%d,%d)\n", (int)self, self?self->ob_refcnt:0, box.xmin, box.ymin, box.xmax,box.ymax);
162     bbox = PyObject_New(BBoxObject, &BBoxClass);
163     bbox->bbox = box;
164     return (PyObject*)bbox;
165 }
166 PyObject* f_BBox2(SRECT box)
167 {
168     BBoxObject* bbox;
169     bbox = PyObject_New(BBoxObject, &BBoxClass);
170     bbox->bbox = box;
171     return (PyObject*)bbox;
172 }
173 static PyObject* bbox_getattr(PyObject * self, char* a)
174 {
175     BBoxObject*bbox = (BBoxObject*)self;
176     if(!strcmp(a, "xmin")) {
177         return Py_BuildValue("f", bbox->bbox.xmin/20.0);
178     } else if(!strcmp(a, "ymin")) {
179         return Py_BuildValue("f", bbox->bbox.ymin/20.0);
180     } else if(!strcmp(a, "xmax")) {
181         return Py_BuildValue("f", bbox->bbox.xmax/20.0);
182     } else if(!strcmp(a, "ymax")) {
183         return Py_BuildValue("f", bbox->bbox.ymax/20.0);
184     }
185     return NULL;
186 }
187 static int bbox_setattr(PyObject * self, char* a, PyObject* o)
188 {
189     BBoxObject*bbox= (BBoxObject*)self;
190     if(!strcmp(a, "xmin")) {
191         float xmin;
192         if (!PyArg_Parse(o, "f", &xmin)) goto err;
193         bbox->bbox.xmin = (int)(xmin*20);
194         return 0;
195     } else if(!strcmp(a, "ymin")) {
196         float ymin;
197         if (!PyArg_Parse(o, "f", &ymin)) goto err;
198         bbox->bbox.ymin = (int)(ymin*20);
199         return 0;
200     } else if(!strcmp(a, "xmax")) {
201         float xmax;
202         if (!PyArg_Parse(o, "f", &xmax)) goto err;
203         bbox->bbox.xmax = (int)(xmax*20);
204         return 0;
205     } else if(!strcmp(a, "ymax")) {
206         float ymax;
207         if (!PyArg_Parse(o, "f", &ymax)) goto err;
208         bbox->bbox.ymax = (int)(ymax*20);
209         return 0;
210     } 
211 err:
212     mylog("swf_setattr %08x(%d) %s = ? (%08x)\n", (int)self, self->ob_refcnt, a, o);
213     return 1;
214 }
215 void bbox_dealloc(PyObject* self)
216 {
217     mylog("-%08x(%d) bbox_dealloc\n", (int)self, self->ob_refcnt);
218     PyObject_Del(self);
219 }
220 SRECT bbox_getSRECT(PyObject*self)
221 {
222     BBoxObject*bbox= 0;
223     if (!PyArg_Parse(self, "O!", &BBoxClass, &bbox)) {
224         SRECT dummy;
225         memset(&dummy, 0, sizeof(dummy));
226         mylog("Error: wrong type for function color_getRGBA");
227         return dummy;
228     }
229     return bbox->bbox;
230 }
231 PyTypeObject BBoxClass = 
232 {
233     PyObject_HEAD_INIT(NULL)
234     0,
235     tp_name: "BBox",
236     tp_basicsize: sizeof(BBoxObject),
237     tp_itemsize: 0,
238     tp_dealloc: bbox_dealloc,
239     tp_print: 0,
240     tp_getattr: bbox_getattr,
241     tp_setattr: bbox_setattr,
242 };
243 SRECT bbox_getBBox(PyObject*self);
244 //----------------------------------------------------------------------------
245 typedef struct {
246     PyObject_HEAD
247     MATRIX matrix;
248 } MatrixObject;
249
250 PyObject* f_Matrix2(MATRIX* m)
251 {
252     PyObject*self = (PyObject*)PyObject_New(MatrixObject, &MatrixClass);
253     MatrixObject*matrix = (MatrixObject*)self;
254     matrix->matrix = *m;
255     return self;
256 }
257
258 PyObject* f_Matrix(PyObject* _self, PyObject* args, PyObject* kwargs)
259 {
260     PyObject*self = (PyObject*)PyObject_New(MatrixObject, &MatrixClass);
261     MatrixObject*matrix = (MatrixObject*)self;
262     mylog("+%08x(%d) f_Matrix", self, self->ob_refcnt);
263     static char *kwlist[] = {"x", "y", "scale", "rotate", "pivotx", "pivoty", NULL};
264     float x=0,y=0,scale=1.0,rotate=0,pivotx=0,pivoty=0;
265     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ffffff", kwlist, &x,&y,&scale,&rotate,&pivotx,&pivoty))
266         return NULL;
267     mylog(" %08x(%d) f_Matrix: x=%f y=%f scale=%f rotate=%f", self, self->ob_refcnt, x,y,scale,rotate);
268     swf_GetMatrix(0, &matrix->matrix);
269
270     matrix->matrix.tx = (int)(x*20);
271     matrix->matrix.ty = (int)(y*20);
272
273     if(!rotate) {
274         matrix->matrix.sx = (int)(scale*65536);
275         matrix->matrix.sy = (int)(scale*65536);
276     } else {
277         matrix->matrix.sx = (int)(scale*cos(rotate)*65536);
278         matrix->matrix.sy = (int)(scale*cos(rotate)*65536);
279         matrix->matrix.r0 = (int)(scale*sin(rotate)*65536);
280         matrix->matrix.r1 = (int)(-scale*sin(rotate)*65536);
281     }
282     if(pivotx || pivoty) {
283         SPOINT p,d;
284         p.x = (int)(pivotx*20);
285         p.y = (int)(pivoty*20);
286         p = swf_TurnPoint(p, &matrix->matrix);
287         matrix->matrix.tx += matrix->matrix.tx-p.x;
288         matrix->matrix.ty += matrix->matrix.ty-p.y;
289     }
290
291     /* TODO: rotate */
292     return self;
293 }
294 static PyObject* matrix_getattr(PyObject * self, char* a)
295 {
296     PY_ASSERT_TYPE(self,&MatrixClass);
297     MatrixObject*matrix = (MatrixObject*)self;
298     if(!strcmp(a, "entries")) {
299         return Py_BuildValue("(ffffff)",
300                 matrix->matrix.sx/65536.0,
301                 matrix->matrix.r0/65536.0,
302                 matrix->matrix.r1/65536.0,
303                 matrix->matrix.sy/65536.0,
304                 matrix->matrix.tx/20.0,
305                 matrix->matrix.ty/20.0
306                 );
307     }
308     return NULL;
309 }
310 static int matrix_setattr(PyObject * self, char* a, PyObject* o)
311 {
312     PY_ASSERT_TYPE(self,&MatrixClass);
313     return 0;
314 }
315 MATRIX matrix_getMatrix(PyObject*self)
316 {
317     mylog(" %08x(%d) matrix_getMatrix", self, self->ob_refcnt);
318     PY_ASSERT_TYPE(self,&MatrixClass);
319     MatrixObject*matrix = (MatrixObject*)self;
320     return matrix->matrix;
321 }
322 void matrix_dealloc(PyObject* self)
323 {
324     mylog("-%08x(%d) matrix_dealloc", self, self->ob_refcnt);
325     PyObject_Del(self);
326 }
327 //SPOINT swf_TurnPoint(SPOINT p, MATRIX* m);
328 //SRECT swf_TurnRect(SRECT r, MATRIX* m);
329 PyTypeObject MatrixClass = 
330 {
331     PyObject_HEAD_INIT(NULL)
332     0,
333     tp_name: "Matrix",
334     tp_basicsize: sizeof(MatrixObject),
335     tp_itemsize: 0,
336     tp_dealloc: matrix_dealloc,
337     tp_print: 0,
338     tp_getattr: matrix_getattr,
339     tp_setattr: matrix_setattr,
340     tp_compare: 0,
341     tp_repr: 0,
342     tp_as_number: 0,
343     tp_as_sequence: 0,
344     tp_as_mapping: 0,
345     tp_hash: 0,     // dict(x)
346     tp_call: 0,     // x()
347     tp_str: 0       // str(x)
348 };
349 //----------------------------------------------------------------------------
350 typedef struct {
351     PyObject_HEAD
352     CXFORM cxform;
353 } CXFormObject;
354
355 PyObject* f_ColorTransform(PyObject* _self, PyObject* args, PyObject* kwargs)
356 {
357     int r0=256,g0=256,b0=256,a0=256,r1=0,g1=0,b1=0,a1=0;
358     static char *kwlist[] = {"r_mul", "g_mul", "b_mul", "a_mul", "r_add", "g_add", "b_add", "a_add", NULL};
359     PyObject*color;
360     if(!kwargs) {
361         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iiiiiiii", kwlist,
362                 &r0,&g0,&b0,&a0,
363                 &r1,&g1,&b1,&a1))
364             return NULL;
365     }
366
367     CXFORM c;
368     c.r0 = r0; c.g0 = g0; c.b0 = b0; c.a0 = a0;
369     c.r1 = r1; c.g1 = g1; c.b1 = b1; c.a1 = a1;
370
371     CXFormObject*self = PyObject_New(CXFormObject, &CXFormClass);
372     self->cxform = c;
373     return (PyObject*)self;
374 }
375 static PyObject* colortransform_getattr(PyObject * self, char* a)
376 {
377     return NULL;
378 }
379 static int colortransform_setattr(PyObject * self, char* a, PyObject* o)
380 {
381     return 0;
382 }
383 CXFORM colortransform_getCXForm(PyObject*self)
384 {
385     CXFormObject*cxform= 0;
386     if (!PyArg_Parse(self, "O!", &CXFormClass, &cxform)) {
387         CXFORM dummy;
388         memset(&dummy, 0, sizeof(dummy));
389         mylog("Error: wrong type for function color_getRGBA");
390         return dummy;
391     }
392     return cxform->cxform;
393 }
394 void colortransform_dealloc(PyObject* self)
395 {
396     mylog("-%08x(%d) colortransform_dealloc", self, self->ob_refcnt);
397     PyObject_Del(self);
398 }
399 PyTypeObject CXFormClass = 
400 {
401     PyObject_HEAD_INIT(NULL)
402     0,
403     tp_name: "ColorTransform",
404     tp_basicsize: sizeof(CXFormObject),
405     tp_itemsize: 0,
406     tp_dealloc: colortransform_dealloc,
407     tp_print: 0,
408     tp_getattr: colortransform_getattr,
409     tp_setattr: colortransform_setattr,
410 };
411 //----------------------------------------------------------------------------
412 typedef struct {
413     PyObject_HEAD
414     GRADIENT gradient;
415 } GradientObject;
416
417 PyObject* f_Gradient(PyObject* self, PyObject* args, PyObject* kwargs)
418 {
419     return NULL;
420 }
421 static PyObject* gradient_getattr(PyObject * self, char* a)
422 {
423     return NULL;
424 }
425 static int gradient_setattr(PyObject * self, char* a, PyObject* o)
426 {
427     return 0;
428 }
429 GRADIENT gradient_getGradient(PyObject*self)
430 {
431     GradientObject*gradient = 0;
432     if (!PyArg_Parse(self, "O!", &gradient, &gradient)) {
433         GRADIENT dummy;
434         memset(&dummy, 0, sizeof(dummy));
435         mylog("Error: wrong type for function color_getRGBA");
436         return dummy;
437     }
438     return gradient->gradient;
439 }
440 void gradient_dealloc(PyObject* self)
441 {
442     mylog("-%08x(%d) gradient_dealloc", self, self->ob_refcnt);
443     PyObject_Del(self);
444 }
445 PyTypeObject GradientClass = 
446 {
447     PyObject_HEAD_INIT(NULL)
448     0,
449     tp_name: "Gradient",
450     tp_basicsize: sizeof(GradientObject),
451     tp_itemsize: 0,
452     tp_dealloc: gradient_dealloc,
453     tp_print: 0,
454     tp_getattr: gradient_getattr,
455     tp_setattr: gradient_setattr,
456 };
457 //----------------------------------------------------------------------------
458
459 typedef struct {
460     PyObject_HEAD
461     LINESTYLE ls;
462 } LineStyleObject;
463
464 PyObject* f_LineStyle2(RGBA color, int width) 
465 {
466     LineStyleObject* self = PyObject_New(LineStyleObject, &LineStyleClass);
467     self->ls.color = color;
468     self->ls.width = width;
469     return (PyObject*)self;
470 }
471 PyObject* f_LineStyle3(LINESTYLE ls)
472 {
473     LineStyleObject* self = PyObject_New(LineStyleObject, &LineStyleClass);
474     self->ls = ls;
475     return (PyObject*)self;
476 }
477 PyObject* f_LineStyle(PyObject* _self, PyObject* args, PyObject* kwargs)
478 {
479     static char *kwlist[] = {"line", "color", NULL};
480     float linewidth;
481     PyObject*color;
482     if(!kwargs) {
483         if (!PyArg_ParseTuple(args, "fO!", &linewidth, &ColorClass, &color))
484             return NULL;
485     }
486     return f_LineStyle2(color_getRGBA(color), (int)(linewidth*20));
487 }
488 LINESTYLE linestyle_getLineStyle(PyObject*_self)
489 {
490     LineStyleObject* self = (LineStyleObject*)_self;
491     return self->ls;
492 }
493 static PyObject* linestyle_getattr(PyObject * _self, char* a)
494 {
495     LineStyleObject*self = (LineStyleObject*)_self;
496     if(!strcmp(a, "width")) {
497         return Py_BuildValue("i", self->ls.width);
498     } else if(!strcmp(a, "color")) {
499         return f_Color2(self->ls.color.r, self->ls.color.g, self->ls.color.b, self->ls.color.a);
500     }
501     return NULL;
502 }
503 static int linestyle_setattr(PyObject * _self, char* a, PyObject* o)
504 {
505     LineStyleObject*self = (LineStyleObject*)_self;
506     if(!strcmp(a, "color")) {
507         self->ls.color = color_getRGBA(o);
508         return 0;
509     }
510     return -1;
511 }
512 static LINESTYLE linestyle_getlinestyle(PyObject*_self)
513 {
514     LineStyleObject*self = (LineStyleObject*)_self;
515     return self->ls;
516 }
517 static void linestyle_dealloc(PyObject* self)
518 {
519     mylog("-%08x(%d) linestyle_dealloc", self, self->ob_refcnt);
520     PyObject_Del(self);
521 }
522 static int linestyle_print(PyObject * _self, FILE *fi, int flags) //flags&Py_PRINT_RAW
523 {
524     LineStyleObject* self = (LineStyleObject*)_self;
525     fprintf(fi, "line-%d-%02x%02x%02x%02x", self->ls.width, self->ls.color.r, self->ls.color.g, self->ls.color.b, self->ls.color.a);
526     return 0;
527 }
528 PyTypeObject LineStyleClass = 
529 {
530     PyObject_HEAD_INIT(NULL)
531     0,
532     tp_name: "linestyle",
533     tp_basicsize: sizeof(LineStyleObject),
534     tp_itemsize: 0,
535     tp_dealloc: linestyle_dealloc,
536     tp_print: linestyle_print,
537     tp_getattr: linestyle_getattr,
538     tp_setattr: linestyle_setattr,
539 };
540 //----------------------------------------------------------------------------
541
542 typedef struct {
543     PyObject_HEAD
544     FILLSTYLE fs;
545 } FillStyleObject;
546
547 PyObject* f_FillStyle2(FILLSTYLE fs)
548 {
549     FillStyleObject* self = PyObject_New(FillStyleObject, &FillStyleClass);
550     self->fs = fs;
551     return (PyObject*)self;
552 }
553 PyObject* f_SolidFillStyle2(RGBA color)
554 {
555     FillStyleObject* self = PyObject_New(FillStyleObject, &FillStyleClass);
556     self->fs.type = FILL_SOLID;
557     self->fs.color = color;
558     return (PyObject*)self;
559 }
560 PyObject* f_SolidFillStyle(PyObject* _self, PyObject* args, PyObject* kwargs)
561 {
562     static char *kwlist[] = {"color", NULL};
563     PyObject*color;
564     if(!kwargs) {
565         if (!PyArg_ParseTuple(args, "O!", &ColorClass, &color))
566             return NULL;
567     }
568     return f_SolidFillStyle2(color_getRGBA(color));
569 }
570 FILLSTYLE fillstyle_getFillStyle(PyObject*_self)
571 {
572     FillStyleObject* self = (FillStyleObject*)_self;
573     return self->fs;
574 }
575 static void fillstyle_dealloc(PyObject* self)
576 {
577     mylog("-%08x(%d) linestyle_dealloc", self, self->ob_refcnt);
578     PyObject_Del(self);
579 }
580 static int fillstyle_print(PyObject * _self, FILE *fi, int flags) //flags&Py_PRINT_RAW
581 {
582     FillStyleObject* self = (FillStyleObject*)_self;
583     if(self->fs.type == FILL_SOLID)
584         fprintf(fi, "fill-solid(%02x%02x%02x%02x)", self->fs.color.r, self->fs.color.g, self->fs.color.b, self->fs.color.a);
585     else
586         fprintf(fi, "fill-%02x", self->fs.type);
587     return 0;
588 }
589 PyObject* fillstyle_issolid(PyObject*_self, PyObject*args)
590 {
591     FillStyleObject* self = (FillStyleObject*)_self;
592     int b = self->fs.type == FILL_SOLID;
593     return PyInt_FromLong(b);
594 }
595 static PyMethodDef FillStyleMethods[] = 
596 {
597     /* Module functions */
598     {"isSolid", fillstyle_issolid, METH_VARARGS, "Queries whether this is a solid fill"},
599     {0,0,0,0}
600 };
601 static PyObject* fillstyle_getattr(PyObject * _self, char* a)
602 {
603     FillStyleObject* self = (FillStyleObject*)_self;
604     if(!strcmp(a, "color")) {
605         return f_Color2(self->fs.color.r, self->fs.color.g, self->fs.color.b, self->fs.color.a);
606     }
607     return Py_FindMethod(FillStyleMethods, _self, a);
608 }
609 static int fillstyle_setattr(PyObject * _self, char* a, PyObject* o)
610 {
611     FillStyleObject*self = (FillStyleObject*)_self;
612     if(!strcmp(a, "color")) {
613         self->fs.color = color_getRGBA(o);
614         return 0;
615     }
616     return -1;
617 }
618
619 PyTypeObject FillStyleClass = 
620 {
621     PyObject_HEAD_INIT(NULL)
622     0,
623     tp_name: "fillstyle",
624     tp_basicsize: sizeof(FillStyleObject),
625     tp_itemsize: 0,
626     tp_dealloc: fillstyle_dealloc,
627     tp_print: fillstyle_print,
628     tp_getattr: fillstyle_getattr,
629     tp_setattr: fillstyle_setattr,
630 };
631 //----------------------------------------------------------------------------
632 static PyMethodDef primitive_methods[] = 
633 {
634     {"Color", (PyCFunction)f_Color, METH_KEYWORDS, "Create a new color object."},
635     {"Gradient", (PyCFunction)f_Gradient, METH_KEYWORDS, "Create a new gradient object."},
636     {"ColorTransform", (PyCFunction)f_ColorTransform, METH_KEYWORDS, "Create a new colortransform object."},
637     {"Matrix", (PyCFunction)f_Matrix, METH_KEYWORDS, "Create a new matrix object."},
638     {"BBox", (PyCFunction)f_BBox, METH_KEYWORDS, "Create a new bounding box object."},
639     {"SolidFillStyle", (PyCFunction)f_SolidFillStyle, METH_KEYWORDS, "Creates a new solid fill style."},
640     {"LineStyle", (PyCFunction)f_SolidFillStyle, METH_KEYWORDS, "Creates a new line style."},
641     {NULL, NULL, 0, NULL}
642 };
643
644 PyMethodDef* primitive_getMethods()
645 {
646     GradientClass.ob_type = &PyType_Type;
647     CXFormClass.ob_type = &PyType_Type;
648     BBoxClass.ob_type = &PyType_Type;
649     MatrixClass.ob_type = &PyType_Type;
650     FillStyleClass.ob_type = &PyType_Type;
651     LineStyleClass.ob_type = &PyType_Type;
652     return primitive_methods;
653 }
654
655