InDesign scripting : lesson 11

this is the fourth in a series of lessons on exporting pdfs using applescript. lessons 08 and 09 showed how to export all open InDesign files at once. this next script will create separate pdfs for different page ranges within the one document. this is really handy in a publishing environment where you often export just portions of a file, rather than the whole document.

as with the first script, this one begins by creating an interface to get user input. InDesign offers scripters an excellent range of UI elements — this dialog has two sets of radio buttons and a text edit field. copy this into your script editor (found in applications > applescript) :

tell application "Adobe InDesign CS4"
  activate
  set mgDialog to make dialog with properties {name:"This script exports specified pages as separate 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
      tell (make border panel)
        tell (make dialog column)
          make static text with properties {static label:"Page range to export :    "}
        end tell
        tell (make dialog column)
          set mgPageRange to make text editbox with properties {edit contents:""}
        end tell
      end tell
      tell (make border panel)
        tell (make dialog column)
          make static text with properties {static label:"Export spreads as :    "}
        end tell
        tell (make dialog column)
          set mgSpreadsButtons to make radiobutton group
          tell mgSpreadsButtons
            make radiobutton control with properties {static label:"Separate pages", checked state:true}
            make radiobutton control with properties {static label:"Spreads"}
          end tell
        end tell
      end tell
    end tell
  end tell
  set mgResult to show mgDialog
end tell

that script gives you a dialog something like this :
screen grab of user interface created by script

well, that’s OK, but it’s a bit fugly. to get things lining up, you need to specify some minimum widths. the static text elements should all be the same width, and the interactive elements should all be the same width :

tell application "Adobe InDesign CS4"
  activate
  set mgDialog to make dialog with properties {name:"This script exports specified pages as separate 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 :    ", min width:170}
        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", min width:150}
            make radiobutton control with properties {static label:"Screen Resolution"}
          end tell
        end tell
      end tell
      tell (make border panel)
        tell (make dialog column)
          make static text with properties {static label:"Page range to export :    ", min width:170}
        end tell
        tell (make dialog column)
          set mgPageRange to make text editbox with properties {edit contents:"", min width:150}
        end tell
      end tell
      tell (make border panel)
        tell (make dialog column)
          make static text with properties {static label:"Export spreads as :    ", min width:170}
        end tell
        tell (make dialog column)
          set mgSpreadsButtons to make radiobutton group
          tell mgSpreadsButtons
            make radiobutton control with properties {static label:"Separate pages", checked state:true}
            make radiobutton control with properties {static label:"Spreads", min width:150}
          end tell
        end tell
      end tell
      make static text with properties {static label:" "}
      make static text with properties {static label:"Commas = separate PDFs (eg. 1, 2, 3, 4 gives four PDFs)"}
      make static text with properties {static label:"Hyphens = the same PDF (eg. 1, 2-3, 4 gives three PDFs)"}
    end tell
  end tell
  set mgResult to show mgDialog
end tell

notice how the static text elements align right by default — you just have to get used to it because there’s no way around it. this version of the dialog also has a couple of hints for the user at the bottom :
screen grab of revised user interface

aawww — nicer. ok, now to capture the results of the dialog. you’ll remember from lesson 08 that you have to check that the ‘OK’ button is clicked, that radio buttons are numbered from 0 and that this is where you must use the exact name of your pdf export presets (case sensitive). this portion of the script comes immediately before the last end tell :

  if mgResult is true then
    set mgExport to selected button of mgExportButtons
    set mgPageList to edit contents of mgPageRange as string
    set mgSpreads to selected button of mgSpreadsButtons
    destroy mgDialog
  else
    destroy mgDialog
    error number -128
  end if
  
  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
  if mgSpreads is 1 then
    set mgSpreads to "true"
  end if

  set text item delimiters of AppleScript to " "
  set mgPageList to text items of mgPageList
  set text item delimiters of AppleScript to {""}
  set mgPageList to mgPageList as string
  set text item delimiters of AppleScript to ","
  set mgPageList to text items of mgPageList
  set text item delimiters of AppleScript to ""

now, you’ll understand most of that because you studied lesson 08 so well. here’s an explanation of that last bit where we process mgPageList through three coercions… imagine your user is a keyboard hack — a really shocking typist who enters this in the text editbox :

"1, 2-3, 14 -15, 26 - 27,   38,   49  "

you could just let them suffer and have the script fail, or you could take pity on them and add some processing to make everything right. the first coercion above gives you this monstrosity :

{"1,", "2-3,", "14", "-15,", "26", "-", "27,", "", "", "38,", "", "", "49", "", ""}

but don’t panic, because the second coercion renders this :

"1,2-3,14-15,26-27,38,49"

and the third coercion makes it all ok. a nice neat list, each item of which will be its own pdf. this example will export six pdfs :

{"1", "2-3", "14-15", "26-27", "38", "49"}

well, that’s it for now. we’ll complete this script in the next lesson. the finished script will add the page ranges to a truncated version of the filename — so exporting from “54321 ThisFile Name.indd” gives a pdf named, for example, “54321 ThisFile_2-3.pdf”. you’ll learn how flexible that process is — so you can tailor the renaming to your specific needs.

until then, keep grunting.

go to lesson 12

macgrunt icon

InDesign scripting : lesson 10

the export pdfs script in lesson 09 showed one form of repeat loop:

repeat with mgDoc in every document

this repeat loop worked only because we closed each document before processing the next one. if you wanted to leave the files open, you’d need to use a different repeat loop.

what the? let’s have a look why. here’s a test to run in script editor (found in applications > applescript) :

tell application "Adobe InDesign CS4"
  set mgList to {}
  repeat with mgDoc in every document
    set active document to mgDoc
    set end of mgList to name of active document
  end repeat
end tell
return mgList

the test loops through all open documents and places a document name into a list at each pass. with six open documents, here are the results for both CS4 and CS2 :

--CS4 - {"Doc_6.indd", "Doc_5.indd", "Doc_3.indd", "Doc_6.indd", "Doc_2.indd", "Doc_3.indd"}
--CS2 - {"Doc_6.indd", "Doc_6.indd", "Doc_6.indd", "Doc_6.indd", "Doc_6.indd", "Doc_6.indd"}

as you can see, the loop does NOT access each document — in CS4 it doubles up on docs 3 and 6, and misses docs 1 and 4 completely; in CS2 the repeat is even more of a disaster. here’s a variation on that test which will give the exact same results :

tell application "Adobe InDesign CS4"
  set mgList to {}
  repeat with mgDoc in every document
    set active document to mgDoc
    set end of mgList to name of mgDoc
  end repeat
end tell
return mgList

now, here’s a form of repeat loop which works with CS2, but no longer works with CS4 and, presumably, later versions :

tell application "Adobe InDesign CS4"
  set mgList to {}
  repeat with mgDoc from 1 to count every document
    set active document to document mgDoc
    set end of mgList to name of active document
  end repeat
end tell
return mgList

… and the results …

--CS4 - {"Doc_6.indd", "Doc_5.indd", "Doc_3.indd", "Doc_6.indd", "Doc_2.indd", "Doc_3.indd"}
--CS2 - {"Doc_6.indd", "Doc_5.indd", "Doc_4.indd", "Doc_3.indd", "Doc_2.indd", "Doc_1.indd"}

no doubt there’s a perfectly reasonable explanation for why these loops, which appear logically correct, fail to cycle through all open documents. and it probably has something to do with the way InDesign indexes open files. whatever. who cares. all we want to know is how to do it correctly. here’s the magic incantation :

tell application "Adobe InDesign CS4"
  set mgList to {}
  set mgDocList to name of every document
  repeat with i from 1 to (count of mgDocList)
    set active document to (every document whose name is item i of mgDocList)
    set end of mgList to name of active document
  end repeat
end tell
return mgList

… and the magic results …

--CS4 - {"Doc_6.indd", "Doc_5.indd", "Doc_4.indd", "Doc_3.indd", "Doc_2.indd", "Doc_1.indd"}
--CS2 - {"Doc_6.indd", "Doc_5.indd", "Doc_4.indd", "Doc_3.indd", "Doc_2.indd", "Doc_1.indd"}

a bit convoluted, granted, but hey, it works. the correct syntax is “every document whose name is…”, even though there’s probably only one file with each name. strange but true.

this is a brilliant example of how applescript syntax is sometimes so complicated and difficult to work out that it may seem preferable to just stab yourself in the eye with a fork. from (dodgy) memory, the genius who shared this was probably the applescript guru — Shane Stanley — over at the adobe user forums.

go to lesson 11

macgrunt icon

InDesign scripting : lesson 09

this is the second of a series of lessons on exporting pdfs using applescript. we started this script in lesson 08 which showed how to create a UI (user interface) so the user can select a PDF export preset to use, and how to capture the resulting data into variables for use in the next part of the script. the finished script will export all open InDesign documents in one go — rather than you having to export each one separately. but, this script may still be useful to you if you only ever work on one document at a time.

ok, here we go. we’ve captured the name of the export preset we want to use in the variable mgExport. now we just need to tell InDesign :

set properties of PDF export preferences to properties of PDF export preset mgExport
set page range of PDF export preferences to all pages

hopefully, the first line is pretty self explanatory. you need the second line because the page range is not saved as part of the export preset. InDesign will default to whatever was used at the last export. so you have to reset it to export all pages.

the rest of the script is held within a repeat loop — to address each of the open documents in turn. this version of the script closes each document after export, so we can use this form of repeat statement :

repeat with mgDoc in every document

each pdf will be saved to a folder in the same location as the InDesign document. so, first we need to determine where the document is saved and then create the appropriate folder if it does not already exist. this is where we use the mgSubFolder variable we created in the first part of the script :

set mgFolder to file path of active document
tell application "Finder"
  if (exists folder mgSubFolder of folder mgFolder) is false then
    make new folder at mgFolder with properties {name:mgSubFolder}
  end if
end tell

the first line returns a colon delimited path something like this “MacGrunt:Users:ThisUser:Documents:”. a colon at the end of the path indicates that it is referring to a folder (we’ll use this information in a moment). the rest uses the finder to first check if the appropriate folder is there (exists) and create one if not (exists is false).

the next thing to do is determine the name for the pdf. this script uses the full name of the InDesign file minus the extension (.indd) — because you don’t want your pdf to be called ThisDocument.indd.pdf :

set mgDocName to name of active document
set text item delimiters of AppleScript to "."
set mgShortName to text item 1 of mgDocName
set text item delimiters of AppleScript to ""
set mgFilePath to mgFolder & mgSubFolder & ":" & mgShortName & ".pdf" as string

text item delimiters determine which character is used to separate bits of text. applescript’s default delimiter is “” (or nothing). by setting the delimiter to “.” we can extract everything before the “.” (your filename). text item 2 of mgDocName is everything after the “.” (ie. the extension indd). this, of course, assumes that you never use “.” as part of your filename which, of course, you never would.

that last line sets the final filepath of the pdf. this is where we use our knowledge that a colon is required to specify a folder. we need to add one to the filepath because the mgSubFolder variable (eg. “Prepress Files”) doesn’t contain a colon. that long last line results in the new variable, mgFilePath, looking something like this : “MacGrunt:Users:ThisUser:Documents:Prepress Files:ThisDocument.pdf”.

ok, now all we need to do is export the pdf. once that is done, we save and close the current document and close the repeat loop. this is the most straightforward part, because we’ve already done the hard work of setting the export preferences and the filepath :

  tell active document
    export format PDF type to mgFilePath without showing options
  end tell
  save active document
  close active document
end repeat

well, that’s it. once you put all those bits together you should have a script which looks like this (click to enlarge) :

screen grab of complete export PDFs script

save that into your scripts panel folder and you’ll be rocking.

the next lesson will show why the type of repeat loop we used here will only work if we close each file after export. if you want to keep all the files open, you’ll need a different form of the repeat loop statement. after that we’ll move on to a different type of pdf export script.

go to lesson 10

macgrunt icon

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