Friday, January 30, 2009

Converting a lot of images

In my previous post, I explained how to convert a PDF file to an image. It is easy to convert one single file, but what if you have hundreds?

A couple of days ago, a friend of mine asked me if it was possible to convert a lot of images from one format to another without having to go through each one. He was making an RPG and the program he had accepted 24-bit BMP files only. He had hundreds (700+) of images to convert from GIF to BMP. He was doing it by opening each one in MS Paint and then saving it as a 24-bit BMP. He sure is glad that he asked me about it.

I immediately thought about the 'convert' command in Linux, but how could I get it to repeat for 700+ files? I don't know a lot about BASH scripting and I didn't want to learn just to get a list of files. Then, the 'find' command came to mind. In Linux, we use this command to find files if we know part of their names. Luckily, 'find' has an option that allows you to execute a command for every file that it finds. This suits perfect for our situation.

Let's say we have a folder. In that folder, we have lots of subfolders, each one containing lots of pictures (as in my friend's case). Being in that folder, we can execute the following command to convert all of the images in that folder and subfolders to a format that we want. Let's assume we are trying to convert from a GIF image to a BMP file.

find ./ -iname '*.gif' -exec convert '{}' '{}.bmp' \;

For every GIF image named 'input.gif', there will be a BMP output file named 'input.gif.bmp' in the same folder as 'input.gif'.

Let me explain the command. We tell 'find' to search for all GIF files (*.gif) in the current folder (./) and subfolders. The '-iname' option tells 'find' to do a case-insensitive search. Using the '-exec' option, we tell 'find' to execute a command for every file it finds. 'find' considers the command to be everything that follows '-exec' until a semicolon (;) is found. We are telling 'find' to execute 'convert' for every GIF file that it finds. The '{}' represents the path and filename of a file found. We then finish the command with '\;'. The backslash is used to escape the semicolon, so the shell does not interpret it as a special thing.

The output files that we get might not be 24-bit BMP files. To do this, I had to execute the following command (after I executed the one above):

find ./ -iname '*.gif.bmp' -exec convert '{}' +matte '{}' \;

Then, I deleted the original files using:

find ./ -iname '*.gif' -exec rm -f '{}' \;

This way of converting images is very powerful for other applications. Let's say you need to resize a lot of JPEG images. You can use:

find ./ -iname '*.JPG' -exec convert '{}' -resize '375' '{}' \;

This command will resize the images that it finds so that they are 375px width. The height is adjusted automatically by 'convert' to preserve the aspect ratio.

No comments:

Post a Comment