Python Tutorial – Batch Image Resizing

Every once and a while I come across a simple task that deserves a script. Instead of using a language I know, this is often a great opportunity to pick up a new language or get a refresher on one I haven’t used in a long time. In this case, I needed to resize an entire directory of images. There are tons of free tools out there to do this, but where’s the fun in that? Also, I could have whipped this tool up very quickly in a language I know, like C#, however I haven’t used Python in several years and I decided it was time for a refresher.

For this tutorial, I’m using Python 2.6.5 and the Python Image Library (PIL). If you’re reading this tutorial, I’m sure you’ve got the first one installed and ready to go. The second one, PIL, is a free download.

I decided to create a simple command line application for this task. It will take three arguments: -d, -w, and -h. -d is the directory where your images are located. -w is the output image’s desired width. -h is the output image’s desired height. It will be used like this:

> python BatchImageResize.py -d "C:\MyImages" -w 1024 -h 768

The first thing we’re going to have to do is parse the command line arguments. Fortunately Python comes with a function, getopt, that makes this very simple.

import getopt, sys

# Parse the command line arguments
opts, args = getopt.getopt(sys.argv[1:], "d:w:h:")

getopt requires two parameters. The first is the list of arguments passed into the script. We’re skipping the first argument because that’s just the name of the script being executed. The second is the shorthand notation for each command line option. Since each option requires extra information, like a directory path, we need to stick a colon after each one. If the option were just a flag, with no extra info, the colon would be omitted. This returns two things. The first is a collection of tuples containing the argument and the extra information. The second contains all the other arguments that didn’t match what we were looking for. getopt has an optional third parameter that lets you specify a long name for each argument, but it’s not necessary for this tutorial.

Now that we’ve got the command line arguments parsed, we need to read the values into some variables. And while we’re at it, we might as well stick in a little bit of validation.

import getopt, sys

# Parse the command line arguments
opts, args = getopt.getopt(sys.argv[1:], "d:w:h:")

directory = ""
width = –1
height = –1

# Read the command line arguments
for opt, arg in opts:
  if opt == ‘-d’:
    directory = arg
  elif opt == ‘-w’:
    width = int(arg)
  elif opt == ‘-h’:
    height = int(arg)

# Check that the options were all set
if directory == "" or width == –1 or height == –1:
  print "Invalid command line arguments.\
  -d [directory] -w [width] -h [height] required"

  exit())

All we’re doing here is iterating through every specified option and saving the value to some variables. The width and height will need to be converted to integers for later use.

We’re now ready to actually convert all the images.

import os, getopt, sys, Image

# Parse the command line arguments
opts, args = getopt.getopt(sys.argv[1:], "d:w:h:")

directory = ""
width = –1
height = –1

# Read the command line arguments
for opt, arg in opts:
  if opt == ‘-d’:
    directory = arg
  elif opt == ‘-w’:
    width = int(arg)
  elif opt == ‘-h’:
    height = int(arg)

# Check that the options were all set
if directory == "" or width == –1 or height == –1:
  print "Invalid command line arguments.\
  -d [directory] -w [width] -h [height] required"

  exit()
 
# Iterate through every image in the directory and resize them
for file in os.listdir(directory):
  print "Resizing image " + file
  # Open the image
  img = Image.open(directory + "\\" + file)
  # Resize it
  img = img.resize((width, height), Image.BILINEAR)
  # Save it back to disk
  img.save(directory + "\\resized" + file)

This is actually the entire contents of the script. We first iterate through every file in the specified directory. We then open, resize, and save the image using PIL. There are several resizing techniques available, however I chose Bilinear because it yields perfectly satisfactory results. Every file will be saved to the same location it came from except with “resized” appended on the beginning.

And that’s it. Python has some great support for easily and quickly creating powerful command line applications. Thanks to the active community of developers there are libraries, like PIL, that will do pretty much anything you’ll need.

Leave a Reply

Your email address will not be published. Required fields are marked *