There are the usual performance improvements and bug fixes, but the main highlight is a simple CLI tool to perform various image operations via the terminal.
You can get an idea of what it can do with:
Usage: zignal [options] <command> [command-options]
Global Options:
--log-level <level> Set the logging level (err, warn, info, debug)
Commands:
blur Apply various blur effects to images.
diff Compute the visual difference between two images.
display Display an image in the terminal using supported graphics protocols.
edges Perform edge detection on an image using Sobel, Canny, or Shen-Castan algorithms.
fdm Apply Feature Distribution Matching (style transfer) from target to source image.
info Display detailed information about one or more image files.
metrics Compute quality metrics (PSNR, SSIM, Mean Error) between a reference and target images.
resize Resize an image using various interpolation methods.
tile Combine multiple images into a single tiled image.
version Display version information.
help Display this help message
Run 'zignal help <command>' for more information on a specific command.
For example:
zignal help display
Usage: zignal display <image> [options]
Display an image in the terminal using supported graphics protocols.
Options:
--width <N> Target width in pixels
--height <N> Target height in pixels
--protocol <p> Force protocol: kitty, sixel, sgr, braille, auto
I think the ‘railroad’ like you’re doing here is as good as it gets for chaining in Zig. And it’s pretty good!
Maybe not worth changing, but I find eval confusing as the name of the finalizer. It makes me think that all the calls before are setting up an operation, and only the final one does it. But it looks like that isn’t how it works.
I would use ok() here for that reason. That I would read right away as “oh, right, the try, railroad pattern”. If you’re past the point where tweaking the API for surface reasons like that feels worth doing, that’s understandable.
It’s been neat seeing this project grow, good work.
Hi! Thank for your encouraging words.
You’re right, .eval() is misleading, since the user might think there’s some kind of lazy evaluation or something…
I need to find a better name and .ok() might be it. I don’t mind breaking the API, it’s explicitly stated in the README. And I don’t think people are using Zig expect a smooth developer experience, once you choose to use Zig, you assume things will break
I will think more about it. Thanks again
@adria thanks for your work on zignal! I’m currently using it to export gif images.
I saw you are working on supporting animated images in the master branch. Do you plan to backport this code into the 0.10.0 branch with zig 0.16 compatibility?
Just dropping in to say I love this library. It has so many features that I’m still just digging through it to find new things to add to txt2img, and the built-in CLI is super nice too. Thanks for all your incredible work!
The big change: most operations now take an io: Io and split their work into row bands, so filters, codecs and resizing run in parallel on a thread pool. Without threads (e.g. on WASM) the same code runs serially, with identical results.
Other bits:
JPEG and PNG got a lot faster (on par with libjpeg-turbo and libpng)
TrueType/OpenType fonts and text layout
QR codes, CMYK JPEGs, BMP and animated GIF/WebP/JPEG XL
The API is namespaced now (image.*, canvas.*, matrix.*…), so expect some breakage
@tgirod animated GIF export is in this release, and it works on a stable Zig now.
@mnemnion I ended up dropping eval() altogether: matrix ops return errors directly, so a plain try works, and the deferred-error chain lives in matrix.Chain with toOwned().
0.12 dev continues on Zig master. Feedback welcome as always!