A couple of weeks ago, my better half asked me if there was an easy way to convert a ton of Pages documents to PDF. One that didn’t involve opening and printing each of them to PDF one by one. I didn’t know about any useful utilities, but I always wanted an excuse to try out AppleScript and Automator. So that’s what I did!
Well, what I thought was going to be an hour of tinkering, turned into at least half a day’s work spread out over multiple days. Turns out that while AppleScript is pretty powerful and Automator is useful, they’re also fiddly as hell! And add to that that Apple seems determined to neuter them without clear workarounds.
First off, the good news; there’s plenty of resources to help you with Automator and AppleScript, with the best one being macosxautomation.com by Sal Soghoian. He served as product manager for the Apple automation technologies for years and his website is full of great resources and snippets to learn from.
Now, the bad news. One of the more amazing features that Apple introduced in macOS recently, is improved sandboxing. This makes it harder for attackers to gain access to your system, which is a good thing! However, it makes life harder for any tools you want to make that need access to your file system. In AppleScript’s case, the export
and save
commands need to create files, which Automator has no sandbox access to!
After asking on Ask Different, a StackOverflow for Apple stuff, someone finally came with a solution for this;
open for access file _location
-- Make sure this line of code is executed before the `export` step, and make sure you don't put it in a `tell` block.
Yay, fiddly! But, that works! 🎉
So, without further ado, the completed AppleScript that I places inside an Automator service;
on run {input, parameters}
repeat with _document in input
tell application "Finder"
set _directory to get container of file _document
set _documentName to name of _document
set _fileName to name of _document
if _documentName ends with ".pages" then ¬
set _documentName to text 1 thru -7 of _documentName
set _PDFName to _documentName & ".pdf"
set _incrementIndex to 1
repeat until not (exists file _PDFName of _directory)
set _PDFName to ¬
_documentName & "-" & (_incrementIndex as string) & ".pdf"
set _incrementIndex to _incrementIndex + 1
end repeat
set _location to (_directory as string) & _PDFName
end tell
open for access file _location
tell application "Pages"
activate
open _document
with timeout of 1200 seconds
export front document to file _location as PDF
end timeout
close front document
end tell
end repeat
return input
end run
I placed this in my Automator service, which accepts documents in Finder and uses them as input for the script. The end result gives you PDF for any document that can be opened by Pages (or undefined behavior for anything else, hah!). Or, if you just the service, you can download the workflow file here.
If you think the snippet is useful – or have an improvement – send me tweet or a toot!