1
0
Fork 0
forked from OpenNeo/impress

optimize outfit image generation - 4x speed boost on my box

Use the ImageMagick flatten command to generate the output all at
once instead of compositing each layer individually, and download
the layers in parallel. On my box, saving roopal27 five times took
a total of 30 seconds before, whereas now it takes 7 seconds. I
expect it to be even better on the production box, where latency
is even lower.
This commit is contained in:
Emi Matchu 2012-07-27 23:07:20 -04:00
parent 28e44d0abd
commit 42827362b6
4 changed files with 25 additions and 18 deletions

View file

@ -46,6 +46,8 @@ gem "mini_magick", "~> 3.4"
gem "fog", "~> 1.1.2" gem "fog", "~> 1.1.2"
gem "carrierwave", "~> 0.5.8" gem "carrierwave", "~> 0.5.8"
gem "parallel", "~> 0.5.17"
group :development_async do group :development_async do
# async wrappers # async wrappers
gem 'eventmachine', :git => 'git://github.com/eventmachine/eventmachine.git' gem 'eventmachine', :git => 'git://github.com/eventmachine/eventmachine.git'

View file

@ -149,6 +149,7 @@ GEM
open4 (1.3.0) open4 (1.3.0)
openneo-auth-signatory (0.1.0) openneo-auth-signatory (0.1.0)
ruby-hmac ruby-hmac
parallel (0.5.17)
polyglot (0.3.3) polyglot (0.3.3)
rack (1.2.5) rack (1.2.5)
rack-fiber_pool (0.9.2) rack-fiber_pool (0.9.2)
@ -256,6 +257,7 @@ DEPENDENCIES
newrelic_rpm newrelic_rpm
nokogiri (~> 1.5.2) nokogiri (~> 1.5.2)
openneo-auth-signatory (~> 0.1.0) openneo-auth-signatory (~> 0.1.0)
parallel (~> 0.5.17)
rack-fiber_pool rack-fiber_pool
rails (= 3.0.5) rails (= 3.0.5)
rdiscount (~> 1.6.5) rdiscount (~> 1.6.5)

View file

@ -138,25 +138,28 @@ class Outfit < ActiveRecord::Base
# file. # file.
def create_image!(output) def create_image!(output)
unless image_layers.empty? unless image_layers.empty?
base_layer = image_layers.first temp_image_files = Parallel.map(image_layers, :in_threads => 8) do |swf_asset|
above_layers = image_layers[1..-1] image_file = Tempfile.open(['outfit_layer', '.png'])
write_temp_swf_asset_image!(base_layer, output) write_temp_swf_asset_image!(swf_asset, image_file)
output.close image_file.close
image_file
end
unless above_layers.empty? # Here we do some awkwardness to get the exact ImageMagick command we
Tempfile.open(['outfit_overlay', '.png']) do |overlay| # want, though it's still less awkward than handling the command
above_layers.each do |layer| # ourselves. Give all of the temporary images as input, flatten them and
overlay.open # write them to the output path.
write_temp_swf_asset_image! layer, overlay command = MiniMagick::CommandBuilder.new('convert')
overlay.close temp_image_files.each { |image_file| command.push image_file.path }
command.layers 'flatten'
command.push output.path
previous_image = MiniMagick::Image.open(output.path) # Though the above command really is sufficient, we still need a dummy
overlay_image = MiniMagick::Image.open(overlay.path) # image to handle execution.
output_image = previous_image.composite(overlay_image) output_image = MiniMagick::Image.new(output.path)
output_image.write output.path output_image.run(command)
end
end temp_image_files.each(&:unlink)
end
else else
output.close output.close
end end

BIN
vendor/cache/parallel-0.5.17.gem vendored Normal file

Binary file not shown.