Penguins, we're at 20% ground force operational status.

A Bash script to force Image Magick to use zero-indexing when it converts GIF to JPG

Date/Time Permalink: 05/14/13 12:33:38 pm
Category: HOWTOs and Guides

I can't believe this hasn't been solved somewhere before, but I was converting a .gif to individual image frames for a project when I discovered this behavior.

UPDATE: Guess what??? image magick CAN output zero-padded files, just by doing:

% > convert mygif.gif mygif_%05d.jpg

no wonder I couldn't find it by Googling. I was looking for an option switch. But you'd still need to find out how many zero-spaces to use for individual gifs for each case. My thing is, I hate remembering fifty commands when I can name a script after what I want it to do and forget about it.

We now return you to my folly, which you can still adapt for programs which don't zero-pad:

The command:
%> convert mygif.gif mygif.jpg

What it does with the file names:

mygif-0.jpg
mygif-100.jpg
mygif-101.jpg
mygif-102.jpg
mygif-103.jpg
mygif-104.jpg
mygif-105.jpg
mygif-106.jpg
mygif-107.jpg
mygif-108.jpg
mygif-109.jpg
mygif-10.jpg
mygif-110.jpg
...

What it should do with the file names:

mygif-000.jpg
mygif-001.jpg
mygif-002.jpg
mygif-003.jpg
...

That's because not all programs that are going to handle these image frames know to ignore Bash-file-sorting order and substitute logical numeric file-sorting.

And I'm searching all over the place, but there doesn't seem to be an option in convert to force this file-naming convention, or else I'm not searching for it right. Anyway, this script whacks the file names into shape:

#!/bin/bash

#
#  Apparently when you call image magick to convert gif to jpg
#    it doesn't use zero-indexing to ensure the files list
#    in order for each program.
#
#  So... ouch!
#

for FILE in $(ls *.gif)
  do
    DIGITS=$(identify $FILE | wc -l | wc -c)
    convert $FILE ${FILE%gif}jpg
      for JFILE in $(ls *.jpg)
      do
        NUM=$(echo $JFILE | cut -d- -f2 | cut -d. -f1)
        PSTRING="%0"$DIGITS"d"
        NEWNUM=$(printf $PSTRING $NUM)
        SEDLINE="s/-.*\./-"$NEWNUM"\./g"
        mv $JFILE $(echo $JFILE | sed $SEDLINE)
      done
  done

exit 0

You'll note the convoluted series of variable abuse. That's because of the various quirks of the individual text-mode tools.

First, $DIGITS finds out how many zeros to index for the file names. Since you want this to work on any gif with any number of frames, we have to use Image Magick's identify command on the gif, pipe it through wc -l to count the frames, then use wc -c to find out how many digits that number is. As you can see, we end up with one superfluous zero here, but the hell with it at this point, it does the job.

I also have to extract the number from the file name, and drop it into the $NUM variable.

In a perfect world, I could just expect to say something like:

% > mv $FILE $(echo $FILE | sed 's/-$NUM\./-printf "%0$DIGITSd" $1./g')

But no.

Second, sed won't take a mixed variable string like "s/$PATTERN1/$PATTERN2/g". So you have to put the sed argument in a variable.

But we're zero-indexing here, and the only tool I know of to do that is printf, and guess what? printf also won't take Bash variables in its argument string! So now you have to make $PSTRING to build the argument to printf so you can make $SEDSTRING to build the argument to sed...

So, is that done now? I'm crazy for doing it this way, aren't I?

It does work. If you use it, be sure to use it in its' own special little directory so it doesn't wantonly mess with other unrelated files...

Follow me on Twitter for an update every time this blog gets a post.
Stumble it Reddit this share on Facebook

suddenly the moon