Created
July 29, 2012 14:35
-
-
Save stanislaw/3199258 to your computer and use it in GitHub Desktop.
Ruby-vips vs Oil
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
require 'rubygems' | |
gem 'ruby-vips' | |
gem 'oil' | |
require 'vips' | |
require 'oil' | |
require 'benchmark' | |
require 'stringio' | |
module Procedure | |
NUMBER = 1 | |
IM_SIZE = 100 | |
class << self | |
def run processor, img, best_of | |
result = nil | |
result = Benchmark.bmbm do |b| | |
(1 .. best_of).each do |number| | |
b.report number.to_s do | |
NUMBER.times do | |
send processor, img | |
end | |
end | |
end | |
end | |
output result | |
end | |
def output result | |
result = (result.map(&:to_a).map{|el| el[5]}.min * 1000).to_i | |
"#{result}ms" | |
end | |
class VipsProcessor | |
HIGH_QUALITY = false | |
SHARPEN_MASK = begin | |
conv_mask = [ | |
[ -1, -1, -1 ], | |
[ -1, 24, -1 ], | |
[ -1, -1, -1 ] | |
] | |
::VIPS::Mask.new conv_mask, 16 | |
end | |
attr_reader :src, :image | |
def initialize src | |
@src = src | |
resize_to_limit IM_SIZE, IM_SIZE | |
end | |
def resize_to_limit(new_width, new_height) | |
manipulate! do |image| | |
image = resize_image(image,new_width,new_height) if new_width < image.x_size || new_height < image.y_size | |
image | |
end | |
end | |
def manipulate! | |
@image ||= VIPS::Image.new(src) | |
@image = yield @image | |
rescue => e | |
raise("Failed to manipulate file, maybe it is not an image? Original Error: #{e}") | |
end | |
def resize_image(image, width, height, min_or_max = :min) | |
ratio = get_ratio image, width, height, min_or_max | |
if jpeg? # find the shrink ratio for loading | |
shrink_factor = [8, 4, 2, 1].find {|sf| 1.0 / ratio >= sf } | |
shrink_factor = 1 if shrink_factor == nil | |
image = VIPS::Image.jpeg src, | |
:shrink_factor => shrink_factor, :sequential => true | |
ratio = get_ratio image, width, height, min_or_max | |
elsif png? | |
image = VIPS::Image.png src, :sequential => true | |
end | |
if ratio > 1 | |
image = image.affinei_resize :nearest, ratio | |
else | |
if HIGH_QUALITY | |
if ratio <= 0.5 | |
factor = (1.0 / ratio).floor | |
puts "int shrink by factor = #{factor}" | |
image = image.shrink(factor) | |
image = image.tile_cache(image.x_size, 1, 10) | |
ratio = get_ratio image, width, height, min_or_max | |
end | |
image = image.affinei_resize :bilinear, ratio | |
image = image.conv SHARPEN_MASK | |
else | |
image = image.affinei_resize :nearest, ratio | |
end | |
end | |
image | |
end | |
def get_ratio(image, width,height, min_or_max = :min) | |
width_ratio = width.to_f / image.x_size | |
height_ratio = height.to_f / image.y_size | |
[width_ratio, height_ratio].send(min_or_max) | |
end | |
def jpeg?(path = src) | |
path =~ /.*jpg$/i or path =~ /.*jpeg$/i | |
end | |
def png?(path = src) | |
path =~ /.*png$/i | |
end | |
end | |
def vips_jpg src | |
processor = VipsProcessor.new(src) | |
output = processor.resize_to_limit IM_SIZE, IM_SIZE | |
output.jpeg("vips.#{src}") | |
end | |
def vips_png src | |
processor = VipsProcessor.new(src) | |
output = processor.resize_to_limit IM_SIZE, IM_SIZE | |
output.png("vips.#{src}") | |
end | |
def oil_jpg src | |
jpeg = Oil::JPEG.new(im(src), IM_SIZE, IM_SIZE) | |
File.open("oil.#{src}", 'wb') do |f| | |
jpeg.each { |data| f << data } | |
end | |
end | |
def oil_png src | |
png = Oil::PNG.new(im(src), IM_SIZE, IM_SIZE) | |
File.open("oil.#{src}", 'wb') do |f| | |
png.each { |data| f << data } | |
end | |
end | |
def im src | |
File.open src, 'rb' | |
end | |
end | |
end | |
best_of = 1 | |
#result_vips_jpg = Procedure.run :vips_jpg, "peacock.jpg", best_of | |
result_vips_jpg = Procedure.run :vips_jpg, "wtc.jpg", best_of | |
result_vips_png = Procedure.run :vips_png, "peacock.png", best_of | |
#result_oil_jpg = Procedure.run :oil_jpg, "peacock.jpg", best_of | |
result_oil_jpg = Procedure.run :oil_jpg, "wtc.jpg", best_of | |
result_oil_png = Procedure.run :oil_png, "peacock.png", best_of | |
puts "Ruby-vips #{VIPS::VERSION} built against libvips #{VIPS::LIB_VERSION}" | |
print "ruby-vips, jpeg image: " | |
puts result_vips_jpg | |
print "ruby-vips, png image: " | |
puts result_vips_png | |
print "oil, jpeg image: " | |
puts result_oil_jpg | |
print "oil, png image: " | |
puts result_oil_png |
If I uncomment :sequential => true
, I get the following on Mac OS X Lion:
Stanislaws-MacBook-Air:ruby-vips-vs-oil Stanislaw$ ./ruby-vips-vs-oil.rb
Rehearsal -------------------------------------
1 0.060000 0.010000 0.070000 ( 0.076529)
2 0.070000 0.010000 0.080000 ( 0.066369)
3 0.050000 0.010000 0.060000 ( 0.063638)
---------------------------- total: 0.210000sec
user system total real
1 0.060000 0.000000 0.060000 ( 0.062379)
2 0.060000 0.010000 0.070000 ( 0.062331)
3 0.060000 0.010000 0.070000 ( 0.061656)
Rehearsal -------------------------------------
1 /Users/Stanislaw/.rvm/gems/ruby-1.9.3-p194/gems/ruby-vips-0.3.0/lib/vips/writer.rb:66:in `write_internal': VIPS error: vips_image_get: field "icc-profile-data" not found (VIPS::Error)
VipsSequential: non-sequential read --- at position 3808 in file, but position 0 requested
vips2png: unable to write "vips.peacock.png"
from /Users/Stanislaw/.rvm/gems/ruby-1.9.3-p194/gems/ruby-vips-0.3.0/lib/vips/writer.rb:66:in `write'
from /Users/Stanislaw/.rvm/gems/ruby-1.9.3-p194/gems/ruby-vips-0.3.0/lib/vips/writer.rb:269:in `invoke_writer'
from /Users/Stanislaw/.rvm/gems/ruby-1.9.3-p194/gems/ruby-vips-0.3.0/lib/vips/writer.rb:245:in `png'
from ./ruby-vips-vs-oil.rb:129:in `vips_png'
from ./ruby-vips-vs-oil.rb:30:in `block (4 levels) in run'
from ./ruby-vips-vs-oil.rb:29:in `times'
from ./ruby-vips-vs-oil.rb:29:in `block (3 levels) in run'
from /Users/Stanislaw/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/benchmark.rb:280:in `measure'
from /Users/Stanislaw/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/benchmark.rb:257:in `block in bmbm'
from /Users/Stanislaw/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/benchmark.rb:255:in `each'
from /Users/Stanislaw/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/benchmark.rb:255:in `inject'
from /Users/Stanislaw/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/benchmark.rb:255:in `bmbm'
from ./ruby-vips-vs-oil.rb:26:in `run'
from ./ruby-vips-vs-oil.rb:157:in `<main>'
Gists act like a common git repositories.
You need to fork this gist and run (replace with your numbers)
git clone git://gist.github.com/3199258.git ruby-vips-vs-oil
cd ruby-vips-vs-oil # It is just a common git repo.
I was running fast, so It could be a mistake somewhere, please check the overall code.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
John, here is my first result:
Ruby-vips 0.3.0 built against libvips 7.30.0-Sun Jul 22 22:44:12 EEST 2012
ruby-vips, jpeg image: 62ms
ruby-vips, png image: 911ms
oil, jpeg image: 34ms
oil, png image: 361ms
Png sequential mode support is commented because of a bug - see next comment below.
Subscribing you to this gist's updates: @jcupitt.