All formats

ruby-vips

LanguageRuby (FFI binding of the C library)
LicenseMIT (gem), LGPL 2.1+ (libvips)
Repositorygithub.com/libvips/ruby-vips
Documentationrubydoc.info/gems/ruby-vips, libvips reference
Depends onlibvips (with libspng or libpng for PNG)
Read / writeyes / 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#

Shell
# 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#

Ruby
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:

Ruby
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#

Ruby
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>:

Ruby
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#

Ruby
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#

Ruby
png_bytes = image.write_to_buffer(".png", compression: 6)
image2 = Vips::Image.new_from_buffer(png_bytes, "")

Tips#