Some packages with native code components (like sharp) will use these hooks to download the correct precompiled native binary for you.
HN user
jcupitt
sharp downloads over https and checks the sha256 (I think?) of the archive.
sharp does this too:
https://sharp.pixelplumbing.com/install/#prebuilt-binaries
it can sometimes need to compile the C++ shim that sits between node and libvips, but that's rare.
sharp does not rebuild libvips, it downloads a pre-compiled libvips for your platform.
https://sharp.pixelplumbing.com/install/#prebuilt-binaries
It can usually also download a precompiled binary for the C++ shim that sits between node and libvips, but if your node / arch / etc. is not supported, it'll compile that (that's what the build.js file you linked does).
Hello, libvips author here, you can get it to do the OKLab averaging for you. For example, using pyvips (ahem, untested):
image = pyvips.Image.new_from_file(filename, access="sequential")
scale = min(200 / image.width, 200 / image.height)
thumbnail = image.colourspace("oklab").resize(scale).extract_bands(0, n=3)
rgbf = thumbnail.write_to_memory()
That'll stream the source image and make a RGBRGBRGB memory buffer of single precision floats. You could perhaps use kernel="linear" and avoid any ringing from lanczos3.
I think I would downsample in a linear light space, like scRGB. Averaging there means averaging photons, which will surely be better than OKLab. Maybe switch to OKLab for clustering. Though of course I've not tested it.
libvips uses imagemagick (via libMagick) for BMP load and save, fwiw
It's just `vips copy src.heic dst.jpg`.
libvips, the library behind sharp, has just released version 8.18.0: https://www.libvips.org/2025/12/04/What's-new-in-8.18.html
It includes support for UltraHDR (HDR and SDR in one JPEG file), camera RAW images, and the Oklab colourspace. This should all be coming to sharp in the next six month or so.
Cleanup can be very useful if you depend on a library that does not support arenas.
`free(NULL);` will crash on some platforms that gcc supports, I believe.
I'm the libvips author, I should have said, so I'm not very neutral. But at least on that test it's usefully quicker and less memory hungry.
pyvips (the libvips Python binding) is quite a bit better than pillow-simd --- 3x faster, 10x less memory use, same quality. On this benchmark at least:
https://github.com/libvips/libvips/wiki/Speed-and-memory-use
Ah no problem! I'm glad it's useful.
`govips` was a pretty early binding and wasn't really done the libvips way. It doesn't expose all the operations or options, it's mostly done by hand, and there are a number of leaks and misfeatures.
It's been replaced by `vipsgen`:
https://github.com/cshum/vipsgen
Which is an automatically generated 100% binding. It should have the complete API, it should be very stable and leak-free, and it should be simple to maintain.
`autorot` is pretty expensive. You'll see much better performance if you flip x and y in your crop instead.
Hello, libvips author here, the JPEG loader has a flag to do this for you. You can write:
VipsImage *image = vips_image_new_from_file("something.jpg", "autorotate", TRUE, NULL);
and it'll flip it upright for you and remove any EXIF orientation tag. It isn't the default since it has (obviously) a large memory and cpu cost.
For simple resize and crop it's much better to use the exif tag to adjust the resize and crop parameters (the vipsthumbnail command does this).
Applying rotation can have a large performance penalty (both cpu and memory), so you want to be able to avoid it if possible.
Those three all use libvips as the image processing engine, fwiw, so it's maybe not a very wide survey.
libvips is fairly highly threaded and does a lot of alloc/free, so it's challenging for most heap implementations.
Hello, libvips author here. This is probably the canonical thread about libvips and memory fragmentation, and the funniest graph:
https://github.com/lovell/sharp/issues/955#issuecomment-5458...
(that specific graph is for switching from glib to the musl memory allocator, but jemalloc gives a very similar result)
The wasm build of libvips (the image processing library this thing uses) does not include HEIC because of the various patent issues:
https://github.com/kleisauke/wasm-vips/issues/3
It does support AVIF and JXL. Hopefully Apple will abandon HEIC hehe.
Although I think this technique was well known before then -- Crosfield were using channel-independent histogram normalization to restore faded transparencies back in the 80s.
libvips dev here -- the CLI interface is deliberately really basic, you'll see much better performance and flexibility with one of the language bindings. pyvips works well:
https://github.com/libvips/pyvips
The idea is that complex CLIs like imagemagick's are almost complete programming languages, and need a lot of learning. It's much better (imo) (and less work) to have a good binding, and to lean on python for the programming side.
libvips is mostly self-binding. It has good introspection support, so the core of pyvips is just 200 lines of code, and automatically updates itself for new libvips versions.
imagemagick 7 (the current version) is namespaced under "magick", fwiw
I made an image viewer for large images:
https://github.com/jcupitt/vipsdisp
It should be fine with your huge PNGs. Internally it's a bit like a tiled map viewer, but it makes the tiles as you view the image with a set of background worker threads. It uses your GPU to scale and composite the set of visible tiles to your screen.
It uses openslide to let you view slide formats like SVS and MRXS, which might be handy. It also supports colour management.
nip2 does this. It's a little like a spreadsheet, but cells can contain images, matrices, text, widgets, stuff like that. You can add scraps of code to link them together (just like a spreadsheet).
https://github.com/libvips/nip2
Your example might look like this:
Everything is live, so you can drag sliders and adjust expressions and it all updates.
There's also imagemagick, of course, but it's command-line only.
We're off topic here, but in pyvips (for example) you can do text overlays like this:
https://github.com/libvips/pyvips/blob/master/examples/annot...
tldr: make an image containing your text, composite it over the image you want to annotate.
Firefox and webkit also have JXL support. Like Chrome, the FF version is behind a flag. The webkit one is a build-time option.
It's actually the other way around: WebP images are about the same size as JPEG encoded with mozjpeg -- compression is no better. WebP does have advantages for images with transparency. Google effectively abandoned webp more than five years ago now and began work on webp2. But they've now abandoned that as well.
JXL, AVIF and HEIC use next-gen compressors and are about half the size of JPEG and WebP at the same quality. HEIC has a range of terrible patent problems, so the current choice is AVIF vs JXL.
AVIF has wider industry support and is likely to get hardware decode. JXL is technically more interesting and more flexible, and far better CPU encode/decode performance.
I use tiled TIFF with jpeg compression for things like this. You get good compression, support for huge sizes, and wide compatibility. TIFF supports image pyramids too, so you can even get good interactive performance.
No direct web browser support is the only big downside :(
Firefox has had basic support behind a flag for a good while, but it needs some work -- their code is missing things like transparency and colour profiles. Sadly mozilla have laid off a lot of their dev team and they don't have much capacity right now.
Safari have support as a build-time option, apparently.
libvips has had libjxl support for a couple of years now, including in our fuzzing and build systems. Everything is pretty much ready to roll, and would have brought support to downstream projects and users like sharp, ActiveRecord, imaginary, Shopify, etc.
We've just been waiting for Chrome to flip the switch and start deployment, To have support pulled like this at the last second is extremely disappointing.
Yes, nip2 workspaces are DAGs, like node graph interfaces. The spreadsheet comparison was originally there to help introduce the interface to a less technical audience. nip2 was written in the 1990s when this stuff was less widespread.
I don't like plug-and-socket style graphical node graph interfaces personally -- I think they are hard to reason about, and things like composition and rewriting feel unnatural (to me). I came out of the functional programming community and I wanted things like referential transparency.
nip2 is supposed to be a graphical interface that's an expression of a set of relations. It has a three part model:
1. You enter scraps of code (or pick menu items) to build an object in nip2's programming language.
2. nip2 looks at the constructed object and draws the GUI.
3. Changes to the GUI trigger "edit" functions on the constructed object to update it.
4. ... if you go back and edit the code that originally constructed the object, the GUI resets.
So your code and the GUI independently update the constructed object, with code taking priority. You get a stateful GUI with a purely functional programming language and you get to keep equational reasoning.