ruby-vips
| Language | Ruby (FFI binding of the C library) |
|---|---|
| License | MIT (gem), LGPL 2.1+ (libvips) |
| Repository | github.com/libvips/ruby-vips |
| Documentation | rubydoc.info/gems/ruby-vips, libvips reference |
| Depends on | libvips (with libspng or libpng for PNG) |
| Read / write | yes / yes, 1-16 bit, palette, text chunks |
ruby-vips calls libvips through FFI. libvips processes images in a streaming, multi-threaded pipeline, so it’s several times faster than ImageMagick and uses a fraction of the memory. Rails Active Storage uses it by default for image variants (through the image_processing gem).
For PNG it reads and writes 8 and 16-bit images, writes palette PNGs with libimagequant, and exposes text chunks as metadata fields. You need libvips installed on the system; the gem itself contains no C code.
Installation#
# Debian / Ubuntu
sudo apt install libvips42
# macOS
brew install vips
# then
gem install ruby-vips
On Windows the gem pulls in the MSYS2 build of libvips.
Basic usage: read, resize and save a PNG#
require "vips"
image = Vips::Image.new_from_file("in.png")
puts "#{image.width} x #{image.height}, #{image.bands} bands, alpha: #{image.has_alpha?}"
resized = image.resize(0.5) # scale factor
resized.write_to_file("out.png", compression: 9)
new_from_file only reads the header; pixels are processed when you write the result.
How to make a PNG thumbnail#
Vips::Image.thumbnail opens, shrinks and sharpens in one step and is the fastest way to make thumbnails:
require "vips"
thumb = Vips::Image.thumbnail("in.png", 300) # fit within 300 px wide
thumb.write_to_file("thumb.png")
How to save a palette (8-bit) PNG#
image = Vips::Image.new_from_file("in.png")
image.write_to_file("palette.png", palette: true, Q: 90, effort: 10)
palette: true quantizes to 256 colors or fewer with libimagequant; files are often 60-80% smaller. bitdepth: 4 or 2 gives smaller palettes.
How to read PNG text chunks#
libvips names text chunks png-comment-<index>-<keyword>:
image = Vips::Image.new_from_file("in.png")
image.get_fields.grep(/\Apng-comment-/).each do |name|
puts "#{name}: #{image.get(name)}"
end
How to convert PNG to JPEG#
image = Vips::Image.new_from_file("in.png")
image = image.flatten(background: [255, 255, 255]) if image.has_alpha?
image.write_to_file("out.jpg", Q: 85)
How to encode a PNG in memory#
png_bytes = image.write_to_buffer(".png", compression: 6)
image2 = Vips::Image.new_from_buffer(png_bytes, "")
Tips#
- Pass
access: :sequentialtonew_from_filewhen you read the image once from top to bottom: it lowers memory use for large files. keep: :noneon save drops all metadata (Exif, XMP, ICC, text).- Check
Vips.version_stringto see which libvips version is installed: some options need a recent release.