InDesign scripting : lesson 26

you learn something new every day — well, at least you should, if you’re paying sufficient attention.

way back in lesson 04 you’ll find this statement :

the first scripting lesson – lesson 01 – suggested you save your InDesign applescripts in script file format (.scpt). but there’s a very good reason why you should ignore such nonsensical advice and save them in text file format (.applescript) instead…

well, it turns out that there’s also a very good reason to ignore THAT and go on and save your scripts in .scpt format — the marvellous script property.

a script property is an immensely handy little scripting trick. it allows you to save data into a variable, within the script, so that it is still available the next time the script is run, and the next time. The data is persistent.

one example of the use of a script property is in the finder cleanup app. on the first run, this script captures the way finder windows are set so that, the next time the script is run, and every time after, those same finder windows can be opened in exactly the same place and pointing to exactly the same folders. so, the data is captured, then used over and over again.

but, if your InDesign script is saved in text format (.applescript) the data captured in the script property is not persistent. it works fine while the script is running, but the data is lost once the script ends and has to be reinstated the next time the script is run.

so, if you’re going to take advantage of a persistent script property you need to save your work in the .scpt format.

the next scripting lesson will show how a script property is used in a variation of the slug form script from lesson 25.

macgrunt icon

InDesign scripting : lesson 25

a slug form is a brilliant way to attach proofing data to an InDesign file — especially when you’re trying to keep track of which version of a job a client is signing off on.

there are many variations on the slug form, but all of them need to be filled out at some stage and many of them need to be updated with each new proof. here’s one that can be updated entirely automatically each time a pdf is exported — using applescript (click to enlarge) :
screen grab of a typical slug form

code and job are details pulled from the filename ;
client will be pulled from the document’s filepath ;
size and page are pulled from data for each page ;
proof is incremented by 1 each time the script is run ; and
proof date is gathered using a shell script.

for this example we’ll be using this document in this folder structure :
screen grab showing indesign file in folder hierarchy

the first part of the script starts capturing the data we need :

set mgDate to do shell script "date '+%d/%m/%y'"

tell application id "com.adobe.InDesign"
  tell active document
    set mgPath to file path as string
    set mgName to name
    
  end tell
end tell

the shell script grabs the current date and pulls the elements we want into a text string (mgDate) like this “31/09/12”. that’s the australian date format, if you wanted that weird month-day-year format you’d change it to :

set mgDate to do shell script "date '+%m/%d/%y'"

if you wanted to add the time as well, you could do it like this :

set mgDate to do shell script "date '+%H:%M %d/%m/%y'"

which would make mgDate something like “13:45 31/09/12”

we’ve also captured mgPath —
“Macintosh HD:macgrunt:clients:macgrizzle:mg34567_stationery:”
and mgName —
“mg34567_letterhead.indd”
which now have to be broken up to get at their bits. this is done with text item delimiters. a text item delimiter specifies which character is used to separate elements in a text string. in a sentence, the space character is used to separate words. in the file path above, the colon character is used to separate the folder names. so, here’s how we get the bits we need :

    set mgPath to file path as string
    set mgName to name
    set text item delimiters of AppleScript to ":"
    set mgClient to text item 4 of mgPath
    set text item delimiters of AppleScript to "."
    set mgShortName to text item 1 of mgName
    set text item delimiters of AppleScript to "_"
    set mgCode to text item 1 of mgShortName
    set mgJob to text item 2 of mgShortName
    set text item delimiters of AppleScript to "" --(updated from 'default')

this gives us three elements : mgClient = “macgrizzle”, mgCode = “mg34567”, and mgJob = “letterhead” (we’ve also captured mgShortName “mg34567_letterhead” which we could use when we export the PDF).

now, this workflow was created for InDesign files that could have different page sizes throughout and needed a separate slug for each page. so the next part gets placed within a repeat loop to address each page in turn :

    repeat with mgPage from 1 to count pages
      set mgWidth to item 4 of bounds of page mgPage
      set mgWidth to mgWidth as integer
      set mgHeight to item 3 of bounds of page mgPage
      set mgHeight to mgHeight as integer
      set mgDimensions to ((mgWidth as string) & "x" & mgHeight as string) & "mm"

      set active page of layout window 1 to page mgPage
      tell active page of layout window 1
        try -- check to see that correct SLUG is on the page
          set mgFrame to ((text frame 1 of group 1) whose label is "SLUG")
        on error
          try
            set mgFrame to (text frame 1 whose label is "SLUG")
          on error
            display dialog "Your SLUG should be in place on every page." & return & return & "(Note : the correct SLUG has been given a script label to help with automation)"
          end try
        end try
      --bits to enter data into slug table here
      end tell
    end repeat

the first part captures the page number (mgPage) and the page size (mgDimensions). notice that a page does not have a ‘size’, it has bounds and we have to get the dimensions from that. bounds are expressed as a list of four numbers which define, in order, the top, left, bottom and right edges of the page. for an A4 page with mm as the measurement unit, the bounds will be approximately {0.0, 0.0, 297.0, 210.0}. if you’re in the habit of moving your origin, you’ll need to change the way you capture the dimensions which may then be something like {-100.0, -50.0, 197, 160} for example.

the next part checks if there’s a slug on the page (mgFrame). the easiest way to do this is to give the text frame in InDesign a script label. you select the text frame and then choose window > utilities > script label (in CS6 — it might be in a different place in other versions of InDesign) and then type in whatever label you are planning to use. DO NOT hit return/enter, as this will become part of your script label — simply click outside the window instead. script labels are case sensitive :
screen grab of script label window

we check for mgFrame twice — first to see if it’s part of a group (the way the slug was originally set up) and then again in case someone inadvertently ungrouped the slug. this is called error handling — we don’t want the whole script to fail just because the slug is ungrouped.

o … k … now we’ve got all the bits of data we need and we just need to plug them all into the slug. to understand the next bit it helps to know how the slug frame has been created — it’s actually a table with three rows — six cells in the first row, eight cells in the second row and one cell in the third row (again, click to enlarge) :
screen grab of slug showing cell breakdown

we captured the text frame (mgFrame) now we need to address the table within that frame :

        tell table 1 of mgFrame
          set contents of cell 2 of row 1 to mgCode
          set contents of cell 4 of row 1 to mgJob
          set contents of cell 6 of row 1 to mgClient
          set contents of cell 2 of row 2 to mgDimensions
          set contents of cell 4 of row 2 to mgPage as string
          if contents of cell 6 of row 2 is "#" then
            set contents of cell 6 of row 2 to "1"
          else
            set contents of cell 6 of row 2 to (contents of cell 6 of row 2) + 1 as string
          end if
          set contents of cell 8 of row 2 to mgDate
        end tell

hopefully that all makes sense. if not, flick a question through. when it’s done its thing the slug will look something like this :
screen grab of completed slug
bonza.

once that process has been repeated for all the pages it’s time to export the pdf proof. we’re not going to go into all that here — you can see how to export pdfs in lesson 08, lesson 11 and lesson 18

when you’re done cobbling all those bits together you’ll have a script that looks something like this :
screen grab of script in script editor

rippa rita

macgrunt icon

InDesign scripting : bringing it together

this post is a response to a question from Tom :

I am working towards a compilation of scripts to take customer supplied Indd documents – Drop them on applet or automator – Print 1 laser / create 3 PDF files (different settings) / email the low res proof to CSR. … What I picture in my head is getting the email PDF proof script running the way I want – Put it into automator as part of a larger workflow. Then get the other elements as scripts – put those into the same workflow – ??

two things to note straight up — you don’t need separate scripts and you don’t need automator. but this is a great little example because all we need to do is pull together a bunch of script snippets already scattered around this site. as you read through you’ll see highlighted bits that link back to posts with more details.

let’s go … first things first — we want this to be a droplet (so you can drag and drop files onto the app for processing) so the whole script will be wrapped in an on open handler. and you’ll need to wrap it in a repeat loop so it can handle more than one dropped file at a time. and it would be a good idea to alert the user when the script has finished doing its thing. so the initial bits will look something like this :

on open mgItems
  repeat with mgThisItem in mgItems
    -- rest of script here
  end repeat
  display dialog "some kind of confirmation message here"
end open

then we need InDesign to open and process each file. but we should put this in a try block to ensure the script doesn’t crash if a different file type is dropped on it inadvertently :

on open mgItems
  repeat with mgThisItem in mgItems
    tell application id "com.adobe.InDesign"
      try
        open mgThisItem
        tell active document
          -- do printing and pdf stuff in InDesign
        end tell
        close active document
      on error
        -- decide what kind of error handling you want to include if the file won't open
      end try
    end tell
    -- rest of script for email processing here
  end repeat
  display dialog "some kind of confirmation message here"
end open

the observant will notice that the tell application command is different from previous scripts on this site. this is the way to address any version of InDesign — but be aware that other parts of this script may have terms or syntax that may need to be adjusted for your particular version of InDesign.

ok — next comes the printing bit. if you’re using only one print preset for this workflow you’d use a simple line :

print using "name_of_print_preset" without print dialog

but if you need to change the print preset based on the file specs you’d need something more complex like in InDesign scripting : lesson 24.

exporting pdfs is covered in lessons 08, 09, 10, 11, and 12 and cover a few different ways to approach the problem. three basic things need to be determined : the export preset to be used, the name of the pdf and the location to save it to.

the simplest version of this part of the workflow might look like this (but depends on Tom’s specific needs) :

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 mgHRFilePath to "path:to:highres:folder:" & mgShortName & "_HR.pdf" as string
set properties of PDF export preferences to properties of PDF export preset "HighRes"
tell active document
  export format PDF type to mgHRFilePath without showing options
end tell
set mgHRDigitalFilePath to "path:to:highresdigital:folder:" & mgShortName & "_HRD.pdf" as string
set properties of PDF export preferences to properties of PDF export preset "HighResDigital"
tell active document
  export format PDF type to mgHRDigitalFilePath without showing options
end tell
set mgProofFilePath to "path:to:proof:folder:" & mgShortName & "_proof.pdf" as string
set properties of PDF export preferences to properties of PDF export preset "Proof"
tell active document
  export format PDF type to mgProofFilePath without showing options
end tell

that’s it for the InDesign bits. now to email that third pdf. first get a reference to the file, then create the message — Tom’s using Entourage (thanks to Ben Waldie at MacTech for the Entourage code) :

tell application "Finder"
  set mgFile to mgProofFilePath as alias
end tell
set mgSubject to "proof of job " & mgShortName as string
tell application "Microsoft Entourage"
   set theRecipients to {{address:{display name:"CSR Name", address:"CSR@tomsplace.com"}, recipient type:to recipient}}
   set theMessage to make new outgoing message with properties {recipient:theRecipients, subject:"mgSubject", content:"here's your proof dude", attachments:mgFile}
   send theMessage
end tell

again, this is pretty much the simplest form this part of the workflow could take. Tom will need to expand it to encompass his particular requirements.

the final basic structure could look something like this :

on open mgItems
  repeat with mgThisItem in mgItems

    tell application id "com.adobe.InDesign"
      try
        open mgThisItem
        tell active document
          print using "name_of_print_preset" without print dialog
        end tell
        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 mgHRFilePath to "path:to:highres:folder:" & mgShortName & "_HR.pdf" as string
        set properties of PDF export preferences to properties of PDF export preset "HighRes"
        tell active document
          export format PDF type to mgHRFilePath without showing options
        end tell
        set mgHRDigitalFilePath to "path:to:highresdigital:folder:" & mgShortName & "_HRD.pdf" as string
        set properties of PDF export preferences to properties of PDF export preset "HighResDigital"
        tell active document
          export format PDF type to mgHRDigitalFilePath without showing options
        end tell
        set mgProofFilePath to "path:to:proof:folder:" & mgShortName & "_proof.pdf" as string
        set properties of PDF export preferences to properties of PDF export preset "Proof"
        tell active document
          export format PDF type to mgProofFilePath without showing options
        end tell
        close active document
      on error
        -- decide what kind of error handling you want to include if the file won't open
      end try
    end tell

    tell application "Finder"
      set mgFile to mgProofFilePath as alias
    end tell
    set mgSubject to "proof of job " & mgShortName as string
    tell application "Microsoft Entourage"
      set theRecipients to {{address:{display name:"CSR Name", address:"CSR@tomsplace.com"}, recipient type:to recipient}}
      set theMessage to make new outgoing message with properties {recipient:theRecipients, subject:"mgSubject", content:"here's your proof dude", attachments:mgFile}
      send theMessage
    end tell

  end repeat
  display dialog "some kind of confirmation message here"
end open

of course, this isn’t a definitive solution — it’s simply a demonstration of one possible approach to the problem.

once you’re done compiling the perfect script, save it as an app and drag it onto your sidebar so it’s easily accessible — then start dropping those indd files.

macgrunt icon

InDesign scripting : lesson 24

waaay back in lesson 04 we looked at a script to automate printing (and lessons 05 and 06 explained how some of the script elements worked).

well, finally, it’s time to take printing automation to the next level. the original script prompts the user to select a print preset from a list. but that’s too much like hard work. what if the script could automatically decide which preset to use based on the document specs?

apologies to you lovely people in the States — we’re going to be using metric for this example because, well, it is the twenty first century after all and anything referred to as ‘imperial’ should be long dead.

the first part of the script captures a few bits of information from the document preferences. facing pages is boolean, so it returns true or false. page orientation returns landscape or portrait (square pages return portrait too). page height and width return real numbers in whatever measurement unit you’re using :

tell application "Adobe InDesign CS6"
  tell active document
    set mgPgFace to facing pages of document preferences as string
    set mgPgOrnt to page orientation of document preferences as string
    set mgPgHght to page height of document preferences
    set mgPgWdth to page width of document preferences
  end tell
end tell

display dialog (mgPgHght as string) & " : " & (mgPgWdth as string) & " : " & mgPgOrnt & " : " & mgPgFace

so, for a single A4 page the resulting dialog will look something like this :
screen grab of initial dialog

now, if you’re a neat freak (and aren’t we all?) you may prefer your real numbers converted to integers. notice that you can’t coerce a real to an integer as it is captured — the conversion has to be done separately :

tell application "Adobe InDesign CS6"
  tell active document
    set mgPgFace to facing pages of document preferences as string
    set mgPgOrnt to page orientation of document preferences as string
    set mgPgHght to page height of document preferences
    set mgPgWdth to page width of document preferences
    set mgPgHght to mgPgHght as integer
    set mgPgWdth to mgPgWdth as integer
  end tell
end tell

display dialog (mgPgHght as string) & " : " & (mgPgWdth as string) & " : " & mgPgOrnt & " : " & mgPgFace

then you’ll have neat (not necessary, but neat) :
screen grab of revised dialog
…and you can get rid of that display dialog line now — dialogs are a handy way to check your progress when developing a script.

ok, now, the complexity of the next bit is dependant on the complexity of your workflow. the workflow this script was developed for has only eight possible scenarios, roughly like so :
table showing print preset options for various document types

so, all we need to do is find out which of the scenarios our document falls into and select the corresponding print preset (which we’ll capture into the variable mgPrintPreset). let’s start with the two facing pages options (printed as spreads) :

if mgPgFace is "true" then --print document as spreads
  if mgPgHght is greater than 277 or mgPgWdth is greater than 200 then --use A3 fit preset
    set mgPrintPreset to "A3S fit"
  else --use A3 100% preset
    set mgPrintPreset to "A3S 100%"
  end if
else --print document as single pages
  --(scripting bits for single page options go here)
end if

this shows the basic approach to these kinds of problems — if/then/else. if something is true, then do this thing, else (otherwise) do this other thing. we just need to break the problem down into pairs of options.

and we can still use this method for eight different scenarios because if statements can also be nested — ifs within ifs. the full code for dealing with all eight possibilities looks like this :

if mgPgFace is "true" then --print document as spreads
  if mgPgHght is greater than 277 or mgPgWdth is greater than 200 then --use A3 fit preset
    set mgPrintPreset to "A3S fit"
  else --use A3 100% preset
    set mgPrintPreset to "A3S 100%"
  end if
else --print document as single pages
  if mgPgOrnt is "portrait" then --use one of the vertical presets
    if mgPgHght is greater than 277 or mgPgWdth is greater than 200 then --use one of the A3 presets
      if mgPgHght is greater than 400 or mgPgWdth is greater than 277 then --use A3 fit preset
        set mgPrintPreset to "A3V fit"
      else --use A3 100% preset
        set mgPrintPreset to "A3V 100%"
      end if
    else --use A4 vertical preset
      set mgPrintPreset to "A4V"
    end if
  else --use one of the horizontal presets
    if mgPgHght is greater than 200 or mgPgWdth is greater than 277 then --use one of the A3 presets
      if mgPgHght is greater than 277 or mgPgWdth is greater than 400 then --use A3 fit preset
        set mgPrintPreset to "A3H fit"
      else --use A3 100% preset
        set mgPrintPreset to "A3H 100%"
      end if
    else --use A4 horizontal preset
      set mgPrintPreset to "A4H"
    end if
  end if
end if

but it’s easier to understand in a screen grab of the code in script editor :
screen grab of this section of code in script editor

the bits in quotation marks are the names of the InDesign print presets, the green elements are the variables (remember you can name variables anything you like, just as long as it’s not a term reserved by applescript), and the other coloured bits are comments to help us keep track of what we’re doing. comments are preceded by two hyphens and are not actually part of the code — they’re little reminders that are especially helpful when revisiting the script sometime in the future.

the last line of code simply tells the document to print using the selected print preset :

print using (mgPrintPreset as string) without print dialog

cobble all those bits together and the complete script for this workflow looks something like this :
screen grab of complete script in script editor

now, obviously you’re not going to be able to use this one straight out of the box — you’ll have to do a little work to update it to your page sizes and print presets and whatnot to suit your workflow.

but once you’ve set it up you can do all your printing with a double click — rather than cmnd-p, click, choose, click, click …

OR, even better, reassign the cmnd-p shortcut to run your script.

bonza.

macgrunt icon

InDesign scripting : lesson 23

here’s a quickie based on a question over at the InDesignSecrets forum. how do you centre the page without changing your zoom level?

there are a few different ways to centre a page :
cmnd-0 = fit page
cmnd-opt-0 = fit spread
cmnd-opt-shift-0 = fit pasteboard
but all of these change your zoom level.

applescript is perfect for this kind of problem — you’ve got something that you want to do time and time again, but it’s not available in the standard package. as with most scripting solutions, you need to be a little bit cunning — if there was a ‘centre page’ command, it would be available in InDesign, but there’s not, so you have use a combination of other commands to get what you want.

for this lesson we’re using CS2, but it’s pretty much the same for other versions. let’s look at the dictionary — search for ‘zoom’ :
screen grab of CS2 dictionary showing zoom command
(click the image to get a clearer view) there’s a whole bunch of entries relating to interactive elements — probably not much use to us. there’s also a ‘zoom’ command — which, you can see, matches up with our zooming options directly in InDesign (view menu). there’s one other dictionary entry for zoom — zoom percentage — let’s check that out :
screen grab of CS2 dictionary showing zoom percentage property
bingo! here we see that the current zoom percentage is a property of the layout window. SO, all we need to do is capture that percentage, then centre the page, then reset the layout window to the correct percentage :

tell application "Adobe InDesign CS2"
  tell layout window 1 of document 1
    set theZoom to zoom percentage
    zoom given show pasteboard
    set zoom percentage to theZoom
  end tell
end tell

awesome — works perfectly… UNLESS you have something selected — then, as you know, InDesign’s default behaviour is to centre on the selection. now, if that’s what you want it to do, no problem. but the original spec was to centre the page. SO, first we need to drop the selection :

tell application "Adobe InDesign CS2"
  tell layout window 1 of document 1
    select nothing
    set theZoom to zoom percentage
    zoom given show pasteboard
    set zoom percentage to theZoom
  end tell
end tell

awesome — again.

just save whichever version works for you into your scripts panel folder. if you don’t know how to do that — go right back and have a look at InDesign scripting : lesson 01. remember to update the first line to your version of InDesign.

then, to complete the awesomeness, assign your preferred keyboard shortcut to activate the script. if you don’t know how to set your own keyboard shortcuts, you need InDesign tip : #06.

and now for your homework…
how would you change the script so that it centred on the page, but still maintained the selection?

macgrunt icon