Available now from a Node Package Market near you! 🌽

https://delucis.github.io/sweetcorn/

Sweetcorn is a small Node.js library for dithering images using classic techniques. It includes 30+ algorithms and a dedicated Astro image service to make it easy to dither any image in an Astro site. (I’d love to add support for other frameworks — if you know how, let me know!)

sweetcorn

JavaScript image dithering tools for Sharp

sweetcorn

Shout out in particular to @lovell for Sharp, which Sweetcorn builds on top of, and to @surma whose “Ditherpunk” article I remembered while thinking about this and was super helpful.

Links:
- https://sharp.pixelplumbing.com/
- https://surma.dev/things/ditherpunk/

High performance Node.js image processing

High performance Node.js image processing. The fastest module to resize JPEG, PNG, WebP and TIFF images.

sharp
@swithinbank Love it, thanks for the shout, I don't think I've seen this many dithering kernels all together in the same place as the same time. We briefly considered adding something similar (but smaller scale) into libvips a few years ago - see https://github.com/jcupitt/vips-dither - let me know if it gets popular and we can revisit.
GitHub - jcupitt/vips-dither: 4x4 ordered dither

4x4 ordered dither. Contribute to jcupitt/vips-dither development by creating an account on GitHub.

GitHub

@lovell Oh interesting! I guess the threshold maps in particular could benefit from native implementations as the operation is parallelisable. And I guess would be easy to support as a generic operation perhaps? It’s a similar operation to how `.convolve()` or `.recomb()` take a matrix. Could even be an extension of `.threshold()` where instead of providing a single threshold value you can provide a matrix instead.

One awkward thing building this was that there’s no way to do something like `image.map()` for generic pixel manipulations, you always have to copy the image into a raw output buffer, operate on that, and then create a new image from it to format a proper output. I guess implementing genuinely custom operations that run on some shared view of the image data may not be possible though.

I haven’t actually benchmarked any of these operations yet. At some point I’d like to see what the processing overhead is.

Another thing a native implementation could benefit from maybe is better transparency handling. I’m working on that at the moment and finding it a bit tricky to detect if an image is really *using* its alpha channel (because if it isn’t, it’s safe to drop and output as a smaller 1-channel B/W image).

@swithinbank Re: "detect if an image is really *using* its alpha channel", this feature is available via:

const { isOpaque } = await sharp(input).stats()

https://sharp.pixelplumbing.com/api-input/#stats

Input metadata

High performance Node.js image processing. The fastest module to resize JPEG, PNG, WebP and TIFF images.

sharp
@lovell Oh wow, how did I miss that! Thank you!