Bulk Resize Images Using Rake and ImageMagick

Feb 15, 2016 Ruby, Rake, ImageMagick

I'm occasionally left with a set of images of all different sizes, when ultimately I want to use them with a specific size. ImageMagick and Rake can help us accomplish this without having to mess with Photoshop.

A word of warning, though. We're going to crop to a specific gravity (and I'm only going to show you center cropping). So, if the focus of your images is all over the place, this likely won't work for you.

Step 01: Setup

If you have Rake and ImageMagick ready to go, great, move on! If not, let's get setup.

We'll assume you have a Gemfile. But if not, add it to your project root. You'll need at least these gems:

Gemfile

source 'https://rubygems.org'

gem 'rake'
gem 'imagemagick'

Once you've added those, install them to your project. You'll want Bundler to help with this.

$ bundle install

To configure rake, you just need a Rakefile at your project's root. Throw this quick one-liner in there.

Rakefile

Dir.glob(File.join('lib/tasks/**/*.rake')).each { |file| load file }

This essentially says we're adding any .rake file in the lib/tasks directory to rake.

Okay, let's move on.

Step 02: Your Files

Now, determine where your files are. I highly suggest making a copy of them, and dumping them all in the lib/assets/resize directory in your project (make it if you don't have it). That's what we'll use for our example.

Copies are always good in case we screw something up. Although we'll be careful, right?

Step 03: The Rake Task

Let's add the rake task to lib/tasks. We'll call it resize.rake, so it'll go to lib/tasks/resize.rake.

To start, I always like to make sure I'm point to right directory, before I start manipulating files. So, let's add this to the task:

lib/tasks/resize.rake

require 'fileutils'

task :resize do
  dir = File.expand_path('../../assets/resize', __FILE__)
  images = Dir.glob("#{dir}/*.*")
  puts images
end

You should be returned with a collection of the images you wish to manipulate. Let's move on.

We already have our collection of images, so we're good there. Next, let's make a directory to put the resized versions of the image in.

output_dir = "#{dir}/output"
FileUtils.mkdir(output_dir) unless Dir.exists?(output_dir)

Let's do it and then walk through it.

images.each do |file_path|
  next if File.directory? file_path
  image = Magick::Image::read(file_path).first
  thumb = image.resize_to_fill(200,200)
  filename = file_path.split('/').last
  thumb.write("#{output_dir}/#{filename}")
  puts "Resized: #{filename}"
end

Remember, images is our array of file paths to each image in the lib/assets/resize directory.

This just tells us to go the next item in the loop if we encounter a directory instead of an image.

Here we initialize an ImageMagic instance, which is what we'll use to manipulate the image.

This is the line that performs the resizing. If you change anything in this task, I suspect this is where you'll start. You can read more about your options here.

The next two lines actually write to file.

Above, we had stored filename in a variable so we could give some feedback, which is nice when we're dealing with many images at one time. And that's what's happening in the line above.


That's it! Altogether it looks like this:

lib/tasks/resize.rake

require 'fileutils'
require 'rmagick'

task :resize do
  dir = File.expand_path('../../assets/resize', __FILE__)
  images = Dir.glob("#{dir}/*.*")

  output_dir = "#{dir}/output"
  FileUtils.mkdir(output_dir) unless Dir.exists?(output_dir)

  images.each do |file_path|
    next if File.directory? file_path
    image = Magick::Image::read(file_path).first
    thumb = image.resize_to_fill(200,200)
    filename = file_path.split('/').last
    thumb.write("#{output_dir}/#{filename}")
    puts "Resized: #{filename}"
  end
end

Did you learn something or find this article interesting?

If so, why not