Code Example¶
Here’s how celiagg can be used to render a red circle with the word “celiagg” inside:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | import celiagg as agg
import numpy as np
from PIL import Image
state = agg.GraphicsState(drawing_mode=agg.DrawingMode.DrawStroke,
line_width=10.0)
transform = agg.Transform()
red_paint = agg.SolidPaint(1.0, 0.0, 0.0)
orange_paint = agg.SolidPaint(0.99, 0.66, 0.0)
canvas = agg.CanvasRGB24(np.zeros((400, 400, 3), dtype=np.uint8))
path = agg.Path()
path.ellipse(200, 200, 190, 190)
canvas.clear(1.0, 1.0, 1.0)
canvas.draw_shape(path, transform, state, stroke=red_paint)
font = agg.Font(agg.example_font(), 96.0)
transform.translate(30.0, 220.0)
canvas.draw_text("celiagg", font, transform, state, fill=orange_paint)
image = Image.fromarray(canvas.array, "RGB")
image.save("example.png")
|
Which gives the resulting image:
Code Breakdown¶
Imports¶
First, we include some libraries. numpy is needed for the memory buffer
which the canvas drawns into. PIL is used for simple image file I/O.
Finally, celiagg is imported for obvious reasons:
1 2 3 | import celiagg as agg
import numpy as np
from PIL import Image
|
State setup¶
Next, some state objects are created. Most important is the
celiagg.GraphicsState object. Pay attention to the
drawing_mode=agg.DrawingMode.DrawStroke keyword argument. This means that
all drawing calls using this state will only draw the outline of the shapes
being drawn.
The remaining state objects are transform which sets the affine
transformation of the drawing and red_paint/orange_paint which determine
the color of strokes (outlines) or fills when drawing.
5 6 7 8 9 | state = agg.GraphicsState(drawing_mode=agg.DrawingMode.DrawStroke,
line_width=10.0)
transform = agg.Transform()
red_paint = agg.SolidPaint(1.0, 0.0, 0.0)
orange_paint = agg.SolidPaint(0.99, 0.66, 0.0)
|
Canvas creation¶
Then, also quite important, a canvas object is created. The canvas is a
400 x 400 pixel RGB bitmap with 8-bits per component.
11 | canvas = agg.CanvasRGB24(np.zeros((400, 400, 3), dtype=np.uint8))
|
Draw a circle¶
We’re now ready to do some drawing. A path object is created to describe the
shape that will be drawn. In this case, it’s an ellipse with an equal width and
height of 190 pixels, ie: a circle. Because the canvas was instantiated with
np.zeros, we call the canvas.clear method first to clear the background
color to white. Finally, the circle is drawn with canvas.draw_shape.
13 14 15 16 | path = agg.Path()
path.ellipse(200, 200, 190, 190)
canvas.clear(1.0, 1.0, 1.0)
canvas.draw_shape(path, transform, state, stroke=red_paint)
|
Draw some text¶
Next up, some text. We’ll use the Montserrat font which is included with
celiagg, conveniently available via the example_font function. A font
object is created with a point size of 96. The transform gets a
translation of (30, 220) set. This corresponds to a point which is 30 pixels
from the left side of the image and 220 pixels from the top of the image.
(celiagg defaults to a top-left origin, but also supports bottom-left origin)
The text will be drawn starting from that point.
18 19 20 | font = agg.Font(agg.example_font(), 96.0)
transform.translate(30.0, 220.0)
canvas.draw_text("celiagg", font, transform, state, fill=orange_paint)
|
Note
Even though state specifies a drawing_mode of DrawStroke, the
text will still be rendered as filled instead of drawing an outline. This
is because text drawing mode is separate from the main [shape] drawing mode.
text_drawing_mode in state defaults to
agg.TextDrawingMode.TextDrawRaster. To draw text as vector data,
state.text_drawing_mode can be set to something like
agg.TextDrawingMode.TextDrawStroke. All modes except TextDrawRaster
are drawn as vectors. Note that there is a performance penalty paid for this
flexibility, but it allows things like patterned fills.
Save¶
Last but not least, the image is written to a PNG file for enjoyment in your favorite image viewer.
22 23 | image = Image.fromarray(canvas.array, "RGB")
image.save("example.png")
|