Your prescription for increased productivity and profitability
In our previous blog (July 21), we put a demonstration script together using AppleScript. This script allows the user to choose a PDF export preset from a list of presets. With the preset chosen, it exports the PDF to a fixed file path on the user’s desktop. This is OK for a demonstration script, but for a real world application, your script should either:
To save the exported PDF to the same folder as the document, you can use the document’s full name property. To see how this would work, enter the following into a new edit window for AppleScript Editor (File > New)
tell application "Adobe InDesign CC 2015" set docRef to document 1 set docName to name of docRef --returns a string reference set docPath to full name of docRef --returns a file reference end tell docPath
Notice that the value returned for the variable docPath is a file reference. Having a file reference, we can use the Finder to return the parent folder (container) for the document. But first we must change the file reference to an alias reference. Add the following to your test script above:
set aliasRef to docPath as alias tell application "Finder" set parentFolder to get container of aliasRef as string end tell
Notice that here we change the value returned from the Finder from a folder reference to a string (text). This is so we can add the name of our PDF export file to its folder path.
To add this bit of code to our previous script would make it even more cumbersome. Instead, lets revisit our original script and break it down into pieces of code that are more easily managed, more robust, and reusable.
The first thing we had our previous script do was to check to make sure there was a document open. If there is more than 1 document, we have it place the top-most document into a variable docRef. This is something a great number of your scripts may need to do. Similarly, we can see that other functionality included in the script could possibly be found in other scripts. Let’s put each of the major functions of our script into a piece of code that, once called, can run all by itself. In AppleScript, this is referred to as a handler; in other languages it is called a function.
You might want to think of a handler (or function) as a subcontractor: Someone who is specialized to perform a specific job as part of a larger project. This contractor could be a plumber or electrician when it comes to building a house. When you want a particular part of a project to be done, you call the subcontractor and send him the specifications for the job. This is similar to how handlers work in AppleScript. From the main section of the script you call a handler to do its job and pass it specifications (parameters) for completing the task.
A handler begins with the word on or to. We will use the word on. It also ends with a parentheses pair.
on doSomething () --steps to be done go here --return the result of the process, if there is one end doSomething
Our script needs to have a way to get a reference to the active document. For this we can create a handler named getDocRef. To get a reference to the document and return it to the main part of the script, you can use the following. Copy and paste it into a new document for the AppleScript Editor.
(*Returns reference to active document; otherwise generates error.*) on getDocRef() tell application "Adobe InDesign CC 2015" if (count of documents) is greater than 0 then set docRef to document 1 if saved of docRef is false then error "Please save document before running the script" end if else error "Script requires an active document" end if return docRef end tell end getDocRef
To run the handler, the AppleScript script refers to it by name. Place the following at the top of your new script:
set docRef to getDocRef()
If, no active document is open, the handler will generate an error. Notice the nested if statement that also checks to make sure the document has been saved. To alert our user to a problem, we need to provide some way to catch the error so we can give the user the message and exit gracefully from the script. We can do this with a try/on error statement block. As part of the block, a display alert statement is used to give the user the error message after which it exits using the return statement. Change the top of your new script to read as follows:
try set docRef to getDocRef() on error errStr activate --makes sure the error message displays above the InDesign document display alert errStr return end try
The next thing our original script did was to get a list of PDF export preset names and have the user choose the one to use by name. If the user does not choose an item from the list, the script needs to alert the user that the script cannot continue without a valid PDF preset. The process of choosing a PDF Export preset from a list is something that can find its way into any number of scripts. Again, let’s put this process into another handler, called ChoosePDFPreset. Copy and paste the following below the getDocRef handler.
(*Returns user chose from list of PDF Export Presets If no preset is chosen, an error is generated*) on choosePDFPreset() set myPrompt to "Choose PDF Export Preset from list" tell application "Adobe InDesign CC 2015" set presetList to get name of PDF export presets set presetList to choose from list presetList with prompt myPrompt without multiple selections allowed if presetList is false then error "Can't continue without PDF export preset choice" else set presetName to item 1 of presetList --only 1 choice was allowed set myExportPreset to PDF export preset presetName end if end tell return myExportPreset end choosePDFPreset
Because this handler can also generate an error, we can place its call inside our try/on error statement block. Place this directly below the line that calls getDocRef()
set myExportPreset to choosePDFPreset()
To place the exported PDF into the same folder as the document, we need to get the path to its parent folder. Again, this is another process that could be used in any number of other scripts. Let’s write this up as another handler getSavePath. For this, we will need a reference to the document. We can pass this information to our handler by placing the variable docRef inside the parentheses provided as part of the handler call. Similarly, the parentheses that is part of the handler will receive the value. You might want to think of the parentheses for the handler in the call and in the handler as in and out baskets. We put the information needed in the out basket for the call which is then received by the in basket for the handler.
set savePath to getSavePath (docRef) --passes value for docRef to handler
For the handler, we need to add the name of the document to the path to its folder (the parent of its full name path)
(*Returns path for PDF export based on document path and name*) on getSavePath(docRef) tell application "Adobe InDesign CC 2015" set docPath to full name of docRef as alias set docName to name of docRef if docName ends with ".indd" then set docName to text 1 thru -6 of docName end if end tell tell application "Finder" set parentFolder to container of docPath as string end tell set savePath to parentFolder & docName & ".pdf" return savePath end getSavePath
Even though this handler should not generate an error, we can place its call inside the try/on error statement block just to be sure. Place the following directly below the call to choosePDFPreset()
.
set savePath to getSavePath (docRef) --passes value for docRef to handler
The only thing left is to actually export the document. We can do this directly below the call to getSavePath(docRef)
. But before you do this, run the script as it is to make sure that the value for savePath is as expected. To do this, place the variable savePath at the end of the script. If the value that shows in the Result panel for Script Editor is as expected, add the following code to export the document as PDF to this path.
--export the document as PDF tell application "Adobe InDesign CC 2015" tell docRef asynchronous export file format PDF type to savePath using myExportPreset without showing options end tell end tell
Of course, there may be other functionality you may want to add to your script before it performs the PDF export. Remember that PDF export presets do not set security preferences, so you may want to add these. Also, you might want to put a watermark on your document to keep users from copying or otherwise using your document without permission.
PDF export preferences are the domain of the application. Security preferences can only be set if the property for use security is set to true. By default, the security preferences are all set to false. The property change security password is accessible and can only be set, if use security is set to true.
To add security settings to our ExportPDF_Preset script, we can add the following handler. This handler wil be effective only if all security settings, with exception of use security and security password, will be set uniformly–all will be either true or false.
(Sets all security settings to the value for the boolean myBool. Sets security password for the PDF export to value of variable tempPassword*) on doSecurity(tempPassword, myBool) tell application "Adobe InDesign CC 2015" tell PDF export preferences set use security to true set change security password to tempPassword set disallow changing to myBool set disallow copying to myBool set disallow document assembly to myBool set disallow extraction for accessibility to myBool set disallow form fill in to myBool set disallow hi res printing to myBool set disallow plaintext metadata to myBool set disallow printing to myBool end tell end tell end doSecurity
The call to the doSecurity handler will require a value for the proposed document password and a boolean (true or false) for use in setting the security settings. For a more usable script, these values will need to be provided by the user as part of a custom dialog. For demonstration, we will hard-code this at the top of the script.
--define the value for the variable docPassword: set docPassword to "myPassword"
Then inside the try/on error statement block, add the following after the set savePath
statement:
doSecurity(docPassword, true)
It would also be a good idea to reset the security settings back to their defaults when the script is completed. For this, set the password to an empty string (“”) and all other values to false (assuming that the defaults for these values are all set to false).
InDesign has its own way for placing a watermark on a document. This is a document preference: watermark preference. The properties for this preference are self explanatory with perhaps the value for the font color. Instead of using a swatch found in the document, a list of RGB values, or one of the system colors is used. The system colors are listed in the AppleScript dictionary for InDesign which include among others red, green, gold, dark blue, and white.
In the minimum, the handler for creating a watermark will require a reference to the document and the values for the watermark visibility, printing, text, font size, color, and opacity. The values for text, font, size, color, and opacity could be hard-wired to the script if the values would never change (which is unlikely). Better, these should be returned as the result of user choices in a custom dialog box. For simplicity sake, however, our values will be hard wired at the top of our demonstration script.
set wText to "DRAFT" set wColor to {255, 0, 0} set wOpacity to 40 set wSize to 120 set wPrint to true set wShow to true
Then inside the try/on error statement block, after the doSecurity statement, add:
doWatermark (docRef, wText, wColor, wOpacity, wSize, wPrint, wShow)
At the bottom of the script, add the handler for doWatermark
(*doWatermark handler requires reference to the document, and values for watermark text, color, opacity, size, and boolean values for do print and visibility*) on doWatermark (docRef, wText, wColor, wOpacity, wSize, wPrint, wShow) tell application "Adobe InDesign CC 2015" tell watermark preferences of docRef set watermark font color to wColor set watermark draw in back to false set watermark font family to "Minion Pro" set watermark font style to "Bold" set watermark horizontal position to watermark h center set watermark opacity to wOpacity set watermark do print to wPrint set watermark font point size to wSize set watermark rotation to 0 set watermark text to wText set watermark vertical position to watermark v center set watermark visibility to wShow set watermark vertical offset to 0 end tell end tell end doWatermark
Remember that these values are preferences for the document and will remain as set until set otherwise. To export your document as PDF without the watermark you will need to set the values for watermark text to an empty string (“”) with watermark visibility and watermark do print set to false.
The top of your script should now look similar to the following:
set wText to "DRAFT" set wColor to {255, 0, 0} set wOpacity to 40 set wSize to 120 set wPrint to true set wShow to true set docPassword to "myPassword" try set docRef to getDocRef() set myExportPreset to choosePDFPreset() set savePath to getSavePath(docRef) doSecurity(docPassword, true) doWatermark(docRef, wText, wColor, wOpacity, wSize, wPrint, wShow) tell application "Adobe InDesign CC 2015" tell docRef asynchronous export file format PDF type to savePath using myExportPreset without showing options end tell end tell doSecurity("", false) --resets all security settings to false, password to empty string on error errStr display alert errStr return end try
This will be followed by your handlers which can be in no particular order.
Put a sample document together in InDesign. Compile and then run your script from within the AppleScript editor. Hopefully, your script will compile and run without a hitch. Select a PDF Export Preset from the list presented and return. All the rest is done by the script. Below is our sample document (5 in by 7 in) as exported with the settings established in our sample script.
PDF of sample document with watermark
With the majority of a script’s functionality stored in handlers, the script becomes well organized and readable. More importantly, handlers provide the ability for reuse in any number of other scripts often with no more than a simple copy and paste. Start saving handlers that you think you may want to use in a folder as a library resource.