Any way to speed up object drawing in InDesign CS2?

I have an application that uses AppleScript to draw crossword puzzles in InDesign CS2, but the drawing seems kinda slow to me. Any way to speed it up?

The script uses separate function calls for each part: one to draw the vertical lines, one to draw the horizontal lines, one to draw black boxes, one to draw letters, etc., and each function is called as many times as needed.

Model: iMac Intel Duo 20"
AppleScript: 1.10.7
Browser: Firefox 1.5.0.6
Operating System: Mac OS X (10.4)

I can’t say I’ve ever tried to do that kind of script, but one idea:

Instead of “lines+boxes” would it be possible to design your draw routine to build the grid with just boxes. Maybe something basically like:

–Draw black box grid (1 point stroke black fill) so many columns wide by so many rows long
–Go back and turn certain box fills to white (leaving the box strokes as the “lines” between fill-in boxes)

In theory this might make the drawing go faster, especially if you can access the built-in “Step and Repeat” functionality.

That make any sense?

Yup, makes sense but unfortunately they do have to be lines.

Then you’re thinking that the slowness is attributed to me accessing separate subroutines?

Mind you, I’m shooting from the hip, but I’d say that in any routine that the more time you call something the longer it takes. The more you do it “the long way” (lines to draw boxes, drawing lines manually) rather than that shortcuts (drawing boxes, accessing Step-and-Repeat), the longer it will take.

Basically, I’m just brainstorming with you. :wink:

Since you are building with lines, how is the grid being build? Is it one line at a time, or have you tried using Step-n-Repeat to pre-build the grid? I would guess Step-n-Repeat would do it faster since it’s a one-step command built-into InDesign, assuming you can get at it with AppleScript (or want to bother to GUI it, which might make the speed advantage moot).

Another idea, have you tried running InDesign in the background? I noticed, as others have, some applications run fastest in the foreground, others run better in the background. Maybe in the background it can ignore refreshing the screen and run faster.

The last idea (for now!) is maybe post your code. The gurus here have a tendancy to make code run faster just by virtue of streamlined coding. I’ve seen them cram 10 lines of code into a single long call which in turn shaves time off execution, which still amazes me. Soooo much more to learn, this Padawan has. :stuck_out_tongue_winking_eye:

Step and Repeat! smacking hand to forehead I’ve been writing my own routine that does the math for each separate object’s coordinates, and draws each one that way. I’m new enough to ID to not know I could do that, yet have been using Quark long enough to know that it must have a Step and Repeat.

I’ve thought about it, but the script has to be called from ID with a template page open, so it might not make sense to do so. But I’ll certainly investigate that route.

Great, I’ll do that once I give it a retweaking. Think I’ll also time it before and after to see how I’m doing. Thanks again for your help. Y’know, you’re a lot more helpful than that Anakin punk was. :wink:

Without the subrutines (aka handlers) it is hard to evaluate. There are workflow issues that might come into play with how the script is used. One way that you might be able to speed it up might be to have a template document that you open up with the script without showing the window, thus eleminating screen redraws compleatly:

tell application "InDesign CS"
  open filePath without showing window
  --insert script rutines here.
end tell 

As noted above try to reduce the calls to InDesign to a minimup, each time you do it slows the script.

I’ll throw in my 2 cents and vote for Jerome’s method as well - I has some very complicated Applescripts that run twice as fast - or more, just by not showing the window as he described. You’ll get a lot of speed by doing this…but it doesn’t look as cool… :wink:

Well, that really wouldn’t take much. :stuck_out_tongue:

Thanks guys I think I’ll use the hiding as well.

The problem is this program is a replacement for doing something similarly in Quark 3.32 (!) so to some point they’re going to have to resign themselves to a slower redraw. But I think the hiding will work out OK – I could always stick up a progress bar or something if it seems to take long enough that they’ll need a distraction. Or maybe even a preference setting for a faster redraw at the price of hiding the template … I’ll have to see if I need to get this complicated.

OK here’s the code that I use for drawing the crossword grid lines. (I’m not including the code for drawing the black boxes or the numbers in the grid because I’m assuming whatever advice I get here in optimizing my code will be applicable there as well):

on run {gridCols, gridRows}

tell application "Adobe InDesign CS2"
	
	set myDoc to active document

	-- use the selected frame as the drawing area for the crossword grid
	
	set mySelectionBounds to geometric bounds of selection
	
	set gridWidth to (item 4 of mySelectionBounds) - (item 2 of mySelectionBounds)
	set gridHeight to (item 3 of mySelectionBounds) - (item 1 of mySelectionBounds)
	
	set gridOriginX to (item 2 of mySelectionBounds)
	set gridOriginY to (item 1 of mySelectionBounds)
	
	set numberOfColumns to gridCols
	set numberOfRows to gridRows
	
	set gridEntryBoxWidth to (gridWidth / numberOfColumns)
	set gridEntryBoxHeight to (gridHeight / numberOfRows)
	
	set gridLineWeight to "0p1"
		
	tell active spread of active window
		
		--draw the vertical main grid lines
		
		set counter to 1
		repeat while counter < numberOfColumns
			set vertGridLine to make graphic line
			tell vertGridLine
				set the geometric bounds to {gridOriginY, (gridOriginX + (counter * gridEntryBoxWidth)), (gridOriginY + gridHeight), (gridOriginX + (counter * gridEntryBoxWidth))}
				set the fill color to swatch "None" of myDoc
				set the fill tint to 0
				set the stroke weight to gridLineWeight
				set the stroke color to swatch "Black" of myDoc
				set the stroke tint to 100
				set counter to counter + 1
			end tell
		end repeat
		
		--draw the horizontal main grid lines
		
		set counter to 1
		repeat while counter < numberOfRows
			set horizGridLine to make graphic line
			tell horizGridLine
				
				set the geometric bounds to {(gridOriginY + (counter * gridEntryBoxHeight)), gridOriginX, (gridOriginY + (counter * gridEntryBoxHeight)), (gridOriginX + gridWidth)}
				set the fill color to swatch "None" of myDoc
				set the fill tint to 0
				set the stroke weight to gridLineWeight
				set the stroke color to swatch "Black" of myDoc
				set the stroke tint to 100
				set counter to counter + 1
			end tell
			
		end repeat
		
	end tell
	
end tell

end run

The values for the variables gridCols and gridRows (how many rows and columns the grid will have) are supplied externally. The grid is drawn on top of the frame the user has selected on the InDesign page.

thanks for any help!

Not knowing the workflow that is needed or how it might be adjusted for better performance this is what I would do:

on MakePuzzle(gridCols, gridRows)
	
	tell application "InDesign CS"
		activate
		set myDoc to active document
		
		-- use the selected frame as the drawing area for the crossword grid
		
		set mySelectionBounds to geometric bounds of selection
		
		set gridWidth to (item 4 of mySelectionBounds) - (item 2 of mySelectionBounds)
		set gridHeight to (item 3 of mySelectionBounds) - (item 1 of mySelectionBounds)
		
		set gridOriginX to (item 2 of mySelectionBounds)
		set gridOriginY to (item 1 of mySelectionBounds)
		
		set numberOfColumns to gridCols
		set numberOfRows to gridRows
		
		set gridEntryBoxWidth to (gridWidth / numberOfColumns)
		set gridEntryBoxHeight to (gridHeight / numberOfRows)
		
		set gridLineWeight to "0p1"
		
		tell active spread of active window
			--draw the vertical main grid lines
			repeat with H from 1 to gridCols
				set vertGridLine to make graphic line with properties {geometric bounds:{gridOriginY, (gridOriginX + (H * gridEntryBoxWidth)), (gridOriginY + gridHeight), (gridOriginX + (H * gridEntryBoxWidth))}, fill color:swatch "None" of myDoc, fill tint:0, stroke weight:gridLineWeight, stroke color:swatch "Black" of myDoc, stroke tint:100}
			end repeat
			--draw the horizontal main grid lines
			repeat with H from 1 to numberOfRows
				set horizGridLine to make graphic line with properties {geometric bounds:{(gridOriginY + (H * gridEntryBoxHeight)), gridOriginX, (gridOriginY + (H * gridEntryBoxHeight)), (gridOriginX + gridWidth)}, fill color:swatch "None" of myDoc, fill tint:0, stroke weight:gridLineWeight, stroke color:swatch "Black" of myDoc, stroke tint:100}
			end repeat
			
		end tell
		
	end tell
	
end MakePuzzle

set a to current date
set b to time of a
set x to display dialog "Columns" default answer 1
set y to display dialog "Rows" default answer 2
MakePuzzle(text returned of x as integer, text returned of y as integer)
set a to current date
set c to time of a
set d to c - b
display dialog d

I added some code to time it and run it easily from the Script Editor as well as from InDesign’s script pallet. Based off of my tests your script takes about 46 seconds to creat a grid of 50 horizontal and 50 vertical rules. Mine does that in about 17 seconds when run from the script editor and run from within InDesign using the Script pallet it is cut down to 10 seconds. This is on a 450 Mhz G4 Cube running InDesign CS. The main thing that I did to gain this effeciency was to consolidate the calls to set the properties of the line into the one to make the new line. It could probably be cleaned up further but I don’t think that this would help with the speed. The best thing that you could do is run it directly from InDesign’s script pallet, this way it will add the rules without redrawing the screen between each one.

Wow thanks Jerome! It’s amazing how much time is saved by using repeat and the consolidation. When I get to the part that adds the black squares and clue numbers I won’t be able to use repeat (they’re too inconsistent for that) but the consolidation part should chop out a good chunk of time.

Joe,

The way I rearranged the loops probably didn’t change the speed in any perceptible way. All the speed is gained in the way the lines are made. You’re script has got me thinking on how I would go about creating one to handle the task at hand. It would be interesting to hear a bit more about the script and how it is used.

As I said, the script will draw a crossword grid based on a saved file created in another application. To allow for some flexibility, it draws the puzzle based on the size of the picture box selected in InDesign.

It’s not very complicated: a file supplies the dimensions (15 squares across by 15 squares down is a typical daily crossword size) as well as the answers, then the script will draw in the lines, black boxes, clue numbers in boxes, and letter answers (only if you want it to be an answer grid; otherwise it skips this step and just draws an answerless grid for solving). The repeat fo drawing the lines is useful, but that’s the only regular part it can be used in. The black boxes, numbers, and answer letters don’t appear regularly enough for its use. So for this part I just use a regular subroutine, like this one:

on run {gridCols, gridRows, columnNumber, rowNumber}
	
	tell application "Adobe InDesign CS2"
		activate
		set myDoc to active document
			
		--default units are picas
		
		-- use the selected frame as the drawing area for the crossword grid
		
		set mySelectionBounds to geometric bounds of selection
		
		set gridWidth to (item 4 of mySelectionBounds) - (item 2 of mySelectionBounds)
		set gridHeight to (item 3 of mySelectionBounds) - (item 1 of mySelectionBounds)
		
		set gridOriginX to (item 2 of mySelectionBounds)
		set gridOriginY to (item 1 of mySelectionBounds)
		
		set numberOfColumns to gridCols
		set numberOfRows to gridRows
		
		set gridEntryBoxWidth to (gridWidth / numberOfColumns)
		set gridEntryBoxHeight to (gridHeight / numberOfRows)
		
		set gridLineWeight to "0p1"
		
		tell active spread of active window
			
			
			--draw a black box in the grid
			
			set blackGridBox to make rectangle with properties {geometric bounds:{(gridOriginY + (rowNumber * gridEntryBoxHeight)), (gridOriginX + (columnNumber * gridEntryBoxWidth)), (gridOriginY + ((rowNumber + 1) * gridEntryBoxHeight)), (gridOriginX + ((columnNumber + 1) * gridEntryBoxWidth))}, fill color:swatch "Black" of myDoc, fill tint:100, stroke weight:0, stroke alignment:center alignment, stroke color:swatch "Black" of myDoc, stroke tint:100}
		end tell
		
	end tell
	
end run

(I’ve shown it as an independent script because that’s how I have it for now until I fold it into the main script as a subroutine.) Off the top of my head there doesn’t seem to be a way to optimize this part to run any faster than it does, but perhaps someone out there can see something I don’t.

Joecab,

I haven’t followed the whole thread here, but I made a couple of scripts for Illustrator CS that make templates for the work I do. There are a couple of different formats they can take, one of which was quite slow. I got the scripts working well and then decided to give AppleScript Studio a go. I had to slightly modify my scripts (I combined the two into the single app) but afterwards, the whole process is done in almost a blink of an eye. I’m not savvy enough with all of the mac’s intricacies to say why this works, but it does.

PreTech

Ouch. I dread looking into learning Studio now, but if it’s true, it may be worth it in the time savings. I just hope there’s some bare minimum way to just compile my script in ASStudio to get the speed benefit.

Joecab,

It’s actually fairly easy. If you do a couple of the tutorials that are in the XCode documentation on connecting the text fields (if input is needed) and connecting buttons, all you should then have to do is paste your code as you have it into a handler and Shazam! there it is.

PreTech

Joe,

From what I have read and seen in the scripts that I have written the best method for an AppleScript in InDesign for speed is to save it as a compiled script and run it through InDesign’s scripting pallet (or a keyboard command). AppleScript Studio would be the second best, but it seams to me that the loading of the interface elements (NIB’s) slows the launching of the script when compared to running the compiled script in InDesign. I think that there are also speed benefits from InDesign running the script in how it deals with redrawing the screen during the execution of the script. To take advantage of these benefits you could have a compiled script in InDesign’s presets and launch it from InDesign then have the script get the information from the other program or file.

What we are really missing here to help you further is the data structure that you are using to build the puzzle. Do you have a database or tab delimited file of how the puzzle is structured, or just the clues and answers and the script figures out the placement? If you have a database or tab delimited file then it should be a simple matter to parse the data into an array and do the placing of the data into the grid structure one row at a time.

PreTech is right, AS Studio is not complex and offers a lot of flexability over AppleScript alone, though InDesign has a good UI scripting set for building custom dialogs which work pretty good.

The file is pretty simple: it has a unique filoe extension, but it’s basically all ASCII, and has stored the dimensions of the puzzle grid (in boxes), and the letters entered in the grid, which is all it really needs. (It may also contain data to let you know which boxes in the crossword get numbers, since this would be faster than writing code to work this out on the fly.)

So my plan is to have the user click on any rectangular object on an Indesign page, then start the script which will ask which file to read to draw the crossword grid. As far as I know having a dialog come up to let you select a non-ID file, much less read in the data, is beyond ID’s AS capabilities so I’m writing that part in REALBasic. Feel free to correct me if I’m wrong.

The script’s speed isn;t too bad when it comes to drawing a blank crossword grid since you only need to draw the lines, black boxes, and clue numbers in some boxes. But when drawing an answer grid it chugs along pretty slowly: for a 21 x 21 grid that’s 441 little boxes to do. I toyed with the idea of doing it as a table or perhaps just a big box with each letter tabbed into position, and the lines and black boxes overlayed, but each letter box in the answer grid needs to be separate for my needs.