Layout

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