# canvas_mojo > A native Mojo 2D drawing library for raster images, SVG, and PDF. > It includes shapes, paths, gradients, compositing, transforms, > clipping, system-font text, and image codecs without C rendering > dependencies. The importable package is `canvas`; the project is `canvas_mojo`. `Canvas`, `SvgCanvas`, and `PdfCanvas` implement the `DrawTarget` trait. The generated public API inventory follows this hand-written guide in `llms.txt`. Documentation: https://randyzwitch.com/canvas_mojo/ Examples: https://randyzwitch.com/canvas_mojo/examples/ ## Install ```toml [workspace] preview = ["pixi-build"] [dependencies] canvas_mojo = { git = "https://github.com/randyzwitch/canvas_mojo.git", branch = "main" } ``` Import common entry points from the package root: ```mojo from canvas import Canvas, Color, Path, fill_circle_aa, write_png ``` ## Core model - `Canvas(width, height, fill)` owns an RGBA pixel buffer. - `SvgCanvas(width, height)` accumulates SVG markup. - `PdfCanvas(width, height)` creates a PDF document; `new_page` adds pages. - A function generic over `DrawTarget` can issue the shared drawing operations to any backend. - `BoundsTarget(width, height)` is a fourth conformer that draws nothing and keeps the union of what it was asked to draw: render a scene into one, read `ink_pixels()` as `(x, y, width, height)`, then render again into a target of that size with `translate(-x, -y)`. That is a tight crop on every backend. `has_ink()` tells an empty scene from a box at the origin; `ink_bounds()` is the geometric box. Measure without the scene's background fill: a full-page background counts as ink, which makes the box the whole page and the crop a no-op. Paint it into the cropped target instead. - Free drawing functions take their target first. `Canvas` also exposes the core operations as methods. - `begin_batch()` / `end_batch()` on any target defer the anti-aliased shapes between them and draw them in one parallel pass, in order, with the same pixels; the vector backends treat both as no-ops. Wrap a loop of markers, gridlines or bars in one. - `draw_image(image, x, y, width, height)` on any target places a `Canvas` as a block of hard-edged cells in user space, where a `fill_rect` at the same box would land: a heatmap or image plot is one `` in SVG and one XObject in PDF rather than a rectangle per cell. ## Coordinate and color conventions - The origin is at the top-left. X increases right and y increases down. - Pixel `(x, y)` is centered at `(x, y)` and spans half a pixel on each side. - `Int` rectangle overloads identify covered pixels. `Float64` rectangle overloads describe geometric edges and snap them to pixel boundaries. - `round_to_int` is the package's rounding (halves away from zero). `snap_to_pixel_edge` moves a coordinate to the nearest pixel boundary, for a filled rectangle's edge; `snap_to_pixel_center` to the nearest pixel center, for a hairline. Snap in user space before a supersampled region so the edge stays hard after the downsample. - Angles are radians and clockwise-positive in the y-down coordinate system. - Functions ending in `_aa` are anti-aliased. Plain variants are hard-edged. - `Color(r, g, b, a=255)` uses 8-bit straight alpha. - Drawing uses source-over by default. Set a `BlendMode` or `ColorSpace` on the target when another behavior is required. - Every primitive respects the current transform and clip. Use `save` and `restore` to scope state changes. ## Paths Build a `Path` from `move_to`, `line_to`, `quad_curve_to`, `cubic_curve_to`, `arc_to`, and `close`. Every subpath begins with `move_to`, including one whose first segment is an arc. `rect`, `round_rect`, `ellipse` and `regular_polygon` add a whole closed shape as one subpath. `curve_through` adds a smooth open subpath through points with Catmull-Rom tangents; `curve_to_through` continues the current subpath with the same curve, for a closed band with two smoothed edges. `arrow_head` adds a closed arrowhead pointing along a direction; stroke the shaft to the tip so the head covers the join. `transformed` maps a whole path into a new one; `extend` appends another path's commands, adopting its current point, so a shape built at unit size and mapped into place joins a larger path as its own subpath -- sharing one fill with the rest under `FillRule.NONZERO` instead of seaming against it. Use `fill_path_aa` for its interior or `stroke_path_aa` for its outline. `FillRule.EVEN_ODD` is the default; use `FillRule.NONZERO` when winding direction should determine the interior. ## Text `draw_text` anchors text at its baseline. `TextAlign.LEFT`, `CENTER`, and `RIGHT` control horizontal placement around the anchor. Fonts are resolved from those installed on the system, with fallback for missing glyphs. It is on `DrawTarget` as a method with a `cache=` keyword, so a function generic over the trait can label what it draws on all three backends. `draw_text_runs` is beside it for one label made of several `TextRun`s that differ in size, slant or offset, an italic variable or a raised superscript: on SVG it is one `` of ``s, so the label stays one string to select or copy; the other backends draw the runs one at a time where `text_run_anchors` measures them. Create one `FontCache` and pass it through the `cache=` overloads when performing related text operations. Construction does not scan the system; font discovery is initialized on the first lookup. - `measure_text` treats text as one line and returns `TextMetrics`, including width, height, and advance. - `measure_text_block` lays out newline-separated text and returns its anchor-relative ink bounds. - `prepare_text` returns a `TextLayout` for reuse with `measure_layout` and `draw_layout`. Draw it with the same `FontCache` that prepared it. ## Images and output - `read_png` and `read_bmp` decode images with their alpha where supported. - `read_jpeg` decodes baseline and progressive JPEG into an opaque `Canvas`. - `write_png` and `write_bmp` write raster output. - `write_svg` writes an `SvgCanvas`; `write_pdf` writes a `PdfCanvas`. - `PngLevel.FAST`, `DEFAULT`, and `SMALL` select encoding effort. They do not change decoded pixels. - `draw_canvas` composites one canvas onto another and can apply opacity, a mask, a transform, and nearest or bilinear filtering. - `downsample` reduces by an integer factor. `resize` accepts any positive output dimensions and uses alpha-aware filtering. ## Minimal raster example ```mojo from canvas import Canvas, Color, fill_circle_aa, write_png def main() raises: var canvas = Canvas(200, 200, Color(255, 255, 255)) fill_circle_aa(canvas, 100, 100, 80, Color(40, 100, 200)) write_png(canvas, "circle.png") ``` ## One scene, three backends ```mojo from canvas import Canvas, Color, PdfCanvas, SvgCanvas, write_pdf, write_png, write_svg from canvas.vector.draw_target import DrawTarget def draw_scene[T: DrawTarget](mut target: T) raises: target.fill_rect(20, 20, 200, 120, Color(40, 100, 200)) target.fill_circle_aa(400.0, 100.0, 70.0, Color(30, 160, 80)) target.draw_line_aa(20.0, 200.0, 760.0, 220.0, Color(0, 0, 0), 4.0) def main() raises: var raster = Canvas(800, 300, Color(255, 255, 255)) draw_scene(raster) write_png(raster, "scene.png") var svg = SvgCanvas(800, 300) draw_scene(svg) write_svg(svg, "scene.svg") var pdf = PdfCanvas(800, 300) pdf.fill_rect(0, 0, 800, 300, Color(255, 255, 255)) draw_scene(pdf) write_pdf(pdf, "scene.pdf") ``` - `push_clip_path(path, fill_rule=FillRule.EVEN_ODD)` / `pop_clip_path()` on any target clips to a path under the transform at push time. Clips intersect; pop mixed rectangle/path clips in reverse push order with the matching pop method, or enclose them in `save()` / `restore()`. BoundsTarget uses a conservative path bounding box. Raster and vector clip edges can differ in anti-aliasing. - `push_clip(x, y, width, height)` / `pop_clip()` on any target restrict drawing to a rectangle and undo that, intersecting with any clip already active. Wrap a chart's marks in one so they cannot paint over the axes. - `draw_text(x, y, text, color, size, ..., cache=cache)` on any target draws a label at a sub-pixel baseline anchor with the same alignment and rotation on every backend; `family` takes the raster names, and SVG maps the generic ones to CSS. - `draw_text_runs(x, y, runs, color, ..., cache=cache)` on any target draws one label from a list of `TextRun(text, size, slant, dx, dy)`: each run at its own size and slant, `dx` a pen shift from the previous run's end, `dy` its baseline below the label's (negative raises a superscript). One `` of ``s on SVG. Gradient path fills, outlined text and text on a path are backend methods rather than part of `DrawTarget`. Use the relevant backend method when a shared trait operation is unavailable. ## Retained drawing `DisplayList` conforms to `DrawTarget` and owns commands and shared resource snapshots. Use `scene.replay(target, cache=cache)` for repeated playback. Set/reset transforms are relative to the destination baseline; incoming clips remain active and graphics state is restored on success or error. Balance recording scopes, and end any destination annotated group before replay. Fonts resolve at playback; caches are not retained. `scene.bounds(cache=cache)` returns conservative logical ink with `known`/`has_ink`; unknown bounds require repainting the widget. Scaling replays a fixed layout; responsive chart layout requires recording again. Direct rendering remains available without capture. ## API Every public name, by module. `_aa` is anti-aliased; the same name without it is hard-edged. Signatures are Mojo: `mut` marks an argument the call modifies. ## canvas.blend Blend and composite modes: what a drawing operation does to the pixels already there, beyond the source-over every primitive uses by default. ### struct BlendMode How a drawn color combines with the pixel underneath. - value `SOURCE_OVER` - value `SOURCE` - value `DESTINATION_IN` - value `DESTINATION_OUT` - value `XOR` - value `CLEAR` - value `DESTINATION` - value `DESTINATION_OVER` - value `SOURCE_IN` - value `SOURCE_OUT` - value `SOURCE_ATOP` - value `DESTINATION_ATOP` - value `ADD` - value `MULTIPLY` - value `SCREEN` - value `OVERLAY` - value `DARKEN` - value `LIGHTEN` - value `DIFFERENCE` - value `EXCLUSION` - value `COLOR_DODGE` - value `COLOR_BURN` - value `HARD_LIGHT` - value `SOFT_LIGHT` - value `HUE` - value `SATURATION` - value `COLOR` - value `LUMINOSITY` - `def __init__(out self, value: Int)` -- Prefer the comptime constants over constructing one directly. - `def write_to[W: Writer](self, mut writer: W)` - `def is_source_over(self) -> Bool` -- Whether this is the default mode. - `def is_separable(self) -> Bool` -- Whether this is one of the eleven separable blend modes, MULTIPLY through SOFT_LIGHT: a `B` applied to each channel on its own. - `def is_non_separable(self) -> Bool` -- Whether this is one of the four non-separable blend modes, HUE, SATURATION, COLOR and LUMINOSITY: a `B` that needs the whole RGB triple. ## canvas.blur Gaussian blur, approximated by three successive box blurs, and `draw_shadowed`, the drop-shadow / glow composite built on it. - `def blur(mut canvas: Canvas, radius: Float64)` -- Blur `canvas` in place with a Gaussian of standard deviation `radius / 2`, approximated by three box blurs (see the module docstring). - `def draw_shadowed(mut dst: Canvas, layer: Canvas, x: Int, y: Int, shadow_color: Color, blur_radius: Float64, offset_x: Int, offset_y: Int) raises` -- Composite `layer` onto `dst` at (x, y) with a blurred, tinted, offset copy of it underneath -- a drop shadow, or (with `offset_x = offset_y = 0`) a soft glow. ## canvas.bounds A `DrawTarget` that draws nothing and remembers where the ink would have gone: `BoundsTarget`. ### struct BoundsTarget A `DrawTarget` that keeps the union of what it was asked to draw and draws nothing. - `def __init__(out self, width: Int, height: Int)` -- A measuring target the size of the page a scene will be drawn on. - `def __init__(out self)` -- Measure logical ink without a page boundary, including negatives. - `def has_ink(self) -> Bool` -- Whether anything drawn so far had positive area inside the page and the clips in force when it was drawn. - `def ink_bounds(self) -> Tuple[Float64, Float64, Float64, Float64]` -- The geometric box around everything drawn, as (min_x, min_y, max_x, max_y) in this target's coordinates, the convention of `Path.bounds`. All zeros with no ink; check `has_ink()` to tell that from a box at the origin. - `def ink_pixels(self) -> Tuple[Int, Int, Int, Int]` -- The whole-pixel box around everything drawn, as (x, y, width, height): every pixel whose square the geometry enters, which is every pixel an anti-aliased edge can touch. - `def reset(mut self)` -- Forget every extent and every piece of state, so the target can measure another scene on the same page. - `def fill_rect(mut self, x: Int, y: Int, width: Int, height: Int, color: Color)` -- The pixels x through x + width - 1 by y through y + height - 1. - `def fill_rect(mut self, x: Float64, y: Float64, width: Float64, height: Float64, color: Color)` -- The geometric box from (x, y) spanning width x height, snapped the way `fill_rect` snaps it. - `def fill_rect_gradient(mut self, x: Int, y: Int, width: Int, height: Int, gradient: LinearGradient)` -- As `fill_rect`; the gradient does not change the extent. - `def fill_rect_gradient(mut self, x: Float64, y: Float64, width: Float64, height: Float64, gradient: LinearGradient)` -- As `fill_rect`; the gradient does not change the extent. - `def draw_line_aa(mut self, x0: Int, y0: Int, x1: Int, y1: Int, color: Color, width: Float64 = 1.0, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0, cap: LineCap = LineCap.ROUND, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0)` -- A stroked segment between two pixel centers, with its caps. - `def draw_line_aa(mut self, x0: Float64, y0: Float64, x1: Float64, y1: Float64, color: Color, width: Float64 = 1.0, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0, cap: LineCap = LineCap.ROUND, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0)` -- A stroked segment between sub-pixel endpoints, with its caps. - `def fill_circle_aa(mut self, cx: Int, cy: Int, radius: Int, color: Color)` -- A disk centered on a pixel center. - `def fill_circle_aa(mut self, cx: Float64, cy: Float64, radius: Float64, color: Color)` -- A disk at a sub-pixel center. - `def fill_circles_aa(mut self, centers: List[FPoint], radius: Float64, color: Color) raises` -- Every disk of a bulk marker call. - `def fill_circles_aa(mut self, centers: List[FPoint], radius: Float64, colors: List[Color]) raises` -- Every disk of a bulk marker call with a color per disk. - `def fill_mesh(mut self, points: List[FPoint], faces: List[Int], colors: List[Color]) raises` -- The box around every vertex a face references. - `def fill_mesh_shaded(mut self, points: List[FPoint], faces: List[Int], vertex_colors: List[Color]) raises` -- The box around every vertex a face references. - `def fill_ellipses_aa(mut self, centers: List[FPoint], rx: Float64, ry: Float64, color: Color) raises` -- Every ellipse of a bulk marker call. - `def fill_ellipses_aa(mut self, centers: List[FPoint], rx: Float64, ry: Float64, colors: List[Color]) raises` -- Every ellipse of a bulk marker call with a color per ellipse. - `def draw_circle_aa(mut self, cx: Float64, cy: Float64, radius: Float64, color: Color, width: Float64 = 1.0)` -- A ring: the disk out to the stroke's outer edge, which is the radius plus half the width. - `def fill_ellipse_aa(mut self, cx: Int, cy: Int, rx: Int, ry: Int, color: Color)` -- An ellipse centered on a pixel center. - `def fill_ellipse_aa(mut self, cx: Float64, cy: Float64, rx: Float64, ry: Float64, color: Color)` -- An ellipse at a sub-pixel center. - `def draw_ellipse_aa(mut self, cx: Int, cy: Int, rx: Int, ry: Int, color: Color)` -- A one-pixel ellipse outline centered on a pixel center. - `def draw_ellipse_aa(mut self, cx: Float64, cy: Float64, rx: Float64, ry: Float64, color: Color, width: Float64 = 1.0)` -- An ellipse outline: the ellipse out to the stroke's outer edge. - `def fill_arc_aa(mut self, cx: Float64, cy: Float64, radius: Float64, start_angle: Float64, end_angle: Float64, color: Color)` -- A pie wedge, flattened the way the fill flattens it. - `def fill_arcs_aa(mut self, centers: List[FPoint], radius: Float64, start_angle: Float64, end_angle: Float64, color: Color) raises` -- Every wedge of a bulk call. - `def fill_arcs_aa(mut self, centers: List[FPoint], radius: Float64, start_angle: Float64, end_angle: Float64, colors: List[Color]) raises` -- Every wedge of a bulk call with a color per wedge. - `def fill_ring_sector_aa(mut self, cx: Float64, cy: Float64, inner_radius: Float64, outer_radius: Float64, start_angle: Float64, end_angle: Float64, color: Color)` -- A ring segment: along the outer arc, in to the inner arc and back along it, flattened the way the fill flattens it. - `def stroke_path_aa(mut self, path: Path, color: Color, width: Float64 = 1.0, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0, cap: LineCap = LineCap.ROUND, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0)` -- A stroke's outline with its caps and joins: `Path.stroke_bounds` with the same style. - `def fill_path_aa(mut self, path: Path, color: Color, fill_rule: FillRule = FillRule.EVEN_ODD)` -- A filled path's flattened outline. - `def draw_image(mut self, image: Canvas, x: Float64, y: Float64, width: Float64 = 0.0, height: Float64 = 0.0) raises` -- The box the image is scaled to, placed as a `fill_rect` at the same coordinates would be. - `def draw_text(mut self, x: Float64, y: Float64, text: String, color: Color, size: Float64, family: String = "Sans", slant: FontSlant = FontSlant.NORMAL, weight: FontWeight = FontWeight.NORMAL, rotation: Float64 = 0.0, align: TextAlign = TextAlign.LEFT, *, mut cache: FontCache) raises` -- The block `draw_text` would lay out, from `measure_text_block` with the same font, alignment and rotation, then mapped through the transform. - `def draw_text_runs(mut self, x: Float64, y: Float64, runs: List[TextRun], color: Color, family: String = "Sans", weight: FontWeight = FontWeight.NORMAL, rotation: Float64 = 0.0, align: TextAlign = TextAlign.LEFT, *, mut cache: FontCache) raises` -- The union of the blocks `draw_text` would lay out for each run at the anchor `canvas.text.render.text_run_anchors` computes for it: what `Canvas.draw_text_runs` inks, since it draws exactly those calls. - `def push_clip(mut self, x: Int, y: Int, width: Int, height: Int)` -- Confine what follows to a rectangle of pixels, under the transform, intersected with the clip already in force. - `def pop_clip(mut self)` -- Undo the innermost `push_clip`; a no-op with none pushed. - `def push_clip_path(mut self, path: Path, fill_rule: FillRule = FillRule.EVEN_ODD) raises` -- Intersect the active clip with the transformed path's box. - `def pop_clip_path(mut self)` -- Undo the innermost path clip; shares the rectangle clip stack. - `def begin_annotated_group(mut self, title: String)` -- A label, which draws nothing here. - `def end_annotated_group(mut self)` -- Ends a label; nothing to do. - `def begin_batch(mut self)` -- Nothing is deferred here, so nothing to begin. - `def end_batch(mut self)` -- Nothing was deferred, so nothing to draw. - `def save(mut self)` -- Record the transform, blend mode, color space and clip depth for `restore`. - `def restore(mut self)` -- Put back what the matching `save` recorded, popping any clip pushed since. - `def translate(mut self, tx: Float64, ty: Float64)` -- Shift user space. - `def rotate(mut self, angle: Float64)` -- Rotate user space about its origin. - `def scale(mut self, sx: Float64, sy: Float64)` -- Scale user space. - `def transform(mut self, matrix: Matrix2D)` -- Compose `matrix` before the current transform, the order `Canvas.transform` composes in. - `def set_transform(mut self, matrix: Matrix2D)` -- Replace the transform. - `def reset_transform(mut self)` -- Back to the identity. - `def current_transform(self) -> Matrix2D` -- The transform in force. - `def has_transform(self) -> Bool` -- Whether the transform is anything but the identity. - `def set_blend_mode(mut self, mode: BlendMode)` -- Carried for `save`/`restore`; every mode counts as ink. - `def blend_mode(self) -> BlendMode` -- The recorded blend mode. - `def set_color_space(mut self, space: ColorSpace)` -- Carried for `save`/`restore`; the space changes no extent. - `def color_space(self) -> ColorSpace` -- The recorded color space. ## canvas.buffer The pixel raster buffer at the core of the canvas package. ### struct Canvas A width x height RGBA raster buffer, row-major, 4 bytes per pixel. - `def __init__(out self, width: Int, height: Int, fill: Color = Color(255, 255, 255)) raises` -- Allocate a `width x height` canvas, every pixel set to `fill`. - `def __init__(out self, width: Int, height: Int, var pixels: List[UInt8]) raises` -- Wrap an already-built RGBA pixel buffer, skipping the solid-fill loop the (width, height, fill) constructor pays for. - `def save(mut self)` -- Push the current transform, blend mode and clip state, for `restore` to put back. - `def restore(mut self)` -- Pop the state `save` pushed: the transform and blend mode go back to what they were, and every clip pushed since -- rectangle or path -- is popped. - `def translate(mut self, tx: Float64, ty: Float64)` -- Shift the origin subsequent drawing is measured from by (tx, ty), in the current user space: after `scale(2.0, 2.0)`, `translate(10.0, 0.0)` moves it 20 pixels. - `def rotate(mut self, angle: Float64)` -- Turn subsequent drawing by `angle` radians about the current origin. - `def scale(mut self, sx: Float64, sy: Float64)` -- Scale subsequent drawing about the current origin, each axis by its own factor. - `def transform(mut self, matrix: Matrix2D)` -- Compose `matrix` into the current transform, applied to coordinates before everything already in place -- the same order `translate`/`rotate`/`scale` compose in, so a `Matrix2D(Transform2D(...))` slots in like any of them. - `def set_transform(mut self, matrix: Matrix2D)` -- Replace the current transform outright. - `def reset_transform(mut self)` -- Back to the identity: coordinates are device pixels again. - `def current_transform(self) -> Matrix2D` -- The map every drawing call currently applies. - `def has_transform(self) -> Bool` -- Whether the current transform is anything but the identity. - `def set_blend_mode(mut self, mode: BlendMode)` -- Set how every later drawing call combines with the pixels already there -- the equivalent of Cairo's `cairo_set_operator` and the HTML5 canvas's `globalCompositeOperation`. - `def blend_mode(self) -> BlendMode` -- The blend mode later drawing calls will use. - `def set_max_workers(mut self, workers: Int)` -- Cap how many worker threads a banded pass on this canvas may use. - `def max_workers(self) -> Int` -- The worker cap `set_max_workers` set. - `def set_color_space(mut self, space: ColorSpace)` -- Set the space later source-over blends mix in: SRGB, the default, blends the stored channel bytes directly; LINEAR converts them to linear light, blends, and converts back (see `ColorSpace`). - `def color_space(self) -> ColorSpace` -- The space source-over blends mix in now. - `def begin_batch(mut self)` -- Start deferring anti-aliased shapes so that `end_batch` can draw them all in one parallel pass, in the order they were called: what a chart's gridlines, ticks and markers want, where each shape is far too small to split across cores on its own and drawing them one call at a time runs on one core. - `def end_batch(mut self)` -- Draw everything recorded since the matching `begin_batch`. A no-op with no batch open, like `pop_clip` with nothing to pop. - `def begin_supersampled(mut self, factor: Int, background: Color = Color(255, 255, 255)) raises` -- Draw the next region at `factor` times this canvas's resolution without holding the enlarged buffer: drawing between here and `end_supersampled` is recorded, and `end_supersampled` replays it one output band at a time into a scratch that holds only that band, downsamples each band and writes it here. - `def end_supersampled(mut self) raises` -- Draw what `begin_supersampled` recorded, band by band, and put the downsampled result on this canvas. - `def row_bounds(self) -> Tuple[Int, Int]` -- The rows this buffer holds, in the coordinates geometry is drawn in: (0, height) for an ordinary canvas, and the band's own slice of the enlarged space inside a supersampled replay (#391). - `def in_bounds(self, x: Int, y: Int) -> Bool` -- Whether (x, y) is a real pixel on this canvas. - `def push_clip(mut self, x: Int, y: Int, width: Int, height: Int)` -- Restrict subsequent drawing to this sub-rectangle. - `def pop_clip(mut self)` -- Remove the most recently pushed clip, reverting to the parent clip if one exists or to the whole canvas if not. - `def push_clip_path(mut self, path: Path, fill_rule: FillRule = FillRule.EVEN_ODD)` -- Clip to a user-space path with the default raster quality. - `def push_clip_path(mut self, path: Path, *, supersample: Int, curve_steps: Int = 0)` -- Clip with explicit raster sampling and the even-odd fill rule. - `def push_clip_path(mut self, path: Path, fill_rule: FillRule = FillRule.EVEN_ODD, *, curve_steps: Int)` -- Clip with explicit curve flattening and default raster sampling. - `def push_clip_path(mut self, path: Path, fill_rule: FillRule, supersample: Int, curve_steps: Int = 0)` -- Restrict subsequent drawing to `path`'s interior. - `def push_clip_coverage(mut self, var mask: List[UInt8])` -- Restrict subsequent drawing to a coverage already computed: one 0-255 byte per canvas pixel, row-major, in device space. - `def has_clip_mask(self) -> Bool` -- Whether a clip path is currently active. - `def pop_clip_path(mut self)` -- Remove the most recently pushed clip path, reverting to the parent clip path if one exists or to no path clip if not. - `def clip_coverage(self, x: Int, y: Int) -> UInt8` -- How much of (x, y) the active clip paths let through: 255 if no clip path is active or the pixel is fully inside one, 0 if fully outside, in between on an anti-aliased boundary. - `def in_clip(self, x: Int, y: Int) -> Bool` -- Whether (x, y) is inside the active clip region. - `def set_pixel(mut self, x: Int, y: Int, color: Color)` -- Write `color` at (x, y), a no-op if it's off-canvas or outside the active clip. - `def write_pixel(mut self, x: Int, y: Int, color: Color)` -- Write `color` at (x, y) *without* set_pixel's in_bounds/ in_clip checks. - `def composite_alpha_row(mut self, x: Int, y: Int, alphas: List[UInt8], base: Int, count: Int, color: Color)` -- `write_pixel` of `color` at alpha `alphas[base + i]` for each of `count` pixels from (x, y) rightward, as one loop over the row: what compositing a cached glyph mask does per pixel, without a method call, an index computation and a clip test for each. - `def effective_fill_rect(self, x: Int, y: Int, width: Int, height: Int) -> Tuple[Int, Int, Int, Int]` -- The (x, y, width, height) a rectangular fill covering [x, x+width) x [y, y+height) may actually touch, intersected against the canvas bounds and the active clip -- the same intersection set_pixel enforces per pixel, computed once for a caller about to loop over the whole region. - `def get_pixel(self, x: Int, y: Int) -> Color` -- Read the color at (x, y). - `def read_pixel(self, x: Int, y: Int) -> Color` -- Read (x, y) *without* `get_pixel`'s in_bounds check, the counterpart to `write_pixel` and subject to the same contract: the caller must already know the coordinate is on the canvas, typically because the loop bounds came from `width`/`height`. - `def draw_text(mut self, x: Float64, y: Float64, text: String, color: Color, size: Float64, family: String = "Sans", slant: FontSlant = FontSlant.NORMAL, weight: FontWeight = FontWeight.NORMAL, rotation: Float64 = 0.0, align: TextAlign = TextAlign.LEFT, *, mut cache: FontCache) raises` -- `canvas.text.render.draw_text` as a method: the `DrawTarget` form, so a caller generic over the trait can label what it draws. - `def draw_text_runs(mut self, x: Float64, y: Float64, runs: List[TextRun], color: Color, family: String = "Sans", weight: FontWeight = FontWeight.NORMAL, rotation: Float64 = 0.0, align: TextAlign = TextAlign.LEFT, *, mut cache: FontCache) raises` -- The `DrawTarget` form: `draw_text` once per run, each at the anchor `canvas.text.render.text_run_anchors` computes for it, so a run lands where the same text drawn alone at that anchor lands, byte for byte. - `def draw_image(mut self, image: Canvas, x: Float64, y: Float64, width: Float64 = 0.0, height: Float64 = 0.0) raises` -- Draw `image` as a block of cells with its top-left at (x, y), scaled to `width x height` (its own pixel size when 0), under the current transform: `DrawTarget`'s image primitive, the method form of `draw_image` in canvas/compose.mojo, which says how the cells land. - `def fill(mut self, color: Color)` -- Fill the whole canvas (or the active clip region, if any) with `color`. - `def begin_annotated_group(mut self, title: String)` -- `DrawTarget`'s group label, which a raster canvas has nowhere to put: a no-op, so code written against the trait runs unchanged on any backend. - `def end_annotated_group(mut self)` -- Closes what `begin_annotated_group` did not open: a no-op, for the same reason. - `def fill_rect(mut self, x: Int, y: Int, width: Int, height: Int, color: Color)` -- Same as `canvas.shapes.rects.fill_rect`, callable as a method. - `def fill_rect(mut self, x: Float64, y: Float64, width: Float64, height: Float64, color: Color)` - `def fill_rect_gradient(mut self, x: Int, y: Int, width: Int, height: Int, gradient: LinearGradient)` -- Same as `canvas.shapes.rects.fill_rect_gradient`, callable as a method. - `def fill_rect_gradient(mut self, x: Float64, y: Float64, width: Float64, height: Float64, gradient: LinearGradient)` - `def draw_line_aa(mut self, x0: Int, y0: Int, x1: Int, y1: Int, color: Color, width: Float64 = 1.0, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0, cap: LineCap = LineCap.ROUND, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0)` -- Same as `canvas.shapes.lines.draw_line_aa`, callable as a method. - `def draw_line_aa(mut self, x0: Float64, y0: Float64, x1: Float64, y1: Float64, color: Color, width: Float64 = 1.0, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0, cap: LineCap = LineCap.ROUND, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0)` -- Same as `canvas.shapes.lines.draw_line_aa`, callable as a method. - `def fill_circle_aa(mut self, cx: Int, cy: Int, radius: Int, color: Color)` -- Same as `canvas.shapes.circles.fill_circle_aa`, callable as a method. - `def fill_circles_aa(mut self, centers: List[FPoint], radius: Float64, color: Color) raises` -- `DrawTarget`'s batched disks: the canvas is split across cores rather than the markers. - `def fill_circles_aa(mut self, centers: List[FPoint], radius: Float64, colors: List[Color]) raises` -- `fill_circles_aa` with a color per marker. - `def fill_mesh(mut self, points: List[FPoint], faces: List[Int], colors: List[Color]) raises` -- `DrawTarget`'s mesh: adjacent triangles drawn as one anti-aliased shape, seam-free along shared edges. - `def fill_mesh_shaded(mut self, points: List[FPoint], faces: List[Int], vertex_colors: List[Color]) raises` -- `DrawTarget`'s smooth-shaded mesh: `fill_mesh` with a color per vertex interpolated across each face, in this canvas's color space. - `def fill_circle_aa(mut self, cx: Float64, cy: Float64, radius: Float64, color: Color)` - `def fill_ellipses_aa(mut self, centers: List[FPoint], rx: Float64, ry: Float64, color: Color) raises` -- `DrawTarget`'s batched ellipses: the canvas is split across cores rather than the markers. - `def fill_ellipses_aa(mut self, centers: List[FPoint], rx: Float64, ry: Float64, colors: List[Color]) raises` -- `fill_ellipses_aa` with a color per marker. - `def draw_circle_aa(mut self, cx: Float64, cy: Float64, radius: Float64, color: Color, width: Float64 = 1.0)` -- Same as `canvas.shapes.circles.draw_circle_aa`, callable as a method. - `def fill_ellipse_aa(mut self, cx: Int, cy: Int, rx: Int, ry: Int, color: Color)` -- Same as `canvas.shapes.ellipses.fill_ellipse_aa`, callable as a method. - `def fill_ellipse_aa(mut self, cx: Float64, cy: Float64, rx: Float64, ry: Float64, color: Color)` - `def draw_ellipse_aa(mut self, cx: Int, cy: Int, rx: Int, ry: Int, color: Color)` -- Same as `canvas.shapes.ellipses.draw_ellipse_aa`, callable as a method. - `def draw_ellipse_aa(mut self, cx: Float64, cy: Float64, rx: Float64, ry: Float64, color: Color, width: Float64 = 1.0)` -- Same as `canvas.shapes.ellipses.draw_ellipse_aa`, callable as a method. - `def fill_arc_aa(mut self, cx: Float64, cy: Float64, radius: Float64, start_angle: Float64, end_angle: Float64, color: Color)` -- Same as `canvas.shapes.arcs.fill_arc_aa`, callable as a method. - `def fill_arcs_aa(mut self, centers: List[FPoint], radius: Float64, start_angle: Float64, end_angle: Float64, color: Color) raises` -- `DrawTarget`'s batched wedges: the canvas is split across cores rather than the wedges. - `def fill_arcs_aa(mut self, centers: List[FPoint], radius: Float64, start_angle: Float64, end_angle: Float64, colors: List[Color]) raises` -- `fill_arcs_aa` with a color per wedge. - `def fill_ring_sector_aa(mut self, cx: Float64, cy: Float64, inner_radius: Float64, outer_radius: Float64, start_angle: Float64, end_angle: Float64, color: Color)` -- Same as `canvas.shapes.arcs.fill_ring_sector_aa`, callable as a method. - `def stroke_path_aa(mut self, path: Path, color: Color, width: Float64 = 1.0, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0, cap: LineCap = LineCap.ROUND, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0)` -- Same as `canvas.path.stroke_path_aa`, callable as a method. - `def fill_path_aa(mut self, path: Path, color: Color, fill_rule: FillRule = FillRule.EVEN_ODD)` -- Same as `canvas.path.fill_path_aa`, callable as a method. - constant `BYTES_PER_PIXEL` ## canvas.color RGBA color type and basic blending. ### struct Color An 8-bit-per-channel RGBA color. - `def __init__(out self, r: UInt8, g: UInt8, b: UInt8, a: UInt8 = 255)` -- An 8-bit-per-channel RGBA color. - `def __init__(out self, hex: String) raises` -- A color from a CSS-style hex string: `"#rrggbb"` or `"#rrggbbaa"`, with or without the leading `#`, in either case. - `def write_to[W: Writer](self, mut writer: W)` - `def with_alpha(self, a: UInt8) -> Color` -- This color at a different alpha, its channels untouched -- the usual way a palette entry is faded for a hover state or a de-emphasized series. - `def to_hex(self) -> String` -- This color as `"#rrggbb"`, lowercase. - `def blend_over(self, bg: Color) -> Color` -- Alpha-composite self over bg (straight-alpha src-over). - `def blend_over_opaque(self, bg_r: UInt8, bg_g: UInt8, bg_b: UInt8) -> Color` -- `blend_over` specialized to a background already known opaque. ### struct ColorSpace The space colors are mixed in: where a blend or a gradient interpolation does its arithmetic. - value `SRGB` - value `LINEAR` - `def __init__(out self, value: Int)` -- Prefer the comptime constants over constructing one directly. - `def is_linear(self) -> Bool` -- Whether this is LINEAR. - `def write_to[W: Writer](self, mut writer: W)` ## canvas.compose Compositing one canvas onto another: everything else in this package draws *shapes* into a buffer, and this draws a buffer into a buffer. ### struct Filter How a transformed `draw_canvas` reads the source between its pixels: `NEAREST` takes the one the sample point lands in, giving hard pixel edges and no color the source did not already hold, and `BILINEAR` mixes the four around it, giving smooth edges and intermediate colors. - value `NEAREST` - value `BILINEAR` - `def __init__(out self, value: Int)` -- Prefer the `NEAREST`/`BILINEAR` comptime constants over constructing one directly. - `def write_to[W: Writer](self, mut writer: W)` - `def draw_canvas(mut dst: Canvas, src: Canvas, x: Int, y: Int)` -- Composite `src` onto `dst` with its top-left corner at (x, y). - `def draw_canvas(mut dst: Canvas, src: Canvas, x: Int, y: Int, opacity: UInt8)` -- `draw_canvas` with the whole source scaled to `opacity` first -- the usual way a layer is faded, without having to have rendered it translucent in the first place. - `def draw_canvas(mut dst: Canvas, src: Canvas, x: Int, y: Int, mask: Mask)` -- `draw_canvas` through a mask: each source pixel's alpha is scaled by the mask's coverage at the same position in the source before it is composited, so a layer fades where the mask does. - `def draw_canvas(mut dst: Canvas, src: Canvas, matrix: Matrix2D, opacity: Float64 = 1.0, filter: Filter = Filter.BILINEAR) raises` -- Draw `src` onto `dst` through `matrix`: scaled, rotated, skewed or mirrored, the equivalent of `cairo_set_source_surface` under the CTM or the HTML5 canvas's `drawImage` with a transform. - `def draw_canvas(mut dst: Canvas, src: Canvas, sx: Int, sy: Int, sw: Int, sh: Int, matrix: Matrix2D, opacity: Float64 = 1.0, filter: Filter = Filter.BILINEAR) raises` -- `draw_canvas` through a matrix, drawing only the `sw x sh` rectangle of `src` at (sx, sy) -- one sprite out of a sheet, or one panel out of a rendered figure. - `def draw_image(mut dst: Canvas, image: Canvas, x: Float64, y: Float64, width: Float64 = 0.0, height: Float64 = 0.0) raises` -- Draw `image` as a block of cells with its top-left at (x, y), scaled to `width x height` (its own pixel size when 0), in the coordinates the shapes use and under the canvas transform: `DrawTarget.draw_image` on the raster backend, and the call for a heatmap, an image plot, or a rendered panel placed in a figure. ## canvas.display_list Owned, reusable DrawTarget commands in a local coordinate system. ### struct DisplayListBounds Conservative logical ink, or an explicit unknown result. - `def __init__(out self, known: Bool = False, has_ink: Bool = False, min_x: Float64 = 0.0, min_y: Float64 = 0.0, max_x: Float64 = 0.0, max_y: Float64 = 0.0)` ### struct DisplayList A movable scene that owns commands and deduplicated resources. - `def __init__(out self)` - `def command_count(self) -> Int` -- Number of commands, including state operations. - `def reserve_commands(mut self, count: Int)` -- Reserve inline command slots before recording a known-size scene. - `def resource_count(self) -> Int` -- Distinct owned aggregates; scalar-only primitives need none. - `def current_transform(self) -> Matrix2D` - `def has_transform(self) -> Bool` - `def blend_mode(self) -> BlendMode` - `def color_space(self) -> ColorSpace` - `def fill_rect(mut self, x: Int, y: Int, width: Int, height: Int, color: Color)` -- Record `fill_rect` with owned arguments. - `def fill_rect(mut self, x: Float64, y: Float64, width: Float64, height: Float64, color: Color)` -- Record `fill_rect` with owned arguments. - `def fill_rect_gradient(mut self, x: Int, y: Int, width: Int, height: Int, gradient: LinearGradient)` -- Record `fill_rect_gradient` with owned arguments. - `def fill_rect_gradient(mut self, x: Float64, y: Float64, width: Float64, height: Float64, gradient: LinearGradient)` -- Record `fill_rect_gradient` with owned arguments. - `def draw_line_aa(mut self, x0: Int, y0: Int, x1: Int, y1: Int, color: Color, width: Float64 = 1.0, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0, cap: LineCap = LineCap.ROUND, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0)` -- Record `draw_line_aa` with owned arguments. - `def draw_line_aa(mut self, x0: Float64, y0: Float64, x1: Float64, y1: Float64, color: Color, width: Float64 = 1.0, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0, cap: LineCap = LineCap.ROUND, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0)` -- Record `draw_line_aa` with owned arguments. - `def fill_circle_aa(mut self, cx: Int, cy: Int, radius: Int, color: Color)` -- Record `fill_circle_aa` with owned arguments. - `def fill_circle_aa(mut self, cx: Float64, cy: Float64, radius: Float64, color: Color)` -- Record `fill_circle_aa` with owned arguments. - `def fill_circles_aa(mut self, centers: List[FPoint], radius: Float64, color: Color) raises` -- Record `fill_circles_aa` with owned arguments. - `def fill_circles_aa(mut self, centers: List[FPoint], radius: Float64, colors: List[Color]) raises` -- Record `fill_circles_aa` with owned arguments. - `def fill_mesh(mut self, points: List[FPoint], faces: List[Int], colors: List[Color]) raises` -- Record `fill_mesh` with owned arguments. - `def fill_mesh_shaded(mut self, points: List[FPoint], faces: List[Int], vertex_colors: List[Color]) raises` -- Record `fill_mesh_shaded` with owned arguments. - `def fill_ellipses_aa(mut self, centers: List[FPoint], rx: Float64, ry: Float64, color: Color) raises` -- Record `fill_ellipses_aa` with owned arguments. - `def fill_ellipses_aa(mut self, centers: List[FPoint], rx: Float64, ry: Float64, colors: List[Color]) raises` -- Record `fill_ellipses_aa` with owned arguments. - `def draw_circle_aa(mut self, cx: Float64, cy: Float64, radius: Float64, color: Color, width: Float64 = 1.0)` -- Record `draw_circle_aa` with owned arguments. - `def fill_ellipse_aa(mut self, cx: Int, cy: Int, rx: Int, ry: Int, color: Color)` -- Record `fill_ellipse_aa` with owned arguments. - `def fill_ellipse_aa(mut self, cx: Float64, cy: Float64, rx: Float64, ry: Float64, color: Color)` -- Record `fill_ellipse_aa` with owned arguments. - `def draw_ellipse_aa(mut self, cx: Int, cy: Int, rx: Int, ry: Int, color: Color)` -- Record `draw_ellipse_aa` with owned arguments. - `def draw_ellipse_aa(mut self, cx: Float64, cy: Float64, rx: Float64, ry: Float64, color: Color, width: Float64 = 1.0)` -- Record `draw_ellipse_aa` with owned arguments. - `def fill_arc_aa(mut self, cx: Float64, cy: Float64, radius: Float64, start_angle: Float64, end_angle: Float64, color: Color)` -- Record `fill_arc_aa` with owned arguments. - `def fill_arcs_aa(mut self, centers: List[FPoint], radius: Float64, start_angle: Float64, end_angle: Float64, color: Color) raises` -- Record `fill_arcs_aa` with owned arguments. - `def fill_arcs_aa(mut self, centers: List[FPoint], radius: Float64, start_angle: Float64, end_angle: Float64, colors: List[Color]) raises` -- Record `fill_arcs_aa` with owned arguments. - `def fill_ring_sector_aa(mut self, cx: Float64, cy: Float64, inner_radius: Float64, outer_radius: Float64, start_angle: Float64, end_angle: Float64, color: Color)` -- Record `fill_ring_sector_aa` with owned arguments. - `def stroke_path_aa(mut self, path: Path, color: Color, width: Float64 = 1.0, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0, cap: LineCap = LineCap.ROUND, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0)` -- Record `stroke_path_aa` with owned arguments. - `def fill_path_aa(mut self, path: Path, color: Color, fill_rule: FillRule = FillRule.EVEN_ODD)` -- Record `fill_path_aa` with owned arguments. - `def draw_image(mut self, image: Canvas, x: Float64, y: Float64, width: Float64 = 0.0, height: Float64 = 0.0) raises` -- Record `draw_image` with owned arguments. - `def draw_text(mut self, x: Float64, y: Float64, text: String, color: Color, size: Float64, family: String = "Sans", slant: FontSlant = FontSlant.NORMAL, weight: FontWeight = FontWeight.NORMAL, rotation: Float64 = 0.0, align: TextAlign = TextAlign.LEFT, *, mut cache: FontCache) raises` -- Record `draw_text` with owned arguments. - `def draw_text_runs(mut self, x: Float64, y: Float64, runs: List[TextRun], color: Color, family: String = "Sans", weight: FontWeight = FontWeight.NORMAL, rotation: Float64 = 0.0, align: TextAlign = TextAlign.LEFT, *, mut cache: FontCache) raises` -- Record `draw_text_runs` with owned arguments. - `def push_clip(mut self, x: Int, y: Int, width: Int, height: Int)` -- Record `push_clip` with owned arguments. - `def pop_clip(mut self)` -- Record `pop_clip` with owned arguments. - `def push_clip_path(mut self, path: Path, fill_rule: FillRule = FillRule.EVEN_ODD) raises` -- Record `push_clip_path` with owned arguments. - `def pop_clip_path(mut self)` -- Record `pop_clip_path` with owned arguments. - `def begin_annotated_group(mut self, title: String)` -- Record `begin_annotated_group` with owned arguments. - `def end_annotated_group(mut self)` -- Record `end_annotated_group` with owned arguments. - `def begin_batch(mut self)` -- Record `begin_batch` with owned arguments. - `def end_batch(mut self)` -- Record `end_batch` with owned arguments. - `def save(mut self)` -- Record `save` with owned arguments. - `def restore(mut self)` -- Record `restore` with owned arguments. - `def translate(mut self, tx: Float64, ty: Float64)` -- Record `translate` with owned arguments. - `def rotate(mut self, angle: Float64)` -- Record `rotate` with owned arguments. - `def scale(mut self, sx: Float64, sy: Float64)` -- Record `scale` with owned arguments. - `def transform(mut self, matrix: Matrix2D)` -- Record `transform` with owned arguments. - `def set_transform(mut self, matrix: Matrix2D)` -- Record `set_transform` with owned arguments. - `def reset_transform(mut self)` -- Record `reset_transform` with owned arguments. - `def set_blend_mode(mut self, mode: BlendMode)` -- Record `set_blend_mode` with owned arguments. - `def set_color_space(mut self, space: ColorSpace)` -- Record `set_color_space` with owned arguments. - `def validate(self) raises` -- Reject unbalanced scopes, malformed paths and nonfinite coordinates. - `def replay[ T: DrawTarget ](self, mut target: T, *, mut cache: FontCache) raises` -- Replay in order, relative to the incoming destination state. - `def bounds(self, *, mut cache: FontCache) raises -> DisplayListBounds` -- Measure conservative logical ink using the supplied font cache. - `def storage_bytes(self) -> Int` -- Retained storage estimate: object, list capacities and string bytes. - `def list_buffer_count(self) -> Int` -- Retained List backing buffers, including resource tables. ## canvas.fill_rule Fill rules: how `fill_polygon`/`fill_path` and their gradient variants decide which regions of a self-intersecting or multi-sub-path shape count as inside. ### struct FillRule - value `EVEN_ODD` - value `NONZERO` - `def __init__(out self, value: Int)` -- Prefer the `EVEN_ODD`/`NONZERO` comptime constants over constructing one directly. - `def write_to[W: Writer](self, mut writer: W)` ## canvas.geometry Geometric types shared by the primitives that take more than a single (x, y) pair. ### struct Point An integer 2D coordinate. - `def __init__(out self, x: Int, y: Int)` -- An integer 2D coordinate. ### struct FPoint A floating-point 2D coordinate: the sub-pixel counterpart of `Point`, and what every anti-aliased path/arc sampler carries through to the coverage sweep. - `def __init__(out self, x: Float64, y: Float64)` -- A floating-point 2D coordinate. - `def round_to_int(value: Float64) -> Int` -- Round-half-away-from-zero, the rounding every primitive here applies when it takes a sub-pixel coordinate to a whole pixel. - `def snap_to_pixel_edge(value: Float64) -> Float64` -- `value` moved to the nearest pixel boundary, for the edge of an axis-aligned filled rectangle. - `def snap_to_pixel_center(value: Float64) -> Float64` -- `value` moved to the nearest pixel center, for the fixed coordinate of a hairline. ### struct Transform2D An affine map from continuous data-space coordinates to integer pixel-space coordinates: scale, then rotate, then translate. - `def __init__(out self, scale_x: Float64, scale_y: Float64, translate_x: Float64, translate_y: Float64, rotation: Float64 = 0.0)` -- Scale, then rotate, then translate -- see the struct docstring above for the full pipeline. - `def to_point(self, x: Float64, y: Float64) -> FPoint` -- Map a data-space point to sub-pixel canvas space. - `def to_pixel(self, x: Float64, y: Float64) -> Point` -- Map a data-space point to the nearest integer pixel. - `def inverse_point(self, px: Float64, py: Float64) raises -> FPoint` -- Map a pixel-space point back to the data-space point `to_point` would have produced it from -- the exact inverse of `to_point`, for hit-testing or cursor readout against a chart's own coordinate transform. ### struct Matrix2D A general affine map of the plane. - `def __init__(out self, a: Float64, b: Float64, c: Float64, d: Float64, e: Float64, f: Float64)` -- The matrix with these coefficients -- see the struct docstring for the layout. - `def __init__(out self, transform: Transform2D)` -- The matrix of `transform`'s scale-then-rotate-then-translate pipeline: the same mapping `transform.to_point` computes. - `def identity() -> Matrix2D` -- The map that leaves every point where it is. - `def translation(tx: Float64, ty: Float64) -> Matrix2D` -- A shift by (tx, ty). - `def scaling(sx: Float64, sy: Float64) -> Matrix2D` -- A scale about the origin, each axis by its own factor. - `def rotation(angle: Float64) -> Matrix2D` -- A rotation about the origin by `angle` radians. - `def apply(self, x: Float64, y: Float64) -> FPoint` -- Map a point. - `def then(self, other: Matrix2D) -> Matrix2D` -- This map followed by `other`: `self.then(o).apply(p)` is `o.apply(self.apply(p))`. - `def determinant(self) -> Float64` -- The area scale of the map, negative if it mirrors. - `def inverse(self) raises -> Matrix2D` -- The map that undoes this one. - `def is_identity(self) -> Bool` -- Whether the map leaves every point where it is. - `def is_translation(self) -> Bool` -- Whether the map is a pure shift. - `def is_axis_aligned(self) -> Bool` -- Whether the map keeps axis-aligned rectangles axis-aligned: scale (possibly mirrored) and translation only, no rotation or shear. - `def is_similarity(self) -> Bool` -- Whether the map keeps circles circular and angles intact: a rotation, a uniform scale and a translation, with no mirroring. - `def scale_factor(self) -> Float64` -- The map's length scale: the factor a similarity scales every length by, and the geometric mean of the two axis scales otherwise -- what a stroke width or dash length is multiplied by to follow the map. - `def rotation_angle(self) -> Float64` -- The angle the map turns the +x axis by, in radians. ## canvas.gradient Color gradients: `LinearGradient`, `RadialGradient` and `ConicGradient`, consumed by the gradient fills in canvas.shapes.rects (`fill_rect_gradient`, `fill_rect_radial_gradient`) and path.mojo (`fill_path_gradient`, `fill_path_radial_gradient`, `fill_path_conic_gradient` and their `_aa` variants). ### struct GradientStop One color stop: the color a ramp holds at `offset`, 0.0 to 1.0. - `def __init__(out self, offset: Float64, color: Color)` ### struct GradientStops A one-dimensional color ramp: stops sorted by offset, and the interpolated color at any position in [0, 1]. - `def __init__(out self)` -- A ramp with no stops yet; `color_at` returns transparent black until one is added. - `def set_color_space(mut self, space: ColorSpace)` -- Set the space `color_at` interpolates in: SRGB, the default, mixes the stops' channel bytes directly; LINEAR mixes them in linear light (see `ColorSpace`), which keeps a ramp between two saturated colors from sagging through a dark middle. - `def color_space(self) -> ColorSpace` -- The space `color_at` interpolates in. - `def add_stop(mut self, offset: Float64, color: Color)` -- Add a stop, keeping the ramp sorted by offset with insertion order preserved among equal offsets. - `def color_at(self, t_in: Float64) -> Color` -- The ramp's color at `t_in`, clamped to [0, 1] first (the "pad" extend), interpolated between the two stops bracketing it. ### trait ColorSource Anything that can answer "what color is at this point?" -- the fill source a gradient-filled shape queries per pixel. - `def color_at(self, x: Float64, y: Float64) -> Color` -- This source's color at (x, y), in canvas pixel coordinates. ### struct LinearGradient A linear gradient along the axis from (x0, y0) to (x1, y1). - `def __init__(out self, x0: Float64, y0: Float64, x1: Float64, y1: Float64)` -- A gradient with no stops yet -- add at least one with add_stop() before calling color_at(). - `def add_stop(mut self, offset: Float64, color: Color)` -- Add a color stop at `offset` (0.0 to 1.0 along the axis). - `def set_color_space(mut self, space: ColorSpace)` -- Set the space the ramp interpolates in; see `GradientStops.set_color_space`. - `def color_space(self) -> ColorSpace` -- The space the ramp interpolates in. - `def color_at(self, x: Float64, y: Float64) -> Color` -- The gradient's color at (x, y): project onto the axis, clamp to [0, 1] ("pad" extend), then interpolate between the two stops bracketing that position. ### struct RadialGradient A radial gradient centered at (cx, cy) with the given radius: offset 0.0 is the center, offset 1.0 is the circle at `radius`. Add stops with add_stop(), then pass to fill_rect_radial_gradient/ fill_path_radial_gradient (or query color_at() directly). - `def __init__(out self, cx: Float64, cy: Float64, radius: Float64)` -- A gradient with no stops yet -- add at least one with add_stop() before calling color_at(). - `def __init__(out self, cx: Float64, cy: Float64, radius: Float64, *, fx: Float64, fy: Float64, fr: Float64 = 0.0) raises` -- The two-circle form: offset 0.0 is the focal circle, offset 1.0 the outer circle at (cx, cy, radius). - `def add_stop(mut self, offset: Float64, color: Color)` -- Add a color stop at `offset` (0.0 at the center, 1.0 at `radius`). - `def set_color_space(mut self, space: ColorSpace)` -- Set the space the ramp interpolates in; see `GradientStops.set_color_space`. - `def color_space(self) -> ColorSpace` -- The space the ramp interpolates in. - `def color_at(self, x: Float64, y: Float64) -> Color` -- The gradient's color at (x, y): project onto [0, 1] as `distance_from_center / radius`, clamp ("pad" extend -- a distance is never negative, so only the far end ever clamps), then the stop lookup LinearGradient.color_at uses. ### struct ConicGradient A conic (angular) gradient centered at (cx, cy): offset 0.0 sits at `start_angle`, and sweeping clockwise around the center reaches offset 1.0 back at `start_angle`, a full turn later. - `def __init__(out self, cx: Float64, cy: Float64, start_angle: Float64)` -- A gradient with no stops yet -- add at least one with add_stop() before calling color_at(). - `def add_stop(mut self, offset: Float64, color: Color)` -- Add a color stop at `offset` (0.0 at `start_angle`, 1.0 a full clockwise turn later, back at `start_angle`). - `def set_color_space(mut self, space: ColorSpace)` -- Set the space the ramp interpolates in; see `GradientStops.set_color_space`. - `def color_space(self) -> ColorSpace` -- The space the ramp interpolates in. - `def color_at(self, x: Float64, y: Float64) -> Color` -- The gradient's color at (x, y): the clockwise angle from `start_angle` to (x, y) around the center, as a fraction of a full turn, then the stop lookup LinearGradient.color_at uses. ## canvas.io.bmp Read and write uncompressed BMP files. - `def write_bmp(canvas: Canvas, path: String) raises` -- Write `canvas` to `path` as an uncompressed 24-bit BMP. - `def read_bmp(path: String) raises -> Canvas` -- Read an uncompressed 24- or 32-bit BMP into a new Canvas. ## canvas.io.deflate DEFLATE (RFC 1951), both directions. - `def inflate(var compressed: List[UInt8]) raises -> List[UInt8]` -- Decompress a raw DEFLATE stream (RFC 1951), not a zlib stream (RFC 1950): a caller holding a zlib-wrapped stream, such as PNG's IDAT data, strips the 2-byte header and 4-byte Adler-32 trailer first. - `def deflate(data: List[UInt8], max_chain: Int = _MAX_CHAIN, max_lazy: Int = _MAX_LAZY, final: Bool = True) raises -> List[UInt8]` -- Compress `data` into a raw DEFLATE stream (RFC 1951): LZ77 over a head/prev hash-chain match search (see _HashChains) capped at _MAX_CHAIN candidates, then one Huffman-coded block. - `def deflate_parallel(data: List[UInt8], max_chain: Int = _MAX_CHAIN, max_lazy: Int = _MAX_LAZY, max_workers: Int = 0) raises -> List[UInt8]` -- `deflate`, with the LZ77 pass split across cores. ## canvas.io.jpeg Read baseline and progressive JPEG files (ITU T.81), stdlib-only, with no libjpeg dependency. - `def read_jpeg(path: String) raises -> Canvas` -- Read a JPEG file into an opaque Canvas. - `def decode_jpeg(var data: List[UInt8]) raises -> Canvas` -- Decode a JPEG held in memory into a Canvas: `read_jpeg` after the file is read. ## canvas.io.png Read and write PNG files, stdlib-only, with no zlib/libpng dependency. ### struct PngLevel How hard `write_png` works to make the file small. - value `FAST` - value `DEFAULT` - value `SMALL` - `def __init__(out self, value: Int)` -- Prefer the `FAST`/`DEFAULT`/`SMALL` comptime constants over constructing one directly. - `def write_to[W: Writer](self, mut writer: W)` - `def write_png(canvas: Canvas, path: String, level: PngLevel = PngLevel.DEFAULT) raises` -- Write `canvas` to `path` as an 8-bit, non-interlaced PNG -- color type 6 (truecolor + alpha) if any pixel is not fully opaque, color type 2 (truecolor) otherwise. - `def encode_png(canvas: Canvas, level: PngLevel = PngLevel.DEFAULT) raises -> List[UInt8]` -- The PNG file `write_png` would write, as bytes: for embedding a raster in an SVG's data URI, sending over a socket, or hashing, without a file in between. - `def read_png(path: String) raises -> Canvas` -- Read a PNG file into a Canvas. - `def decode_png(var data: List[UInt8]) raises -> Canvas` -- Decode a PNG image held in memory into a Canvas: `read_png` after the file is read, for bytes that come from somewhere else, such as a font's embedded bitmaps. ## canvas.io.view A pointer that knows, in a checked build, how far it may reach. - constant `CHECKED_READS` ## canvas.machine What the CPU this process is running on looks like, for the few thresholds that depend on it. - `def l3_slice_bytes() -> Int` -- The bytes of last-level cache one core reaches without crossing to another complex: the threshold at which a pure-store pass is worth banding and a read-heavy one should stop spreading. ## canvas.mask Alpha masks: a per-pixel coverage, 0-255, that a fill is painted through, a layer is composited through, or drawing is clipped to -- the shape of an operation separated from how the shape was made. ### struct Mask A `width x height` grid of 0-255 coverage, row-major, one byte per pixel: 255 lets everything through, 0 nothing. - `def __init__(out self, width: Int, height: Int, fill: UInt8 = 0)` -- A mask of uniform coverage. - `def __init__(out self, width: Int, height: Int, var coverage: List[UInt8]) raises` -- A mask over existing coverage bytes, taken by value. - `def from_path(path: Path, width: Int, height: Int, fill_rule: FillRule = FillRule.EVEN_ODD, supersample: Int = 4, curve_steps: Int = 0) -> Mask` -- `path`'s anti-aliased interior over a `width x height` grid: the coverage `push_clip_path` would keep, and the coverage `fill_path_aa` would blend by, so a mask's edge lands where the fill's does. - `def from_alpha(canvas: Canvas) -> Mask` -- A canvas's alpha channel as a mask of its size: an opaque pixel is 255, a transparent one 0. Draw a shape onto a transparent canvas and blur it, and this is a soft-edged stencil of it. - `def from_luminance(canvas: Canvas) -> Mask` -- A canvas's brightness as a mask of its size, scaled by its alpha: opaque white is 255, black or transparent 0. The luminance is `0.30 R + 0.59 G + 0.11 B`, the weighting canvas/blend.mojo's non-separable modes use. - `def coverage_at(self, x: Int, y: Int) -> UInt8` -- The coverage at (x, y), 0 outside the mask. - `def inverted(self) -> Mask` -- The complement: `255 - coverage` everywhere, so what this mask hides the result shows. - `def fill_mask(mut canvas: Canvas, mask: Mask, color: Color, x: Int = 0, y: Int = 0)` -- Paint `color` through `mask`, its top-left corner at (x, y): each pixel the mask covers is written with the color's alpha scaled by the coverage there. - `def fill_mask_source[ S: ColorSource ](mut canvas: Canvas, mask: Mask, source: S, x: Int = 0, y: Int = 0)` -- `fill_mask` taking each pixel's color from `source` -- a gradient or a pattern -- instead of one flat color. - `def push_clip_mask(mut canvas: Canvas, mask: Mask, x: Int = 0, y: Int = 0)` -- Restrict subsequent drawing to `mask`, its top-left corner at (x, y) -- `push_clip_path` for a coverage built elsewhere. - `def apply_mask(canvas: Canvas, mask: Mask) -> Canvas` -- A copy of `canvas` with every pixel's alpha scaled by the mask's coverage at the same position; pixels the mask does not reach become transparent. ## canvas.named_colors Named colors: the CSS Color Module Level 3 / X11 "extended color keywords" list () plus `REBECCAPURPLE` (Level 4), as `Color` constants, so a caller can write `CORNFLOWERBLUE` instead of `Color(100, 149, 237)`. Each name is the CSS keyword uppercased with no separators (`CORNFLOWERBLUE`, not `CORNFLOWER_BLUE`), so it matches the spec and any color picker directly. Constants: ALICEBLUE, ANTIQUEWHITE, AQUA, AQUAMARINE, AZURE, BEIGE, BISQUE, BLACK, BLANCHEDALMOND, BLUE, BLUEVIOLET, BROWN, BURLYWOOD, CADETBLUE, CHARTREUSE, CHOCOLATE, CORAL, CORNFLOWERBLUE, CORNSILK, CRIMSON, CYAN, DARKBLUE, DARKCYAN, DARKGOLDENROD, DARKGRAY, DARKGREEN, DARKGREY, DARKKHAKI, DARKMAGENTA, DARKOLIVEGREEN, DARKORANGE, DARKORCHID, DARKRED, DARKSALMON, DARKSEAGREEN, DARKSLATEBLUE, DARKSLATEGRAY, DARKSLATEGREY, DARKTURQUOISE, DARKVIOLET, DEEPPINK, DEEPSKYBLUE, DIMGRAY, DIMGREY, DODGERBLUE, FIREBRICK, FLORALWHITE, FORESTGREEN, FUCHSIA, GAINSBORO, GHOSTWHITE, GOLD, GOLDENROD, GRAY, GREEN, GREENYELLOW, GREY, HONEYDEW, HOTPINK, INDIANRED, INDIGO, IVORY, KHAKI, LAVENDER, LAVENDERBLUSH, LAWNGREEN, LEMONCHIFFON, LIGHTBLUE, LIGHTCORAL, LIGHTCYAN, LIGHTGOLDENRODYELLOW, LIGHTGRAY, LIGHTGREEN, LIGHTGREY, LIGHTPINK, LIGHTSALMON, LIGHTSEAGREEN, LIGHTSKYBLUE, LIGHTSLATEGRAY, LIGHTSLATEGREY, LIGHTSTEELBLUE, LIGHTYELLOW, LIME, LIMEGREEN, LINEN, MAGENTA, MAROON, MEDIUMAQUAMARINE, MEDIUMBLUE, MEDIUMORCHID, MEDIUMPURPLE, MEDIUMSEAGREEN, MEDIUMSLATEBLUE, MEDIUMSPRINGGREEN, MEDIUMTURQUOISE, MEDIUMVIOLETRED, MIDNIGHTBLUE, MINTCREAM, MISTYROSE, MOCCASIN, NAVAJOWHITE, NAVY, OLDLACE, OLIVE, OLIVEDRAB, ORANGE, ORANGERED, ORCHID, PALEGOLDENROD, PALEGREEN, PALETURQUOISE, PALEVIOLETRED, PAPAYAWHIP, PEACHPUFF, PERU, PINK, PLUM, POWDERBLUE, PURPLE, REBECCAPURPLE, RED, ROSYBROWN, ROYALBLUE, SADDLEBROWN, SALMON, SANDYBROWN, SEAGREEN, SEASHELL, SIENNA, SILVER, SKYBLUE, SLATEBLUE, SLATEGRAY, SLATEGREY, SNOW, SPRINGGREEN, STEELBLUE, TAN, TEAL, THISTLE, TOMATO, TURQUOISE, VIOLET, WHEAT, WHITE, WHITESMOKE, YELLOW, YELLOWGREEN ## canvas.path A general path type: move/line/quadratic-curve/cubic-curve/arc-to/ close, built up through chained calls, then flattened into straight- line segments and handed to canvas.shapes' polyline/polygon/fill machinery. ### struct PathOp Which builder call a `PathCommand` records: one of `MOVE_TO`, `LINE_TO`, `QUAD_TO`, `CUBIC_TO`, `CLOSE`, `ARC_TO`. Prints as its name, so `assert_equal(cmd.op, PathOp.MOVE_TO)` reports which op it found. - value `MOVE_TO` - value `LINE_TO` - value `QUAD_TO` - value `CUBIC_TO` - value `CLOSE` - value `ARC_TO` - `def __init__(out self, value: Int)` -- Prefer the comptime constants over constructing one directly. - `def write_to[W: Writer](self, mut writer: W)` ### struct PathCommand One path command, as `Path.commands` records it. - `def __init__(out self, op: PathOp, p1: FPoint, p2: FPoint, p3: FPoint)` ### struct Path Build with move_to/line_to/quad_curve_to/cubic_curve_to/arc_to/ close, or a whole shape at once with rect/round_rect/ellipse/ regular_polygon/arrow_head, then hand to fill_path/stroke_path/ stroke_path_aa. - `def __init__(out self)` - `def move_to(mut self, x: Float64, y: Float64)` -- Start a new sub-path at (x, y). - `def line_to(mut self, x: Float64, y: Float64) raises` -- A straight segment from the current point to (x, y). - `def quad_curve_to(mut self, cx: Float64, cy: Float64, x: Float64, y: Float64) raises` -- A quadratic Bezier from the current point to (x, y), pulled toward control point (cx, cy). - `def cubic_curve_to(mut self, c1x: Float64, c1y: Float64, c2x: Float64, c2y: Float64, x: Float64, y: Float64) raises` -- A cubic Bezier from the current point to (x, y), pulled toward control points (c1x, c1y) and (c2x, c2y). - `def arc_to(mut self, cx: Float64, cy: Float64, radius: Float64, start_angle: Float64, end_angle: Float64) raises` -- A circular arc segment, center (cx, cy), swept from `start_angle` to `end_angle` in radians -- the same angle convention as draw_arc/fill_arc/fill_ring_sector, flattened through that family's `_arc_fpoints`. An `end_angle` below `start_angle` sweeps the other way round, which is what a counter-clockwise corner or a reflected shape needs. - `def rect(mut self, x: Float64, y: Float64, width: Float64, height: Float64) raises` -- Add a closed rectangular sub-path, clockwise from its top-left corner. - `def round_rect(mut self, x: Float64, y: Float64, width: Float64, height: Float64, radius: Float64) raises` -- Add a closed rectangular sub-path with rounded corners. - `def ellipse(mut self, cx: Float64, cy: Float64, rx: Float64, ry: Float64) raises` -- Add a closed elliptical sub-path. - `def regular_polygon(mut self, cx: Float64, cy: Float64, radius: Float64, sides: Int, rotation: Float64 = 0.0) raises` -- Add a closed regular polygon: `sides` vertices on the circle of `radius` about `(cx, cy)`, vertex `k` at angle `rotation + 2 * pi * k / sides`, in this package's angle convention (0 along +x, increasing clockwise on screen because y grows downward). - `def arrow_head(mut self, tip_x: Float64, tip_y: Float64, direction_x: Float64, direction_y: Float64, length: Float64, half_width: Float64) raises` -- Add a closed arrowhead: the triangle whose tip is at `(tip_x, tip_y)`, pointing along `(direction_x, direction_y)`, with its base `length` back from the tip and `2 * half_width` wide. - `def curve_through(mut self, points: List[FPoint], tension: Float64 = 1.0) raises` -- Add a smooth open sub-path through `points`: a move_to to the first, then one cubic Bezier per consecutive pair with Catmull-Rom tangents, so the curve passes through every point. - `def curve_to_through(mut self, points: List[FPoint], tension: Float64 = 1.0) raises` -- Continue the current sub-path with a smooth curve from the current point through `points`, with no move_to: the continuation form of `curve_through`, whose tangents and `tension` it shares. - `def transformed(self, transform: Transform2D) raises -> Path` -- This path mapped through `transform`, as a new path. - `def transformed(self, matrix: Matrix2D) raises -> Path` -- This path mapped through `matrix`, as a new path -- the general-affine counterpart of the `Transform2D` overload, and what every drawing call applies to a path under a canvas transform. - `def bounds(self, curve_steps: Int = 0) -> Tuple[Float64, Float64, Float64, Float64]` -- The axis-aligned box the path's flattened outline spans, as (min_x, min_y, max_x, max_y) in canvas coordinates. - `def stroke_bounds(self, width: Float64 = 1.0, curve_steps: Int = 0, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0, cap: LineCap = LineCap.ROUND, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0) -> Tuple[Float64, Float64, Float64, Float64]` -- The axis-aligned box `stroke_path_aa` paints with the same arguments, as (min_x, min_y, max_x, max_y) in canvas coordinates. - `def in_fill(self, x: Float64, y: Float64, fill_rule: FillRule = FillRule.EVEN_ODD, curve_steps: Int = 0) -> Bool` -- Whether (x, y) lies inside the region `fill_path_aa` paints under `fill_rule`: the point's winding number over every sub-path, each treated as closed, on the same flattening the fills use. - `def in_stroke(self, x: Float64, y: Float64, width: Float64 = 1.0, curve_steps: Int = 0, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0, cap: LineCap = LineCap.ROUND, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0) -> Bool` -- Whether (x, y) lies inside the stroke `stroke_path_aa` paints with the same arguments: the nonzero winding number of the point over the stroke's outline, caps, joins and dashes included, built the way the stroke draws it. - `def extend(mut self, other: Path) raises` -- Append `other`'s commands onto this path, and adopt its current point and sub-path start so the builder state stays in step with `commands` -- the thing a caller cannot do from outside, since those fields are private. - `def close(mut self) raises` -- Draw a straight segment back to this sub-path's move_to and mark it closed. - `def fill_path(mut canvas: Canvas, path: Path, color: Color, fill_rule: FillRule = FillRule.EVEN_ODD, curve_steps: Int = 0)` -- Fill a path's interior with the scanline algorithm, combining every sub-path's crossings per scanline into a signed winding number (via polygon_fill's `_spans_from_crossings`, shared with fill_polygon). - `def fill_path_aa(mut canvas: Canvas, path: Path, color: Color, fill_rule: FillRule = FillRule.EVEN_ODD, supersample: Int = 4, curve_steps: Int = 0)` -- Anti-aliased fill_path. - `def fill_path_gradient(mut canvas: Canvas, path: Path, gradient: LinearGradient, fill_rule: FillRule = FillRule.EVEN_ODD, curve_steps: Int = 0)` -- Fill a path's interior as fill_path does, but sourcing each pixel's color from `gradient` (gradient.mojo) rather than one flat Color. - `def fill_path_radial_gradient(mut canvas: Canvas, path: Path, gradient: RadialGradient, fill_rule: FillRule = FillRule.EVEN_ODD, curve_steps: Int = 0)` -- Like fill_path_gradient, but for a RadialGradient (gradient.mojo). - `def fill_path_conic_gradient(mut canvas: Canvas, path: Path, gradient: ConicGradient, fill_rule: FillRule = FillRule.EVEN_ODD, curve_steps: Int = 0)` -- Like fill_path_gradient, but for a ConicGradient (gradient.mojo). - `def fill_path_pattern(mut canvas: Canvas, path: Path, pattern: PatternSource, fill_rule: FillRule = FillRule.EVEN_ODD, curve_steps: Int = 0)` -- Like fill_path_gradient, but for a PatternSource (pattern.mojo): each pixel's color comes from a sampled raster tile rather than a gradient projection. - `def fill_path_gradient_aa(mut canvas: Canvas, path: Path, gradient: LinearGradient, fill_rule: FillRule = FillRule.EVEN_ODD, supersample: Int = 4, curve_steps: Int = 0)` -- Anti-aliased `fill_path_gradient` -- `fill_path_aa`'s coverage with a gradient as the fill source. - `def fill_path_radial_gradient_aa(mut canvas: Canvas, path: Path, gradient: RadialGradient, fill_rule: FillRule = FillRule.EVEN_ODD, supersample: Int = 4, curve_steps: Int = 0)` -- Like fill_path_gradient_aa, but for a RadialGradient. - `def fill_path_conic_gradient_aa(mut canvas: Canvas, path: Path, gradient: ConicGradient, fill_rule: FillRule = FillRule.EVEN_ODD, supersample: Int = 4, curve_steps: Int = 0)` -- Like fill_path_gradient_aa, but for a ConicGradient. - `def fill_path_pattern_aa(mut canvas: Canvas, path: Path, pattern: PatternSource, fill_rule: FillRule = FillRule.EVEN_ODD, supersample: Int = 4, curve_steps: Int = 0)` -- Like fill_path_gradient_aa, but for a PatternSource. - `def stroke_path(mut canvas: Canvas, path: Path, color: Color, curve_steps: Int = 0, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0)` -- Stroke every sub-path, hard-edged 1px: closed ones (close() was called) via draw_polygon, open ones via draw_polyline. - `def stroke_path_aa(mut canvas: Canvas, path: Path, color: Color, width: Float64 = 1.0, supersample: Int = 4, curve_steps: Int = 0, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0, cap: LineCap = LineCap.ROUND, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0)` -- Anti-aliased stroke_path, via draw_polyline_aa/draw_polygon_aa. ## canvas.pattern Raster patterns as a fill source: `PatternSource`, a `ColorSource` (gradient.mojo) that samples a small `Canvas` tile instead of projecting onto a gradient axis. ### struct Extend How `PatternSource.color_at` samples outside the tile's own [0, width) x [0, height) bounds. - value `REPEAT` - value `REFLECT` - value `PAD` - value `NONE` - `def __init__(out self, value: Int)` -- Prefer the REPEAT/REFLECT/PAD/NONE comptime constants over constructing one directly. - `def write_to[W: Writer](self, mut writer: W)` ### struct PatternSource A `ColorSource` that samples a raster tile -- the fill source a pattern/image fill queries per pixel, mirroring how LinearGradient/RadialGradient/ConicGradient project a point onto a gradient axis instead. - `def __init__(out self, tile: Canvas, extend: Extend = Extend.REPEAT, ox: Float64 = 0.0, oy: Float64 = 0.0)` -- Args: tile: The pattern's raster tile. - `def color_at(self, x: Float64, y: Float64) -> Color` -- The tile's color at (x, y): shift by the offset, round to the nearest tile pixel, then wrap/clamp/reject that coordinate per `extend`. ### struct Hatch Which pattern `hatch_tile` renders. - value `DIAGONAL` - value `CROSS` - value `DOTS` - value `HORIZONTAL` - value `VERTICAL` - `def __init__(out self, value: Int)` -- Prefer the DIAGONAL/CROSS/DOTS/HORIZONTAL/VERTICAL comptime constants over constructing one directly. - `def write_to[W: Writer](self, mut writer: W)` - `def hatch_tile(spacing: Int, width: Float64, color: Color, background: Color, kind: Hatch) raises -> Canvas` -- Render a hatch pattern once into a `spacing` x `spacing` tile, ready to hand to `PatternSource` under `Extend.REPEAT`. ## canvas.provenance Identify the Mojo compiler that produced a committed reference. - `def mojo_version() -> String` -- The active pixi environment's Mojo version, or unknown outside it. - `def require_release_compiler() raises` -- Keep committed references from being recorded with a nightly. ## canvas.resize Box-filter downsampling: shrink a Canvas by an integer factor, each output pixel the average of the corresponding factor x factor block of input pixels. - `def downsample(source: Canvas, factor: Int) raises -> Canvas` -- Shrink `source` by `factor`, which must evenly divide both `source.width` and `source.height` -- raises rather than truncating a partial edge block away. - `def resize(source: Canvas, width: Int, height: Int) raises -> Canvas` -- Resample `source` to exactly `width` x `height`, with alpha- correct filtering and no constraint on the ratio. ## canvas.shapes.arcs Arc/pie-wedge/ring-sector drawing: outline (draw_arc/draw_arc_aa, built by sampling the arc into points and handing them to canvas.shapes.lines' draw_polyline/draw_polyline_aa), solid wedge/ring fill (fill_arc/fill_ring_sector, built the same way via canvas.shapes.polygon_fill's fill_polygon), and their supersampled analytic-coverage AA counterparts (fill_arc_aa/ fill_ring_sector_aa) -- see canvas.shapes.lines for the hard-edged vs. - `def draw_arc(mut canvas: Canvas, cx: Float64, cy: Float64, radius: Float64, start_angle: Float64, end_angle: Float64, color: Color)` -- The arc's curved boundary only, no radii back to center: hard-edged, ~1px, via draw_polyline over _arc_points' samples. - `def draw_arc_aa(mut canvas: Canvas, cx: Float64, cy: Float64, radius: Float64, start_angle: Float64, end_angle: Float64, color: Color, width: Float64 = 1.0, supersample: Int = 4, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0, cap: LineCap = LineCap.ROUND, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0)` -- Anti-aliased version of draw_arc: the arc's sub-pixel samples (`_arc_fpoints`) stroked through draw_polyline_aa, so the stroke follows the circle rather than a grid-snapped copy of it, and takes the same dash, cap and join options. - `def fill_arc(mut canvas: Canvas, cx: Float64, cy: Float64, radius: Float64, start_angle: Float64, end_angle: Float64, color: Color)` -- A solid pie-slice wedge: the arc plus two straight radii back to the center, filled. - `def fill_arc_aa(mut canvas: Canvas, cx: Float64, cy: Float64, radius: Float64, start_angle: Float64, end_angle: Float64, color: Color, supersample: Int = 4)` -- Anti-aliased pie-slice wedge: supersampled analytic coverage, testing each sub-sample against the wedge's exact definition -- within `radius` of center and within the angle span (_angle_in_span) -- rather than rasterizing a flattened polygon. - `def fill_ring_sector(mut canvas: Canvas, cx: Float64, cy: Float64, inner_radius: Float64, outer_radius: Float64, start_angle: Float64, end_angle: Float64, color: Color)` -- A solid ring/donut segment: the region between inner_radius and outer_radius within the angle span. - `def fill_arcs_aa(mut canvas: Canvas, centers: List[FPoint], radius: Float64, start_angle: Float64, end_angle: Float64, color: Color) raises` -- Fill many equal-size anti-aliased wedges in one call. - `def fill_arcs_aa(mut canvas: Canvas, centers: List[FPoint], radius: Float64, start_angle: Float64, end_angle: Float64, colors: List[Color]) raises` -- `fill_arcs_aa` with a colour per wedge. - `def fill_ring_sector_aa(mut canvas: Canvas, cx: Float64, cy: Float64, inner_radius: Float64, outer_radius: Float64, start_angle: Float64, end_angle: Float64, color: Color, supersample: Int = 4)` -- Anti-aliased fill_ring_sector: fill_arc_aa's per-sample technique plus a second radius test, both of which must pass. ## canvas.shapes.circles Circle drawing: midpoint-algorithm hard-edged outline/fill (draw_circle/fill_circle) and exact-area anti-aliased variants (draw_circle_aa/fill_circle_aa) -- see canvas.shapes.lines for the hard-edged vs. - `def draw_circle(mut canvas: Canvas, cx: Int, cy: Int, radius: Int, color: Color)` -- The midpoint circle algorithm: integer-only, plotting via 8-way symmetry around the center. - `def fill_circle(mut canvas: Canvas, cx: Int, cy: Int, radius: Int, color: Color)` -- Fill a solid disk, one horizontal span per row, so each pixel is set exactly once and a translucent color never double-blends. - `def fill_circle_aa(mut canvas: Canvas, cx: Int, cy: Int, radius: Int, color: Color, supersample: Int = 4)` -- Anti-aliased filled disk. - `def fill_circle_aa(mut canvas: Canvas, cx: Float64, cy: Float64, radius: Float64, color: Color, supersample: Int = 4)` -- `fill_circle_aa` at a sub-pixel center and radius -- the same disk, placed and sized to a fraction of a pixel rather than snapped to the pixel grid. - `def fill_circles_aa(mut canvas: Canvas, centers: List[FPoint], radius: Float64, color: Color) raises` -- Fill many equal-radius anti-aliased disks in one call. - `def fill_circles_aa(mut canvas: Canvas, centers: List[FPoint], radius: Float64, colors: List[Color]) raises` -- `fill_circles_aa` with a color per marker -- a scatter whose points carry a color scale. - `def draw_circle_aa(mut canvas: Canvas, cx: Int, cy: Int, radius: Int, color: Color, supersample: Int = 4, width: Float64 = 1.0)` -- Anti-aliased circle outline, `width` pixels wide (default 1). - `def draw_circle_aa(mut canvas: Canvas, cx: Float64, cy: Float64, radius: Float64, color: Color, supersample: Int = 4, width: Float64 = 1.0)` -- `draw_circle_aa` at a sub-pixel center and radius -- the same ring, placed and sized to a fraction of a pixel rather than snapped to the pixel grid. ## canvas.shapes.ellipses Ellipse drawing: midpoint-algorithm hard-edged outline/fill (draw_ellipse/fill_ellipse, independent-x/y-radii generalizations of canvas.shapes.circles' draw_circle/fill_circle) and supersampled analytic-coverage anti-aliased variants (draw_ellipse_aa/ fill_ellipse_aa) -- see canvas.shapes.lines for the hard-edged vs. - `def draw_ellipse(mut canvas: Canvas, cx: Int, cy: Int, rx: Int, ry: Int, color: Color)` -- The midpoint ellipse algorithm -- draw_circle's generalization to independent x/y radii. - `def fill_ellipse(mut canvas: Canvas, cx: Int, cy: Int, rx: Int, ry: Int, color: Color)` -- Fill a solid ellipse: fill_circle generalized to independent x/y radii, one span per row, each pixel set exactly once. - `def fill_ellipse_aa(mut canvas: Canvas, cx: Int, cy: Int, rx: Int, ry: Int, color: Color, supersample: Int = 4)` -- Anti-aliased filled ellipse: fill_circle_aa generalized to independent x/y radii, same per-pixel supersampled analytic coverage, each output pixel visited once. - `def fill_ellipse_aa(mut canvas: Canvas, cx: Float64, cy: Float64, rx: Float64, ry: Float64, color: Color, supersample: Int = 4)` -- `fill_ellipse_aa` at a sub-pixel center and radii -- the same ellipse, placed and sized to a fraction of a pixel rather than snapped to the pixel grid. - `def fill_ellipses_aa(mut canvas: Canvas, centers: List[FPoint], rx: Float64, ry: Float64, color: Color) raises` -- Fill many equal-size anti-aliased ellipses in one call. - `def fill_ellipses_aa(mut canvas: Canvas, centers: List[FPoint], rx: Float64, ry: Float64, colors: List[Color]) raises` -- `fill_ellipses_aa` with a colour per marker. - `def draw_ellipse_aa(mut canvas: Canvas, cx: Int, cy: Int, rx: Int, ry: Int, color: Color, supersample: Int = 4, width: Float64 = 1.0)` -- Anti-aliased ellipse outline, `width` pixels wide (default 1) -- draw_circle_aa's generalization to independent x/y radii. - `def draw_ellipse_aa(mut canvas: Canvas, cx: Float64, cy: Float64, rx: Float64, ry: Float64, color: Color, supersample: Int = 4, width: Float64 = 1.0)` -- `draw_ellipse_aa` at a sub-pixel center and radii; the whole-pixel overload above converts and calls this. ## canvas.shapes.lines Line, polyline, and polygon-*outline* drawing: Bresenham hard-edged (draw_line/draw_polyline/draw_polygon), supersampled analytic-coverage anti-aliased (draw_line_aa/draw_polyline_aa/draw_polygon_aa), and the dash-aware cores they share (_draw_line_core, _draw_polyline_core_aa). ### struct LineCap How an open stroke ends. - value `ROUND` - value `BUTT` - value `SQUARE` - `def __init__(out self, value: Int)` -- Prefer the ROUND/BUTT/SQUARE comptime constants over constructing one directly. - `def write_to[W: Writer](self, mut writer: W)` - `def draw_line(mut canvas: Canvas, x0: Int, y0: Int, x1: Int, y1: Int, color: Color, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0)` -- Bresenham's line algorithm -- integer-only, works for any slope or direction. - `def draw_line_aa(mut canvas: Canvas, x0: Int, y0: Int, x1: Int, y1: Int, color: Color, width: Float64 = 1.0, supersample: Int = 4, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0, cap: LineCap = LineCap.ROUND, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0)` -- Anti-aliased line, `width` pixels wide (default 1), finished with `cap` at each end. - `def draw_line_aa(mut canvas: Canvas, x0: Float64, y0: Float64, x1: Float64, y1: Float64, color: Color, width: Float64 = 1.0, supersample: Int = 4, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0, cap: LineCap = LineCap.ROUND, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0)` -- `draw_line_aa` at sub-pixel endpoints -- the same line, placed to a fraction of a pixel rather than snapped to the pixel grid. - `def draw_polyline(mut canvas: Canvas, points: List[Point], color: Color, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0)` -- Connect consecutive points with line segments (Bresenham). - `def draw_polygon(mut canvas: Canvas, points: List[Point], color: Color, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0)` -- Like draw_polyline, but closes the shape by connecting the last point back to the first. ### struct LineJoin How a stroke turns a corner. - value `ROUND` - value `BEVEL` - value `MITER` - `def __init__(out self, value: Int)` -- Prefer the ROUND/BEVEL/MITER comptime constants over constructing one directly. - `def write_to[W: Writer](self, mut writer: W)` - `def draw_polyline_aa(mut canvas: Canvas, points: List[Point], color: Color, width: Float64 = 1.0, supersample: Int = 4, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0, cap: LineCap = LineCap.ROUND, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0)` -- Anti-aliased polyline; draw_polyline is the hard-edged version. - `def draw_polyline_aa(mut canvas: Canvas, points: List[FPoint], color: Color, width: Float64 = 1.0, supersample: Int = 4, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0, cap: LineCap = LineCap.ROUND, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0)` -- `draw_polyline_aa` at sub-pixel vertices -- the same polyline, placed to a fraction of a pixel rather than snapped to the pixel grid. - `def draw_polygon_aa(mut canvas: Canvas, points: List[Point], color: Color, width: Float64 = 1.0, supersample: Int = 4, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0)` -- Anti-aliased polygon outline; draw_polygon is the hard-edged version. - `def draw_polygon_aa(mut canvas: Canvas, points: List[FPoint], color: Color, width: Float64 = 1.0, supersample: Int = 4, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0)` -- `draw_polygon_aa` at sub-pixel vertices -- the same polygon outline, placed to a fraction of a pixel rather than snapped to the pixel grid. ## canvas.shapes.mesh A mesh of adjacent faces drawn as one shape: full coverage wherever two faces meet, anti-aliasing only at the outer silhouette. - `def fill_mesh(mut canvas: Canvas, points: List[FPoint], faces: List[Int], colors: List[Color]) raises` -- Many adjacent triangles in one call, drawn as one anti-aliased shape: no seam along an edge two faces share, and anti-aliasing only at the outline of the whole. - `def fill_mesh_shaded(mut canvas: Canvas, points: List[FPoint], faces: List[Int], vertex_colors: List[Color]) raises` -- `fill_mesh` with a color per vertex, interpolated across each face: a smoothly shaded surface rather than a faceted one (#426). ## canvas.shapes.polygon_fill A polygon's *interior* fill: the scanline/winding-number machinery (`_Crossing`, `_Span`, `_spans_from_crossings`), its two consumers here (`fill_polygon`, `fill_polygon_aa`), and `_point_in_polygon`, the real-valued membership test the anti-aliased sweep is checked against. - `def fill_polygon(mut canvas: Canvas, points: List[Point], color: Color, fill_rule: FillRule = FillRule.EVEN_ODD)` -- Fill a polygon's interior with the scanline algorithm. - `def fill_polygon_aa(mut canvas: Canvas, points: List[Point], color: Color, fill_rule: FillRule = FillRule.EVEN_ODD, supersample: Int = 4)` -- Anti-aliased filled polygon: for every pixel near the polygon, samples an NxN sub-pixel grid and turns the coverage fraction into that pixel's alpha. - `def fill_polygon_aa(mut canvas: Canvas, points: List[FPoint], color: Color, fill_rule: FillRule = FillRule.EVEN_ODD, supersample: Int = 4)` -- `fill_polygon_aa` at sub-pixel vertices -- the same fill, with its outline placed to a fraction of a pixel rather than snapped to the pixel grid. ## canvas.shapes.rects Rectangle drawing: stroked outline (draw_rect, via canvas.shapes.lines.draw_line), solid fill (fill_rect), and gradient-sourced fill (fill_rect_gradient/fill_rect_radial_gradient -- see gradient.mojo) and pattern-sourced fill (fill_rect_pattern -- see pattern.mojo). - `def draw_rect(mut canvas: Canvas, x: Int, y: Int, width: Int, height: Int, color: Color)` -- Stroke a rectangle's outline (x, y is the top-left corner). - `def fill_rect(mut canvas: Canvas, x: Int, y: Int, width: Int, height: Int, color: Color)` -- Fill a solid rectangle (x, y is the top-left corner). - `def fill_rect(mut canvas: Canvas, x: Float64, y: Float64, width: Float64, height: Float64, color: Color)` -- `fill_rect` for a geometric rectangle: the box from (x, y) spanning width x height, in the pixel-center convention (pixel k spans k - 0.5 to k + 0.5), snapped to whole pixels. - `def fill_rect_gradient(mut canvas: Canvas, x: Int, y: Int, width: Int, height: Int, gradient: LinearGradient)` -- Fill a rectangle as fill_rect does, sourcing each pixel's color from `gradient` (gradient.mojo) rather than one flat Color. - `def fill_rect_gradient(mut canvas: Canvas, x: Float64, y: Float64, width: Float64, height: Float64, gradient: LinearGradient)` -- `fill_rect_gradient` for a geometric rectangle, snapped to whole pixels as the `Float64` `fill_rect` snaps. - `def fill_rect_radial_gradient(mut canvas: Canvas, x: Int, y: Int, width: Int, height: Int, gradient: RadialGradient)` -- Like fill_rect_gradient, but for a RadialGradient. - `def fill_rect_pattern(mut canvas: Canvas, x: Int, y: Int, width: Int, height: Int, pattern: PatternSource)` -- Like fill_rect_gradient, but for a PatternSource (pattern.mojo): each pixel's color comes from a sampled raster tile rather than a gradient projection. ## canvas.text.bidi Unicode bidirectional layout for mixed-direction text. - `def is_formatting_control(cp: Int) -> Bool` -- Whether the codepoint is one of the structural directional formatting characters -- the embeddings, the overrides, PDF, the isolates and PDI. - `def is_combining_mark(cp: Int) -> Bool` -- Whether the codepoint is a non-spacing mark (UAX #9's NSM). - `def detect_base_level(codepoints: List[Int]) -> Int` -- UAX #9 rules P2/P3, simplified to their common-case outcome: the paragraph's base embedding level is RTL (1) if the first strongly-directional codepoint is STRONG_R, LTR (0) otherwise (including the case where every codepoint is weak -- an all-digit or all-punctuation line has no basis to be anything but LTR). ### struct BidiRun One maximal span of a line at a single embedding level. - `def __init__(out self, start: Int, length: Int, level: Int)` - `def is_rtl(self) -> Bool` -- Whether this run draws right to left. - `def visual_runs(codepoints: List[Int], base_level: Int) -> List[BidiRun]` -- The line's level runs, left to right, each still holding its characters in logical order. - `def visual_order(codepoints: List[Int], base_level: Int) -> List[Int]` -- The full pipeline: resolve each codepoint's embedding level, reorder into visual (left-to-right-drawable) order, and mirror any paired character left at an odd (RTL) level. ## canvas.text.bidi_data Unicode data for `bidi.mojo`, generated -- do not hand-edit. - `def bidi_class(cp: Int) -> Int` -- The codepoint's UAX #9 bidi class. - `def canonical_bracket(cp: Int) -> Int` -- BD16 pairs brackets under canonical equivalence. - `def bracket_partner(cp: Int) -> Int` -- The other half of a paired bracket, or 0 for anything that is not one (rule N0). - `def bracket_is_open(cp: Int) -> Bool` -- Whether `cp` is the opening half of a pair. ## canvas.text.font_cache Caller-owned cache for font resolution, parsed faces, and glyph masks. ### struct FontCache Construct one, then pass it by `cache=` into draw_text/measure_text/measure_text_block for every call reusing the same fonts. - `def __init__(out self)` -- Scans nothing. - `def has_scanned(self) -> Bool` -- Whether the installed fonts have been scanned yet: False after construction, True from the first lookup that needed them. - `def glyph_mask_count(self) -> Int` -- How many rasterized glyph masks the cache holds. - `def glyph_mask_bytes(self) -> Int` -- How much the rasterized-glyph store is holding. - `def glyph_mask_turnovers(self) -> Int` -- How many times the store has released a generation. - `def clear_glyph_masks(mut self)` -- Release every rasterized glyph mask, keeping the resolved font paths and faces. - `def resolve(mut self, family: String, slant: FontSlant, weight: FontWeight) raises -> String` -- Cached resolve_font_file: the scanned font database is matched once per distinct (family, slant, weight), and every later call for that combination reads the path from the Dict. - `def resolve_for_char(mut self, family: String, slant: FontSlant, weight: FontWeight, codepoint: Int) raises -> String` -- Cached resolve_font_file_for_char, keyed additionally on `codepoint`, since a charset-constrained match can return a different font than the unconstrained one. - `def resolve_face(mut self, family: String, slant: FontSlant, weight: FontWeight, size: Float64) raises -> ArcPointer[TTFFace]` -- `resolve` plus `_face_for_path` in one call. - `def resolve_face_for_char(mut self, family: String, slant: FontSlant, weight: FontWeight, codepoint: Int, size: Float64) raises -> ArcPointer[TTFFace]` -- `resolve_face`'s fallback-glyph counterpart. ## canvas.text.font_discovery Font discovery: resolves a family/slant/weight request to a font file path on disk, with no linked library. ### struct FontSlant A font's upright/italic/oblique style. - value `NORMAL` - value `ITALIC` - value `OBLIQUE` - `def __init__(out self, value: Int)` -- Prefer the `NORMAL`/`ITALIC`/`OBLIQUE` comptime constants over constructing one directly. - `def write_to[W: Writer](self, mut writer: W)` ### struct FontWeight A font's normal/bold weight, defined here for the same reason FontSlant is. - value `NORMAL` - value `BOLD` - `def __init__(out self, value: Int)` -- Prefer the `NORMAL`/`BOLD` comptime constants over constructing one directly. - `def write_to[W: Writer](self, mut writer: W)` ### struct FontFace One installed face: where its file is, what it calls itself, and the handful of style axes matching compares. ### struct FontDatabase Every installed face on this machine, scanned once. - `def __init__(out self)` -- Scan the platform's font directories. - `def __init__(out self, var faces: List[FontFace])` -- A database over `faces` alone, with no scan of the installed fonts: what `FontCache` holds until its first lookup, and a way to build a database over known faces. - `def resolve_selection(self, family: String, slant: FontSlant = FontSlant.NORMAL, weight: FontWeight = FontWeight.NORMAL, codepoint: Int = -1) raises -> Tuple[String, Int]` -- The file and collection index of the best matching face. - `def resolve(self, family: String, slant: FontSlant = FontSlant.NORMAL, weight: FontWeight = FontWeight.NORMAL, codepoint: Int = -1) raises -> String` -- Best-matching font file for this request. - `def resolve_font_file(family: String, slant: FontSlant = FontSlant.NORMAL, weight: FontWeight = FontWeight.NORMAL) raises -> String` -- Resolve `family`/`slant`/`weight` to an absolute font file path. - `def resolve_font_file_for_char(family: String, slant: FontSlant, weight: FontWeight, codepoint: Int) raises -> String` -- Like `resolve_font_file`, but constrained to a font that contains `codepoint` -- the fallback `render.mojo` uses when the requested family has no glyph for a character, such as CJK text under a Latin-only "Sans". ## canvas.text.glyph_outline Glyph outlines and metrics: the adapter between `font_discovery.mojo`, which resolves a family/slant/weight to a file, and `ttf.mojo`, which parses that file's binary tables. ### struct LineMetrics This face's line metrics at its current size, in pixels. - `def __init__(out self, ascender: Float64, descender: Float64, line_height: Float64)` -- This face's line metrics at its current pixel size. - `def face_line_metrics(face: TTFFace) raises -> LineMetrics` -- This face's line metrics at whatever pixel size `TTFFace.set_pixel_size` last set; raises if it was never called (see `TTFFace.scale`). ### struct GlyphMetrics One glyph's layout-relevant measurements, in pixels, at whatever size was last set. - `def __init__(out self, advance: Float64, bearing_x: Float64, bearing_y: Float64, width: Float64, height: Float64)` -- One glyph's layout-relevant measurements, in pixels. - `def has_glyph(mut face: TTFFace, codepoint: Int) raises -> Bool` -- Whether `face` has a real glyph for `codepoint`. Glyph index 0 is TrueType's ".notdef", what `cmap` returns for an unmapped codepoint. - `def glyph_metrics(mut face: TTFFace, codepoint: Int) raises -> GlyphMetrics` -- This character's advance/bearing/size, in pixels. - `def glyph_index_metrics(mut face: TTFFace, glyph_index: Int) raises -> GlyphMetrics` -- One glyph's advance/bearing/size, in pixels, addressed by glyph index rather than codepoint -- what a glyph `GSUB` substitution produced has, since a ligature stands for several characters and none of their codepoints names it. - `def glyph_path(mut face: TTFFace, codepoint: Int, pen_x: Float64, pen_y: Float64) raises -> Path` -- One character's outline as a `Path`, positioned so its local (0, 0) -- the glyph origin -- lands at (pen_x, pen_y) in pixel space. - `def glyph_index_path(mut face: TTFFace, glyph_index: Int, pen_x: Float64, pen_y: Float64) raises -> Path` -- `glyph_path` addressed by glyph index rather than codepoint, the form a `GSUB` substitution's output needs. ## canvas.text.joining Arabic joining: which contextual form -- isolated, initial, medial or final -- each letter of a run takes from the letters beside it. - `def is_arabic(cp: Int) -> Bool` -- Whether `cp` belongs to one of the Arabic blocks -- what selects the `arab` OpenType script for a run, and so the joining features. - `def joining_type(cp: Int) -> Int` -- `cp`'s Unicode Joining_Type, over the blocks this module's docstring lists. - `def joining_forms(codepoints: List[Int]) -> List[Int]` -- The contextual form each character of a run is eligible for, one per codepoint. ## canvas.text.render Text rendering: font matching from `font_discovery.mojo`, glyph outlines and metrics from `ttf.mojo` via `glyph_outline.mojo`, and rasterization from `fill_path_aa` (`path.mojo`) under `FillRule.NONZERO`, the rule TrueType outlines are drawn with, which also puts every glyph on the exact-area rasterizer (`canvas.aa_area`). ### struct TextMetrics A single line's measured size. - `def __init__(out self, width: Float64, height: Float64, advance: Float64)` -- A single line's measured size. - `def measure_text(text: String, size: Float64, family: String = "Sans", slant: FontSlant = FontSlant.NORMAL, weight: FontWeight = FontWeight.NORMAL, kerning: Bool = True, ligatures: Bool = True) raises -> TextMetrics` -- Measure `text` at `size` points in `family` without drawing it. - `def measure_text(text: String, size: Float64, family: String = "Sans", slant: FontSlant = FontSlant.NORMAL, weight: FontWeight = FontWeight.NORMAL, kerning: Bool = True, ligatures: Bool = True, *, mut cache: FontCache) raises -> TextMetrics` -- Like measure_text above, but resolving fonts through `cache`. Pass the same `FontCache` to every call in a batch. ### struct TextBlockBounds The axis-aligned bounding box draw_text's ink would occupy for a given text/rotation/align/font, anchor-relative: `x`/`y` are the top-left corner relative to draw_text's `(x, y)` anchor, and either can be negative (RIGHT-aligned text extends left of the anchor; a label rotated upward extends above it). - `def __init__(out self, x: Float64, y: Float64, width: Float64, height: Float64)` -- The bounding box draw_text's ink would occupy, anchor- relative -- see the struct docstring above. - `def measure_text_block(text: String, size: Float64, family: String = "Sans", slant: FontSlant = FontSlant.NORMAL, weight: FontWeight = FontWeight.NORMAL, rotation: Float64 = 0.0, align: TextAlign = TextAlign.LEFT, kerning: Bool = True, ligatures: Bool = True) raises -> TextBlockBounds` -- The bounding box draw_text(canvas, x, y, text, ..., rotation= rotation, align=align) would render into, anchor-relative and without drawing -- see TextBlockBounds. - `def measure_text_block(text: String, size: Float64, family: String = "Sans", slant: FontSlant = FontSlant.NORMAL, weight: FontWeight = FontWeight.NORMAL, rotation: Float64 = 0.0, align: TextAlign = TextAlign.LEFT, kerning: Bool = True, ligatures: Bool = True, *, mut cache: FontCache) raises -> TextBlockBounds` -- Like measure_text_block above, but resolving fonts through `cache` rather than fresh every call. - `def text_run_anchors(x: Float64, y: Float64, runs: List[TextRun], family: String = "Sans", weight: FontWeight = FontWeight.NORMAL, rotation: Float64 = 0.0, align: TextAlign = TextAlign.LEFT, *, mut cache: FontCache) raises -> List[FPoint]` -- Where each run of `draw_text_runs(x, y, runs, ...)` lands: the anchor `draw_text` takes for that run drawn alone, with `TextAlign.LEFT` and the same `rotation`. One entry per run, in order. ### struct TextLayout Text already shaped, kerned, line-broken and aligned, ready to be measured or drawn without doing that work again. - `def __init__(out self, var block: _BlockLayout, var text: String, size: Float64, var family: String, slant: FontSlant, weight: FontWeight, rotation: Float64, align: TextAlign, kerning: Bool, ligatures: Bool)` - `def has_ink(self) -> Bool` -- Whether anything would actually be drawn. - `def prepare_text(text: String, size: Float64, family: String = "Sans", slant: FontSlant = FontSlant.NORMAL, weight: FontWeight = FontWeight.NORMAL, rotation: Float64 = 0.0, align: TextAlign = TextAlign.LEFT, kerning: Bool = True, ligatures: Bool = True, *, mut cache: FontCache) raises -> TextLayout` -- Shape and lay `text` out once, for `measure_layout` and `draw_layout` to share. - `def measure_layout(layout: TextLayout) -> TextBlockBounds` -- The prepared layout's anchor-relative bounding box: what `measure_text_block` returns for the same arguments, without laying the text out again. - `def draw_layout(mut canvas: Canvas, x: Float64, y: Float64, layout: TextLayout, color: Color, *, mut cache: FontCache) raises` -- Draw a prepared layout with its anchor at (x, y): what `draw_text` draws for the same arguments, without laying the text out again. - `def draw_text(mut canvas: Canvas, x: Int, y: Int, text: String, color: Color, size: Float64, family: String = "Sans", slant: FontSlant = FontSlant.NORMAL, weight: FontWeight = FontWeight.NORMAL, rotation: Float64 = 0.0, align: TextAlign = TextAlign.LEFT, kerning: Bool = True, ligatures: Bool = True) raises` -- Render `text` (one or more "\\n"-separated lines) anchored at `(x, y)` in `family` at `size` points, compositing onto `canvas` in `color`. AA coverage combines with `color.a` through the same set_pixel() blend every other filled shape uses. - `def draw_text(mut canvas: Canvas, x: Int, y: Int, text: String, color: Color, size: Float64, family: String = "Sans", slant: FontSlant = FontSlant.NORMAL, weight: FontWeight = FontWeight.NORMAL, rotation: Float64 = 0.0, align: TextAlign = TextAlign.LEFT, kerning: Bool = True, ligatures: Bool = True, *, mut cache: FontCache) raises` -- Like draw_text above, but resolving fonts through `cache` rather than fresh every call. - `def draw_text(mut canvas: Canvas, x: Float64, y: Float64, text: String, color: Color, size: Float64, family: String = "Sans", slant: FontSlant = FontSlant.NORMAL, weight: FontWeight = FontWeight.NORMAL, rotation: Float64 = 0.0, align: TextAlign = TextAlign.LEFT, kerning: Bool = True, ligatures: Bool = True) raises` -- Draw text at a sub-pixel anchor, resolving fonts for this call. - `def draw_text(mut canvas: Canvas, x: Float64, y: Float64, text: String, color: Color, size: Float64, family: String = "Sans", slant: FontSlant = FontSlant.NORMAL, weight: FontWeight = FontWeight.NORMAL, rotation: Float64 = 0.0, align: TextAlign = TextAlign.LEFT, kerning: Bool = True, ligatures: Bool = True, *, mut cache: FontCache) raises` -- Draw text at a sub-pixel anchor using `cache` for font resolution. - `def stroke_text(mut canvas: Canvas, x: Float64, y: Float64, text: String, color: Color, size: Float64, width: Float64 = 1.0, family: String = "Sans", slant: FontSlant = FontSlant.NORMAL, weight: FontWeight = FontWeight.NORMAL, rotation: Float64 = 0.0, align: TextAlign = TextAlign.LEFT, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0, kerning: Bool = True, ligatures: Bool = True) raises` -- Stroke text outlines, resolving fonts for this call. - `def stroke_text(mut canvas: Canvas, x: Float64, y: Float64, text: String, color: Color, size: Float64, width: Float64 = 1.0, family: String = "Sans", slant: FontSlant = FontSlant.NORMAL, weight: FontWeight = FontWeight.NORMAL, rotation: Float64 = 0.0, align: TextAlign = TextAlign.LEFT, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0, kerning: Bool = True, ligatures: Bool = True, *, mut cache: FontCache) raises` -- Outline `text` rather than filling it: the layout `draw_text` produces, with each glyph's outline handed to `stroke_path_aa` instead of `fill_path_aa`. Cairo's `text_path` + `stroke` and the HTML5 canvas's `strokeText`; an outlined label reads over a busy background where a filled one does not. - `def text_path(x: Float64, y: Float64, text: String, size: Float64, family: String = "Sans", slant: FontSlant = FontSlant.NORMAL, weight: FontWeight = FontWeight.NORMAL, rotation: Float64 = 0.0, align: TextAlign = TextAlign.LEFT, kerning: Bool = True, ligatures: Bool = True, *, mut cache: FontCache) raises -> Path` -- The outline of `text` as one `Path`: every glyph's contours, laid out exactly as `draw_text` lays them out (shaping, kerning, line breaking, alignment and rotation about the `(x, y)` anchor), in canvas coordinates. - `def draw_text_on_path(mut canvas: Canvas, path: Path, text: String, color: Color, size: Float64, offset: Float64 = 0.0, family: String = "Sans", slant: FontSlant = FontSlant.NORMAL, weight: FontWeight = FontWeight.NORMAL, align: TextAlign = TextAlign.LEFT, kerning: Bool = True, ligatures: Bool = True) raises` -- Draw text along a curve, resolving fonts for this call. - `def draw_text_on_path(mut canvas: Canvas, path: Path, text: String, color: Color, size: Float64, offset: Float64 = 0.0, family: String = "Sans", slant: FontSlant = FontSlant.NORMAL, weight: FontWeight = FontWeight.NORMAL, align: TextAlign = TextAlign.LEFT, kerning: Bool = True, ligatures: Bool = True, *, mut cache: FontCache) raises` -- Draw `text` with its baseline running along `path`: a label around a donut segment, a curved axis label on a polar grid. ## canvas.text.text_align TextAlign, in its own module so it can be referenced by `canvas.vector.draw_target` -- and transitively by `canvas.buffer`'s `Canvas` -- without pulling in render.mojo's font-touching imports (font_discovery.mojo/ttf.mojo/glyph_outline.mojo/bidi.mojo). ### struct TextAlign Horizontal alignment of each line relative to draw_text's (x, y) anchor. - value `LEFT` - value `CENTER` - value `RIGHT` - `def __init__(out self, value: Int)` -- Prefer the `LEFT`/`CENTER`/`RIGHT` comptime constants over constructing one directly. - `def write_to[W: Writer](self, mut writer: W)` ## canvas.text.text_run TextRun, in its own module for the reason `text_align.mojo` gives: `canvas.vector.draw_target` and `canvas.buffer` name it in a signature and cannot import render.mojo, which imports `canvas.buffer` itself. ### struct TextRun One piece of a label `draw_text_runs` draws: its text at its own size and slant, placed against the runs around it. - `def __init__(out self, text: String, size: Float64, slant: FontSlant = FontSlant.NORMAL, dx: Float64 = 0.0, dy: Float64 = 0.0)` -- One run of a label made of several. ## canvas.text.ttf Native TrueType (`sfnt`/`glyf`) font file parser: reads a font file's binary tables directly (table directory, `head`, `maxp`, `hhea`, `hmtx`, `cmap`, `glyf`, `loca`, `kern`, `GPOS`, `GSUB`) rather than linking a font library. ### struct ShapedRun A glyph sequence after `GSUB` substitution. - `def __init__(out self, var glyphs: List[Int], var clusters: List[Int], changed: Bool)` ### struct RawGlyphOutline A decoded glyph outline in plain-`List` form: on-curve/off-curve points plus per-contour end indices -- FreeType's `FT_Outline` shape (points, tags, contour ends) as owned `List`s rather than raw C pointers, so this module has no pointer surface. - `def __init__(out self)` - `def copied(self) -> RawGlyphOutline` -- An independent copy of this outline's point lists. - `def bounding_box(self) -> Tuple[Int, Int, Int, Int]` -- (xMin, yMin, xMax, yMax) across every point, computed from the point coordinate data the way the OpenType spec defines a glyph's bounding box ("obtained directly from the point coordinate data for the glyph, comparing all on-curve and off-curve points"), rather than from the `glyf` header's xMin/yMin/xMax/yMax. ### struct BitmapMetrics A color bitmap glyph's placement, in the strike's own pixels: `found` is False when the glyph has no bitmap. - `def __init__(out self, found: Bool, ppem: Int, width: Int, height: Int, bearing_x: Int, bearing_y: Int, advance: Int)` ### struct TTFFace A parsed TrueType font file: the raw file bytes plus the table offsets and global metrics this module reads. - `def __init__(out self, path: String, collection_index: Int = 0) raises` -- Parse a TrueType (`glyf`-outline) font file. - `def set_pixel_size(mut self, pixel_size: Int)` -- Set this face's active rasterization size in pixels. - `def scale(self) raises -> Float64` -- Font-design-units -> pixels conversion factor at the active pixel size (`pixel_size / units_per_em`). - `def advance_width(self, glyph_index: Int) raises -> Int` -- `hmtx`'s rule that when there are fewer hMetrics entries than glyphs, the last entry's advance width repeats for the rest -- the spec's optimization for monospace and large fonts. - `def has_kerning(self) -> Bool` -- Whether this font carries pair kerning this module reads -- a `GPOS` `kern` feature with PairPos lookups, or a format 0 horizontal `kern` subtable. - `def kern_adjustment(mut self, left: Int, right: Int) raises -> Int` -- The x-advance adjustment to apply between two adjacent glyphs, in font design units. - `def has_substitutions(self, script_tag: String = _SCRIPT_DEFAULT) -> Bool` -- Whether this font carries glyph substitutions this module reads for a script -- a single or ligature lookup under one of the features `_script_feature_tags` lists for it. - `def substitute_glyphs(self, glyphs: List[Int]) raises -> ShapedRun` -- Apply the default script's `liga` and `ccmp` lookups to a glyph sequence: "f", "f", "i" comes back as the one "ffi" glyph where the font has it. - `def substitute_glyphs(self, glyphs: List[Int], masks: List[Int], script_tag: String) raises -> ShapedRun` -- Apply `script_tag`'s substitution features to a glyph sequence, each lookup running only where its features are enabled. - `def glyph_index_for_codepoint(mut self, codepoint: Int) raises -> Int` -- Look up `codepoint` in the `cmap` table, preferring a full-Unicode format 12 subtable (covering supplementary planes: emoji, some CJK) over a BMP-only format 4 one. - `def has_color_bitmaps(self) -> Bool` -- Whether the font carries a `CBLC`/`CBDT` color strike, so some glyphs draw as bitmaps rather than outlines. - `def color_bitmap_metrics(self, glyph_index: Int) raises -> BitmapMetrics` -- The color bitmap's size and placement for `glyph_index` in the largest strike, `found` False when the strike has no image for it. - `def color_bitmap(mut self, glyph_index: Int) raises -> ArcPointer[Canvas]` -- The decoded color bitmap for `glyph_index`, at the strike's size, cached per face. - `def glyph_outline(mut self, glyph_index: Int) raises -> RawGlyphOutline` -- This glyph's decoded outline, in font design units. - `def glyph_outline_shared(mut self, glyph_index: Int) raises -> ArcPointer[RawGlyphOutline]` -- This glyph's decoded outline, shared rather than copied. - `def outline_to_path(outline: RawGlyphOutline, pen_x: Float64, pen_y: Float64, scale: Float64) raises -> Path` -- One glyph's full outline (all contours) as a `Path`, positioned so its local (0, 0) lands at (pen_x, pen_y), the convention `glyph_outline.glyph_path` uses. ## canvas.vector.draw_target DrawTarget: the drawing-primitive interface a higher-level charting layer renders through, so a plot/scale/theme layer can target a raster `Canvas`, a vector `SvgCanvas` or a `PdfCanvas` page without knowing which it holds. ### trait DrawTarget - `def fill_rect(mut self, x: Int, y: Int, width: Int, height: Int, color: Color)` -- Fill the pixels x through x + width - 1 by y through y + height - 1 with a solid color. - `def fill_rect(mut self, x: Float64, y: Float64, width: Float64, height: Float64, color: Color)` -- Fill the geometric box from (x, y) spanning width x height, snapped to whole pixels: each edge goes to the nearest pixel boundary (pixel k spans k - 0.5 to k + 0.5), so a caller laying out in `Float64` gets crisp edges without rounding itself. - `def fill_rect_gradient(mut self, x: Int, y: Int, width: Int, height: Int, gradient: LinearGradient)` -- Fill a rectangle, sourcing each point's color from `gradient` rather than one flat color. - `def fill_rect_gradient(mut self, x: Float64, y: Float64, width: Float64, height: Float64, gradient: LinearGradient)` -- `fill_rect_gradient` for a geometric box, snapped to whole pixels as the `Float64` `fill_rect` is. - `def draw_line_aa(mut self, x0: Int, y0: Int, x1: Int, y1: Int, color: Color, width: Float64 = 1.0, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0, cap: LineCap = LineCap.ROUND, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0)` -- An anti-aliased line, round-capped by default. - `def draw_line_aa(mut self, x0: Float64, y0: Float64, x1: Float64, y1: Float64, color: Color, width: Float64 = 1.0, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0, cap: LineCap = LineCap.ROUND, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0)` -- An anti-aliased line between sub-pixel endpoints, round-capped by default. - `def fill_circle_aa(mut self, cx: Int, cy: Int, radius: Int, color: Color)` -- An anti-aliased filled disk. - `def fill_circle_aa(mut self, cx: Float64, cy: Float64, radius: Float64, color: Color)` -- An anti-aliased filled disk at a sub-pixel center and radius. - `def fill_circles_aa(mut self, centers: List[FPoint], radius: Float64, color: Color) raises` -- Many equal-radius disks in one call, in draw order. - `def fill_circles_aa(mut self, centers: List[FPoint], radius: Float64, colors: List[Color]) raises` -- `fill_circles_aa` with a color per marker -- a scatter whose points carry a color scale. - `def fill_mesh(mut self, points: List[FPoint], faces: List[Int], colors: List[Color]) raises` -- Many adjacent triangles in one call, drawn as one shape: no seam along an edge two faces share, anti-aliasing only at the outline of the whole. - `def fill_mesh_shaded(mut self, points: List[FPoint], faces: List[Int], vertex_colors: List[Color]) raises` -- `fill_mesh` with a color per vertex, interpolated across each face: a smoothly shaded surface rather than a faceted one (#426). - `def fill_ellipses_aa(mut self, centers: List[FPoint], rx: Float64, ry: Float64, color: Color) raises` -- Many equal-size ellipses in one call, in draw order. - `def fill_ellipses_aa(mut self, centers: List[FPoint], rx: Float64, ry: Float64, colors: List[Color]) raises` -- `fill_ellipses_aa` with a color per marker. - `def draw_circle_aa(mut self, cx: Float64, cy: Float64, radius: Float64, color: Color, width: Float64 = 1.0)` -- An anti-aliased circle outline, `width` pixels wide (default 1), at a sub-pixel center and radius. - `def fill_ellipse_aa(mut self, cx: Int, cy: Int, rx: Int, ry: Int, color: Color)` -- An anti-aliased filled ellipse. - `def fill_ellipse_aa(mut self, cx: Float64, cy: Float64, rx: Float64, ry: Float64, color: Color)` -- An anti-aliased filled ellipse at a sub-pixel center and radii. - `def draw_ellipse_aa(mut self, cx: Int, cy: Int, rx: Int, ry: Int, color: Color)` -- An anti-aliased ellipse outline, ~1px wide. - `def draw_ellipse_aa(mut self, cx: Float64, cy: Float64, rx: Float64, ry: Float64, color: Color, width: Float64 = 1.0)` -- An anti-aliased ellipse outline, `width` pixels wide (default 1), at a sub-pixel center and radii. - `def fill_arc_aa(mut self, cx: Float64, cy: Float64, radius: Float64, start_angle: Float64, end_angle: Float64, color: Color)` -- An anti-aliased filled pie-slice wedge. - `def fill_arcs_aa(mut self, centers: List[FPoint], radius: Float64, start_angle: Float64, end_angle: Float64, color: Color) raises` -- Many equal-size wedges in one call, in draw order. - `def fill_arcs_aa(mut self, centers: List[FPoint], radius: Float64, start_angle: Float64, end_angle: Float64, colors: List[Color]) raises` -- `fill_arcs_aa` with a color per wedge. - `def fill_ring_sector_aa(mut self, cx: Float64, cy: Float64, inner_radius: Float64, outer_radius: Float64, start_angle: Float64, end_angle: Float64, color: Color)` -- An anti-aliased filled ring/donut segment. - `def stroke_path_aa(mut self, path: Path, color: Color, width: Float64 = 1.0, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0, cap: LineCap = LineCap.ROUND, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0)` -- An anti-aliased stroke of a Path's outline. - `def fill_path_aa(mut self, path: Path, color: Color, fill_rule: FillRule = FillRule.EVEN_ODD)` -- An anti-aliased fill of a Path's interior. - `def draw_image(mut self, image: Canvas, x: Float64, y: Float64, width: Float64 = 0.0, height: Float64 = 0.0) raises` -- Draw a block of pixels with its top-left at (x, y), scaled to `width x height` in user space (the image's own pixel size when 0), under the current transform, each image pixel one hard-edged cell of the block. - `def draw_text(mut self, x: Float64, y: Float64, text: String, color: Color, size: Float64, family: String = "Sans", slant: FontSlant = FontSlant.NORMAL, weight: FontWeight = FontWeight.NORMAL, rotation: Float64 = 0.0, align: TextAlign = TextAlign.LEFT, *, mut cache: FontCache) raises` -- Draw `text`, one or more "\\n"-separated lines, anchored at `(x, y)` on the first line's baseline, under the current transform. - `def draw_text_runs(mut self, x: Float64, y: Float64, runs: List[TextRun], color: Color, family: String = "Sans", weight: FontWeight = FontWeight.NORMAL, rotation: Float64 = 0.0, align: TextAlign = TextAlign.LEFT, *, mut cache: FontCache) raises` -- Draw one label made of several runs, each at its own size, slant and offset (`TextRun`), anchored at `(x, y)` on the label's baseline. - `def push_clip(mut self, x: Int, y: Int, width: Int, height: Int)` -- Restrict drawing to the pixels x through x + width - 1 by y through y + height - 1, until the matching `pop_clip`. - `def pop_clip(mut self)` -- Undo the innermost `push_clip`, reverting to the clip outside it or to no clip at all. - `def push_clip_path(mut self, path: Path, fill_rule: FillRule = FillRule.EVEN_ODD) raises` -- Restrict subsequent drawing to the interior of a user-space path. - `def pop_clip_path(mut self)` -- Undo the matching `push_clip_path` in reverse push order. - `def begin_annotated_group(mut self, title: String)` -- Open a group labeled `title`, covering every primitive drawn until `end_annotated_group`. A backend that can carry the label does; one that cannot ignores it. - `def end_annotated_group(mut self)` -- Close the group opened by `begin_annotated_group`, a no-op if none is open -- matching `Canvas.pop_clip`, which also treats an unbalanced close as nothing to undo rather than an error. - `def begin_batch(mut self)` -- Start deferring anti-aliased shapes so that `end_batch` can draw them in one parallel pass, in the order they were called. - `def end_batch(mut self)` -- Draw everything deferred since the matching `begin_batch`; a no-op with none open. - `def save(mut self)` -- Push the current transform (and, on a backend that clips, the clip state) for `restore` to put back. - `def restore(mut self)` -- Pop what `save` pushed. - `def translate(mut self, tx: Float64, ty: Float64)` -- Shift subsequent drawing by (tx, ty) in the current user space. - `def rotate(mut self, angle: Float64)` -- Turn subsequent drawing by `angle` radians about the current origin; positive is clockwise on screen. - `def scale(mut self, sx: Float64, sy: Float64)` -- Scale subsequent drawing about the current origin, each axis by its own factor. - `def transform(mut self, matrix: Matrix2D)` -- Compose `matrix` into the current transform, applied to coordinates before everything already in place. - `def set_transform(mut self, matrix: Matrix2D)` -- Replace the current transform outright. - `def reset_transform(mut self)` -- Back to the identity. - `def current_transform(self) -> Matrix2D` -- The map every drawing call currently applies. - `def has_transform(self) -> Bool` -- Whether the current transform is anything but the identity. - `def set_blend_mode(mut self, mode: BlendMode)` -- Set how later drawing calls combine with what is already there. - `def blend_mode(self) -> BlendMode` -- The blend mode later drawing calls will use. - `def set_color_space(mut self, space: ColorSpace)` -- Set the space later source-over blends mix in (see `ColorSpace`). - `def color_space(self) -> ColorSpace` -- The color space later drawing calls will blend in. ## canvas.vector.pdf `PdfCanvas`: a `DrawTarget` that writes PDF documents. ### struct PdfCanvas A PDF document built from `DrawTarget` calls, one page at a time; see the module docstring for what each becomes. - `def __init__(out self, width: Int, height: Int) raises` -- A document with one empty page of `width x height` points. - `def new_page(mut self, width: Int = -1, height: Int = -1)` -- Finish the current page and start another, of the same size unless `width` and `height` say otherwise. - `def page_count(self) -> Int` -- How many pages the document has, the current one included. - `def save(mut self)` -- Push the transform, blend mode, color space and clip depth for `restore` to put back, as `Canvas.save` does. - `def restore(mut self)` -- Pop the state `save` pushed, closing every clip pushed since. - `def translate(mut self, tx: Float64, ty: Float64)` -- Move the origin by (tx, ty) in the current user space. - `def rotate(mut self, angle: Float64)` -- Rotate later drawing by `angle` radians about the origin. - `def scale(mut self, sx: Float64, sy: Float64)` -- Scale later drawing by (sx, sy) about the origin. - `def transform(mut self, matrix: Matrix2D)` -- Apply `matrix` ahead of the current transform. - `def set_transform(mut self, matrix: Matrix2D)` -- Replace the current transform with `matrix`. - `def reset_transform(mut self)` -- Back to the identity. - `def current_transform(self) -> Matrix2D` -- The transform later drawing goes through. - `def has_transform(self) -> Bool` -- Whether the current transform is not the identity. - `def set_blend_mode(mut self, mode: BlendMode)` -- Set the blend mode later elements carry as an `ExtGState` `/BM`. The Porter-Duff operators have no PDF equivalent and draw source-over. - `def blend_mode(self) -> BlendMode` -- The blend mode later elements carry. - `def set_color_space(mut self, space: ColorSpace)` -- Recorded for `color_space` and `save`/`restore`; PDF has no linear-light compositing to ask for, so it changes nothing drawn. - `def color_space(self) -> ColorSpace` -- The color space last set. - `def set_title(mut self, title: String)` -- The document's `/Title`, in its `/Info` dictionary. - `def set_author(mut self, author: String)` -- The document's `/Author`, in its `/Info` dictionary. - `def fill_rect(mut self, x: Int, y: Int, width: Int, height: Int, color: Color)` -- A filled rectangle (`re f`). - `def fill_rect(mut self, x: Float64, y: Float64, width: Float64, height: Float64, color: Color)` -- A filled rectangle at a geometric position. - `def draw_line_aa(mut self, x0: Int, y0: Int, x1: Int, y1: Int, color: Color, width: Float64 = 1.0, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0, cap: LineCap = LineCap.ROUND, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0)` -- A stroked line segment. - `def draw_line_aa(mut self, x0: Float64, y0: Float64, x1: Float64, y1: Float64, color: Color, width: Float64 = 1.0, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0, cap: LineCap = LineCap.ROUND, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0)` -- A stroked line segment at geometric endpoints. - `def fill_circles_aa(mut self, centers: List[FPoint], radius: Float64, color: Color) raises` -- `DrawTarget`'s batched disks. - `def fill_circles_aa(mut self, centers: List[FPoint], radius: Float64, colors: List[Color]) raises` -- `fill_circles_aa` with a color per marker. - `def fill_mesh(mut self, points: List[FPoint], faces: List[Int], colors: List[Color]) raises` -- `DrawTarget`'s mesh: one path per face. - `def fill_mesh_shaded(mut self, points: List[FPoint], faces: List[Int], vertex_colors: List[Color]) raises` -- `DrawTarget`'s smooth-shaded mesh, as PDF has it natively: a Type 4 shading, a free-form Gouraud triangle mesh, painted with `sh`. Each vertex is a flag byte, two 32-bit coordinates over the mesh's own bounding box and three color bytes, so the viewer interpolates exactly the corners this was given. - `def fill_circle_aa(mut self, cx: Int, cy: Int, radius: Int, color: Color)` -- A filled circle. - `def fill_circle_aa(mut self, cx: Float64, cy: Float64, radius: Float64, color: Color)` -- A filled circle at a geometric center. - `def fill_ellipses_aa(mut self, centers: List[FPoint], rx: Float64, ry: Float64, color: Color) raises` -- `DrawTarget`'s batched ellipses. - `def fill_ellipses_aa(mut self, centers: List[FPoint], rx: Float64, ry: Float64, colors: List[Color]) raises` -- `fill_ellipses_aa` with a color per marker. - `def draw_circle_aa(mut self, cx: Float64, cy: Float64, radius: Float64, color: Color, width: Float64 = 1.0)` -- A stroked circle. - `def fill_ellipse_aa(mut self, cx: Int, cy: Int, rx: Int, ry: Int, color: Color)` -- A filled ellipse. - `def fill_ellipse_aa(mut self, cx: Float64, cy: Float64, rx: Float64, ry: Float64, color: Color)` -- A filled ellipse at a geometric center. - `def draw_ellipse_aa(mut self, cx: Int, cy: Int, rx: Int, ry: Int, color: Color)` -- A stroked ellipse, one unit wide. - `def draw_ellipse_aa(mut self, cx: Float64, cy: Float64, rx: Float64, ry: Float64, color: Color, width: Float64 = 1.0)` -- A stroked ellipse. - `def fill_arc_aa(mut self, cx: Float64, cy: Float64, radius: Float64, start_angle: Float64, end_angle: Float64, color: Color)` -- A filled pie wedge from `start_angle` to `end_angle`. - `def fill_arcs_aa(mut self, centers: List[FPoint], radius: Float64, start_angle: Float64, end_angle: Float64, color: Color) raises` -- `DrawTarget`'s batched wedges. - `def fill_arcs_aa(mut self, centers: List[FPoint], radius: Float64, start_angle: Float64, end_angle: Float64, colors: List[Color]) raises` -- `fill_arcs_aa` with a color per wedge. - `def fill_ring_sector_aa(mut self, cx: Float64, cy: Float64, inner_radius: Float64, outer_radius: Float64, start_angle: Float64, end_angle: Float64, color: Color)` -- A filled annular sector (donut segment). - `def stroke_path_aa(mut self, path: Path, color: Color, width: Float64 = 1.0, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0, cap: LineCap = LineCap.ROUND, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0)` -- Stroke `path`. - `def fill_path_aa(mut self, path: Path, color: Color, fill_rule: FillRule = FillRule.EVEN_ODD)` -- Fill `path` under `fill_rule`. - `def fill_rect_gradient(mut self, x: Int, y: Int, width: Int, height: Int, gradient: LinearGradient)` -- A rectangle filled with an axial shading. - `def fill_rect_gradient(mut self, x: Float64, y: Float64, width: Float64, height: Float64, gradient: LinearGradient)` -- A rectangle at a geometric position filled with an axial shading; a one-stop ramp fills solid with that color. - `def fill_rect_radial_gradient(mut self, x: Int, y: Int, width: Int, height: Int, gradient: RadialGradient)` -- A rectangle filled with a radial shading. - `def fill_path_gradient_aa(mut self, path: Path, gradient: LinearGradient, fill_rule: FillRule = FillRule.EVEN_ODD)` -- `path` filled with an axial shading, clipped under `fill_rule`. Not on `DrawTarget`. - `def fill_path_radial_gradient_aa(mut self, path: Path, gradient: RadialGradient, fill_rule: FillRule = FillRule.EVEN_ODD)` -- `path` filled with a radial shading, clipped under `fill_rule`. Not on `DrawTarget`. - `def push_clip(mut self, x: Int, y: Int, width: Int, height: Int)` -- Clip later drawing to a rectangle, intersected with any active clip, until `pop_clip`. Under a transform the rectangle is in the transformed space, as the other backends have it. - `def pop_clip(mut self)` -- End the innermost clip. - `def push_clip_path(mut self, path: Path, fill_rule: FillRule = FillRule.EVEN_ODD) raises` -- Clip later drawing to `path` under `fill_rule`, until `pop_clip_path`. - `def pop_clip_path(mut self)` -- End the innermost clip path; the same stack as `pop_clip`. - `def draw_text_on_path(mut self, path: Path, text: String, color: Color, size: Float64, offset: Float64 = 0.0, family: String = "Sans", slant: FontSlant = FontSlant.NORMAL, weight: FontWeight = FontWeight.NORMAL, align: TextAlign = TextAlign.LEFT, kerning: Bool = True, ligatures: Bool = True) raises` -- Place selectable, embedded-font glyphs along `path`. - `def draw_text(mut self, x: Float64, y: Float64, text: String, color: Color, size: Float64, family: String = "Sans", slant: FontSlant = FontSlant.NORMAL, weight: FontWeight = FontWeight.NORMAL, rotation: Float64 = 0.0, align: TextAlign = TextAlign.LEFT) raises` -- Draw `text` as real, selectable text in an embedded subset of the font, laid out exactly as the raster `draw_text` lays it out (shaping, kerning, line breaking, alignment, rotation about the anchor). - `def draw_text(mut self, x: Float64, y: Float64, text: String, color: Color, size: Float64, family: String = "Sans", slant: FontSlant = FontSlant.NORMAL, weight: FontWeight = FontWeight.NORMAL, rotation: Float64 = 0.0, align: TextAlign = TextAlign.LEFT, *, mut cache: FontCache) raises` -- The `DrawTarget` form of `draw_text`: the same call with a `cache`, which the document does not read. - `def draw_text_runs(mut self, x: Float64, y: Float64, runs: List[TextRun], color: Color, family: String = "Sans", weight: FontWeight = FontWeight.NORMAL, rotation: Float64 = 0.0, align: TextAlign = TextAlign.LEFT, *, mut cache: FontCache) raises` -- The `DrawTarget` form: `draw_text` once per run, each at the anchor `canvas.text.render.text_run_anchors` computes for it. - `def stroke_text(mut self, x: Float64, y: Float64, text: String, color: Color, size: Float64, width: Float64 = 1.0, family: String = "Sans", slant: FontSlant = FontSlant.NORMAL, weight: FontWeight = FontWeight.NORMAL, rotation: Float64 = 0.0, align: TextAlign = TextAlign.LEFT, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0) raises` -- Outline `text` rather than fill it (text render mode 1); see `draw_text`. - `def text_outline(mut self, x: Float64, y: Float64, text: String, size: Float64, family: String = "Sans", slant: FontSlant = FontSlant.NORMAL, weight: FontWeight = FontWeight.NORMAL, rotation: Float64 = 0.0, align: TextAlign = TextAlign.LEFT) raises -> Path` -- `text`'s outline as a `Path`, through this document's font cache: `canvas.text.text_path` for a caller that wants glyphs as shapes (to clip with, or to fill with a gradient) rather than as text. - `def draw_image(mut self, image: Canvas, x: Float64, y: Float64, width: Float64 = 0.0, height: Float64 = 0.0)` -- Draw `image` with its top-left at (x, y), scaled to `width x height` points (its own pixel size when 0), as an image XObject; a pixel that is not opaque gives the image a soft mask. - `def begin_batch(mut self)` -- Nothing to defer: every element goes into the content stream in order as it is drawn. - `def end_batch(mut self)` -- The other half of `begin_batch`, also nothing. - `def begin_annotated_group(mut self, title: String)` -- Open a marked-content sequence labeled `title` (`/Span << /Alt (title) >> BDC`), closed by `end_annotated_group`. Groups do not nest. - `def end_annotated_group(mut self)` -- Close the open marked-content sequence, if any. - `def content(self) -> String` -- The current page's content stream operators as written so far, without the flip that opens the stream in the file: what a test reads to see what a call became. - `def to_bytes(mut self, compress: Bool = True) raises -> List[UInt8]` -- The complete PDF file: catalog, page tree, the embedded fonts, the images, each page with its content stream, and the `/Info` dictionary when a title or author was set. - `def write_pdf(mut pdf: PdfCanvas, path: String) raises` -- Write `pdf` to `path`, the PDF counterpart to `write_png` and `write_svg`. ## canvas.vector.svg A `DrawTarget` that accumulates resolution-independent SVG markup. ### struct SvgCanvas Accumulates SVG body markup for a `width x height` document. - `def __init__(out self, width: Int, height: Int)` -- An empty `width x height` SVG document. - `def save(mut self)` -- Push the current transform, blend mode and clip depth for `restore` to put back, as `Canvas.save` does. - `def restore(mut self)` -- Pop the state `save` pushed. - `def translate(mut self, tx: Float64, ty: Float64)` -- Shift subsequent elements by (tx, ty) in the current user space -- see `Canvas.translate`. - `def rotate(mut self, angle: Float64)` -- Turn subsequent elements by `angle` radians about the current origin -- see `Canvas.rotate`. - `def scale(mut self, sx: Float64, sy: Float64)` -- Scale subsequent elements about the current origin -- see `Canvas.scale`. - `def transform(mut self, matrix: Matrix2D)` -- Compose `matrix` into the current transform, applied first -- the order `Canvas.transform` composes in. - `def set_transform(mut self, matrix: Matrix2D)` -- Replace the current transform outright. - `def reset_transform(mut self)` -- Back to the identity: elements carry no `transform`. - `def current_transform(self) -> Matrix2D` -- The map every element drawn now carries. - `def has_transform(self) -> Bool` -- Whether elements drawn now carry a `transform` attribute. - `def set_blend_mode(mut self, mode: BlendMode)` -- Set how elements drawn from here on combine with what is already painted, the counterpart of `Canvas.set_blend_mode`. - `def blend_mode(self) -> BlendMode` -- The blend mode elements drawn now carry. - `def set_color_space(mut self, space: ColorSpace)` -- Set the space elements drawn from here on composite in, the counterpart of `Canvas.set_color_space`: under LINEAR each element carries `color-interpolation="linearRGB"`, which asks the viewer to composite it in linear light. - `def color_space(self) -> ColorSpace` -- The color space elements drawn now carry. - `def fill_rect(mut self, x: Int, y: Int, width: Int, height: Int, color: Color)` -- Emit a `` element. - `def fill_rect(mut self, x: Float64, y: Float64, width: Float64, height: Float64, color: Color)` -- `fill_rect` for a geometric box, snapped to whole pixels in user space -- the same snap the raster backend applies, so both emit the same rectangle -- and written as the `Int` form. - `def fill_rect_gradient(mut self, x: Float64, y: Float64, width: Float64, height: Float64, gradient: LinearGradient)` -- `fill_rect_gradient` for a geometric box, snapped to whole pixels as the `Float64` `fill_rect` is. - `def fill_rect_gradient(mut self, x: Int, y: Int, width: Int, height: Int, gradient: LinearGradient)` -- An SVG `` with `gradientUnits="userSpaceOnUse"`. `LinearGradient`'s (x0, y0)-(x1, y1) axis is already in the same absolute pixel space as this document's ``, so `userSpaceOnUse` carries it over untranslated instead of SVG's default shape-relative `objectBoundingBox` units. - `def fill_rect_radial_gradient(mut self, x: Int, y: Int, width: Int, height: Int, gradient: RadialGradient)` -- `fill_rect_gradient` for a `RadialGradient`: a fresh `` in the document's pixel space, with the focal circle when the gradient has one, and a `` filled from it. - `def fill_path_gradient_aa(mut self, path: Path, gradient: LinearGradient, fill_rule: FillRule = FillRule.EVEN_ODD)` -- `fill_path_aa` filled from a `LinearGradient`: a fresh `` in the document's pixel space and a `` referencing it, with the fill rule written out as `fill_path_aa` writes it. - `def fill_path_radial_gradient_aa(mut self, path: Path, gradient: RadialGradient, fill_rule: FillRule = FillRule.EVEN_ODD)` -- `fill_path_gradient_aa` for a `RadialGradient`. - `def draw_line_aa(mut self, x0: Int, y0: Int, x1: Int, y1: Int, color: Color, width: Float64 = 1.0, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0, cap: LineCap = LineCap.ROUND, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0)` -- Emit a `` element, round-capped by default. - `def draw_line_aa(mut self, x0: Float64, y0: Float64, x1: Float64, y1: Float64, color: Color, width: Float64 = 1.0, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0, cap: LineCap = LineCap.ROUND, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0)` -- Emit a `` element, round-capped by default. - `def fill_circle_aa(mut self, cx: Float64, cy: Float64, radius: Float64, color: Color)` -- A `` at a sub-pixel center and radius. - `def fill_circles_aa(mut self, centers: List[FPoint], radius: Float64, color: Color) raises` -- `DrawTarget`'s batched disks. - `def fill_circles_aa(mut self, centers: List[FPoint], radius: Float64, colors: List[Color]) raises` -- `fill_circles_aa` with a color per marker. - `def fill_mesh(mut self, points: List[FPoint], faces: List[Int], colors: List[Color]) raises` -- `DrawTarget`'s mesh: one `` per face. - `def fill_mesh_shaded(mut self, points: List[FPoint], faces: List[Int], vertex_colors: List[Color]) raises` -- `DrawTarget`'s smooth-shaded mesh, flat here: each face at the mean of its three corner colors. - `def fill_circle_aa(mut self, cx: Int, cy: Int, radius: Int, color: Color)` -- Emit a `` element. - `def fill_ellipses_aa(mut self, centers: List[FPoint], rx: Float64, ry: Float64, color: Color) raises` -- `DrawTarget`'s batched ellipses. - `def fill_ellipses_aa(mut self, centers: List[FPoint], rx: Float64, ry: Float64, colors: List[Color]) raises` -- `fill_ellipses_aa` with a color per marker. - `def draw_circle_aa(mut self, cx: Float64, cy: Float64, radius: Float64, color: Color, width: Float64 = 1.0)` -- Emit an unfilled `` element, at a sub-pixel center and radius. - `def fill_ellipse_aa(mut self, cx: Float64, cy: Float64, rx: Float64, ry: Float64, color: Color)` -- An `` at a sub-pixel center and radii. - `def fill_ellipse_aa(mut self, cx: Int, cy: Int, rx: Int, ry: Int, color: Color)` -- Emit an `` element. - `def draw_ellipse_aa(mut self, cx: Int, cy: Int, rx: Int, ry: Int, color: Color)` -- Emit an unfilled `` element, ~1px stroke. - `def draw_ellipse_aa(mut self, cx: Float64, cy: Float64, rx: Float64, ry: Float64, color: Color, width: Float64 = 1.0)` -- Emit an unfilled `` element, at a sub-pixel center and radii. - `def fill_arc_aa(mut self, cx: Float64, cy: Float64, radius: Float64, start_angle: Float64, end_angle: Float64, color: Color)` -- A wedge, drawn as `M center L start-point A ... - `def fill_arcs_aa(mut self, centers: List[FPoint], radius: Float64, start_angle: Float64, end_angle: Float64, color: Color) raises` -- `DrawTarget`'s batched wedges. - `def fill_arcs_aa(mut self, centers: List[FPoint], radius: Float64, start_angle: Float64, end_angle: Float64, colors: List[Color]) raises` -- `fill_arcs_aa` with a color per wedge. - `def fill_ring_sector_aa(mut self, cx: Float64, cy: Float64, inner_radius: Float64, outer_radius: Float64, start_angle: Float64, end_angle: Float64, color: Color)` -- A donut wedge: `M outer-start A ... - `def stroke_path_aa(mut self, path: Path, color: Color, width: Float64 = 1.0, dashes: List[Float64] = List[Float64](), dash_offset: Float64 = 0.0, cap: LineCap = LineCap.ROUND, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0)` -- Emit a `` element, stroked only. - `def fill_path_aa(mut self, path: Path, color: Color, fill_rule: FillRule = FillRule.EVEN_ODD)` -- Emit a `` element, filled only. - `def push_clip(mut self, x: Int, y: Int, width: Int, height: Int)` -- Restrict subsequent elements to a rectangle, the counterpart of `Canvas.push_clip`: a `` holding the `` (in the current user space, so it carries the transform attribute an element drawn now would) and a `` every element until the matching pop lands inside. - `def push_clip_path(mut self, path: Path, fill_rule: FillRule = FillRule.EVEN_ODD)` -- Restrict subsequent elements to `path`'s interior, the counterpart of `Canvas.push_clip_path`: a `` holding the `` with its fill rule as `clip-rule`, and a `` referencing it. - `def pop_clip(mut self)` -- Remove the most recently pushed clip, rectangle or path: this backend keeps one stack of `` wrappers, so the two pops are the same operation. - `def pop_clip_path(mut self)` -- Remove the most recently pushed clip, rectangle or path -- see `pop_clip`. - `def draw_image(mut self, image: Canvas, x: Float64, y: Float64, width: Float64 = 0.0, height: Float64 = 0.0) raises` -- Emit an `` element with `image` as a PNG in a base64 `data:` URI, its top-left at (x, y), scaled to `width x height` (its own pixel size when 0): `DrawTarget`'s image primitive. - `def begin_batch(mut self)` -- Nothing to defer: every element goes into the markup in order as it is drawn. - `def end_batch(mut self)` -- The other half of `begin_batch`, also nothing. - `def begin_annotated_group(mut self, title: String)` -- Open `title`, labeling every element emitted until `end_annotated_group`. Browsers show a `` inside a `<g>` as a hover tooltip over anything in the group, which is what gives a chart per-datum tooltips without any scripting. - `def end_annotated_group(mut self)` -- Close the group `begin_annotated_group` opened, a no-op when none is open. - `def draw_text(mut self, x: Int, y: Int, text: String, color: Color, size: Float64, align: TextAlign, family: String = "sans-serif", rotation: Float64 = 0.0, weight: FontWeight = FontWeight.NORMAL)` -- Draw a `<text>` element at a whole-pixel anchor with a literal CSS `font-family`. The `DrawTarget` form below takes a sub-pixel anchor, a slant and the raster backend's family names; this one predates it and stays for callers that write the CSS stack themselves. - `def draw_text(mut self, x: Float64, y: Float64, text: String, color: Color, size: Float64, family: String = "Sans", slant: FontSlant = FontSlant.NORMAL, weight: FontWeight = FontWeight.NORMAL, rotation: Float64 = 0.0, align: TextAlign = TextAlign.LEFT, *, mut cache: FontCache) raises` -- The `DrawTarget` form: a `<text>` element at a sub-pixel anchor, with `family` in the raster backend's terms. - `def draw_text_runs(mut self, x: Float64, y: Float64, runs: List[TextRun], color: Color, family: String = "Sans", weight: FontWeight = FontWeight.NORMAL, rotation: Float64 = 0.0, align: TextAlign = TextAlign.LEFT, *, mut cache: FontCache) raises` -- One `<text>` element with a `<tspan>` per run: SVG's own form for a label whose pieces differ in size or slant, and what keeps the label one string in a viewer -- one selection, one copy with its spaces in place, one announcement -- where the same runs as separate `draw_text` calls are as many elements. - `def stroke_text(mut self, x: Int, y: Int, text: String, color: Color, size: Float64, align: TextAlign, width: Float64 = 1.0, family: String = "sans-serif", rotation: Float64 = 0.0, weight: FontWeight = FontWeight.NORMAL, join: LineJoin = LineJoin.ROUND, miter_limit: Float64 = 4.0)` -- Draw a `<text>` element outlined rather than filled: `fill="none"` plus the stroke attributes. - `def draw_text_on_path(mut self, path: Path, text: String, color: Color, size: Float64, align: TextAlign, offset: Float64 = 0.0, family: String = "sans-serif", weight: FontWeight = FontWeight.NORMAL)` -- Draw `text` along `path`, as a `<textPath>` referring to a `<path>` in a `<defs>` block emitted just before it. - `def set_title(mut self, title: String, description: String = "")` -- Give the document an accessible title: the root `<svg>` gains `role="img"` and `aria-label`, and `<title>` (and `<desc>` when `description` is non-empty) become its first children, which is what screen readers that walk an SVG's accessible tree look for. - `def to_string(self) -> String` - `def write_svg(svg: SvgCanvas, path: String) raises` -- Write `svg`'s accumulated markup to `path`, the SVG counterpart to `write_bmp`/`write_png`. ## canvas.workers Helpers for splitting parallel passes into row bands, and the one place the library runs a band as a task. - `def run_bands(bands: Int, work: Some[def(Int) -> None])` -- Run `work(b)` for every band `b` in `0 <= b < bands` and return once all have finished.