#include #include #include #include #include #include #include using namespace std; // Here are all the constants defined in the paper, with somewhat // arbitrary initial values. float f_sigma = 0.5; float f_g = 1.0; float T = 100.0; size_t maxStrokeLength = 32; size_t minStrokeLength = 4; float f_c = 1.0; float alpha = 1.0; float jh = 0.0; float js = 0.0; float jv = 0.0; float jr = 0.0; float jg = 0.0; float jb = 0.0; // Sample code to paint a piecewise polygonal path onto a canvas // using libart. void paintPolyline( unsigned char *canvas, size_t w, size_t h, const vector& xs, const vector& ys, unsigned char r, unsigned char g, unsigned char b, float radius ) { ArtVpath *stroke = NULL; stroke = art_new( ArtVpath, xs.size() + 1 ); stroke[0].code = ART_MOVETO; stroke[0].x = xs[0]; stroke[0].y = ys[0]; for( size_t idx = 1; idx < xs.size(); ++idx ) { stroke[idx].code = ART_LINETO; stroke[idx].x = xs[idx]; stroke[idx].y = ys[idx]; } stroke[ xs.size() ].code = ART_END; ArtSVP *svp = art_svp_vpath_stroke( stroke, ART_PATH_STROKE_JOIN_ROUND, ART_PATH_STROKE_CAP_ROUND, radius, 1.0, 1.0 ); art_rgb_svp_alpha( svp, 0, 0, w, h, (r<<24) | (g<<16) | (b<<8) | 0xff, canvas, 3*w, NULL ); art_free( stroke ); art_free( svp ); } // An example of painting piecewise cubic curves based on Bezier control // points. If you want to use this, you should modify it to permit // any number of control points. The example as given is purely // pedagogical. // // Assume you want to draw two connected Bezier curves, specified // as P1, P2, P3, Q1(=P4), Q2, Q3, Q4 // void paintBezier( unsigned char *canvas, size_t w, size_t h, float px1, float py1, float px2, float py2, float px3, float py3, float px4, float py4, float qx2, float qy2, float qx3, float qy3, float qx4, float qy4, unsigned char r, unsigned char g, unsigned char b, float radius ) { ArtBpath *bpath = art_new( ArtBpath, 5 ); bpath[0].code = ART_MOVETO; bpath[0].x3 = px1; bpath[0].y3 = py1; bpath[1].code = ART_CURVETO; bpath[1].x1 = px2; bpath[1].y1 = py2; bpath[1].x2 = px3; bpath[1].y2 = py3; bpath[1].x3 = px4; bpath[1].y3 = py4; bpath[2].code = ART_CURVETO; bpath[2].x1 = qx2; bpath[2].y1 = qy2; bpath[2].x2 = qx3; bpath[2].y2 = qy3; bpath[2].x3 = qx4; bpath[2].y3 = qy4; // Let's add a line segment to the end, just to show it it's done... bpath[3].code = ART_LINETO; bpath[3].x3 = qx4 + 100.0; bpath[3].y3 = qy4; bpath[4].code = ART_END; // Turn the Bezier path into a sequence of line segments // by flattening it. ArtVpath *stroke = art_bez_path_to_vec( bpath, 0.1 ); art_free( bpath ); // Turn the line segments into an SVP (a data structure that // libart uses to optimize drawing). ArtSVP *svp = art_svp_vpath_stroke( stroke, ART_PATH_STROKE_JOIN_ROUND, ART_PATH_STROKE_CAP_ROUND, radius, 1.0, 1.0 ); // Draw the SVP into a byte buffer. art_rgb_svp_alpha( svp, 0, 0, w, h, (r<<24) | (g<<16) | (b<<8) | 0xff, canvas, 3*w, NULL ); art_free( stroke ); art_free( svp ); } // Same as the paintLayer function in the paper. Takes pointers to // buffers holding the canvas and ref images (in RGB byte triples), // the width and height of both images (they have to be the same size) // and the current brush radius. void paintLayer( unsigned char *canvas, unsigned char *ref, size_t w, size_t h, float R ) { // Your implementation goes here... } // The Python glue function. Unpack the Python-level arguments and // pass them to the paintLayer function. PyObject *py_paintlayer( PyObject *self, PyObject *args ) { unsigned char *canvas; unsigned char *ref; int w; int h; int l; float R; if ( !PyArg_ParseTuple( args, "s#s#iif", (char**)&canvas, &l, (char**)&ref, &l, &w, &h, &R ) ) { return NULL; } // Just to be safe, I don't want to overwrite the passed in // canvas string. So I construct a new object to hold the // returned Python string, copy the passed in canvas to the // new string, and allow paintLayer to operate on the new // object. /* Create a Python string to hold the returned image data. */ PyObject *ret = PyString_FromStringAndSize( NULL, 3 * w * h ); /* Get the char * buffer out of the string. */ unsigned char *buf = (unsigned char *)PyString_AsString( ret ); copy( canvas, canvas + (w*h*3), buf ); paintLayer( buf, ref, w, h, R ); return ret; } // A useful function that lets you set the paper's constants from // Python code. You can set any subset of them with a function call, // using keyword arguments. Examples: // // painthelp.setparams( jr=0.1, jg=0.1, jb=0.1 ) // painthelp.setparams( T=100.0 ) // // Especially useful if you build a command-line-driven Python script // as I did. A GUI for this program should probably let you set the // values from a dialog box. // PyObject *py_setparams( PyObject *self, PyObject *args, PyObject *kwds ) { static char *kwlist[] = { "f_sigma", "f_g", "T", "maxStrokeLength", "minStrokeLength", "f_c", "alpha", "jh", "js", "jv", "jr", "jg", "jb", NULL }; if( !PyArg_ParseTupleAndKeywords( args, kwds, "|fffiiffffffff", kwlist, &f_sigma, &f_g, &T, &maxStrokeLength, &minStrokeLength, &f_c, &alpha, &jh, &js, &jv, &jr, &jg, &jb ) ) { return NULL; } Py_INCREF( Py_None ); return Py_None; } /* * Build a table containing all the methods that will be exported * by this module. */ static PyMethodDef gr_method_table[] = { { "paintLayer", py_paintlayer, METH_VARARGS, "Paint a layer" }, { "setparams", (PyCFunction)py_setparams, METH_VARARGS|METH_KEYWORDS, "Set parameters" }, { NULL, NULL, 0, NULL } }; /* * This function is called automatically by Python when this module * is first imported. It adds the module and all the C functions into * the running interpreter. */ extern "C" { DL_EXPORT(void) initpainthelp(void); } DL_EXPORT(void) initpainthelp(void) { (void)Py_InitModule( "painthelp", gr_method_table ); }