Decided to copy decades of digital photos from Photos (nee iPhoto) to NAS. If your client doesn’t decode and your server doesn’t transcode HEIC then you’ll need to convert HEIC image files. Unlike iPhoto, Photos makes the task of exporting the library in a sane manner with keywords intact unnecessarily impossible, or nearly so. Turns out some brave person created a Python script, osxphotos, to accomplish that task. It’s certainly robust and installation failed for me using Mac Ports (likely due to the age of my system and plenty of outdated deps and other crud from unmaintained packages). But I digress. The instructions for ‘pip’ worked no sweat.
This particular script doesn’t rely on osxphotos, but it does use exiftool and heif-dec (which is provided by libheif). Where I got libheif I don’t know. I initially was going to try imagemagick but that also would not install from Mac Ports (c’mon guys). Could be re-written to use imagemagick I’m sure, so long as it can decode HEIC.
Read through and understand what this script does before running! You won’t want it to touch your Photos Library.photolibrary so be sure it is no where below your starting directory first. This script then finds all file paths ending in “.HEIC” which is the iPhone naming scheme. Perhaps find...-iname would be better. Next, check to see if a .jpg file with the same name in the same directory exists, if so suffix the new name, then convert the heic image as a jpg. Last step is to mv (move & rename) the original into a directory created at pwd (present working directory), adding YYYYMMDD- from the file’s Create Date exif tag as a prefix so it will be possible to relocate them should that become something someone desires. My directory tree drothers for digital photos are Y>M>D>files, which explains the preceding logic. As it is here this script writes a file in pwd with each command it would otherwise execute. Change $dryrun to, well, anything else to execute the conversion(s) instead.
#!/bin/bash
# Are we dry running first? Or fsck it we'll do it live!
dryrun="true"
# We are working here. Please be sure to cd to the proper dir as there is no prompt for assurance!
here=`pwd`
# Quality level of jpg output. You can adjust from stdin, though there is no check against it.
qlvl=90
if [ $1 ]; then
qlvl=$1
fi
# Originals HEIC image files will be moved here (prefixed with their 'Create Date').
origs=$here/heic-originals
if [ ! -d $origs ]; then
mkdir $here/heic-originals
fi
# Start the loop. Find all files with 'HEIC' extension. Ignore the "heic-originals" dir.
for i in $(find $here -type f -iname "*.HEIC" ! -path "$origs/*")
do
filename=$(basename $i)
_ext=${filename##*.}
_name=${filename%.*}
_dir=$(dirname $i)
# Name of new jpg file. Unless...
_newf=$_dir/$_name.jpg
# If a jpg with the same name exists, I guess salt the new one with what happened.
if [ -f $_newf ]; then
_newf=$_dir/$_name-heic2.jpg
fi
# Get Create Date to add to original filename when it is mv'd to Originals directory.
odate=$(exiftool -s3 -d %Y%m%d -CreateDate $i)
# Finally we can build our command.
_com="heif-dec -q $qlvl $i $_newf && mv $i $origs/$odate-$_name.$_ext"
# For dry run sanity, maybe cd to a directory with only a few HEIC files to test.
if [ $dryrun = "true" ]; then
echo "$_com" >> $here/test-run.txt;
else
eval $_com
fi
# Done.
done