Archive

Posts Tagged ‘ImageMagick’

ruby from the command line, taking it too far

September 24th, 2009 No comments

In my last post I looked at using -e to run scripting languages directly from the command line. Just as I was not sure what would make ruby a good candidate for an example, a colleague from work scoffed at some image manipulation suggestion I made which I claimed would take only half an hour to code. If something takes 30 minutes to code then it surely can be run directly from the command line?

The problem is such, given a company logo of a particular aspect ration, create a new logo, with a different aspect ratio and fill out the logo with the predominant color (most used color) from the original logo. Of course there are other ways around this like setting transparent backgrounds and default to something neutral like white but in this case I suggested that using the predominant color of the logo would maintain the branding of the company logo.

A search on the internet for “color quantization”, “color count” and “color histogram” quickly directed me to ImageMagick and in this case RMagick for ruby bindings to the library. More info can be found at http://www.imagemagick.org/RMagick/doc/

As a starting point I simply required the library, instantiated an image and returned the width and height of it

ruby -e 'require "rubygems"; require "RMagick"; \
img = Magick::ImageList.new("filename.gif"); puts img.columns; puts img.rows'
160
30

Ok having to require rubygens and RMagick as well as using the package name Magick starts making the command line a little bit unwieldily. Considering up to this moment I had not done anything, it was going to get worse. First some code to return the histogram of colors and how many pixels use it, sorted to get the main color, then one which is used by the most pixels

main_color = img.color_histogram.sort{|a,b| b[1] <=> a[1]}.firtst

then create a new larger image in this case 2 x width and 6 x height, fill it’s background with the main color, create a drawing object, create an image composite using the original image and place it so that it will be centered on the new larger image, finally draw the composite on the new larger image and write to disk

l_img = Image.new(img.columns*2, img.rows*6) {
  self.background_color = main_color[0]
};
gc = Magick::Draw.new;
gc.composite((l_img.columns - img.columns)/2,(l_img.rows - img.rows)/2,0,0,img);
gc.draw(l_img);
l_img.write("large_file.gif")

to make the work worth while, wrap it in a find to look for all gif’s in a given directory tree, and create new large_<filename>.gif image

ruby -e ' \
require "rubygems"; \
require "find"; \
require "RMagick"; \
include Magick; \
Find.find("images") {|file| \
  if file =~ /gif$/ then \
    img = ImageList.new(file); \
    main_color = img.color_histogram.sort{|a,b| b[1] <=> a[1]}.first; \
    l_img = Image.new(img.columns*2, img.rows*6) {self.background_color = main_color[0]}; \
    gc = Magick::Draw.new; \
    gc.composite((l_img.columns-img.columns)/2,(l_img.rows-img.rows)/2,0,0,img);  \
    gc.draw(l_img); \
    l_img.write(File.join(File.dirname(file), "large_"+File.basename(file))) \
  end \
}'

or if you want to just run this and use some images directly from the internet try this

ruby -e 'require "rubygems"; require "RMagick"; include Magick; \
img = ImageList.new("http://cdn-0.nflximg.com/us/layout/signup/950/header/netflix_logo.gif"); \
main_color = img.color_histogram.sort{|a,b| b[1] <=> a[1]}.first; \
l_img = Image.new(img.columns*2, img.rows*6){self.background_color = main_color[0]}; \
gc = Magick::Draw.new; \
gc.composite((l_img.columns-img.columns)/2,(l_img.rows-img.rows)/2,0,0,img); \
gc.draw(l_img); img.write("original.gif"); l_img.write("large.gif")'

and the results are

Ok so in this case I am taking the command line programming a little too far. I did manage to do the whole task above without ever opening up a text editor but I had some clever command line tricks up my sleeve which I will cover in a future post. Still it is good to know that such power is available from the command line.