geomotif.io.gif
¶
Write an animated GIF, in pure standard library.
A design that draws itself on, a motif whose parameter sweeps, a figure turning: an animation says something a still image cannot, and GIF is the one animated format that plays everywhere with nothing installed -- a README, a chat window, an issue comment.
It is also, unusually for a 1989 format, small enough to write by hand. The file is a color table, a run of frames, and a trailer; the only real work is LZW, and GIF's variant of it fits on a page: build a dictionary of byte strings as you go, emit each match as a code, widen the code as the dictionary fills, and start again from empty when it is full at 4096 entries. That is the whole of it, and it is why an animation costs no dependency either.
The frames come from :mod:geomotif.animate and the pixels from
:mod:geomotif.io.raster; this module is only the container::
from geomotif.animate import draw_on
from geomotif.io.gif import save_gif
from geomotif.motifs import KochSnowflake
save_gif(draw_on(KochSnowflake(depth=4).build(), frames=60), "koch.gif")
Functions:
| Name | Description |
|---|---|
to_gif |
Render a sequence of designs as an animated GIF. |
save_gif |
Write an animated GIF and return the path written. |
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_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.