New image processing library: Zignal

Hi everyone!

I work for a company where we use Zig in production.

In particular, we built a virtual makeup try on that runs on WebAssembly for the Korean makeup manufacturer Ameli. You can try it directly for yourself here. Don’t worry, we don’t store any images, since all the processing is done locally on the end device.

My employer, B factory, has agreed to letting me release the foundation library I developed for the virtual makeup. The library features:

I still haven’t uploaded all the features, but I couldn’t wait to share it with you.
Notably, the drawing and blurring parts are missing, since their current implementations are not generic enough to be in the library.

Here’s the library git repo: GitHub - bfactory-ai/zignal: Image processing library in Zig

Be sure to check the examples’ directory, where you can try the face alignment demo for yourself.

A little bit about me: I am a contributor to the dlib C++ library: http://dlib.net/
Some of the functionality in Zignal has been ported from dlib, from where I drew a lot of inspiration.
Other features were developed for Zignal first, and then ported back to dlib:

Finally, I am thrilled to share this and get some feedback: I am sure there are things that can be done better; do not hesitate to give me some advice! It’s still a work in progress.

51 Likes

Small update, I am porting back functionality from our internal code, now you can already blur images with Zignal. The demo has been updated accordingly

It supports box-blur because it’s really fast because it computes the integral image. It works on grayscale images with SIMD and Color images (with any kind of pixel type).

It’s an updated version of what I had here @floatToInt, @intToFloat gone - #29 by adria

But the thing I am most excited about is the new logo/mascot for the library.

I called her Liza:

  • it sounds feminine like the venerable Lenna - Wikipedia
  • it has a Z, so it feels Ziggy
  • it’s a substring of lizard :exploding_head:

10 Likes

good logo/mascot, nice

3 Likes

That’s very impressive! I will definitely be taking a look.

2 Likes

Another small update: I’ve set up GitHub Actions to host the documentation and examples, so that they can now be run from the browser.

4 Likes

Hi everyone.

Following up on my New image processing library: Zignal post from a few months ago, I’m excited to announce that Zignal has reached its first tagged release!

Here’s the TL;DR of this release:

  • 12 color spaces with seamless conversions (RGB, HSV, HSL, Lab, Oklab, XYZ, etc.)
  • Full linear algebra suite with SVD and PCA implementations
  • 2D drawing API with antialiased primitives and Bézier curves
  • Geometric transforms and convex hull algorithms
  • WASM-first design with interactive browser examples
  • Complete image I/O with native PNG codec and JPEG decoder (had to read the zigimg at some point, since I was getting stuck, parts of my understanding of JPEG was wrong)

Here are the full release notes if you’re interested: Release zignal 0.1.0 · bfactory-ai/zignal · GitHub

What pushed me to tag a release was the fact that I wanted to provide python packages, though.

I’ve spent the last week or so trying to get it to work with Python via native bindings using the Python C interface.
I know Ziggy Pydust exists, but I wanted to learn how to do it myself: write the native Python bindings, see which patterns repeat and can be automated with Zig’s comptime reflection, and slowly build my best effort python utils.
Before, I was always compiling a generic shared library with ctypes to bind it to Python.

Right now, I am building the wheels myself via CI, because I am using Zig 0.15-0.dev, and as far as I know, it’s not available in PyPI. At some point I’d like to add the ziglang dependency, so users can build the library themselves and get full native optimizations. It’s also nicer on the PyPI, since we won’t be uploading any binaries.

Let me know if you find this useful!

10 Likes

Sorry for spamming here, but I just tagged 0.2.0 with a pretty nice feature: terminal image display.

I am a in image processing guy, but I love working on the terminal (foot + kakoune + tmux)

I like having my program running on a split pane with zig build run-whatever --watch so whenever I make changes I can see if the program runs. However, working with images made me have to switch to an image viewer. Well, no more!

With Zignal, you can now do:

const std = @import("std");
const zignal = @import("zignal");
const Image = zignal.Image;
const Rgba = zignal.Rgba;

pub fn main() !void {
    var debug_allocator: std.heap.DebugAllocator(.{}) = .init;
    defer _ = debug_allocator.deinit();
    const gpa = debug_allocator.allocator();

    var image: Image(Rgba) = try .load(gpa, "../assets/liza.jpg");
    defer image.deinit(gpa);
    std.debug.print("{f}", .{image.display(.auto)});
}

That’s foot displaying the image with sixel. By default, the .format method on Image will progressively degrade, depending on what your terminal supports:

  • .kitty: it works on Ghostty
  • .sixel: it works on Foot (the default settings use an adaptive palette of 256 colors with dithering)
  • .ansi_blocks: it works on GNOME Terminal (▀)

But it also supports
.ansi_basic using spaces with background (image is stretched, but doesn’t require unicode characters
.braille for monochrome graphics

Here’s how you can customize the printing format:

    std.debug.print("{f}", .{image.display(.ansi_basic)});
    std.debug.print("{f}", .{image.display(.ansi_blocks)});
    std.debug.print("{f}", .{image.display(.{ .sixel = .default })});
    std.debug.print("{f}", .{image.display(.{ .kitty = .default })});
    std.debug.print("{f}", .{image.display(.{ .braille = .default} })});

Have fun!

9 Likes

Don’t apologize, awesome update! Look forward to test this out :slight_smile:

3 Likes

New version: 0.3.0

Highlights

  • font rendering of bitmap fonts (BDF/PCF, with automatic decompression)
  • improved the python bindings to be more on par with the main library
  • improved the documentation generation for the python bindings

zignal-python-demo

8 Likes