libVIPS
a demand-driven, horizontally threaded image processing library. Compared to similar libraries, libvips runs quickly and uses little memory. - libVIPS / github / blog / wikipedia
- Automatic computation reordering
- support jpeg-xl since libvips 8.11 - but not as part as ubuntu release
Compiling
sudo apt install build-essential ninja-build
It straitghforward through meson. But it requires additional libraries to support features:
- libspng (recommended) - faster png operation
- otherwise use libpng
- mozjpeg (recommended) - compatible with the libjpeg API and ABI. It is intended to be a drop-in replacement for libjpeg. MozJPEG is a patch for libjpeg-turbo.
- libjpeg-turbo - a JPEG image codec that uses SIMD instructions to accelerate baseline JPEG compression and decompression
- libjpeg - fallback
- libjxl - for jpegxl
-
libwebp
- highway - SIMD support
- orc - Optimized Inner Loops Runtime Compiler
nip2
A user interface for libvips.
see also
- Difference Hash computation - use libvips for image shrinking - access band[0] direclty
- Color Quantisation - Color Quantisation CLI - direct pixels reading within region
Doc / c++ / SO
- Hello World
- How libvips opens a file
- Sequential mode read - Not all operations need random access to their source pixels. For example, thumbnailing, the process of shrinking images for display, can work strictly top-to-bottom. But this has re-reading constraint
- Fancy transforms
- Some newbie questions on how to do things with libvips
C++ API
The libvips C++ API is a thin layer over the libvips GObject API. It adds automatic reference counting, exceptions, operator overloads, and automatic constant expansion.
You can drop down to the C API at any point, so all the C API docs also work for C++.
- The API overloads () to be vips_getpoint() - which is very slow
- The API overloads [] to be vips_extract_band()
- VIPS images / c++
VIPS images are three-dimensional arrays, the dimensions being width, height and bands
- crop synonym for extract_area - Extract an area from an image.
- data - Arrange for the underlying object to be entirely in memory, then return a pointer to the first pixel.
see also
Iterating over Region
An image can be very large, much larger than the available memory, so you can’t just access pixels with a pointer *.
That will only work for 8-bit images, and I’ve not tried to handle errors or int overflow correctly. With a 10k x 10k pixel RGB JPEG I see: 700ms to decompress and scan a 300mb image, with a peak memory use of 150mb.
Code...
Code...
/* compile with:
*
* gcc -g -Wall try350.c `pkg-config vips --cflags --libs`
*/
#include <stdio.h>
#include <vips/vips.h>
int
main(int argc, char **argv)
{
VipsImage *image;
if (VIPS_INIT(argv[0]))
vips_error_exit(NULL);
if (!(image = vips_image_new_from_file(argv[1], "access", VIPS_ACCESS_SEQUENTIAL, NULL)))
vips_error_exit(NULL);
VipsRegion *region = vips_region_new(image);
int sum = 0;
for (int y = 0; y < image->Ysize; y++) {
if (vips_region_prepare(region, &(VipsRect) { 0, y, image->Xsize, 1 }))
vips_error_exit(NULL);
unsigned char *p = VIPS_REGION_ADDR(region, 0, y);
int size = VIPS_REGION_SIZEOF_LINE(region);
for (int x = 0; x < size; x++)
sum += p[x];
}
printf("sum = %d\n", sum);
g_object_unref(region);
g_object_unref(image);
return 0;
}
see also
Colors
- filters like sepia, black-white
- New colour package
- autodetect CMYK and convert to sRGB JPEG
- colour operators - These operators let you transform coordinates and images between colour spaces, calculate colour differences, and move to and from device spaces. - Use vips_colourspace() to move an image to a target colourspace using the best sequence of colour transform operations.
- Contrast-Limited Adaptive Histogram Equalisation
Image shrinking
- vips_thumbnail() - don’t use thumbnail_image on already loaded images. - Because the image has already been opened, it can’t do any of the shrink-on-load tricks that help make thumbnail fast.
- Making DeepZoom, Zoomify and Google Maps image pyramids with vips
- How to use libvips to shrink giant images with limited memory - not possible on progressive or interlaced image (like some jpegs).
Image arithmetic
Perform an arithmetic operation, such as addition, on every pixel in an image or a pair of images.
- vips_project - the sum of every row of pixels, and the sum of every column of pixels.
Defining Matrix
int akernel[] = { -1, -1, -1,
-1, 16, -1,
-1, -1, -1 };
VImage kernel = VImage::new_from_memory( akernel, sizeof(akernel),
3, 3, 1, VIPS_FORMAT_INT);
VImage conv = in.colourspace(VIPS_INTERPRETATION_sRGB,
VImage::option()
->set ("source_space", VIPS_INTERPRETATION_B_W)
)
.conv( kernel );
Internals
pyvips
import pyvips
image = pyvips.Image.new_from_file('some-image.jpg', access='sequential')
image *= [1, 2, 1]
mask = pyvips.Image.new_from_array([[-1, -1, -1],
[-1, 16, -1],
[-1, -1, -1]
], scale=8)
image = image.conv(mask, precision='integer')
image.write_to_file('x.jpg')
Ruby
Full bindings are available for
Iterate over pixel
You can’t really iterate over pixels in libvips, since images don’t really exist. Everything is a delayed computation and pixels only exist on demand. You can either implement a new vips operation, or render the whole image to an area of memory and then treat it like any other array. Have a look at vips_image_write_to_memory().
For eg:
From version 8.4
uint64_t dhash( VImage hash ) {
VImage cache = VImage::new_memory();
hash[0].write( cache);
auto* p = (uint8_t*) cache.data();
uint64_t hash_value = 0;
for (int j = 0; j < h; j++) {
for (int i = 0; i < w; i++) {
hash_value <<= 1;
hash_value |= *p++ > 0 ? 1 : 0;
}
}
return hash_value;
}
before
uint64_t dhash( VImage hash ) {
auto w = hash.width();
auto h = hash.height();
cout << "w: " << w << " h: " << h << "band: " << hash.bands() << "\n";
size_t size;
auto* p = (uint8_t*) hash[0].write_to_memory( &size);
uint64_t hash_value = 0;
for (int j = 0; j < h; j++) {
for (int i = 0; i < w; i++) {
hash_value <<= 1;
//hash_value |= hash(i, j)[0] > 0 ? 1 : 0; // 1001101100111001101011010110000010011000011000110000111
hash_value |= *p++ > 0 ? 1 : 0; // 1001101100111001101011010110000010011000011000110000111
}
}
return hash_value;
}
Note: it is much faster to do that than accessing pixels through vips_getpoint()
VIPS History
background on its 30 years of development