geomotif.io
¶
Getting designs out of Python, and back in again.
Five things can be written, and they answer five different questions:
========================== ==================================== ===========
What Written by Reads back
========================== ==================================== ===========
The coordinates :func:save_points --
The design, strokes and all :func:save_design JSON only
The recipe that made it :func:save_spec yes
A picture of it :func:save_svg, :func:save_dxf --
A still picture of it :func:save_png, :func:save_jpeg --
A moving picture of it :func:save_gif --
========================== ==================================== ===========
A spec is the one worth reaching for by default: it is a few hundred bytes
rather than a few hundred kilobytes, it survives a change of point count, and
it is what the gallery manifest and the CLI's --spec flag are built on.
SVG is for anything that displays -- a browser, a vector editor, these docs --
and DXF for anything that cuts, mills or plots. The two disagree about which
way y points, which each module handles rather than leaving to the caller.
The two rasters are the still and the moving picture: :func:save_png and
:func:save_jpeg write the finished design as one frame (a PNG lossless, a
JPEG lossy and smaller), and :func:save_gif writes the animation from
:mod:geomotif.animate, since a moving picture has no vector form that plays
everywhere.
:mod:geomotif.io.plotter is the SVG writer again with a pen plotter in mind:
real millimeters on a named sheet of paper, and a pass that joins strokes up
and orders them so the pen wastes less time in the air.
Every writer here is pure standard library, so the zero-dependency core stays zero-dependency all the way out to the file -- LZW and zlib compression, color tables, chunk CRCs and all.
Modules:
| Name | Description |
|---|---|
dxf |
Write a design as DXF R12, in pure standard library. |
gif |
Write an animated GIF, in pure standard library. |
jpeg |
Write a JPEG still, in pure standard library. |
plotter |
Preparing a design for a pen plotter. |
png |
Write a PNG still, in pure standard library. |
points |
Write coordinates out, and read a structured design back in. |
raster |
Turn a design into pixels, in pure standard library. |
spec |
A design's recipe rather than its points: the motif and its parameters. |
svg |
Write a design as SVG, in pure standard library. |
Classes:
| Name | Description |
|---|---|
Raster |
An in-memory picture, top-left origin. |
Functions:
| Name | Description |
|---|---|
save_dxf |
Write a design to a DXF file and return the path written. |
to_dxf |
Render a design as a DXF R12 document. |
save_gif |
Write an animated GIF and return the path written. |
to_gif |
Render a sequence of designs as an animated GIF. |
save_jpeg |
Render a design -- or re-encode a raster -- as JPEG and write it. |
to_jpeg |
Render a design -- or re-encode a :class: |
save_plotter_svg |
Write a plotter-ready SVG and return the path written. |
to_plotter_svg |
Render a design as an SVG measured in real millimeters. |
to_vpype |
Return this design as a |
save_png |
Render a design -- or re-encode a raster -- as a PNG and write it. |
to_png |
Render a design -- or re-encode a :class: |
load_design |
Read a design back from a JSON file written by :func: |
save_design |
Write a design, strokes kept apart, and return the path written. |
save_points |
Write points to a file and return the path written. |
colors_in |
Return the palette a set of designs needs, background first. |
colours_in |
Keep the British spelling working while it is phased out. |
quantize |
Shrink RGBA frames to one shared indexed palette of at most |
rasterize |
Draw a design into an indexed bitmap. |
rasterize_rgba |
Draw a design into a full-color RGBA frame, supersampled and antialiased. |
from_spec |
Rebuild the motif a spec describes. |
load_spec |
Read a spec file and return the motif it describes. |
save_spec |
Write a motif's recipe to a JSON file and return the path written. |
to_spec |
Return the JSON-ready recipe for a motif, or for the design it built. |
save_svg |
Write a design to an SVG file and return the path written. |
to_svg |
Render a design as an SVG document. |
Raster
dataclass
¶
Raster(width: int, height: int, pixels: bytes, palette: tuple[str, ...] = (), mode: str = 'indexed')
An in-memory picture, top-left origin.
A :class:Raster holds either an indexed bitmap -- one palette index
per pixel, which is what GIF wants -- or a direct one -- RGB or RGBA
bytes per pixel, which is what PNG and JPEG want. Everything downstream
(antialiasing, styling, the encoders) feeds off one of the two, so the
picture is drawn once and encoded many ways.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
width
|
int
|
Size in pixels. |
required |
height
|
int
|
Size in pixels. |
required |
pixels
|
bytes
|
|
required |
palette
|
tuple of str
|
The colors an indexed bitmap's indices name, as |
()
|
mode
|
str
|
|
'indexed'
|
save_dxf
¶
save_dxf(design: Design, path: str | PathLike[str], *, layer: str = '0', precision: int = 4) -> Path
Write a design to a DXF file and return the path written.
See :func:to_dxf for what the options mean.
Source code in src/geomotif/io/dxf.py
to_dxf
¶
to_dxf(design: Design, *, layer: str = '0', precision: int = 4) -> str
Render a design as a DXF R12 document.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
design
|
Design
|
What to write. Strokes become |
required |
layer
|
str
|
Layer for geometry that does not name one of its own. |
'0'
|
precision
|
int
|
Decimal places for coordinates. |
4
|
Returns:
| Type | Description |
|---|---|
str
|
A complete DXF R12 document. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the design is empty, the precision is negative, or a layer name -- the argument's or a style's -- is not one R12 permits. |
Source code in src/geomotif/io/dxf.py
save_gif
¶
save_gif(frames: Sequence[Design], path: str | PathLike[str], **kwargs: Any) -> Path
Write an animated GIF and return the path written.
Keyword arguments are passed straight through to :func:to_gif.
Source code in src/geomotif/io/gif.py
to_gif
¶
to_gif(frames: Sequence[Design], *, width: int = 480, height: int = 480, padding: float = 8.0, fps: float = 20.0, loop: int = 0, ink: str = '#0b0b0b', background: str = '#ffffff', thickness: int = 1, dot_radius: int | None = None, antialias: bool = False, aa_level: int = 8, dither: bool = True, transparent: bool = False) -> bytes
Render a sequence of designs as an animated GIF.
Every frame is drawn against the same world rectangle -- the union of all of their bounds -- and the same color table, so a drawing that grows stays put instead of swimming about as its own extent changes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
frames
|
sequence of Design
|
What to draw, in order. At least one is needed. |
required |
width
|
int
|
Canvas size in pixels. |
480
|
height
|
int
|
Canvas size in pixels. |
480
|
padding
|
float
|
Margin reserved on all four sides, in pixels. |
8.0
|
fps
|
float
|
Frames per second. GIF stores a delay in hundredths of a second, so the rate is rounded to what the format can actually say. |
20.0
|
loop
|
int
|
How many times to play; |
0
|
ink
|
str
|
Default stroke color and the color behind everything. A stroke with a style of its own is drawn in that instead. |
'#0b0b0b'
|
background
|
str
|
Default stroke color and the color behind everything. A stroke with a style of its own is drawn in that instead. |
'#0b0b0b'
|
thickness
|
int
|
Stroke width in pixels. |
1
|
dot_radius
|
int
|
Radius for loose points. Defaults to |
None
|
antialias
|
bool
|
Supersample and blend edges. Off by default, so the output is exactly the hard-edged picture it has always been. |
False
|
aa_level
|
int
|
When antialiasing, how many shades an edge may blend into per color pair, which is what keeps the whole animation inside GIF's 256-color budget. Must be >= 1. |
8
|
dither
|
bool
|
Error-diffuse the round-off onto a gradient, which keeps an antialiased edge on a colored ground from banding inside the palette budget. On by default. |
True
|
transparent
|
bool
|
Leave the background empty. Index 0 is flagged transparent in the file, so the drawing sits over whatever the page shows instead of a painted ground. Off by default, so the picture stays what it has always been. |
False
|
Returns:
| Type | Description |
|---|---|
bytes
|
A complete GIF89a file. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If there are no frames, the rate is not positive, the antialias level is zero, or the designs' own colors (the inks and background) exceed 256 between them -- which is GIF's limit, not this writer's. |
Source code in src/geomotif/io/gif.py
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | |
save_jpeg
¶
Render a design -- or re-encode a raster -- as JPEG and write it.
Keyword arguments are passed straight through to :func:to_jpeg.
Source code in src/geomotif/io/jpeg.py
to_jpeg
¶
to_jpeg(source: Design | Raster, *, width: int = 480, height: int = 480, padding: float = 8.0, ink: str = '#0b0b0b', background: str = '#ffffff', thickness: int = 1, dot_radius: int | None = None, antialias: bool = False, aa_level: int = 8, quality: int = 85) -> bytes
Render a design -- or re-encode a :class:~geomotif.io.Raster -- as JPEG.
A still is drawn once, exactly the way :func:to_png draws a frame, and
then encoded with baseline JPEG: 4:2:0 chroma subsampling, an 8x8 DCT on
each block, quality-scaled quantization, and Huffman coding against the
reference tables. The styling parameters are shared with the PNG and GIF
writers so one summoning controls all three.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source
|
Design or Raster
|
What to write. A design is drawn; a raster is encoded as it is. |
required |
width
|
int
|
Canvas size in pixels. Ignored when |
480
|
height
|
int
|
Canvas size in pixels. Ignored when |
480
|
padding
|
float
|
Margin reserved on all four sides, in pixels. |
8.0
|
ink
|
str
|
Default stroke color and the color behind everything. |
'#0b0b0b'
|
background
|
str
|
Default stroke color and the color behind everything. |
'#0b0b0b'
|
thickness
|
int
|
Stroke width in pixels. |
1
|
dot_radius
|
int
|
Radius for loose points. Defaults to |
None
|
antialias
|
bool
|
Supersample and blend edges. Off by default, so the edges are the same hard Bresenham edges they have always been. |
False
|
aa_level
|
int
|
How many shades an antialiased edge may blend into. A JPEG keeps full color anyway, so this only bounds the drawing, not the encode. |
8
|
quality
|
int
|
From 0 (smallest, most loss) to 100 (closest to the original). This is what the quantization tables are scaled by. |
85
|
Returns:
| Type | Description |
|---|---|
bytes
|
A complete baseline JPEG file. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/geomotif/io/jpeg.py
save_plotter_svg
¶
save_plotter_svg(design: Design, path: str | PathLike[str], **kwargs: Any) -> Path
Write a plotter-ready SVG and return the path written.
Keyword arguments are passed straight through to :func:to_plotter_svg.
Source code in src/geomotif/io/plotter.py
to_plotter_svg
¶
to_plotter_svg(design: Design, *, paper: str = 'a4', margin: float = 10.0, landscape: bool = False, stroke_width: float = DEFAULT_PEN, **kwargs: Any) -> str
Render a design as an SVG measured in real millimeters.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
design
|
Design
|
What to plot. |
required |
paper
|
str
|
A name from :data: |
'a4'
|
margin
|
float
|
Border to leave unplotted, in millimeters. Worth more than you would think: most plotters cannot reach the last few millimeters of a sheet. |
10.0
|
landscape
|
bool
|
Turn the paper on its side. |
False
|
stroke_width
|
float
|
Pen width in millimeters. Only affects how the file looks -- a plotter draws with the pen it has -- but getting it right makes the preview honest. |
DEFAULT_PEN
|
**kwargs
|
Any
|
Passed to :func: |
{}
|
Returns:
| Type | Description |
|---|---|
str
|
An SVG whose |
Source code in src/geomotif/io/plotter.py
to_vpype
¶
to_vpype(design: Design, *, paper: str = 'a4', margin: float = 10.0, landscape: bool = False) -> Any
Return this design as a vpype document, fitted to a page.
vpype is the pen-plotter toolchain -- occlusion, hatching, HPGL output,
and a plotting pipeline this library is deliberately not trying to be. This
is the door to it: one layer per :mod:geomotif.core.style layer, named the
same, on a page of the size asked for.
::
import vpype_cli
document = to_vpype(design, paper="a3")
vpype_cli.execute("linemerge linesort write out.svg", document)
Returns:
| Type | Description |
|---|---|
Document
|
Typed loosely because |
Raises:
| Type | Description |
|---|---|
ImportError
|
If |
Source code in src/geomotif/io/plotter.py
save_png
¶
Render a design -- or re-encode a raster -- as a PNG and write it.
Keyword arguments are passed straight through to :func:to_png.
Source code in src/geomotif/io/png.py
to_png
¶
to_png(source: Design | Raster, *, width: int = 480, height: int = 480, padding: float = 8.0, ink: str = '#0b0b0b', background: str = '#ffffff', thickness: int = 1, dot_radius: int | None = None, antialias: bool = False, aa_level: int = 8, color: str = 'rgb', compression: int = 6, transparent: bool = False) -> bytes
Render a design -- or re-encode a :class:~geomotif.io.Raster -- as PNG.
A still is drawn once, exactly the way :func:to_gif draws a frame, and
then written as a PNG instead of being quantized toward a GIF's colors.
The styling parameters are shared with the GIF writer so one summoning
controls both.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source
|
Design or Raster
|
What to write. A design is drawn; a raster is encoded as it is. |
required |
width
|
int
|
Canvas size in pixels. Ignored when |
480
|
height
|
int
|
Canvas size in pixels. Ignored when |
480
|
padding
|
float
|
Margin reserved on all four sides, in pixels. |
8.0
|
ink
|
str
|
Default stroke color and the color behind everything. |
'#0b0b0b'
|
background
|
str
|
Default stroke color and the color behind everything. |
'#0b0b0b'
|
thickness
|
int
|
Stroke width in pixels. |
1
|
dot_radius
|
int
|
Radius for loose points. Defaults to |
None
|
antialias
|
bool
|
Supersample and blend edges. Off by default, so the edges are the same hard Bresenham edges they have always been. |
False
|
aa_level
|
int
|
When antialiasing into an indexed frame, how many shades an edge may blend into per color pair. Ignored for the truecolor paths, which keep every level. |
8
|
color
|
str
|
|
'rgb'
|
compression
|
int
|
zlib level from 0 (fast, big) to 9 (slow, small). Must be an integer in that range. |
6
|
transparent
|
bool
|
Leave the background empty instead of painting |
False
|
Returns:
| Type | Description |
|---|---|
bytes
|
A complete PNG file. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/geomotif/io/png.py
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | |
load_design
¶
load_design(path: str | PathLike[str]) -> Design
Read a design back from a JSON file written by :func:save_design.
A plain JSON array of pairs -- what :func:save_points writes -- also
loads, as a design of loose points with no strokes. The two shapes are an
array and an object, so there is nothing to guess at.
Returns:
| Type | Description |
|---|---|
Design
|
With |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the file is not one of the two shapes above. |
Source code in src/geomotif/io/points.py
save_design
¶
save_design(design: Design, path: str | PathLike[str], *, fmt: PointFormat | None = None, precision: int | None = None, meta: bool = True) -> Path
Write a design, strokes kept apart, and return the path written.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
design
|
Design
|
What to write. |
required |
path
|
str or path - like
|
Destination file. |
required |
fmt
|
('csv', 'txt', 'json')
|
Output format, inferred from the suffix when omitted.
|
"csv"
|
precision
|
int
|
Round coordinates to this many decimal places, as for
:func: |
None
|
meta
|
bool
|
Record the design's recipe alongside its points, for the JSON format only. Turn it off for a design whose motif takes a parameter that cannot be written as data. |
True
|
Returns:
| Type | Description |
|---|---|
Path
|
The file that was written. |
Raises:
| Type | Description |
|---|---|
TypeError
|
If |
Source code in src/geomotif/io/points.py
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | |
save_points
¶
save_points(points: Iterable[Point], path: str | PathLike[str], *, fmt: PointFormat | None = None, precision: int | None = None) -> Path
Write points to a file and return the path written.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
points
|
iterable of (float, float)
|
The points to export. A :class: |
required |
path
|
str or path - like
|
Destination file. |
required |
fmt
|
('csv', 'txt', 'json')
|
Output format. Inferred from the file suffix when omitted
(
|
"csv"
|
precision
|
int
|
Round coordinates to this many decimal places. This rounds the file rather than the design, so it says nothing about
what the other writers do with the same points.
:meth: |
None
|
Returns:
| Type | Description |
|---|---|
Path
|
The file that was written. |
Source code in src/geomotif/io/points.py
colors_in
¶
colors_in(designs: Iterable[Design], *, ink: str, background: str) -> tuple[str, ...]
Return the palette a set of designs needs, background first.
Shared across every frame of an animation rather than worked out per frame: a GIF has one global color table, and an index that meant crimson in one frame and black in the next would make the whole thing flicker.
Source code in src/geomotif/io/raster.py
colours_in
¶
colours_in(designs: Iterable[Design], *, ink: str, background: str) -> tuple[str, ...]
Keep the British spelling working while it is phased out.
:func:colors_in is the name of this function now; this alias exists so
1.1.0 callers keep working, and it warns that it will go away in a future
major release.
Source code in src/geomotif/io/raster.py
quantize
¶
quantize(frames: Sequence[Raster], *, seeds: Sequence[str] = (), max_colors: int = 256, dither: bool = True, transparent: bool = False) -> tuple[Raster, ...]
Shrink RGBA frames to one shared indexed palette of at most max_colors.
The palette is built once across every frame -- so an animation does not
flicker as the index a color means changes -- and is seeded with the
colors given in seeds first, background first, keeping them exact. Any
remaining color budget is filled from the blends the antialiasing made,
cut down with median-cut when there are more of them than budget. A seed
color is never dropped: asking for more seeds than max_colors raises
instead.
With transparent set, index 0 is reserved for empty space: a pixel
whose alpha lies below the half point maps there instead of to a color,
and the transparent slot does not count against the color budget.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
frames
|
sequence of Raster
|
|
required |
seeds
|
sequence of str
|
colors that must survive exactly, background first, as |
()
|
max_colors
|
int
|
The largest palette the output may hold. Must be >= 1. |
256
|
dither
|
bool
|
Whether to error-diffuse (Floyd-Steinberg) the rounding of each pixel onto its neighbours, which keeps antialiased gradients smooth within a small palette. On by default, since indexed output is where the color budget bites. |
True
|
transparent
|
bool
|
Reserve index 0 for empty pixels and drop the background from the color budget. Off by default. |
False
|
Returns:
| Type | Description |
|---|---|
tuple of Raster
|
One indexed :class: |
Source code in src/geomotif/io/raster.py
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 | |
rasterize
¶
rasterize(design: Design, *, width: int = 480, height: int = 480, padding: float = 8.0, bounds: Bounds | None = None, palette: Sequence[str] | None = None, ink: str = '#0b0b0b', background: str = '#ffffff', thickness: int = 1, dot_radius: int | None = None) -> Raster
Draw a design into an indexed bitmap.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
design
|
Design
|
What to draw. |
required |
width
|
int
|
Canvas size in pixels. |
480
|
height
|
int
|
Canvas size in pixels. |
480
|
padding
|
float
|
Margin reserved on all four sides, in pixels. |
8.0
|
bounds
|
Bounds
|
The world rectangle to map onto the canvas. Defaults to the design's own, which is right for a single image and wrong for a frame of an animation -- there, pass the same bounds to every frame or the drawing will swim about as its extent changes. |
None
|
palette
|
sequence of str
|
colors the indices name, background first. Defaults to
|
None
|
ink
|
str
|
Default stroke color and the color behind everything. |
'#0b0b0b'
|
background
|
str
|
Default stroke color and the color behind everything. |
'#0b0b0b'
|
thickness
|
int
|
Stroke width in pixels. |
1
|
dot_radius
|
int
|
Radius for loose points. Defaults to |
None
|
Returns:
| Type | Description |
|---|---|
Raster
|
Ready to hand to :func: |
Source code in src/geomotif/io/raster.py
rasterize_rgba
¶
rasterize_rgba(design: Design, *, width: int = 480, height: int = 480, padding: float = 8.0, bounds: Bounds | None = None, ink: str = '#0b0b0b', background: str = '#ffffff', thickness: int = 1, dot_radius: int | None = None, scale: int = _AA_SCALE, aa_level: int | None = None, transparent: bool = False) -> Raster
Draw a design into a full-color RGBA frame, supersampled and antialiased.
Every pixel is a real (r, g, b, a) value rather than a palette index, so
the edges can blend into the background -- which is the whole point of
antialiasing. The design is painted scale times as large and each
output pixel is the stroke color over the background weighted by the
fraction of its sub-pixels the ink covered.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
design
|
Design
|
What to draw. |
required |
width
|
int
|
Canvas size in pixels. |
480
|
height
|
int
|
Canvas size in pixels. |
480
|
padding
|
float
|
Margin reserved on all four sides, in pixels. |
8.0
|
bounds
|
Bounds
|
The world rectangle to map onto the canvas. Pass the same bounds to every frame of an animation or the drawing will swim about. |
None
|
ink
|
str
|
Default stroke color and the color behind everything. When
|
'#0b0b0b'
|
background
|
str
|
Default stroke color and the color behind everything. When
|
'#0b0b0b'
|
thickness
|
int
|
Stroke width in pixels. |
1
|
dot_radius
|
int
|
Radius for loose points. Defaults to |
None
|
scale
|
int
|
Supersampling factor; |
_AA_SCALE
|
aa_level
|
int
|
If given, each sub-pixel coverage fraction is rounded to one of
|
None
|
transparent
|
bool
|
Leave the background empty rather than painting it. A pixel with no
ink becomes |
False
|
Returns:
| Type | Description |
|---|---|
Raster
|
An |
Source code in src/geomotif/io/raster.py
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 | |
from_spec
¶
from_spec(data: Mapping[str, object]) -> Motif
Rebuild the motif a spec describes.
The version stamp is not consulted; a spec is data, and data that loaded once should keep loading.
Raises:
| Type | Description |
|---|---|
ValueError
|
If the mapping names no motif, or names a value type this library will not import. |
KeyError
|
If the motif name is not registered -- including when it belongs to a plugin that is not installed. |
Source code in src/geomotif/io/spec.py
load_spec
¶
load_spec(path: str | PathLike[str]) -> Motif
Read a spec file and return the motif it describes.
Returns:
| Type | Description |
|---|---|
Motif
|
Ready to :meth: |
Source code in src/geomotif/io/spec.py
save_spec
¶
save_spec(source: SupportsBuild | Design, path: str | PathLike[str], *, indent: int | None = 2) -> Path
Write a motif's recipe to a JSON file and return the path written.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source
|
Motif or Design
|
What to describe; see :func: |
required |
path
|
str or path - like
|
Destination file. |
required |
indent
|
int
|
Passed through to :func: |
2
|
Returns:
| Type | Description |
|---|---|
Path
|
The file that was written. |
Source code in src/geomotif/io/spec.py
to_spec
¶
to_spec(source: SupportsBuild | Design, *, animation: Mapping[str, object] | None = None) -> dict[str, object]
Return the JSON-ready recipe for a motif, or for the design it built.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source
|
Motif or Design
|
A motif, or any design whose :attr: |
required |
animation
|
mapping
|
An animation recipe to carry alongside the still, so a moving picture
round-trips through the same file the CLI's |
None
|
Returns:
| Type | Description |
|---|---|
dict
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
TypeError
|
If a parameter cannot be written as data -- see the module docstring. |
Examples:
Source code in src/geomotif/io/spec.py
save_svg
¶
save_svg(design: Design, path: str | PathLike[str], **kwargs: Any) -> Path
Write a design to an SVG file and return the path written.
Keyword arguments are passed straight through to :func:to_svg.
Source code in src/geomotif/io/svg.py
to_svg
¶
to_svg(design: Design, *, width: float | None = None, height: float | None = None, padding: float = 8.0, stroke: str = '#0b0b0b', stroke_width: float = 1.0, fill: str = 'none', background: str | None = None, dot_radius: float | None = None, flip_y: bool = True, precision: int = 3, group_by_path: bool = True, title: str | None = None, units: str = '') -> str
Render a design as an SVG document.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
design
|
Design
|
What to draw. Its strokes become |
required |
width
|
float
|
Canvas size in user units. Give both to fit the design into exactly
that rectangle; give one and the other follows from the design's own
proportions; give neither and the design keeps its own measurements,
with |
None
|
height
|
float
|
Canvas size in user units. Give both to fit the design into exactly
that rectangle; give one and the other follows from the design's own
proportions; give neither and the design keeps its own measurements,
with |
None
|
padding
|
float
|
Margin reserved on all four sides. |
8.0
|
stroke
|
(str, float, str)
|
Applied to the group holding the strokes. |
'#0b0b0b'
|
stroke_width
|
(str, float, str)
|
Applied to the group holding the strokes. |
'#0b0b0b'
|
fill
|
(str, float, str)
|
Applied to the group holding the strokes. |
'#0b0b0b'
|
background
|
str
|
Draw a filled rectangle behind everything. Omitted by default, which leaves the canvas transparent. |
None
|
dot_radius
|
float
|
Radius for the loose points. Defaults to |
None
|
flip_y
|
bool
|
Mirror vertically, so a design drawn y-up appears the right way up in SVG's y-down space. On by default. |
True
|
precision
|
int
|
Decimal places for coordinates. Trailing zeros are dropped, so a whole number costs one character rather than five. |
3
|
group_by_path
|
bool
|
Give every stroke its own |
True
|
title
|
str
|
The document's |
None
|
units
|
str
|
A physical unit for the document's |
''
|
Returns:
| Type | Description |
|---|---|
str
|
A complete SVG document, ending in a newline. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the design has no points, |
Source code in src/geomotif/io/svg.py
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | |