InDesign scripting : lesson 12

this is the fifth and final (for now) in a series of lessons on exporting pdfs using applescript. we started this script in lesson 11 which showed how to create an interface to capture some choices from the user. the finished script will export separate pdfs for different page ranges within the one document.

the next portion of the script does three things : it creates a folder in the same location as the InDesign file with the ‘mgSubFolder’ name specified in the first part of the script ; it creates a truncated version of the filename for us to append the page ranges to ; and it tells InDesign the pdf export preset we want to use :

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

set mgDocName to name of active document
set text item delimiters of AppleScript to {"."}
set mgDocName to text item 1 of mgDocName --strips extension from filename
set text item delimiters of AppleScript to {" "}
set mgDocName to (text item 1 of mgDocName & " " & text item 2 of mgDocName)
set text item delimiters of AppleScript to ""

set export reader spreads of PDF export preferences to false
set properties of PDF export preferences to properties of PDF export preset mgExport

that middle section is the place to play around with your own preference for how to name your pdfs. text item delimiters determine which character is used to separate bits of text — and those bits of text are called text items. these three examples should help to demonstrate :

set mgDocName to "54321 This_Is A-Weird File_Name.indd"
set text item delimiters of AppleScript to {"."}
return text items of mgDocName
-- > {"54321 This_Is A-Weird File_Name", "indd"}  - 2 text items
set mgDocName to "54321 This_Is A-Weird File_Name.indd"
set text item delimiters of AppleScript to {"_"}
return text items of mgDocName
-- > {"54321 This", "Is A-Weird File", "Name.indd"} - 3 text items
set mgDocName to "54321 This_Is A-Weird File_Name.indd"
set text item delimiters of AppleScript to {" "}
return text items of mgDocName
-- > {"54321", "This_Is", "A-Weird", "File_Name.indd"} - 4 text items

so, you need to change that middle section to suit your current filenaming protocol. ALWAYS set your text item delimiters back to the default “” before moving on.

ok, the last bit of the script repeats through the list of page ranges we captured in ‘mgPageList’ :

repeat with mgExportPage in mgPageList
  set page range of PDF export preferences to mgExportPage
  set mgFilePath to mgFolder & mgSubFolder & ":" & mgDocName & "_" & mgExportPage & ".pdf" as string
  if mgSpreads is "true" then
    if mgExportPage contains "-" then
      set export reader spreads of PDF export preferences to true
    end if
  end if
  tell active document
    export format PDF type to mgFilePath without showing options
  end tell
  set export reader spreads of PDF export preferences to false
end repeat

well, that’s it. it’s a good idea to add another dialog box at the end, just to let you know when all the exporting has completed. once you put all those bits together you should have a script which looks something like this (click to enlarge) :
screen grab of final Export As Separate PDFs script

or, if you’re feeling particularly lazy, you can get the completed script

macgrunt icon

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

image processing with applescript II

the previous post showed how to scale a whole bunch of images without having to open them in photoshop — using image events in applescript. image events can do a few other transformations as well — flip, crop, rotate, pad. but one very important transformation is missing from image events — changing colour space.

this is odd because image events is really just an easy way to access the power of sips — the command line image processor you would use through terminal — and sips lets you change colour space. well, that’s not precisely true — if you open terminal and type in “man sips” you’ll find that the key “space” is read only. but what you can change is the image’s profile.

fortunately, you can still access the power of sips through applescript by using the “do shell script” command. here’s one way :

do shell script "sips -m '/System/Library/ColorSync/Profiles/sRGB Profile.icc' " & quoted form of POSIX path of [yourImage]

-m is the match profile function. if you match to an rgb profile, your image will be converted to the rgb colour space. if you wanted your image saved with a preview icon you’d need to add the -i function.

now, you could integrate that command into the script from the previous post. but if you have to use sips for the colour conversion, you might as well use it for the rescaling as well. this will give you a much cleaner script because, unlike image events, you can specify a pixel height (or pixel width) without the hassle of that calculation we did in the previous post :

do shell script "sips --resampleHeight '500' " & quoted form of POSIX path of [yourImage]

you’d have to agree, that’s a hell of a lot cleaner than the image events version. ok, just one other thing we need to replicate from the previous script — it saved a duplicate of the image and left the original untouched. to do that with sips, you add an out function to the first sips command :

do shell script "sips -m '/System/Library/ColorSync/Profiles/sRGB Profile.icc' " & quoted form of POSIX path of [yourImage] & " --out " & [yourNewImage]
do shell script "sips --resampleHeight '500' -i " & quoted form of POSIX path of [yourNewImage]

the first command saves a duplicate of the image to a new posix path (yourNewImage) and the second command does its conversion on that duplicate (and adds the preview icon).

The final script could look something like this :

tell application "Finder"
  set mgFolder to choose folder
  set mgFiles to items of mgFolder
  if (exists folder "500px" of folder mgFolder) is false then
    make folder at mgFolder with properties {name:"500px"}
  end if
end tell

set mgFinalFolder to mgFolder & "500px:" as string

repeat with mgFile in mgFiles
  set mgName to name of mgFile
  set mgFinalpath to mgFinalFolder & mgName
  set mgPath to POSIX path of (mgFile as text)

  --convert mgFinalpath to POSIX form
  set text item delimiters to ":"
  set mgFinalpath to text items 2 thru -1 of mgFinalpath
  set text item delimiters to "/"
  set mgFinalpath to mgFinalpath as string
  set text item delimiters to ""
  
  set mgFinalpath to quoted form of mgFinalpath
  
  do shell script "sips --resampleHeight '500' " & quoted form of POSIX path of mgPath & " --out " & mgFinalpath
  do shell script "sips -m '/System/Library/ColorSync/Profiles/sRGB Profile.icc' -i " & mgFinalpath
end repeat

notice this version of the script asks you to select a folder of images to process. the script has no error handling built in, so if the folder contained non-image files (or folders) the script in its current state would fail. you can easily change it back if you prefer the other functionality, or, even better, create it as a droplet instead. see renaming finder items for how to save an applescript as a droplet.

so there you have it — a way to scale and colour convert a bunch of images without the need for photoshop.

macgrunt icon

image processing with applescript

you can use photoshop to automate your image processing by creating an action and then running it as a batch or saving it as a droplet. it’s a really powerful way to get lots of repetitive work done quickly. but you probably already knew that.

it’s also possible to do basic image processing without photoshop or whatever image editor you use. this post will show how to resize images with applescript. the advantages? you don’t tie up photoshop for what is essentially monkey-work, you don’t get those flickering windows while photoshop opens and closes the files it’s processing, and this way is usually faster. interested now?

this method uses an application called “image events” which comes standard on the mac and is only accessible through applescript. here’s how you would scale an image selected in the finder. caution: this version of the script overwrites the original file — only use it on a duplicate.

copy this into your script editor (found in applications > applescript) :

tell application "Finder"
  set mgFile to selection
end tell
set mgPath to POSIX path of (mgFile as text)
tell application "Image Events"
  set mgImage to open mgPath as text
  scale mgImage to size 500
  save mgImage
  close mgImage
end tell

notice that the file goes through the same process in image events as it would in photoshop : open > scale > save > close. the scale command works on the longest edge — so, if your image is portrait, it will now be 500 pixels high; if it is landscape it will now be, you guessed it, 500 pixels wide.

ok, but what if you don’t want to overwrite your original? here’s one way to save the scaled version as a duplicate. this script will create a folder called “500px” for the scaled copy, leaving the original untouched :

tell application "Finder"
  set mgFile to selection
end tell

set mgFile to mgFile as alias
set mgPath to POSIX path of (mgFile as text)

tell application "Finder"
  set mgFolder to container of mgFile as alias
  set mgName to name of mgFile
  set mg500folder to "500px"
  if (exists folder mg500folder of folder mgFolder) is false then
    make folder at mgFolder with properties {name:mg500folder}
  end if
  set mg500path to (mgFolder as text) & mg500folder & ":" & mgName
end tell

tell application "Image Events"
  set mgImage to open mgPath as text
  scale mgImage to size 500
  save mgImage in mg500path
  close mgImage
end tell

this script first creates the folder if it does not already exist and then sets a new filepath to that folder for the final image (“set mg500path to …”). in image events we use the command “save mgImage in mg500path” rather than simply “save mgImage”. if you add “with icon” to the end of that line, your image will have a tiny preview as its icon instead of a generic icon.

alrighty, hopefully that’s all pretty straightforward — now let’s get a little complex. this next version of the script will scale a whole bunch of images to the same height. remember, image events scales the longest edge — so how would you scale a landscape image to 500 pixels high? :

global newHeight

tell application "Finder"
  set mgFiles to selection
end tell

repeat with mgFile in mgFiles
  set mgFile to mgFile as alias
  set mgPath to POSIX path of (mgFile as text)
  
  tell application "Finder"
    set mgFolder to container of mgFile as alias
    set mgName to name of mgFile
    set mg500folder to "500px"
    if (exists folder mg500folder of folder mgFolder) is false then
      make folder at mgFolder with properties {name:mg500folder}
    end if
    set mg500path to (mgFolder as text) & mg500folder & ":" & mgName
  end tell
  
  tell application "Image Events"
    set mgImage to open mgPath as text
    copy dimensions of mgImage to {Wdth, Hght}
    my processData(Wdth, Hght)
    scale mgImage to size newHeight
    save mgImage in mg500path
    close mgImage
  end tell
end repeat

on processData(Wdth, Hght)
  set mgComparison to Wdth - Hght
  if mgComparison > 0 then -- image is landscape
    set mgCalculation to Wdth / Hght
    set newHeight to round (500 * mgCalculation)
  else --image is square or portrait
    set newHeight to 500
  end if
end processData

you can see here, we use image events to get the dimensions of the image, then we use a subroutine to do a comparison to work out if the image is landscape or portrait. if the image is landscape we divide the width by the height to get a proportion by which to multiply the scale factor (500). no doubt you can work out how to change that subroutine if you wanted to scale all images to 500 pixels wide instead.

please note that this method is not always 100% accurate — you will sometimes get an image only 499 pixels high.

this workflow was developed to process hundreds of product images for a webshop. however, there’s still one step missing — ensuring all the images are rgb — but that’s going to have to wait until the next post.

macgrunt icon

InDesign tip : #10

since CS4 you’ve been able to rotate the preview of a page or spread, making it easy to review rotated content. you do it like this :
screen grab of unrotated page
screen grab of how to rotate spread from view menu
screen grab of rotated page

you’re not actually rotating the page, just the preview of the page. you’ll notice the pasteboard also gets rotated. a special icon in the pages panel shows you the preview has been rotated :
screen grab of pages panel showing rotation icon

this is a fantastic feature for people working with packaging because artwork for boxes and whatnot usually have elements rotated 90, 180 and 270 degrees — all on the one page.

this is also really useful when you are working on a document to be produced as vertical spreads — like a wall calendar. traditionally these had to be compiled as single pages, but now an entire document can be set up in rotated spreads.

hopefully InDesign will someday allow for true vertical spreads because, brilliant as rotated previews are, there is one major drawback — it really makes it difficult when working out x and y ruler coordinates.

macgrunt icon