image processing with applescript III

a little while ago we had a look at how to use applescript and sips to scale image files without the hassle of going through photoshop – see image processing with applescript II. open the terminal application, type in “man sips” and you’ll find there’s a whole bunch stuff you can do with images without ever opening photoshop — pretty cool :
screen grab of the sips manual in terminal

… but you can play around with all that another time. today we’re focussing on extending the functionality of the image resize script from that post to make it a little more user friendly. rather than a have script that’s hard-wired to scale images to 500px high, we’ll create one that can accept user input, so that the pixel dimensions can be changed each time the script is run.

to do that we need to first create a dialog. unfortunately the dialog possibilities with standard applescript are pretty crap — particularly when compared to all the options available to applescript dialogs in InDesign – border panels, columns, rows, checkbox controls, dropdowns, enabling groups, event listeners, comboboxes, editboxes, radiobuttons, etc.

here is all you get with standard dialogs :
screen grab of dialog entry in standard additions dictionary

well, although that’s pretty diabolical, it’s still enough for what we need. here’s the first part of the script :

display dialog "enter the pixel ratio you want these scaled to" with title "resize images" default answer "800" buttons {"cancel", "wide", "high"} default button 1
set mgResult to result
set mgText to text returned of mgResult
set mgButton to button returned of mgResult

that’ll give us a dialog something like this :
screen grab of resize images script dialog

… which gives us two pieces of information — the text entered and the button clicked – both captured into variables. if you want to make the script fool-proof, you’ll need to add some error handling to ensure that the text entered is an integer. but in its current form, the script assumes that the user is not an idiot.

the next part of the script creates a subfolder in the finder to save the transformed images into (this script creates duplicates of the original images rather than overwriting the originals with the resized versions) – then creates a reference to that folder for use later in the script :

set mgFolder to (mgText & "px") as string

tell application "Finder"
  set mgItems to selection
  set mgContainer to container of item 1 of mgItems
  set mgContainer to mgContainer as alias
  if (exists folder mgFolder of folder mgContainer) is false then
    make folder at mgContainer with properties {name:mgFolder}
  end if
end tell

set mgFinalFolder to mgContainer & mgFolder & ":" as string

then comes the key to the adaptability of this script — altering the final sips command based on the user’s choices in the dialog. we capture this into a variable called mgScriptString :

if mgButton is "high" then
  set mgScriptString to "sips --resampleHeight '" & mgText & "' "
else
  if mgButton is "wide" then
    set mgScriptString to "sips --resampleWidth '" & mgText & "' "
  end if
end if

the rest of the script is pretty much as per the previous post except that we insert the mgScriptString variable into the do shell script command :

repeat with mgItem in mgItems
  set mgName to name of mgItem
  set mgFinalpath to mgFinalFolder & mgName
  set mgPath to POSIX path of (mgItem as text)
  
  --convert mgFinalpath to POSIX form
  set text item delimiters to ":"
  set mgFinalpath to text items 2 thru -1 of mgFinalpath
  set text item delimiters to "/"
  set mgFinalpath to mgFinalpath as string
  set text item delimiters to ""
  
  set mgFinalpath to quoted form of mgFinalpath
  
  try
    do shell script mgScriptString & quoted form of POSIX path of mgPath & " --out " & mgFinalpath
    do shell script "sips -m '/System/Library/ColorSync/Profiles/sRGB Profile.icc' -i " & mgFinalpath
  end try
end repeat

wrap all that in an open handler (and delete the line “set mgItems to selection”) and you’ll have a script that looks like this :
screen grab of finished script

save that as an application and whack it in your sidebar. drag and drop as many images as you like onto the app — they’ll all be scaled quicker than you could do it through photoshop. don’t worry about accidentally dropping non-image files — these just get skipped.

you can also go here to get the complete image processing script.

have a good one

macgrunt icon

image processing with applescript II

the previous post showed how to scale a whole bunch of images without having to open them in photoshop — using image events in applescript. image events can do a few other transformations as well — flip, crop, rotate, pad. but one very important transformation is missing from image events — changing colour space.

this is odd because image events is really just an easy way to access the power of sips — the command line image processor you would use through terminal — and sips lets you change colour space. well, that’s not precisely true — if you open terminal and type in “man sips” you’ll find that the key “space” is read only. but what you can change is the image’s profile.

fortunately, you can still access the power of sips through applescript by using the “do shell script” command. here’s one way :

do shell script "sips -m '/System/Library/ColorSync/Profiles/sRGB Profile.icc' " & quoted form of POSIX path of [yourImage]

-m is the match profile function. if you match to an rgb profile, your image will be converted to the rgb colour space. if you wanted your image saved with a preview icon you’d need to add the -i function.

now, you could integrate that command into the script from the previous post. but if you have to use sips for the colour conversion, you might as well use it for the rescaling as well. this will give you a much cleaner script because, unlike image events, you can specify a pixel height (or pixel width) without the hassle of that calculation we did in the previous post :

do shell script "sips --resampleHeight '500' " & quoted form of POSIX path of [yourImage]

you’d have to agree, that’s a hell of a lot cleaner than the image events version. ok, just one other thing we need to replicate from the previous script — it saved a duplicate of the image and left the original untouched. to do that with sips, you add an out function to the first sips command :

do shell script "sips -m '/System/Library/ColorSync/Profiles/sRGB Profile.icc' " & quoted form of POSIX path of [yourImage] & " --out " & [yourNewImage]
do shell script "sips --resampleHeight '500' -i " & quoted form of POSIX path of [yourNewImage]

the first command saves a duplicate of the image to a new posix path (yourNewImage) and the second command does its conversion on that duplicate (and adds the preview icon).

The final script could look something like this :

tell application "Finder"
  set mgFolder to choose folder
  set mgFiles to items of mgFolder
  if (exists folder "500px" of folder mgFolder) is false then
    make folder at mgFolder with properties {name:"500px"}
  end if
end tell

set mgFinalFolder to mgFolder & "500px:" as string

repeat with mgFile in mgFiles
  set mgName to name of mgFile
  set mgFinalpath to mgFinalFolder & mgName
  set mgPath to POSIX path of (mgFile as text)

  --convert mgFinalpath to POSIX form
  set text item delimiters to ":"
  set mgFinalpath to text items 2 thru -1 of mgFinalpath
  set text item delimiters to "/"
  set mgFinalpath to mgFinalpath as string
  set text item delimiters to ""
  
  set mgFinalpath to quoted form of mgFinalpath
  
  do shell script "sips --resampleHeight '500' " & quoted form of POSIX path of mgPath & " --out " & mgFinalpath
  do shell script "sips -m '/System/Library/ColorSync/Profiles/sRGB Profile.icc' -i " & mgFinalpath
end repeat

notice this version of the script asks you to select a folder of images to process. the script has no error handling built in, so if the folder contained non-image files (or folders) the script in its current state would fail. you can easily change it back if you prefer the other functionality, or, even better, create it as a droplet instead. see renaming finder items for how to save an applescript as a droplet.

so there you have it — a way to scale and colour convert a bunch of images without the need for photoshop.

macgrunt icon

image processing with applescript

you can use photoshop to automate your image processing by creating an action and then running it as a batch or saving it as a droplet. it’s a really powerful way to get lots of repetitive work done quickly. but you probably already knew that.

it’s also possible to do basic image processing without photoshop or whatever image editor you use. this post will show how to resize images with applescript. the advantages? you don’t tie up photoshop for what is essentially monkey-work, you don’t get those flickering windows while photoshop opens and closes the files it’s processing, and this way is usually faster. interested now?

this method uses an application called “image events” which comes standard on the mac and is only accessible through applescript. here’s how you would scale an image selected in the finder. caution: this version of the script overwrites the original file — only use it on a duplicate.

copy this into your script editor (found in applications > applescript) :

tell application "Finder"
  set mgFile to selection
end tell
set mgPath to POSIX path of (mgFile as text)
tell application "Image Events"
  set mgImage to open mgPath as text
  scale mgImage to size 500
  save mgImage
  close mgImage
end tell

notice that the file goes through the same process in image events as it would in photoshop : open > scale > save > close. the scale command works on the longest edge — so, if your image is portrait, it will now be 500 pixels high; if it is landscape it will now be, you guessed it, 500 pixels wide.

ok, but what if you don’t want to overwrite your original? here’s one way to save the scaled version as a duplicate. this script will create a folder called “500px” for the scaled copy, leaving the original untouched :

tell application "Finder"
  set mgFile to selection
end tell

set mgFile to mgFile as alias
set mgPath to POSIX path of (mgFile as text)

tell application "Finder"
  set mgFolder to container of mgFile as alias
  set mgName to name of mgFile
  set mg500folder to "500px"
  if (exists folder mg500folder of folder mgFolder) is false then
    make folder at mgFolder with properties {name:mg500folder}
  end if
  set mg500path to (mgFolder as text) & mg500folder & ":" & mgName
end tell

tell application "Image Events"
  set mgImage to open mgPath as text
  scale mgImage to size 500
  save mgImage in mg500path
  close mgImage
end tell

this script first creates the folder if it does not already exist and then sets a new filepath to that folder for the final image (“set mg500path to …”). in image events we use the command “save mgImage in mg500path” rather than simply “save mgImage”. if you add “with icon” to the end of that line, your image will have a tiny preview as its icon instead of a generic icon.

alrighty, hopefully that’s all pretty straightforward — now let’s get a little complex. this next version of the script will scale a whole bunch of images to the same height. remember, image events scales the longest edge — so how would you scale a landscape image to 500 pixels high? :

global newHeight

tell application "Finder"
  set mgFiles to selection
end tell

repeat with mgFile in mgFiles
  set mgFile to mgFile as alias
  set mgPath to POSIX path of (mgFile as text)
  
  tell application "Finder"
    set mgFolder to container of mgFile as alias
    set mgName to name of mgFile
    set mg500folder to "500px"
    if (exists folder mg500folder of folder mgFolder) is false then
      make folder at mgFolder with properties {name:mg500folder}
    end if
    set mg500path to (mgFolder as text) & mg500folder & ":" & mgName
  end tell
  
  tell application "Image Events"
    set mgImage to open mgPath as text
    copy dimensions of mgImage to {Wdth, Hght}
    my processData(Wdth, Hght)
    scale mgImage to size newHeight
    save mgImage in mg500path
    close mgImage
  end tell
end repeat

on processData(Wdth, Hght)
  set mgComparison to Wdth - Hght
  if mgComparison > 0 then -- image is landscape
    set mgCalculation to Wdth / Hght
    set newHeight to round (500 * mgCalculation)
  else --image is square or portrait
    set newHeight to 500
  end if
end processData

you can see here, we use image events to get the dimensions of the image, then we use a subroutine to do a comparison to work out if the image is landscape or portrait. if the image is landscape we divide the width by the height to get a proportion by which to multiply the scale factor (500). no doubt you can work out how to change that subroutine if you wanted to scale all images to 500 pixels wide instead.

please note that this method is not always 100% accurate — you will sometimes get an image only 499 pixels high.

this workflow was developed to process hundreds of product images for a webshop. however, there’s still one step missing — ensuring all the images are rgb — but that’s going to have to wait until the next post.

macgrunt icon