Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.Sign up
HOWTO Image shrinking
This page attempts to give best-practice guidelines
for image resizing with libvips. They are implemented in the
operations, so read along in the source
if you're curious.
You can call these operations from any language with a libvips binding, so just use (for example):
$filename = ...; $image = Vips\Image::thumbnail($filename, 200, ["height" => 200]); $image->writeToFile("my-thumbnail.jpg");
And everything listed here will be done for you.
vipsthumbnail command-line tool gives a handy interface to these
operations, see the docs for an
When downsizing an image you need to follow approximately these steps:
Many image formats support some sort of resize-on-load. This is generally
much faster than shrinking in libvips, so it's a good idea to exploit this
if you can.
vipsthumbnail does shrink-on-load for the following formats:
libjpeg (and libjpeg-turbo) can quickly produce a 1/8, 1/4 or 1/2 size image during decode.
This down-sampled image is produced by the equivalent of a block shrink (each pixel is the simple average of the corresponding 2x2, 4x4 or 8x8 block), and the hard edges of these square blocks can cause rather bad aliasing in the final image. It's best to use jpeg shrink-on-load to make an image about 2x larger than your final output size and then do a further shrink with something more sophisticated. See the Block shrink section below.
Vector formats like PDF and SVG can be rendered directly at the required size. Do this and don't do anything else.
libwebp supports a rather general shrink-on-load feature. Again, keep at least x2 headroom for the final resize.
Pyramidal formats like openslide and TIFF pyramids can have layers which contain subsampled versions of the image. As with libjpeg, to avoid aliasing it's best to extract a layer 2x larger than the target and do a further shrink with something else.
vipsthumbnaildoes not currently try to do anything clever with these openslide or TIFF images, it probably should.
libvips supports file and memory input. See
You can also make images from simple memory arrays; useful
if you've used some other library to decode the image. See
If you mix two image samples, it's like mixing two sources of light. Or it should be; in fact, most image formats do not deal in values which are related to the amount of light, mostly they deal in perception, that is, how bright a point would appear to a human observer.
If you want to resize an image, you really ought to translate the image to a linear light colourspace first. @nathanaeljones has a nice example of the difference this makes. If you resample in a perceptual space you see this:
If you resample in a linear space you see this:
Obviously the snowflakes are more visible in linear light.
Unfortunately this translation is not cheap and things like shrink-on-load, essential for good performance, do not support linear light. For now, linear light resampling is a luxury.
If you want to do linear-light resampling in libvips you must not do any
of the shrink-on-load tricks and you need to go to a linear-light space
immediately after loading the image. If there's an attached ICC profile, use
to import the image to XYZ PCS. If there's no profile, use
to transform the image to CIEXYZ.
After loading the image, you need to move it to a processing
colourspace. libvips supports a large number of colourspaces, with
sRGB being the most common. If you are not doing linear light resampling, use
to move to sRGB.
If the image has an alpha channel, you
need to premultiply before shrinking. See
libvips has a very fast block shrink,
where each output pixel is the simple average of the square nxn block of
pixels in the source. Use this to get to 2x above your final target size.
The x2 headroom is necessary to prevent aliasing. Here's a 800x600 JPEG image shrunk to 400x300 with a 2x2 block shrink (in fact, with libjpeg's shrink-on-load feature):
And here's the same image, but shrunk from 800x600 to 400x300 with lanczos3:
If you look at the roof of the block-shrink version you'll see nasty aliasing artifacts. To fix these, you have to block shrink to a size above your target and then use something better to get to the final target size.
Resize to target
For the final resize, use
This uses a pair of high-quality 1D lanczos3 kernels to get the image to
the exact dimensions you need. You can pick other kernels if you wish.
If you have an alpha, now's the time to call
Most image viewers, including web browsers, will show an image with no embedded colour profile as sRGB. You can therefore save the storage and transmission costs of the profile by writing the output image as sRGB and removing any profile data.
When libvips opens an image, it attaches any colour
profile embedded in the image as metadata. You can use this with
to move the image to sRGB using an sRGB
profile. If you are doing linear light resampling, use
to transform directly to sRGB or
with XYZ PCS if you used
vips_icc_import() to convert to XYZ colourspace.
Some images will have orientation tags giving the camera
angle when the photo was taken. You can save transmitting
this metadata by baking the orientation into the image, see
You can save a lot of space by deleting metadata. See
Image savers also all support a
strip option which will remove all metadata.
libvips supports some of mozjpeg's output options. You can get a smaller
final image by adjusting these controls. See the documentation for