Set Ruler Origin (CS2/CS3)
Very important for ease of placing elements according to Adobe’s own documentation. I’m only duplicating this code (duped almost verbatim from their guides) because this command’s importance cannot be understated in ensuring that your scripts will run as expected.
set ruler origin of view preferences of SLCDocument to page origin
Changing individual objects
In these examples, select objects first. The selection is actually an array, even if only one object is selected.
Set/Alter the label of an object
This is fairly straightforward and simple, but I use the label property for all sorts of uses especially for dynamic layouts.
tell application "Adobe InDesign CS2"
tell document 1
set theItem to item 1 of selection
set label of theItem to "biblio_frame"
return label of theItem
end tell
end tell
Get Page Item
This subroutine essentially requires that a page item be tagged in some manner
on GetPageItem(PageNumber, PageItemName) -- as page item (usually text frame) (Integer, String)
log "sub GetPageItem"
tell application "Adobe InDesign CS3"
tell kCurrentDocument
tell page PageNumber
set thisPageItem to 1
set firstPageItem to 1
set lastPageItem to (get count of page items)
repeat with thisPageItem from firstPageItem to lastPageItem
set thePageItem to page item thisPageItem
set thePageItemLabel to label of thePageItem
if thePageItemLabel is PageItemName then
return thePageItem
end if
end repeat
end tell
end tell
end tell
end GetPageItem
Get Bounds Of Page
on GetGeometricBoundsOfPage(PageNumber) --as list of integers {y1, x1, y2, x2}
tell application "Adobe InDesign CS3"
tell document 1
set thePage to page PageNumber
return geometric bounds of thePage
end tell
end tell
end GetGeometricBoundsOfPage
Create text frame, insert auto page number, style text
This is the core of all dynamic layouts.
set newTextFrame to make new text frame with properties {geometric bounds:{729, 36, 750, 75}, label:"PageNumberVerso"}
tell newTextFrame
set contents to auto page number -- inserts the glyph behind "^#" in the find and change window/preferences
tell every paragraph
set applied paragraph style to "FolioVerso"
set justification to left align
end tell
end tell
Expand Text Frame
This expands a text frame until the text contained inside is no longer overflowed. This and the Shrink Text Frame snippet below make for easy dynamic layouts.
on ExpandTextFrame(theFrame, theIncrement)
log "Sub ExpandTextFrame"
tell application "Adobe InDesign CS3"
set frameOverflow to overflows of theFrame
repeat while frameOverflow is true
set frameBounds to geometric bounds of theFrame
set mY1top to (item 1 of frameBounds)
set mX1left to (item 2 of frameBounds)
set mY2bottom to (item 3 of frameBounds)
set mX2right to (item 4 of frameBounds)
set mY2bottom to mY2bottom + theIncrement
tell theFrame
set geometric bounds to {mY1top, mX1left, mY2bottom, mX2right}
end tell
set frameOverflow to overflows of theFrame
end repeat
end tell
end ExpandTextFrame
Shrink Text Frame and Move Another Frame Relative To Final Size
As I’ve written elsewhere in the site, I prefer readable over all else.
MoveFrameDownRelativeToFrameAbove is neither brief nor abbreviated, but there is absolutely no mistaking what it does.
on ShrinkTextFrame(theFrame, theIncrement)
log "Sub ShrinkTextFrame"
tell application "Adobe InDesign CS3"
set frameOverflow to overflows of theFrame
repeat while frameOverflow is false
set frameBounds to geometric bounds of theFrame
set mY1top to (item 1 of frameBounds)
set mX1left to (item 2 of frameBounds)
set mY2bottom to (item 3 of frameBounds)
set mX2right to (item 4 of frameBounds)
set mY2bottom to mY2bottom - theIncrement
tell theFrame
set geometric bounds to {mY1top, mX1left, mY2bottom, mX2right}
end tell
set frameOverflow to overflows of theFrame
end repeat
end tell
end ShrinkTextFrame
on MoveFrameDownRelativeToFrameAbove(currentFrame, frameAbove)
log "MoveFrameDownRelativeToFrameAbove"
tell application "Adobe InDesign CS3"
set frameAboveBounds to geometric bounds of frameAbove
set faY2bottom to (item 3 of frameAboveBounds)
set currentFrameBounds to geometric bounds of currentFrame
set cfY1top to (item 1 of currentFrameBounds)
set cfX1left to (item 2 of currentFrameBounds)
set cfY2bottom to (item 3 of currentFrameBounds)
set cfX2right to (item 4 of currentFrameBounds)
set cfHeight to cfY2bottom - cfY1top
set cfY1top to faY2bottom + kFrameMargin --move the top of the current frame down.
set cfY1Bottom to cfY1top + cfHeight -- move the bottom of the current frame down.
tell currentFrame
set geometric bounds to {cfY1top, cfX1left, cfY2bottom, cfX2right}
end tell
end tell
end MoveFrameDownRelativeToFrameAbove
Get Margins
This makes use of one of several properties that are contained in preferences.
tell page 1
set pageMarginPreferences to margin preferences
set bottomMargin to bottom of pageMarginPreferences
end tell
Delete a page if the main text frame is empty
Uses the aforementioned
GetPageItem
set pageTwoTextFrameText to ""
tell page pageTwoNumber
set kPageTwoTextFrame to GetPageItem(pageTwoNumber, kPageTwoTextFrameName) of me
set pageTwoTextFrameText to get count of text of kPageTwoTextFrame
end tell
if pageTwoTextFrameText is 0 then
delete page pageTwoNumber
end if
Get name of linked file in an image frame
QuarkXpress can't do this and they should. This is one of the most useful things that InDesign can do for transforming content. If Quark had put this much thought into their Applescript implementation (and their software in general), I’d be using it today.
tell application "Adobe InDesign CS3"
tell document 1
set theSelection to the selection
set selectionProperties to properties of selection
set theImage to item 1 of all graphics of selectionProperties
set theGraphicItemLink to item link of theImage
set theGraphicName to name of theGraphicItemLink
return theGraphicName
end tell
end tell
The Transformation Matrix (Rotating and Moving Objects)
Rotate a page item
Rotating a page item is about as an obfuscated, non-obvious tasks one can do in Applescript with InDesign (and that's a very unfortunate turn of events for the API). Looking at Move, a related action, is of no help. In order to rotate an object, we have to use the transform command. From the Dictionary (via Script Debugger)...
transform reference ¬
in in ¬
from anything ¬
with matrix anything ¬
replacing current anything ¬
considering ruler units boolean
The trick with the transform command is the value needed for the with matrix argument: anything isn't really anything, it is actually a transformation matrix. To make a simple rotation transformation matrix, just start with the following code...
tell application "Adobe InDesign CS4"
set myMatrix to make transformation matrix with properties {counterclockwise rotation angle:90}
transform myLayoutObject in pasteboard coordinates from center anchor with matrix myMatrix
end tell
The transformation matrix is an all-purpose class that can also replace the Move command.
Applying multiple transformations to a single object
When applying both scale and movement transformations to an object, it is important to note two things
- Scale is a 1-based number, and not a percentage. Scaling something by 150% needs to be translated to 1.5 when applying it to the transformation matrix.
- Scale is applied first, then the object is moved second. In other words, translation needs to be based on the position of the anchor after the scale has been applied.
tell application "Adobe InDesign CS4"
set theSelection to selection
set scaleFactor to 1.3
set rectoXPre to 396
set rectoYPre to 304.5
set rectoXPost to 97.2
set rectoYPost to 396.5
set versoXPre to 396.5
set versoYPre to 304.5
set versoXPost to 514.8
set versoYPost to 396.5
set myMatrix to make transformation matrix with properties {horizontal scale factor:scaleFactor, horizontal translation:(versoXPost - versoXPre), vertical scale factor:scaleFactor, vertical translation:(versoYPost - versoYPre)}
transform theSelection in parent coordinates from center anchor with matrix myMatrix
end tell