I'm using Python's Imaging Library and I would like to draw some bezier curves. I guess I could calculate pixel by pixel but I'm hoping there is something simpler.
相关问题
- how to define constructor for Python's new Nam
- streaming md5sum of contents of a large remote tar
- How to get the background from multiple images by
- Evil ctypes hack in python
- Correctly parse PDF paragraphs with Python
I found a simpler way creating a bezier curve (without aggraw and without complex functions).
You can use the aggdraw on top of PIL, bezier curves are supported.
EDIT:
I made an example only to discover there is a bug in the
Path
class regardingcurveto
:(Here is the example anyway:
This should fix the bug if you're up for recompiling the module...
Although bezier curveto paths don't work with Aggdraw, as mentioned by @ToniRuža, there is another way to do this in Aggdraw. The benefit of using Aggdraw instead of PIL or your own bezier functions is that Aggdraw will antialias the image making it look smoother (see pic at bottom).
Aggdraw Symbols
Instead of using the aggdraw.Path() class to draw, you can use the
aggdraw.Symbol(pathstring)
class which is basically the same except you write the path as a string. According to the Aggdraw docs the way to write your path as a string is to use SVG path syntax (see: http://www.w3.org/TR/SVG/paths.html). Basically, each addition (node) to the path normally starts withIn your pathstring just separate your multiple nodes with a space. Once you have created your symbol, just remember to draw it by passing it as one of the arguments to
draw.symbol(args)
.Bezier Curves in Aggdraw Symbols
Specifically for cubic bezier curves you write the letter "C" or "c" followed by 6 numbers (3 sets of xy coordinates x1,y1,x2,y2,x3,y3 with commas in between the numbers but not between the first number and the letter). According the docs there are also other bezier versions by using the letter "S (smooth cubic bezier), Q (quadratic bezier), T (smooth quadratic bezier)". Here is a complete example code (requires PIL and aggdraw):
And the output is a smooth-looking curved bezier figure:
A bezier curve isn't that hard to draw yourself. Given three points
A
,B
,C
you require three linear interpolations in order to draw the curve. We use the scalart
as the parameter for the linear interpolation:This interpolates between two edges we've created, edge AB and edge BC. The only thing we now have to do to calculate the point we have to draw is interpolate between P0 and P1 using the same t like so:
There are a couple of things that need to be done before we actually draw the curve. First off we have will walk some
dt
(delta t) and we need to be aware that0 <= t <= 1
. As you might be able to imagine, this will not give us a smooth curve, instead it yields only a discrete set of positions at which to plot. The easiest way to solve this is to simply draw a line between the current point and the previous point.This, for example, draws a heart: