0
# Drawing Context
1
2
The Context class provides the central interface for all Cairo drawing operations. It maintains the current drawing state including path, colors, line styles, transformations, and clipping regions. Context objects are created with a target Surface and provide methods for path construction, painting, stroking, and state management.
3
4
## Capabilities
5
6
### Context Creation and State Management
7
8
```python { .api }
9
class Context:
10
def __init__(self, target: Surface) -> None:
11
"""Create a new Context for the target surface.
12
13
Args:
14
target: The surface to draw on
15
"""
16
17
def save(self) -> None:
18
"""Save the current graphics state to an internal stack."""
19
20
def restore(self) -> None:
21
"""Restore the graphics state from the most recently saved state."""
22
23
def get_target(self) -> Surface:
24
"""Get the target surface for the context."""
25
26
def push_group(self) -> None:
27
"""Temporarily redirect drawing to an intermediate surface."""
28
29
def push_group_with_content(self, content: Content) -> None:
30
"""Push a group with specific content type."""
31
32
def pop_group(self) -> SurfacePattern:
33
"""Pop the group and return it as a pattern."""
34
35
def pop_group_to_source(self) -> None:
36
"""Pop the group and set it as the source pattern."""
37
```
38
39
### Color and Source Setting
40
41
```python { .api }
42
def set_source_rgb(self, red: float, green: float, blue: float) -> None:
43
"""Set the source pattern to an opaque RGB color.
44
45
Args:
46
red: Red component (0.0 to 1.0)
47
green: Green component (0.0 to 1.0)
48
blue: Blue component (0.0 to 1.0)
49
"""
50
51
def set_source_rgba(self, red: float, green: float, blue: float, alpha: float) -> None:
52
"""Set the source pattern to a translucent RGBA color.
53
54
Args:
55
red: Red component (0.0 to 1.0)
56
green: Green component (0.0 to 1.0)
57
blue: Blue component (0.0 to 1.0)
58
alpha: Alpha component (0.0 to 1.0)
59
"""
60
61
def set_source(self, source: Pattern) -> None:
62
"""Set the source pattern for drawing operations."""
63
64
def set_source_surface(self, surface: Surface, x: float = 0.0, y: float = 0.0) -> None:
65
"""Set a surface as the source pattern with optional offset."""
66
67
def get_source(self) -> Pattern:
68
"""Get the current source pattern."""
69
```
70
71
### Path Construction
72
73
```python { .api }
74
def new_path(self) -> None:
75
"""Clear the current path and begin a new empty path."""
76
77
def new_sub_path(self) -> None:
78
"""Begin a new sub-path within the current path."""
79
80
def close_path(self) -> None:
81
"""Add a line segment from current point to the start of current sub-path."""
82
83
def move_to(self, x: float, y: float) -> None:
84
"""Begin a new sub-path at the given point."""
85
86
def line_to(self, x: float, y: float) -> None:
87
"""Add a line to the path from current point to given point."""
88
89
def curve_to(self, x1: float, y1: float, x2: float, y2: float, x3: float, y3: float) -> None:
90
"""Add a cubic Bézier spline to the path."""
91
92
def arc(self, xc: float, yc: float, radius: float, angle1: float, angle2: float) -> None:
93
"""Add a circular arc to the path.
94
95
Args:
96
xc: X coordinate of center
97
yc: Y coordinate of center
98
radius: Radius of the arc
99
angle1: Start angle in radians
100
angle2: End angle in radians
101
"""
102
103
def arc_negative(self, xc: float, yc: float, radius: float, angle1: float, angle2: float) -> None:
104
"""Add a circular arc in the negative direction."""
105
106
def rectangle(self, x: float, y: float, width: float, height: float) -> None:
107
"""Add a rectangle to the path."""
108
109
def rel_move_to(self, dx: float, dy: float) -> None:
110
"""Begin a new sub-path at a point relative to current point."""
111
112
def rel_line_to(self, dx: float, dy: float) -> None:
113
"""Add a line to the path relative to current point."""
114
115
def rel_curve_to(self, dx1: float, dy1: float, dx2: float, dy2: float, dx3: float, dy3: float) -> None:
116
"""Add a cubic Bézier spline relative to current point."""
117
118
def text_path(self, text: str) -> None:
119
"""Add closed paths for text to the current path."""
120
121
def glyph_path(self, glyphs: list[Glyph]) -> None:
122
"""Add closed paths for glyphs to the current path."""
123
```
124
125
### Path Information and Manipulation
126
127
```python { .api }
128
def get_current_point(self) -> tuple[float, float]:
129
"""Get the current point in the path."""
130
131
def has_current_point(self) -> bool:
132
"""Check if there is a current point defined."""
133
134
def copy_path(self) -> Path:
135
"""Create a copy of the current path."""
136
137
def copy_path_flat(self) -> Path:
138
"""Create a flattened copy of the current path."""
139
140
def append_path(self, path: Path) -> None:
141
"""Append a path to the current path."""
142
143
def path_extents(self) -> tuple[float, float, float, float]:
144
"""Compute bounding box of current path."""
145
```
146
147
### Drawing Operations
148
149
```python { .api }
150
def fill(self) -> None:
151
"""Fill the current path with the current source pattern."""
152
153
def fill_preserve(self) -> None:
154
"""Fill the current path and preserve the path for further operations."""
155
156
def fill_extents(self) -> tuple[float, float, float, float]:
157
"""Compute bounding box that would be affected by fill operation."""
158
159
def in_fill(self, x: float, y: float) -> bool:
160
"""Test if point would be affected by fill operation."""
161
162
def stroke(self) -> None:
163
"""Stroke the current path with the current source pattern."""
164
165
def stroke_preserve(self) -> None:
166
"""Stroke the current path and preserve the path."""
167
168
def stroke_extents(self) -> tuple[float, float, float, float]:
169
"""Compute bounding box that would be affected by stroke operation."""
170
171
def in_stroke(self, x: float, y: float) -> bool:
172
"""Test if point would be affected by stroke operation."""
173
174
def paint(self) -> None:
175
"""Paint entire surface with current source pattern."""
176
177
def paint_with_alpha(self, alpha: float) -> None:
178
"""Paint entire surface with current source pattern using alpha."""
179
```
180
181
### Line and Stroke Properties
182
183
```python { .api }
184
def set_line_width(self, width: float) -> None:
185
"""Set the line width for stroking operations."""
186
187
def get_line_width(self) -> float:
188
"""Get the current line width."""
189
190
def set_line_cap(self, line_cap: LineCap) -> None:
191
"""Set the line cap style."""
192
193
def get_line_cap(self) -> LineCap:
194
"""Get the current line cap style."""
195
196
def set_line_join(self, line_join: LineJoin) -> None:
197
"""Set the line join style."""
198
199
def get_line_join(self) -> LineJoin:
200
"""Get the current line join style."""
201
202
def set_miter_limit(self, limit: float) -> None:
203
"""Set the miter limit for line joins."""
204
205
def get_miter_limit(self) -> float:
206
"""Get the current miter limit."""
207
208
def set_dash(self, dashes: list[float], offset: float = 0.0) -> None:
209
"""Set dash pattern for line stroking."""
210
211
def get_dash(self) -> tuple[list[float], float]:
212
"""Get current dash pattern and offset."""
213
214
def get_dash_count(self) -> int:
215
"""Get number of dashes in current dash pattern."""
216
217
def set_hairline(self, set_hairline: bool) -> None:
218
"""Enable or disable hairline mode for 1-pixel wide lines."""
219
220
def get_hairline(self) -> bool:
221
"""Get current hairline mode setting."""
222
```
223
224
### Transformations
225
226
```python { .api }
227
def translate(self, tx: float, ty: float) -> None:
228
"""Modify transformation matrix to translate by given amounts."""
229
230
def scale(self, sx: float, sy: float) -> None:
231
"""Modify transformation matrix to scale by given factors."""
232
233
def rotate(self, angle: float) -> None:
234
"""Modify transformation matrix to rotate by given angle in radians."""
235
236
def transform(self, matrix: Matrix) -> None:
237
"""Apply transformation matrix to current transformation."""
238
239
def set_matrix(self, matrix: Matrix) -> None:
240
"""Set the current transformation matrix."""
241
242
def get_matrix(self) -> Matrix:
243
"""Get the current transformation matrix."""
244
245
def identity_matrix(self) -> None:
246
"""Reset transformation matrix to identity."""
247
248
def user_to_device(self, x: float, y: float) -> tuple[float, float]:
249
"""Transform point from user space to device space."""
250
251
def user_to_device_distance(self, dx: float, dy: float) -> tuple[float, float]:
252
"""Transform distance from user space to device space."""
253
254
def device_to_user(self, x: float, y: float) -> tuple[float, float]:
255
"""Transform point from device space to user space."""
256
257
def device_to_user_distance(self, dx: float, dy: float) -> tuple[float, float]:
258
"""Transform distance from device space to user space."""
259
```
260
261
### Clipping
262
263
```python { .api }
264
def clip(self) -> None:
265
"""Establish clipping region from current path."""
266
267
def clip_preserve(self) -> None:
268
"""Establish clipping region and preserve current path."""
269
270
def clip_extents(self) -> tuple[float, float, float, float]:
271
"""Get bounding box of current clipping region."""
272
273
def in_clip(self, x: float, y: float) -> bool:
274
"""Test if point is inside current clipping region."""
275
276
def reset_clip(self) -> None:
277
"""Reset clipping region to unlimited."""
278
279
def copy_clip_rectangle_list(self) -> list[Rectangle]:
280
"""Get list of rectangles covering current clipping region."""
281
```
282
283
### Compositing and Blending
284
285
```python { .api }
286
def set_operator(self, operator: Operator) -> None:
287
"""Set compositing operator for drawing operations."""
288
289
def get_operator(self) -> Operator:
290
"""Get current compositing operator."""
291
292
def set_tolerance(self, tolerance: float) -> None:
293
"""Set tolerance for curve flattening."""
294
295
def get_tolerance(self) -> float:
296
"""Get current tolerance value."""
297
298
def set_antialias(self, antialias: Antialias) -> None:
299
"""Set antialiasing mode."""
300
301
def get_antialias(self) -> Antialias:
302
"""Get current antialiasing mode."""
303
304
def set_fill_rule(self, fill_rule: FillRule) -> None:
305
"""Set fill rule for path filling."""
306
307
def get_fill_rule(self) -> FillRule:
308
"""Get current fill rule."""
309
```
310
311
### PDF Tagging Support
312
313
```python { .api }
314
def tag_begin(self, tag_name: str, attributes: str) -> None:
315
"""Begin a tagged content sequence for PDF accessibility.
316
317
Args:
318
tag_name: Name of the tag (e.g., 'P', 'H1', 'Link')
319
attributes: Tag attributes as string
320
"""
321
322
def tag_end(self, tag_name: str) -> None:
323
"""End a tagged content sequence.
324
325
Args:
326
tag_name: Name of the tag to close
327
"""
328
```
329
330
### Text Rendering
331
332
```python { .api }
333
def select_font_face(self, family: str, slant: FontSlant, weight: FontWeight) -> None:
334
"""Select a font face for text rendering."""
335
336
def set_font_size(self, size: float) -> None:
337
"""Set font size for text rendering."""
338
339
def set_font_matrix(self, matrix: Matrix) -> None:
340
"""Set font transformation matrix."""
341
342
def get_font_matrix(self) -> Matrix:
343
"""Get current font transformation matrix."""
344
345
def set_font_options(self, options: FontOptions) -> None:
346
"""Set font rendering options."""
347
348
def get_font_options(self) -> FontOptions:
349
"""Get current font rendering options."""
350
351
def set_font_face(self, font_face: FontFace) -> None:
352
"""Set font face for text rendering."""
353
354
def get_font_face(self) -> FontFace:
355
"""Get current font face."""
356
357
def set_scaled_font(self, scaled_font: ScaledFont) -> None:
358
"""Set scaled font for text rendering."""
359
360
def get_scaled_font(self) -> ScaledFont:
361
"""Get current scaled font."""
362
363
def show_text(self, text: str) -> None:
364
"""Render text at current point."""
365
366
def show_glyphs(self, glyphs: list[Glyph]) -> None:
367
"""Render glyphs at specified positions."""
368
369
def show_text_glyphs(self, text: str, glyphs: list[Glyph], clusters: list[TextCluster], cluster_flags: TextClusterFlags) -> None:
370
"""Render text with glyph and cluster information for advanced typography."""
371
372
def text_extents(self, text: str) -> TextExtents:
373
"""Get extents of text using current font."""
374
375
def glyph_extents(self, glyphs: list[Glyph]) -> TextExtents:
376
"""Get extents of glyphs using current font."""
377
378
def font_extents(self) -> tuple[float, float, float, float, float]:
379
"""Get metrics of current font."""
380
```
381
382
## Usage Examples
383
384
### Basic Drawing Operations
385
386
```python
387
import cairo
388
389
# Create surface and context
390
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 400, 300)
391
ctx = cairo.Context(surface)
392
393
# Set background
394
ctx.set_source_rgb(1, 1, 1)
395
ctx.paint()
396
397
# Draw and fill a rectangle
398
ctx.set_source_rgb(0.8, 0.2, 0.2)
399
ctx.rectangle(50, 50, 100, 80)
400
ctx.fill()
401
402
# Draw and stroke a circle
403
ctx.set_source_rgb(0.2, 0.2, 0.8)
404
ctx.arc(200, 150, 40, 0, 2 * 3.14159)
405
ctx.set_line_width(3)
406
ctx.stroke()
407
408
surface.write_to_png("basic_drawing.png")
409
```
410
411
### Complex Path with Curves
412
413
```python
414
import cairo
415
import math
416
417
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 400, 300)
418
ctx = cairo.Context(surface)
419
420
# Create a complex path with curves
421
ctx.move_to(50, 150)
422
ctx.curve_to(50, 50, 150, 50, 150, 150)
423
ctx.curve_to(150, 250, 250, 250, 250, 150)
424
ctx.line_to(350, 150)
425
426
# Stroke the path
427
ctx.set_source_rgb(0, 0, 0)
428
ctx.set_line_width(2)
429
ctx.stroke()
430
431
surface.write_to_png("complex_path.png")
432
```
433
434
### Transformations and Clipping
435
436
```python
437
import cairo
438
import math
439
440
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 400, 300)
441
ctx = cairo.Context(surface)
442
443
# Save state and apply transformations
444
ctx.save()
445
ctx.translate(200, 150)
446
ctx.rotate(math.pi / 4)
447
ctx.scale(1.5, 0.8)
448
449
# Create clipping region
450
ctx.arc(0, 0, 50, 0, 2 * math.pi)
451
ctx.clip()
452
453
# Draw something that will be clipped
454
ctx.set_source_rgb(0.8, 0.4, 0.2)
455
ctx.rectangle(-80, -80, 160, 160)
456
ctx.fill()
457
458
# Restore state
459
ctx.restore()
460
461
surface.write_to_png("transforms_clipping.png")
462
```