Reformat images with bash

With macOS there’s a CLI tool called sips that’s been around since Mac OS X 10.3 Panther. That’s from 2003. Yep, pretty old news. I’m gonna focus on that.

This sets the ouput image to jpg with a quality of 80 and a maximum width and height of 3000 with maintained aspect ratio.

sips -s format jpeg -s formatOptions 80 -Z 3000 image.NEF --out image.jpg

Batch conversions

There’s a lot of ways of doing this. I’ll be doing an example with a for loop and then another with find and xargs piped and another with a while loop.

Loops

Put it into a loop to batch convert multiple images with for loop. Remember that I write in bash. And there’s a lot of pitfalls involving for loops, rant about why you shouln’t use a for loop. And http://mywiki.wooledge.org/BashPitfalls#for_f_in_.24.28ls_.2A.mp3.29

For loop

I will show you one example that is ok to use with a for loop:

for file in *.NEF; do sips -s format jpeg -Z 50% "$file" --out "${file%.NEF}-small.jpg"; done;

While loop

Why you should use while instead of for loops:

find -E . -regex '.*2018.*$' -print0 | while read -r -d '' file; do sips -s format jpeg -Z 50% "$file" --out "${file%.NEF}-small.jpg"; done;

There’s other ways of doing the while loop, of course. But I chose to just show this one.

Find and xargs and some regex

This is actually the way I like the most. It feels most flexible and have a reasonable syntax. At least when you understand how xargs works 😬.

Going through directories recursively and convert files with the filename ending in .NEF:

find -E ./* -type f -regex '.*\.NEF$' -print0 | xargs -0 -I {} sips -s format jpeg -Z 50% {} --out "{}-small.jpg"

Another clever alternative involving a check if it’s an image with file and grep, taken from here. It also puts the resulting images into the directory ./thumbs. Here I also use the -exec option which execute a command on every file found.

find . -exec file {} ";" | grep -i image | cut -d ":" -f 1 | xargs -I {} sips -Z 50% "{}" --out ./thumbs/

Takes all files ending with .jpg and that have the text 2018 in it and puts them into a folder named 2018, 50% smaller.

find -E ./* -regex '.*2018.*\.jpg$' -print0 | xargs -0 -I {} sips -Z 50% "{}" --out ./2018/

Alternative image tool

If you’re not on a mac or just don’t wanna use sips, there’s the mogrify tool from imagemagick which I’ve been using before I discovered sips.

References