[update Jan 2016: The resizing algorithm vipsthumbnail uses has changed for vips8 and I've updated the advice here to reflect that]
libvips has shipped with a handy thumbnail maker for a while now. I thought a post of tips and tricks might be useful. Scroll all the way to the bottom for a summary and recommended usage.
Why use vipsthumbnail?
It's fast and uses little memory. For example, here's ImageMagick with wtc.tif, a 10,000 x 10,000 pixel RGB tiff image:$ time convert wtc.tif -resize 128 tn_wtc.jpgAnd here's vipsthumbnail:
peak RSS: 705m
real 0m2.639s
user 0m4.036s
sys 0m0.516s
$ time vipsthumbnail wtc.tifSo vipsthumbnail is about 11 times faster and needs 1 / 13th of the memory.
peak RSS: 52mb
real 0m0.239s
user 0m0.168s
sys 0m0.072s
vipsthumbnail and convert are using the same downsizing algorithm: a fast box filter for large-scale reduction, and a high-quality lanczos3 interpolator for the final 200%.
You see similar improvements with png images, but much less with jpeg. This is because libjpeg includes support for shrink-during-load, so the image processing system has much less effect.
$ time convert -define jpeg:size=256x256 wtc.jpg -resize 128 tn_wtc.jpg
peak rss: 19mb
real 0m0.259s
user 0m0.284s
sys 0m0.004s
$ time vipsthumbnail wtc.jpg
peak rss: 30mb
real 0m0.268s
user 0m0.256s
sys 0m0.016s
The -define argument makes convert load the image at twice the target size, then use a high-quality downsampler to get to the exact output dimensions. If you don't leave this headroom you can get bad aliasing artifacts. vipsthumbnail does exactly this automatically.
At larger output sizes you start to see a difference, since there are actually some pixels being processed:
$ time convert -define jpeg:size=4000x4000 wtc.jpg -resize 2000 tn_wtc.jpg
peak rss: 285mb
real 0m1.126s
user 0m2.508s
sys 0m0.240s
$ time vipsthumbnail wtc.jpg -s 2000
peak rss: 47mb
real 0m0.499s
user 0m0.928s
sys 0m0.028s
libvips options
vipsthumbnail supports the usual range of vips command-line options. A few of them are useful:--vips-cache-trace shows each operation as libvips starts it. It can be handy to see exactly what operations vipsthumbnail is running for you.
--vips-leak turns on the libvips memory leak checker. As well as reporting leaks (hopefully there are none) it also tracks and reports peak memory use.
--vips-progress runs a progress indicator during computation. It can be useful to see where libvips is looping and how often.
--vips-info shows a higher level view of the operations that vipsthumbnail is running.
Looping
vipsthumbnail can process many images in one operation. For example:$ vipsthumbnail *.jpgwill make a thumbnail for every jpeg in the current directory. See the Output directory section below to see how to change where thumbnails are written.
vipsthumbnail will process images one after the other. You can get a good speedup by running several vipsthumbnails in parallel, depending on how much load you want to put on your system.
Colour management
vipsthumbnail will optionally put images through LittleCMS for you. You can use this to move all thumbnails to the same colour space. All web browsers assume that images without an ICC profile are in sRGB colourspace, so if you move your thumbnails to sRGB, you can strip all the embedded profiles. This can save several kb per thumbnail.For example:
$ vipsthumbnail shark.jpgNow encode with sRGB and delete any embedded profile:
$ ls -l tn_shark.jpg
-rw-r--r-- 1 john john 7295 Nov 9 14:33 tn_shark.jpg
$ vipsthumbnail shark.jpg --eprofile /usr/share/color/icc/sRGB.icc --deleteIt'll look identical to a user, but be almost half the size. You can make it even smaller with the optimize_coding option, see the end of this post.
$ ls -l tn_shark.jpg
-rw-r--r-- 1 john john 4229 Nov 9 14:33 tn_shark.jpg
You can also specify a fallback input profile to use if the image has no embedded one, but this is less useful.
Thumbnail size
You can set the bounding box of the generated thumbnail with the --size option. For example:$ vipsthumbnail shark.jpg --size 200x100Use a single number to set a square bounding box.
Output directory
You set the thumbnail write parameters with the -o option. This is a pattern which the input filename is pasted into to produce the output filename. For example:$ vipsthumbnail fred.jpg jim.tif -o tn_%s.jpgFor each of the files to be thumbnailed, vipsthumbnail will drop the extension (.jpg and .tif, in this case) and then substitute the name into the -o option, replacing the %s. So this example will write thumbnails to tn_fred.jpg and tn_jim.jpg.
If the pattern given to -o is an absolute path, any path components are dropped from the input filenames. This lets you write all of your thumbnails to a specific directory, if you want. For example:
$ vipsthumbnail fred.jpg ../jim.tif -o /mythumbs/tn_%s.jpgNow both thumbnails will be written to /mythumbs, even though the source images are in different directories.
Conversely, if -o is set to a relative path, any path component from the input file is prepended. For example:
$ vipsthumbnail fred.jpg ../jim.tif -o mythumbs/tn_%s.jpgNow both input files will have thumbnails written to a subdirectory of their current directory.
Output format and options
You can use -o to specify the thumbnail image format too. For example:$ vipsthumbnail fred.jpg ../jim.tif -o tn_%s.pngWill write thumbnails in PNG format.
You can give options to the image write operation as a list of comma-separated arguments in square brackets. For example:
$ vipsthumbnail fred.jpg ../jim.tif -o tn_%s.jpg[Q=90,optimize_coding]will write jpeg images with quality 90, and will turn on the libjpeg coding optimizer.
Check the image write operations to see all the possible options. For example:
$ vips jpegsave
usage:
jpegsave in filename
save image to jpeg file
where:
in - Image to save, input VipsImage
filename - Filename to save to, input gchararray
optional arguments:
Q - Q factor, input gint
profile - ICC profile to embed, input gchararray
optimize-coding - Compute optimal Huffman coding tables, input gboolean
Final suggestion
Putting all this together, I suggest this as a sensible set of options:$ vipsthumbnail fred.jpg -o tn_%s.jpg[optimize_coding] --eprofile /usr/share/color/icc/sRGB.icc --delete
Recent versions
Since libvips 7.38, vipsthumbnail has gained a couple of new features.First, the jpeg writer has three new options. One is --optimize_coding, contributed by Lovell Fuller. This enables libjpeg's Huffman table optimiser and will typically shrink your JPEGs by about 5%, at the cost of slightly longer encoding times. Second is --no-subsample. This turns off chrominance subsampling, which will improve image quality at the cost of larger file size. It's useful at high Q values. Finally, --strip stops the JPEG writer from attaching any metadata. Some JPEG metadata types, such as XMP and IPCT, can be rather large and this can save a useful amount of space.
For example, here's a photo library image with a large amount of IPCT data:
$ vipsthumbnail 42-32157534.jpgTry using the --delete option explained above to remove an ICC profile:
$ ls -l tn_42-32157534.jpg
-rw-r--r-- 1 john john 6682 Nov 12 21:27 tn_42-32157534.jpg
$ vipsthumbnail 42-32157534.jpg -o x.jpg --deleteSmaller, but not dramatically. Now try optimize_coding:
$ ls -l x.jpg
-rw-r--r-- 1 john john 6104 Nov 12 21:28 x.jpg
$ vipsthumbnail 42-32157534.jpg -o x.jpg[optimize_coding] --deleteA bit better. Now try strip as well:
$ ls -l x.jpg
-rw-r--r-- 1 john john 5780 Nov 12 21:30 x.jpg
$ vipsthumbnail 42-32157534.jpg -o x.jpg[optimize_coding,strip]Tiny! About half the size of where we started, with no quality loss.
$ ls -l x.jpg
-rw-r--r-- 1 john john 3600 Nov 12 21:27 x.jpg
Secondly, vipsthumbnail has a --crop option. This shrinks the image to completely fill the bounding box, then crops off any excess.
Thirdly, the jpeg writer now supports some of the mozjpeg optimization options, including trellis quantization. They can reduce thumbnail size and improve quality.
FInally, there's a --rotate option. This looks at any orientation flags in the image and applies them.
Hello,
ReplyDeleteI am trying to use vipsthumbnail on a Windows 7 system (64bit) but the batch option *.jpg reports only a message. It runs ok file by file though. Here is the command I use for testing:
I:/vipsthumbnail.exe *.jpg -o %s_tn.jpg -s 80x60
Any idea what is wrong?
Thanks for the otherwise great piece of software.
Oh, and in the VIPS Reference Manual page (http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips/index.html), the link to the VIPS website is incorrect.
ReplyDeleteMy first message has been mangled. Here is the error: VipsForeignLoad: file "*.jpg" not found
ReplyDeleteHi, vipsthumbnail does not do globbing. On Windows, you need to expand wildcards yourself. I found this article, it might help:
ReplyDeletehttp://superuser.com/questions/460598/is-there-any-way-to-get-the-windows-cmd-shell-to-expand-wildcard-paths
Thanks for telling me about the messed up URL, I've fixed it in the next version:
http://www.vips.ecs.soton.ac.uk/supported/7.42/doc/html/libvips/
We use github for issue tracking, that's proabbly the best place to ask questions:
https://github.com/jcupitt/libvips
Click on "issues" at the top-right.