Repository navigation
v0.9.0
This release repairs image-to-ANSI conversion, which raised ValueError: assignment destination is read-only for every image opened from a path or supplied as a PIL object, and carries animation support through ansify and the CLI. The chromatic.demo module and the bundled demo images are deleted, rgb_dispatch now raises on unknown color names by default, and ansify renames two keyword parameters; see Removals and Compatibility notes.
Removals
chromatic.demo, includingpython -m chromatic.demoand all nine demo routines. No replacement.chromatic.data.butterfly,chromatic.data.escher,chromatic.data.goblin_virus. Pass your own image path toimg2ansi,img2ascii, oransify.- The bundled demo images, also dropped from the package data in
pyproject.toml, cutting roughly 590 KB from an install. -o/--output-dironchromatic image. Name the file with--outfile.-d, the short name for--dump-text.
Compatibility notes
ansify renames fg/bg and gives bg a new meaning
ansify reused one bg value for both stages of the conversion, conflating the canvas color the source is composited against with the fallback for cells carrying no color of their own. The old keyword-only fg and bg become fg_default and bg_default, matching ansi2img, and bg is now the input canvas color:
# before
ansify(img, font, fg=(170, 170, 170), bg=(0, 0, 0))
# after
ansify(img, font, fg_default=(170, 170, 170), bg_default=(0, 0, 0))Rename the keywords to preserve prior output, and leave bg unset unless a canvas color is wanted. All three accept color names such as black in place of tuples.
rgb_dispatch raises on unknown color names
The new strict parameter defaults to True, so a targeted string that is not a known color name raises KeyError instead of passing through. Defaults resolve at decoration time, so a non-color default raises where the function is defined:
@rgb_dispatch
def func(r="red", x="not a color", /): ...This previously decorated and left x as the string. It now raises KeyError: 'not a color'. Pass strict=False for the old pass-through behavior.
--outfile takes the lowercase -o
With --output-dir gone, --outfile moves from -O to the freed -o. Scripts passing -O FILE need updating; scripts passing -o DIRECTORY named a directory and now name a file.
New features
Animated ansify
ansify converts every frame of an animated input and returns an animated image rather than the first frame alone, reading duration and loop count from the source and preserving its format, falling back to GIF. Save options such as duration and loop may be passed through and override the source values. The returned image carries the array it rendered from on info["ansi_array"], 3D for animated input.
img = ansify("input.gif", font, factor=200)
img.save("out.gif", save_all=True)RGBA conversion output
Passing a 4-tuple bg produces an RGBA result: the ANSI array's rgb field widens from (2, 4) to (2, 5) to carry alpha. A 3-tuple keeps the RGB path. The color parameters of img2ansi, ascii2img, ansi2img, ansify, and render_ans accept a 4-tuple wherever they previously took only a 3-tuple.
chromatic image npy and --dump-npy
--dump-npy FILE writes the intermediate ANSI array, and the npy subcommand reads one back, accepting the same font, rendering, and output options as ansify:
chromatic image ansify input.png --dump-npy art.npy --outfile art.png
chromatic image npy art.npy --stdoutAnimation options and in-terminal playback
--format {WEBP,GIF}, --duration N in milliseconds, and --loop N control animated output for both subcommands, and --outfile writes every frame. When the text dump target is a terminal and the array holds multiple frames, the animation plays in place, honoring --loop and --duration and restoring the cursor on exit, including on Ctrl-C.
Typing improvements and changes
img2ascii and img2ansi infer the result rank from the input
The separate 2D and 3D overloads for outarray=True collapse into one shape-generic overload each. A 2D image array now types as a 2D result and a 3D frame array as a 3D result, where both previously widened to a union of the two.
Changes
LICENSE restored
The MIT LICENSE file, dropped by an earlier commit, is back in the source tree and the sdist.
Generated CLI reference in the docs
An MkDocs hook renders the argparse definitions into a CLI section covering chromatic image, chromatic font, and their subcommands. The README is rewritten around color_chain, img2ansi, ansi2img, ansify, animated images, and ColorStr.
Fixes
Conversion no longer fails on images opened from a path
Any image Pillow opened, which covers every path and every PIL object, was backed by read-only memory that the conversion then wrote into, raising ValueError: assignment destination is read-only. This broke img2ansi, ansify, and chromatic image ansify outright for file inputs. Those inputs convert again, and an array passed in directly is still left unmutated.
img2ascii returns the documented type for each input
The branches were swapped: a single image returned list[str] of rows and an animated image returned one concatenated str. A single image now returns str and an animated image list[str], one per frame, matching img2ansi.
Trailing newlines no longer accumulate
img2ascii left a newline after the final row, and color_chain.fromarray appended a newline column to any 2D array, doubling them for input already terminated, such as img2ansi(..., outarray=True) output. Both detect existing termination and trim the trailing newline.
--reverse reverses the glyph sort
The option had no effect: glyphs were sorted in normal order whether or not it was passed. It now flips the luminance mapping to light-to-dark as documented.
Full Changelog: v0.8.1...v0.9.0