turn an applescript into a service

the applescript outlined in email file from finder II takes selected items in the finder and attaches them to a new outgoing email message. it allows for multiple recipients from your address book and automatically adds a subject line and some basic content to the email.

there are a few ways to make that applescript accessible in the finder but the most convenient is to turn it into a service. this method is for OS X 10.6 and later — you can see a similar procedure for earlier operating systems in the post get file path of finder items.

Automator Iconapplescript services can be created through automator — the automation program that comes standard on every mac since OS X 10.4 (you’ll find it in your applications folder).

when you first open automator you’ll see this screen — choose service :
screen grab of automator startup screen

this next screen grab shows a couple of different things you need to do. in the main window on the right are two dropdowns — set the first to files or folders and the second to finder. in the search field on the left type ‘applescript’ to easily find the run applescript action. drag and drop this action into the right window :
screen grab of automator with service being built

then paste your applescript into that action window — you can entirely replace the default script. this is what it should look like after you hit the compile button (hammer) :
screen grab of automator service window with applescript in place

save that out and you’re done. now, whenever you want to email something from the finder just select it and right-click — you’ll see your service near the bottom of the contextual menu :
screen grab showing the service as a contextual menu item

you can also activate it under finder > services :
screen grab of services menu

under that menu you can also access the services preferences. this allows you to even set a keyboard shortcut for your new handy service :
screen grab of services preferences window

of course, services aren’t just restricted to running your applescripts. investigate the full power of automator … and get grunting.

macgrunt icon

Advertisements

email file from finder II

the previous post — email file from finder — showed how to use applescript to quickly attach a selected finder item to an email — adding a recipient, subject and basic content along the way. this post will show how to adapt that script to allow for multiple attachments and multiple recipients.

here’s the original script :

set mgPeople to {}
set mgFirsts to {}
set mgAddresses to {}

tell application "Address Book"
  repeat with mgPerson in people
    tell mgPerson
      repeat with mgEmail in emails
        copy name to the end of mgPeople
        copy first name to the end of mgFirsts
        copy value of mgEmail to the end of mgAddresses
      end repeat
    end tell
  end repeat
end tell

-- thanks to Mark J. Reed 
-- http://lists.apple.com/archives/applescript-users/2007/Mar/msg00086.html
set text item delimiters of AppleScript to (ASCII character 10)
set mgSortedPeople to paragraphs of (do shell script "echo " & quoted form of (mgPeople as string) & "| sort  -d -f")
set text item delimiters of AppleScript to ""
-------------

choose from list mgSortedPeople with prompt "who you emailing then?"
if result is not false then
  set mgChosenOne to item 1 of result
else
  error number -128
end if

repeat with x from 1 to count of mgPeople
  if item x of mgPeople = mgChosenOne then
    set mgFirstName to item x of mgFirsts
    set mgChosenEmail to item x of mgAddresses
  end if
end repeat

tell application "Finder"
  set mgSelection to the selection
  set text item delimiters of AppleScript to ":"
  if class of (item 1 of mgSelection) is folder then
    set mgSubject to text item -2 of ((item 1 of mgSelection) as string)
    set mgContent to "Hi " & mgFirstName & return & return & "Here's that folder we were talking about." & return & return
  else
    set mgSubject to text item -1 of ((item 1 of mgSelection) as string)
    set mgContent to "Hi " & mgFirstName & return & return & "Here's the file you're waiting for." & return & return
  end if
  set text item delimiters of AppleScript to "."
  set mgSubject to text item 1 of mgSubject
  set text item delimiters of AppleScript to ""
end tell

tell application "Mail"
  activate
  set mgMessage to make new outgoing message with properties {subject:mgSubject, content:mgContent, visible:true}
  tell mgMessage
    make new to recipient with properties {name:mgChosenOne, address:mgChosenEmail}
    make new attachment with properties {file name:(mgSelection as alias)} at after last paragraph of content
    save
  end tell
end tell

that script first creates three lists — names, first names and email addresses. the list of first names was used to create the salutation in the email (“Hi whoever”). but this script allows for multiple recipients so the salutation will change (in this script we’ll use “Hi all”). so, the start of the script will be stripped back to this :

set mgPeople to {}
set mgAddresses to {}

tell application "Address Book"
  repeat with mgPerson in people
    tell mgPerson
      repeat with mgEmail in emails
        copy name to the end of mgPeople
        copy value of mgEmail to the end of mgAddresses
      end repeat
    end tell
  end repeat
end tell

-- thanks to Mark J. Reed 
-- http://lists.apple.com/archives/applescript-users/2007/Mar/msg00086.html
set text item delimiters of AppleScript to (ASCII character 10)
set mgSortedPeople to paragraphs of (do shell script "echo " & quoted form of (mgPeople as string) & "| sort  -d -f")
set text item delimiters of AppleScript to ""
-------------

the next thing we need to do is allow the user to select multiple email recipients. that’s as simple as changing the end of that choose from list command. we also need to change the way we capture that data — it’s no longer a list with only one item :

choose from list mgSortedPeople with prompt "who you emailing then?" with multiple selections allowed
if result is not false then
  set mgChosenOnes to result
else
  error number -128
end if

as per standard mac functionality, you can select multiple items in the dialog by holding down the command key :
screen grab of choose from list dialog with multiple recipients selected

we’re going to dump the next repeat loop from the original script — we’ll integrate that functionality once we start talking to Mail. here’s the new code we need for addressing the finder. this time we’re going to capture the name of the folder containing the finder selection to use as our subject line :

tell application "Finder"
  set mgSelection to the selection
  set text item delimiters of AppleScript to ":"
  if class of (item 1 of mgSelection) is folder then
    set mgSubject to text item -3 of ((item 1 of mgSelection) as string)
  else
    set mgSubject to text item -2 of ((item 1 of mgSelection) as string)
  end if
  set text item delimiters of AppleScript to ""
end tell

the original script allowed for one attachment and one recipient, so the last portion of the script — the bit that created the actual email — was quite simple. with this version we need two repeat loops — one to process the multiple recipients and one to process the multiple attachments :

tell application "Mail"
  activate
  set mgContent to "Hi all" & return & return & "Please find attached ..." & return & return
  set mgMessage to make new outgoing message with properties {subject:mgSubject, content:mgContent, visible:true}
  tell mgMessage
    repeat with mgChosenOne in mgChosenOnes
      repeat with x from 1 to count of mgPeople
        if item x of mgPeople = (mgChosenOne as string) then
          set mgChosenEmail to item x of mgAddresses
          make new to recipient with properties {name:mgChosenOne, address:mgChosenEmail}
        end if
      end repeat
    end repeat
    repeat with mgitem in mgSelection
      make new attachment with properties {file name:(mgitem as alias)} at after last paragraph of content
    end repeat
    save
  end tell
end tell

screen grab of email created by the script

your homework for this week is to come up with a way to make the salutation personal if only one recipient is selected (eg. “Hi John”) but generic if multiple recipients are selected (eg. “Hi all”).

next time we’ll look again at how to turn this script into a service for easy accessibility from within the finder.

macgrunt icon

email file from finder

InDesign scripting : lesson 22 showed an applescript that exports a pdf from InDesign and attaches it to an email — adding a subject and recipient along the way. here’s a variation that lets you email an existing file directly from the finder. the previous script used a predefined list of email addresses — this one accesses your address book.

the first part of the script compiles three lists — names, first names and email addresses. we start by creating three empty lists before moving on to copying the relevant data into those lists. then we use the choose from list command to create a UI for the user to make a selection from. mgPeople is the list of names for people in your address book who have an email address :

set mgPeople to {}
set mgFirsts to {}
set mgAddresses to {}

tell application "Address Book"
  repeat with mgPerson in people
    tell mgPerson
      repeat with mgEmail in emails
        copy name to the end of mgPeople
        copy first name to the end of mgFirsts
        copy value of mgEmail to the end of mgAddresses
      end repeat
    end tell
  end repeat
end tell

choose from list mgPeople

you’ll notice the list is in a crazy order. that’s because the list is in ID order — the order in which the contacts were entered into your address book :
screen grab of initial choose from list dialog

so, to make things a leetle easier, we need to reorder the list alphabetically. thanks to mark j. reed over at the apple mailing lists for the shell script :

set mgPeople to {}
set mgFirsts to {}
set mgAddresses to {}

tell application "Address Book"
  repeat with mgPerson in people
    tell mgPerson
      repeat with mgEmail in emails
        copy name to the end of mgPeople
        copy first name to the end of mgFirsts
        copy value of mgEmail to the end of mgAddresses
      end repeat
    end tell
  end repeat
end tell

-- thanks to Mark J. Reed 
-- http://lists.apple.com/archives/applescript-users/2007/Mar/msg00086.html
set text item delimiters of AppleScript to (ASCII character 10)
set mgSortedPeople to paragraphs of (do shell script "echo " & quoted form of (mgPeople as string) & "| sort  -d -f")
set text item delimiters of AppleScript to ""
-------------

choose from list mgSortedPeople with prompt "who you emailing then?"
if result is not false then
  set mgChosenOne to item 1 of result
else
  error number -128
end if

that last part captures the result of the dialog into a variable (mgChosenOne) or, if the user hits cancel instead, stops the script (error number -128). this is needed because of a quirk of the choose from list command — the cancel button doesn’t actually cancel the process it just returns a ‘false’ result. the observant will notice we’ve added our own prompt to this version of the dialog. you can also add a title to that top bar as well if you like :
screen grab of alphabetisied choose from list dialog

the next bit simply matches up the chosen recipient with their first name and email address and captures those into variables too :

repeat with x from 1 to count of mgPeople
  if item x of mgPeople = mgChosenOne then
    set mgFirstName to item x of mgFirsts
    set mgChosenEmail to item x of mgAddresses
  end if
end repeat

then we need to get a reference to the selected object in the finder. and we set a subject and content for the email message. you can see that we’re checking to see if the selected object is a file or folder first, then setting the subject and content accordingly. the subject will be the name of the file or folder and the content is our own chosen verbage :

tell application "Finder"
  set mgSelection to the selection
  set text item delimiters of AppleScript to ":"
  if class of (item 1 of mgSelection) is folder then
    set mgSubject to text item -2 of ((item 1 of mgSelection) as string)
    set mgContent to "Hi " & mgFirstName & return & return & "Here's that folder we were talking about." & return & return
  else
    set mgSubject to text item -1 of ((item 1 of mgSelection) as string)
    set mgContent to "Hi " & mgFirstName & return & return & "Here's the file you're waiting for." & return & return
  end if
  set text item delimiters of AppleScript to "."
  set mgSubject to text item 1 of mgSubject
  set text item delimiters of AppleScript to ""
end tell

the last part creates the email based on all the bits and pieces we’ve put together in the other parts of the script. this is how you would do it for Mail. see InDesign scripting : lesson 22 to see how to do it for Outlook. for other email software, consult your applescript dictionary for that program :

tell application "Mail"
  activate
  set mgMessage to make new outgoing message with properties {subject:mgSubject, content:mgContent, visible:true}
  tell mgMessage
    make new to recipient with properties {name:mgChosenOne, address:mgChosenEmail}
    make new attachment with properties {file name:(mgSelection as alias)} at after last paragraph of content
    save
  end tell
end tell

put all those bits together, customise it to your particular way of working, and you’ve got yourself a handy little timesaver. there are a number of ways to activate a script like this, but the easiest is to turn it into a service so that you can activate the script with a right-click or keyboard shortcut. see get file path of finder items which shows how to do this through automator.

screen grab of email created by the script

the next post will show how to convert this script to allow for multiple attachments and multiple recipients.

til then, keep grunting.

macgrunt icon

Photoshop tip : layers

here are a couple of handy tricks for working with layers.

this image is going to be deep-etched. we first have to turn the background layer into an active layer (notice the lock in the layers panel) :
screen grab of initial flattened photoshop file

to achieve that, just double-click the layer. this will open a dialog box asking you to name the layer. if you’re happy to just use the default name (Layer 0) — hold down your option key before you double-click to bypass the dialog. but in this case a different name was applied :
screen grab of file with layer made active

now, we’re only a couple of sentences in and it’s already time for a rant …
if you are going to deep-etch an image, DO NOT DESTROY PIXELS. there is absolutely no good reason for permanently erasing a background. you should always use a mask instead. you can read more about making masks here. masks are created with the mask button at the bottom of the layers panel :
screen grab of masked photoshop file

if you click the new layer button you’ll get a new layer above the currently selected layer or, if no layers are selected, at the top of the layer stack. but if you want the new layer beneath the current one, or at the bottom of the stack, hold the command key as you click :
screen grab showing new layer added

to name a new layer as you create it, just hold the option key as you click the new layer button. this also works if you are duplicating an existing layer by dragging it onto the new layer button (but not if you are duplicating with the right-click method).

now we need to add a logo from another file. first you need the new file in a separate window in front of your working file (so that you can see both files) then just click and drag the layer you want from the new file’s layers panel into your working file. you can also do this with multiple layers (just command-click to select multiple layers) :
screen grab showing one file being dragged onto another

to make things a little easier, hold the shift key as you click and drag. this will place the new layers dead centre :
screen grab showing new art in the centre of the working file

to rename an existing layer, double-click on the name in the layers panel.

macgrunt icon

Photoshop tip : masking

let’s start with a belligerent directive … if you are going to deep-etch an image, DO NOT DESTROY PIXELS. there is absolutely no good reason for permanently erasing a background. you should always use a mask instead. if you make a mistake or change your mind or whatever, it’s easier to alter a mask than it is to reclaim lost pixels. ok, you’ve been warned.

a mask is a non-destructive way to create a transparent or translucent portion of a photoshop layer. the mask appears next to the image in the layers panel. white areas are totally opaque, black areas are totally transparent, and grey areas are somewhere between :
screen grab showing a basic mask

it may be a little easier to see the difference with a red background :
screen grab showing the basic mask with a red background

different images require different approaches to deep-etching. here’s one way to do one kind of image.

we need to get rid of the white background of this image so we can put it on a black background. to start with we can make a quick selection with the magic wand tool or by using the color range command under the select menu :
screen grab showing initial selection

this is not a perfect selection however, because the chrome highlights are white too and have also been selected. if we use this selection as our mask we’ll get big black spaces in our chrome — not pretty. refining the selection is a perfect job for quick mask mode (hit the Q key) :
screen grab showing the initial selection in quick mask mode

zoom in and use your brush tool to paint in the missing areas. you can change the colour and transparency of the quick mask by double-clicking the quick mask tool near the bottom of your tool panel :
screen grab showing the refined selection in quick mask mode

now you can exit quick mask (Q) and create the actual mask by hitting the add layer mask button at the bottom of the layers panel :
screen grab showing initial application of layer mask

well, that’s not quite right — we’ve masked out the bike instead of the background. not to worry, there are at least two easy ways to fix this : either undo and hold your option key as you click the add layer mask button; or click on the layer mask and hit command-i to invert the mask.

now we can see the mask is not quite tight enough — there’s a white halo around the bike. this can be fixed by selecting the layer mask and choosing filter > other > minimum (this example only needed a 1 pixel contraction) :
screen grab showing the minimum filter being applied to the layer mask

the next obvious thing to fix are those shadow areas under the wheels. you can do this by painting directly onto the layer mask with your brush tool, or you could make a selection and fill it with black (again, on the mask itself, not the image) :
screen grab showing a further refined layer mask

the only problem now is those disastrous spokes. let’s have a closer look :
screen grab showing closeup of badly masked spokes

now, you could try patching all that up with a lot of brush and eraser work, but here’s a simpler way. first, use the brush and eraser to completely mask out all the spokes and do a basic cleanup (tip: you don’t actually need to swap between the brush and eraser, you could just swap between a black brush and a white brush — whatever you find easier) :
screen grab showing closeup of cleaned up spokes area

next, disable the layer mask (shift-click on the layer mask) so you can see the original image. and use your pen tool to draw straight paths for each of the spokes :
screen grab showing closeup of spokes area with mask disabled

here are the completed paths with the top layer turned off so you can see them easily :
screen grab showing closeup of spokes area with finished paths

make a new layer, select your brush tool and set it to a fine solid brush (this example uses a 1 pixel, 100% hardness brush), then select your path in the paths panel and choose stroke path from the dropdown menu. if the resulting lines are not quite strong enough you can just stroke the path again with the same settings — try that before opting for a bigger brush :
screen grab showing closeup of spokes area showing new lines

now select the lines by holding down the command key as you click on the layer preview in the layers panel. turn off that top layer and hit command-h (hide selection) so you can see what you’re doing. click on the layer mask and hit delete. if the result isn’t strong enough, just hit delete again :
screen grab showing closeup of spokes area showing new masked spokes

bonza :
screen grab showing completed mask

as mentioned, this is just one way to mask this image. feel free to share your favourite way.

keep grunting.

macgrunt icon