InDesign scripting : lesson 08

this is the first of a series of lessons on exporting pdfs using applescript in script editor (found in applications > applescript). the end result of the first two lessons will be a script that will export all your open InDesign files while you go off to get a hot bevvie — rather than you having to sit there exporting each file individually. the script relies on pdf presets — you can use your own, or the defaults, or both.

first we’ll build a user interface (UI) which will ask you to select a pdf export preset. InDesign offers scripters an excellent range of UI elements — text fields, check boxes, dropdowns and, in this case, radio buttons. here is a very simple version of a UI and the script to produce it :

screen grab of simple export pdfs user interface

tell application "Adobe InDesign CS4"
  activate
  set mgDialog to make dialog with properties {name:"Export preset to use :  "}
  tell mgDialog
    make dialog column
    tell the result
      set mgExportButtons to make radiobutton group
      tell mgExportButtons
        make radiobutton control with properties {static label:"Press Quality", checked state:true}
        make radiobutton control with properties {static label:"Inhouse Printing"}
        make radiobutton control with properties {static label:"Screen Resolution"}
      end tell
    end tell
  end tell
  show mgDialog
end tell

the basic structure is this : make dialog > put stuff in the dialog > show dialog. the observant will notice that in order to put stuff in a dialog you first need to make a dialog column. if you miss this step, it ain’t gonna work. you’ll also notice that you need to make a radiobutton group to contain the individual radiobutton controls. if you scroll right, you’ll see that you can set which of the radio buttons will be highlighted by default. you can add a bunch more radio buttons if you like, and you can label them however suits you — the labels do not have to exactly match the names of your pdf export presets — that bit comes later.

InDesign also let’s you play around with the layout a bit too — to give your UI windows a bit more presence. this comes in handy later when you start building more complex dialogs :

screen grab of export pdfs user interface

this version of the dialog has three dialog columns : the first one has a border around it and contains the other two ; the second contains the text “Export preset to use : ” ; and the third contains the radio buttons. here’s how to script it :

tell application "Adobe InDesign CS4"
  activate
  set mgDialog to make dialog with properties {name:"Export all open PDFs"}
  tell mgDialog
    tell (make dialog column)
      tell (make border panel)
        tell (make dialog column)
          make static text with properties {static label:"Export preset to use :  "}
        end tell
        tell (make dialog column)
          set mgExportButtons to make radiobutton group
          tell mgExportButtons
            make radiobutton control with properties {static label:"Press Quality", checked state:true}
            make radiobutton control with properties {static label:"Inhouse Printing"}
            make radiobutton control with properties {static label:"Screen Resolution"}
          end tell
        end tell
      end tell
    end tell
  end tell
  show mgDialog
end tell

this script uses the form “tell (make dialog column)” instead of “make dialog column > tell the result”. choose whichever suits you — one’s easier to understand, the other requires less lines of code.

next we need to capture the results of the dialog. first we need to determine which of the two buttons was clicked — ‘ok’ = true and ‘cancel’ = false. there are different ways to handle these two possibilities, here’s one — it goes immediately after show mgDialog, before that last end tell :

if result is true then
  set mgExport to selected button of mgExportButtons
  destroy mgDialog
else
  error number -128
end if

if the result is true then the ‘ok’ button was clicked — in which case we capture the radio button selected into a new variable (mgExport), ready for further processing. if the result is false then the cancel button was clicked — in which case we tell the script to quit immediately (error number -128). it’s good to get in the habit of destroying a dialog once you’ve captured the data you need. this prevents funky things happening in scripts that reference multiple dialogs.

ok, finally, we need to tell the script what to do, depending on the radio button selected. radio buttons are numbered from zero — so, for this script, mgExport could be 0, 1 or 2. again, this goes before the last end tell :

if mgExport is 0 then
  set mgExport to "Offset Printing"
  set mgSubFolder to "Prepress Files"
else if mgExport is 1 then
  set mgExport to "Xerox Printing"
  set mgSubFolder to "Xerox PDFs"
else if mgExport is 2 then
  set mgExport to "[Smallest File Size]"
  set mgSubFolder to "Low Res PDFs"
end if

here is an example of how you can change the value of a variable — mgExport starts as a number (0, 1 or 2) but gets changed to the name of an export preset. this is where we have to use the exact name (case sensitive) of the Adobe PDF export preset. notice that default presets need to be in square brackets — that’s exactly as they are in the InDesign menu. the other thing we are doing here is setting the name for the folder the final PDFs will be saved in. this folder doesn’t have to already exist — the script will create it if it’s not there already.

ok, that’s it for the first part. we’re actually more than half way through. the next lesson will cover the guts of the export process.

go to lesson 09

macgrunt icon

Advertisements

create folders from list II

the original create folders from list post prompted a question from Jocely. basically the question is… it’s all very good being able to create folders through applescript, but what about subfolders and whatnot? it’s such a great question — it needs its own post as a reply.

to run either of these scripts — copy it into script editor, save it out as an application, then double-click to run it. you’ll be prompted to select your csv file — then the folders will be created in the same location as the csv file.

ok, scripts build up over time — first you try something and, once you get it working, you add, refine, stabilise, improve, etc. that’s how this development progressed — the first stab at this challenge looks like this :

set mgCSVfile to choose file
open for access mgCSVfile
set mgList to (read mgCSVfile)
close access mgCSVfile

tell application "Finder"
  set mgFolder to container of mgCSVfile as string
  repeat with x from 1 to count paragraphs of mgList
    set text item delimiters of AppleScript to ","
    set mgThisList to text items of paragraph x of mgList as list
    set text item delimiters of AppleScript to ""
    
    set mgTopFolder to item 1 of mgThisList
    if (exists folder mgTopFolder of folder mgFolder) is false then
      make new folder at mgFolder with properties {name:mgTopFolder}
    end if
    set mgNewFolder to (folder mgTopFolder of folder mgFolder) as alias
    
    repeat with i from 2 to count mgThisList
      if item i of mgThisList is not "" then
        set mgSubFolder to item i of mgThisList
        if (exists folder mgSubFolder of folder mgNewFolder) is false then
          make new folder at mgNewFolder with properties {name:mgSubFolder}
        end if
      end if
    end repeat
    
  end repeat
end tell

… and it will render a csv file like this :
screen grab of basic csv file
… into a folder structure like this :
screen grab of first folder structure

well, that’s not a bad start. but what about a folder hierarchy a little more complex than that? we need to go deeper with the nesting. so here’s the second stab. and you’ll notice it’s actually a simpler script :

set mgCSVfile to choose file

open for access mgCSVfile
set mgList to (read mgCSVfile)
close access mgCSVfile

tell application "Finder"
  repeat with x from 1 to count paragraphs of mgList
    set mgFolder to container of mgCSVfile as string
    set text item delimiters of AppleScript to ","
    set mgThisList to text items of paragraph x of mgList as list
    set text item delimiters of AppleScript to ""
    
    repeat with i from 1 to count mgThisList
      if item i of mgThisList is not "" then
        set mgSubFolder to item i of mgThisList
        if (exists folder mgSubFolder of folder mgFolder) is false then
          make new folder at mgFolder with properties {name:mgSubFolder}
        end if
        set mgFolder to (folder mgSubFolder of folder mgFolder) as alias
      end if
    end repeat
    
  end repeat
end tell

… and the results using the same csv file :
screen grab of second folder structure

now we see that each line (paragraph) in the csv file renders a single nested folder structure. this is more like what we’re looking for. what do you reckon you’ll get if you run this csv file through that second script? :

screen grab of more complex csv file

you can get a copy of the CreateFoldersII app here

update : if you are in the german or dutch regions you may find that your CSV files export as semi-colon separated (rather than comma separated). in which case you would replace this line :

    set text item delimiters of AppleScript to ","

with this :

    set text item delimiters of AppleScript to ";"

macgrunt icon

GUI scripting : acrobat

some applications have poor scripting support — acrobat is a shocker. have a look at the acrobat scripting dictionary to see just how restricted the opportunities are — even for the pro version. but it IS still possible to automate acrobat through GUI (graphical user interface, or gooey) scripting. GUI scripting has been available since OSX 10.3 (panther) and uses system events to, basically, activate menus, open windows and click buttons in the same way that you would using a mouse.

this post will outline a process for working out just one example — running a batch sequence from the advanced menu. but hopefully you’ll glean enough information to be able to adapt what’s here for other scripts too.

first you need to enable GUI scripting. you can do this through the applescript utility found in applications > applescript :

screen grab of applescript utility showing gooey scripting enabled

with GUI scripting, rather than telling an application to do something (eg. tell application “Adobe Acrobat Pro”), you tell system events to tell the application to do something. system events refers to applications as processes. make sure acrobat is running and then run this in script editor (also found in applications > applescript) :

tell application "System Events"
  get name of every process
end tell

you’ll get a list of names in the results window — some of which you may not recognise. this is where you find out that system events refers to ‘adobe acrobat pro’ as, simply, ‘acrobat’. so you would address acrobat like this :

tell application "System Events"
  tell process "Acrobat"
    -- do something --
  end tell
end tell

the first thing you’ll want to address is the menu bar at the top of the screen — acrobat, file, edit, view, etc. the following script shows that, to access a menu, you need to first address the associated menu item. weird eh? :

tell application "System Events"
  tell process "Acrobat"
    tell menu bar 1
      tell menu bar item "Advanced"
        tell menu "Advanced"
          tell menu item "Document processing"
            tell menu "Document processing"
              click menu item "Batch Processing..."
            end tell
          end tell
        end tell
      end tell
    end tell
  end tell
end tell

pretty straightforward so far? ok. now, the above script will open the ‘batch sequences’ window :

screen grab of batch sequences window

with this example we want to run the optimise sequence — so we need to select the sequence and then click the run sequence button. and this is where things REALLY get confusing. exactly how do we find the terminolgy to address the right bits? we ask for the window’s UI elements :

tell application "System Events"
  tell menu bar 1 of process "Acrobat"
    tell menu "Advanced" of menu bar item "Advanced"
      tell menu "Document Processing" of menu item "Document Processing"
        click menu item "Batch Processing..."
      end tell
    end tell
  end tell
  tell window "Batch Sequences" of process "Acrobat"
    return UI elements
  end tell
end tell

two things to notice here : first, the number of lines has been reduced by combining sets of two (eg. tell menu bar 1 of process “Acrobat”); second, when a new window is opened you need to go right back to system events to address that window (you can’t just continue on from after “click menu item “Batch Processing…””). the above script will give you something like this in script editor’s results window :
screen grab of UI elements of batch sequences window

a whole bunch of buttons — most of them are listed by name (that makes it easy to find the run sequence button) but what about those first three? buttons 1, 2, & 3 are the red, yellow and green lights you get at the top of every window these days. the only other UI elements are some static text (the window’s title) and a scroll area — ahh, that sounds right, the list of sequences are within something that might be called a scroll area… ok, how do we find out how to talk to the scroll area? we ask for its UI elements :

tell application "System Events"
  tell menu bar 1 of process "Acrobat"
    tell menu "Advanced" of menu bar item "Advanced"
      tell menu "Document Processing" of menu item "Document Processing"
        click menu item "Batch Processing..."
      end tell
    end tell
  end tell
  tell window "Batch Sequences" of process "Acrobat"
    tell scroll area 1
      return UI elements
    end tell
  end tell
end tell

… and here are the results :
screen grab of UI elements of scroll area 1

only two UI elements for the scroll area — one is a scroll bar (probably not what we’re looking for) and the other is an outline. outline? WTF? oh well, let’s keep going, see what we find (we’re actually nearly there) :

tell application "System Events"
  tell menu bar 1 of process "Acrobat"
    tell menu "Advanced" of menu bar item "Advanced"
      tell menu "Document Processing" of menu item "Document Processing"
        click menu item "Batch Processing..."
      end tell
    end tell
  end tell
  tell window "Batch Sequences" of process "Acrobat"
    tell outline 1 of scroll area 1
      return UI elements
    end tell
  end tell
end tell

… gives us this :
screen grab of UI elements of outline 1

ooh… that looks like something we can work with. let’s try it :

tell application "System Events"
  tell menu bar 1 of process "Acrobat"
    tell menu "Advanced" of menu bar item "Advanced"
      tell menu "Document Processing" of menu item "Document Processing"
        click menu item "Batch Processing..."
      end tell
    end tell
  end tell
  tell window "Batch Sequences" of process "Acrobat"
    tell outline 1 of scroll area 1
      select row 4
    end tell
    click button "Run Sequence"
  end tell
end tell

bingo! first we have to open the batch sequences window, then select row 4 of outline 1 of scroll area 1, then click the run sequence button. phew!

now you can see why GUI scripting is only used as a last resort. there are third party products which make it easy to drill down through the various UI elements. and apple provide a free accessibility inspector with its developer tools or the, also free, UI elements inspector.

but why do things the easy way when you can have sooo much fun working it out the hard way?

macgrunt icon

InDesign tip : #08

this tip is more about personalisation than automation — but it can still save you some time. different types of jobs require different tools. it makes sense to change your tool kit to suit your job, so that your screen isn’t cluttered with lots of unnecessary stuff. this is what workspaces are for.

a workspace saves which panels you have open and where they appear on the screen. this has two key advantages : if you have a saved workspace you can quickly declutter your screen if it starts to get a bit out of control; and by using multiple workspaces you can have different setups for different tasks — for example, you may have one set of panels open when you are working on interactive documents, but a completely different set when you’re working with lots of tables.

from CS3 onwards, a workspace also saves your menu customisation (did you know that you can customise your menus now? — check the bottom of your ‘edit’ menu).

workspaces are easy — set your panels up the way you want them to appear for a particular project type. and then choose window menu > workspaces > new workspace (or save workspace, depending on your version) :

screen grab of workspaces in window menu

give your new workspace a name and save it :

screen grab of save workspace window

now, whenever you want to revert to that particular setup, just choose that workspace from the dropdown at the top right of your screen (prior to CS4 you need to access the workspaces from the window menu) :

screen grab showing how to choose workspace from dropdown

note: in later versions, for some reason, if you’re already using a particular workspace and it becomes a bit messy, you can’t revert by simply selecting it again from the list. you need to go further down and select reset [your workspace name]. that’s a really strange change from the simpler functionality in CS2.

macgrunt icon

InDesign scripting : lesson 07

here’s a simple one-lesson script before we start on a series of lessons about exporting PDFs. sometimes it’s handy to be able to toggle between different preference settings: measurement units; dictionaries; keyboard increments; or, in this case, vector display. most of the time it’s better to display vector images as high res, because the proxy vector preview is truly atrocious. but your screen redraw time gets really bogged down for files which have too many vector images — so then it’s better to set it back to proxy. here’s a basic if/then script to toggle between the two preferences :

tell application "Adobe InDesign CS4"
    if (vector of display settings) contains proxy then
        set properties of display settings to {vector:high resolution}
    else
        set properties of display settings to {vector:proxy}
    end if
end tell

this is the simplest form of toggle — two possible states, check which one is current then switch to the other.

the real purpose of this lesson is to have another look at the InDesign applescript dictionary first discussed in lesson 02. this is an example of how sometimes it may take a little digging around to find the exact terminology you’re looking for.

if you have a look at your InDesign preferences you’ll find that the vector view settings are managed from the ‘display performance’ window :

screen grab of display performance preferences window

that seems like a logical place to start searching the dictionary. but if you search for “display performance” you’ll get something like this :

screen grab of display performance entry in applescript library

… not very helpful. no mention at all of how to display vector images. bugger. InDesign has excellent applescript support. that is, there aren’t too many InDesign commands that can’t be performed through scripting. BUT the documentation — the dictionary — could be structured a leetle bit more closely to the user interface.

anyway, that’s just the way it is — so, maybe try “vector” :

screen grab of vector entry in applescript library

… ah, that’s better. here we can see an entry for “vector” as a property belonging to the “preferences suite”. and this is where we find out that if we want to change how vector art is previewed, we have to address display settings, not display performance.

luckily, this was an easy one. it’s not always so straightforward. but always remember, when things get difficult, google is your friend.

ok. now for your homework. how would you alter the script so that it toggles between all three vector display options?

macgrunt icon