Search code examples
macosbashterminalimage-resizingsips

Bin Bash Terminal script to resize PNG/CR2/JPG images using Mac SIPS with space saving check


I made a cool little script to take my massive photo collection of JPG/PNG/CR2 (raw files) and convert them into MacBook Pro Retina resolution of 2880px JPEGs.

This allows me to have all my pics on my computer while storing the giant originals on an external hard drive. Best of all the pics look fantastic because they're resized to my exact physical screen resolution 2880px wide!

You can easily adapt the script to your own needs...


OK so on to my question....

My pictures on my external hard drive are stored like this:

(Hard drive root)

Pictures

2013-05 Wedding in Vermont

img_0001.jpg

img_0002.jpg

2014-10 Las Vegas Trip

img_0001.cr2

img_0002.cr2

...

Right now the script OVERWRITES the original files... so I always need to make a complete copy of all my pictures to a 2nd drive and then run the script. Is there an easy way to make the script re-create the entire directory structure and write the new files out to a new folder/drive while maintaining the directory structure?

THANKS FOR YOUR HELP!

##################################
#!/bin/bash - resize2880px.sh (It's for Mac OS X computers)
# By Jason Fox of GetFoxy.com 2014 - hit me at jfox {at} foxnv.com if you have questions
# This script converts all PNG/JPG/CR2 files to JPG at a max resolution of 2880px (saving tons of space in the process).
# run it like this:
# 0. Save this script in your Documents Folder as resize2880px.sh
# 1. Open Terminal and CD into the directory of pictures to shrink
# 2. paste in:  find . -type f \( -iname "*.png" -o -iname "*.jpg" -o -iname "*.cr2" \) -exec sh ~/Documents/resize2880px.sh {} \;
# 3. If you have the awesome JPEGMini app... use it now to further save space! ;)

#the sizes to convert to
width=2880                                                                              
height=2880

#theFile given in input   
theFile=$1
echo ""
echo "$theFile"

#using sips to retrieve the width & height            
#size[0] = width
#size[1] = height
size=($(sips -g pixelWidth -g pixelHeight "$theFile" | grep -o '[0-9]*$'))                     

if [[ ${size[0]} -le $width && ${size[1]} -le $height ]];
    then echo "Width = ${size[0]} & Height = ${size[1]} SO... W<=$width H<=$height - no resize - just JPG convert"
    sips -s format jpeg "$theFile" --out "$theFile-t2880px.jpg"
elif [[ ${size[0]} -gt $width && ${size[1]} -le $height ]];
    then echo "Width = ${size[0]} & Height = ${size[1]} SO... W>$width H<=$height - Run SIPS $width JPG conversion"
    sips -Z 2880 -s format jpeg "$theFile" --out "$theFile-t2880px.jpg"
elif [[ ${size[0]} -le $width && ${size[1]} -gt $height ]];
    then echo "Width = ${size[0]} & Height = ${size[1]} SO... W<=$width H>$height - Run SIPS $width JPG conversion"
    sips -Z 2880 -s format jpeg "$theFile" --out "$theFile-t2880px.jpg"
elif [[ ${size[0]} -gt $width && ${size[1]} -gt $height ]];
    then echo "Width = ${size[0]} & Height = ${size[1]} SO... W>$width H>=$height - Run SIPS $width JPG conversion"
    sips -Z 2880 -s format jpeg "$theFile" --out "$theFile-t2880px.jpg"
else echo "Something is wrong."
fi

# Determine number of file system blocks used to store the original and new files
origfilesize=$(ls -s "$theFile" | awk '{print $1}')
newfilesize=$(ls -s "$theFile-t2880px.jpg" | awk '{print $1}')

if [[ $origfilesize -le $newfilesize ]];
    then echo "$origfilesize is less than or equal to $newfilesize - no space saved so deleting the new file"
    rm "$theFile-t2880px.jpg"
else
    echo "$origfilesize is greater than $newfilesize - deleting original file"
    rm "$theFile"   
fi

Solution

  • Sure. Either set a variable in the script at the top, or pass in a new parameter that says where the new tree structure is to be created. Or do a mixture, and set a default new root directory but allow the user to overwrite it with a second parameter on the command line like this:

    newroot=${2:-~/Desktop/resized}
    

    Then use dirname to get the name of the directory that each input image is in, like this:

    dir=$(dirname "/users/bozo/tmp/image.jpg")
    

    that will give you

    /users/bozo/tmp
    

    now put the new directory path on the front

    newpath="$newroot/$dir"
    

    and make it, including all intervening folders and ignoring errors with

    mkdir -p "$newpath" 2> /dev/null
    

    and change your commands to output like this

     file=$(basename "input image path")
     sips ... --out "$newpath/$file"