2

I have a directory with 10,000 JPEGs. I made a mistake while generating the files and now some are 720px × 480px, but they should all be 448px × 336px. The directory contains both the too large files and the correctly sized 448px × 336px. They need to be all the same size, so I need to scale the 720px × 480px images down to the correct 448px × 336px.

  • Every file must be 448px × 336px.
  • Since there are 10,000 files, it is difficult to check each one to see which are too big.

Is there some way to use ImageMagick or a similar batch tool to selectively only resize those wrong-sized images?

3

You can find the files that are 720 pixels wide with the following command:

identify -format '%w %i\n' *.jpg | awk '/^720/ {print $2}'

Possibly use this variation if there are really a lot of files that might lead to the *.jpg expansion to give the dreaded "argument list too long" error:

find -name '*.jpg' -exec identify -format '%w %i\n' {} + | awk '/^720/ {print $2}'

With that list you can then resize those files, e.g.:

find -name '*.jpg' -exec identify -format '%w %i\n' {} + | awk '/^720/ {print $2}' | xargs -I {} convert -resize 488x336! {} {}

The exclamation mark ! after the 488x336 forces the new image to be exactly that size; without it the aspect ratio is preserved and the given size are maximum dimensions for width and height.

3

One could hope that

convert in.jpg -resize "448x336!" out.jpg

would not touch the file if the size is already right?
Unfourtunately not - but thinking about the way the imagemagic command line format works, that is not surprising.

So the image dimensions of each file needs to be checked first. Now, we want to use ImageMagic, which has the command identify for that purpose;

identify -format "%wx%h\n" file.jpg

shows just the size in WxH format, like 448x336.

We want to resize if the size is not 448x336. In this case, we use convert to resize to 448x336 - we have to tell convert that we want to resize even if it means changing the aspect ratio to force the image to the new dimensions - we do that by adding a ! as an option/flag in the size specification:

convert in.jpg -resize "448x336!" out.jpg

does the resizing we need. But we do not have a fixed file name for the output. Let's take the original name and insert -res before the .jpg, like in-res.jpg:

convert in.jpg -resize "448x336!" -set filename:path "%d/%t-res.%e" "%[filename:path]"

We use the command find to traverse the directories for '.jpg' images - or ".JPG". The identify part is run in a shell to use the test command, [ ... ]. I also use a shell for the convert command, which is run if the first -exec action (not option) succeded. In this case it's only to run a second command after resizing, showing a message for each resized file.

find  . -type f -iname "*.jpg" -exec bash -c \
    '[ $(identify -format "%wx%h\n" "{}") != 448x336 ]' \;  -exec bash -c \
    'convert "{}" -resize "448x336!" -set filename:path "%d/%t-res.%e" \
    "%[filename:path]" ; echo "Resized {}"' \; 

Instead of the second bash, one could use plain -exec convert ..., and add a new action, like -print or -ls, to show the names of resized files.

The command is one line technically (shown with continuation lines to avoid scrolling).
And, after this explanation, somehow I feel the line is still not easy to read...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.