Applescript Calling Shellscript to run Software that Calls Other Software – A Path Odessey
Since my previous adventure with Applescript, I made a few tweaks, and then I got hung up on a bigger problem. I did a lot of googling, and while I found cases of my problem, I never found an answer that worked, so I thought I would post more information for someone to stumble on some time down the road.
First, a little background information: When I pull images off of digital cameras, they always display with the correct orientation. Like almost all digital cameras now, mine has a sensor that can tell which way the camera was being held when the picture was taken. So there’s a little bit of information in the picture’s metadata (called the picture’s EXIF information) that tells how it’s oriented.
I wanted wanted my import to do is to actually rotate the image. My Mac reads the EXIF information and displays the image correctly, but that’s not the case if I use Windows to browse my image, or more importantly, if I upload it for display on the web. Another requirement is that the rotation be done without losing JPEG image quality.
I found Applescript commands to rotate an image 90 degrees one way or another, but that requires me to look at each image and tell the script which way to go. That’s not automation.
It turns out that I have to use a command shell utility to read the EXIF information and rotate the image.
jhead is the tool for EXIF information, and I’m sure I could have made it do the file rename part of my script.
jpegtran rotates the image losslessly.
Installing these isn’t trivial, but it isn’t particularly difficult either. (I’m pleased to learn that Mac OS shares most of its DNA with Linux. I had thought that any of this would mean learning completely new and foreign operating system commands.)
Then, came the Applescript. There’s a command for running a shell script, so it looked to be easy.
1 |
do shell script "/usr/local/bin/jhead -autorot \"" & (POSIX path of strPath as text) & strNewFileName & "\"" |
All this does is call the shell (“do shell script”), and then in the shell, run /usr/local/bin/jhead, which is the path where the program is installed. On the same line, we’re passing two parameters to jhead. First, the switch “-autorot”, followed by the path and file name of the file that we want to rotate. The path and file name are cobbled together from variables that are set earlier in the loop. The POSIX path is one using slashes. Otherwise, the MAC like to use colons to seperate folders in the path.
Backslash-quote (\”) is an escape sequence that means put a single quote within a string that’s already in quotes. The backslash is how the language knows that’s not the end of your quoted string.
This seemed to work, but it told me that it couldn’t find the jpegtran file.
That made sense. I didn’t tell the shell to start in /usr/local/bin or to look there for subsequent programs. I thought I could fix this by changing to that directory, and then running jhead from there:
1 |
cd /usr/bin/local;jhead -autorot & (POSIX path of strPath as text) & strNewFileName & "\"" |
The trick here is that the semicolon seperates commands. So the cd runs first, changing the shell over to that directory. Then jhead is run from the directory where it lives.
I’m more baffled about why this didn’t work. My error said that it couldn’t find jhead, although search after search showed that the file was there, and that no permissions issues should prvent processes from seeing or executing it.
I thought that maybe my error message was poorly worded and that the target file for rotation was the real problem, but making adjustments there were no help either.
It turns out that all I needed to do was this:
1 |
do shell script "export PATH=$PATH:/usr/local/bin/; jhead -autorot \"" & (POSIX path of strPath as text) & strNewFileName & "\"" |
The export of the PATH variable isn’t something I ever saw in hours of searching for this issue. But I posted the quetion on an apple forum, and I had this answer in a couple of hours.
And now, my entire import Applescript looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
on run {input, parameters} tell application "Finder" set theSelection to selection repeat with thisFile in theSelection set strFileName to the name of thisFile as text set strExt to the name extension of thisFile set strPath to the container of thisFile as text --set x to the POSIX path of thisFile as text --display dialog x if not (class of thisFile is folder) then set rename to false set fileMove to "" set autorotate to false if (strExt is "JPG" or strExt is "jpg") then set strBegin to "IMG_" set rename to true set autorotate to true else if (strExt is "CR2") then set strBegin to "IMG_" set rename to true set fileMove to "Raw" else if (strExt is "MOV" or strExt is "mov" or strExt is "mpg" or strExt is "MPG") then set strBegin to "MOV_" set rename to true set fileMove to "" # else if (strExt is "THM") then # set strBegin to "" # set rename to false # set fileMove to "_MoveToTrash" end if if (rename) then set {year:y, month:m, day:d} to the creation date of thisFile set strThisDate to (y * 10000 + m * 100 + d) as text set AppleScript's text item delimiters to {"_", "."} set strEnum to text item 2 of strFileName set strNewFileName to strBegin & strThisDate & "_" & strEnum & "." & strExt set the name of thisFile to strNewFileName else -- let's do this just in case we use the file name below, and -- have it for one that doesn't get renamed. set strNewFileName to strFileName end if if (autorotate) then -- jhead reads the exif information about orientation, then calls jpegtran -- to do a lossless rotation of the actual image. This way, it will show -- up with correct orientation on web sites and windows. It sets orientation -- information to "normal" since it has rotated the image (don't want macs/others -- to think that the image still needs to be rotated.) do shell script "export PATH=$PATH:/usr/local/bin/; jhead -autorot \"" & (POSIX path of strPath as text) & strNewFileName & "\"" end if if (not fileMove is "") then if (not (exists strPath & fileMove)) then make new folder at strPath with properties {name:fileMove} end if move thisFile to folder (strPath & fileMove) end if end if end repeat end tell end run |
I save this as an Automator app, and then all I have to do is drag my images to the app file. The script renames the files the way I want them to be named, sorts movies and raw images to seperate folders, and then rotate each image to its correct orientation based on EXIF information left by the camera.