Friday, January 11, 2008
Speeding up a Script
Most of the time, I pay scant attention to how long a script takes to run because most of them are so quick it hardly matters, but every now and then a simple script comes along that takes serious time to run. I just hit one as I sit here working on a catalog. I'm getting near the end of the job, making corrections and changes (mainly changes).
I realized that I've done so much dickering around to get things to fit on the page in earlier passes that it's time to reset the space before/after of every paragraph. Well, that's easy:
Clearly, we could cut that in half by changing the loop to this:
Ah well, back to work!
I realized that I've done so much dickering around to get things to fit on the page in earlier passes that it's time to reset the space before/after of every paragraph. Well, that's easy:
//DESCRIPTION: Restore vertical paragraph style spacingIf I were just running this on the odd page here and there, it wouldn't take too long, but document has 43 pages and the story has 782 paragraphs, so this loop interacts with InDesign 1564 times.
if (app.documents.length > 0 &&
app.selection.length == 1 &&
app.selection[0].hasOwnProperty("baseline")) {
restoreParagraphSpacing(app.selection[0]);
}
function restoreParagraphSpacing(myText) {
var myParas = myText.paragraphs;
for (var j = 0; myParas.length > j; j++) {
myParas[j].spaceBefore = myParas[j].appliedParagraphStyle.spaceBefore;
myParas[j].spaceAfter = myParas[j].appliedParagraphStyle.spaceAfter;
}
}
Clearly, we could cut that in half by changing the loop to this:
for (var j = 0; myParas.length > j; j++) {But this still requires 782 interactions with InDesign. And all of them happen even if the script does nothing because I'm running it for a second time. There's one more thing worth trying:
myParas[j].properties = {
spaceBefore:myParas[j].appliedParagraphStyle.spaceBefore,
spaceAfter:myParas[j].appliedParagraphStyle.spaceAfter
}
}
//DESCRIPTION: Restore vertical paragraph style spacingThe script still does a lot of interacting, but most of it is reading. It only writes a value into the document if there is a change needed, so right now the script runs very quickly because there are no longer any changes to be made.
if (app.documents.length > 0 &&
app.selection.length == 1 &&
app.selection[0].hasOwnProperty("baseline")) {
restoreParagraphSpacing(app.selection[0]);
}
function restoreParagraphSpacing(myText) {
var myParas = myText.paragraphs;
var mySBs = myParas.everyItem().spaceBefore;
var mySAs = myParas.everyItem().spaceAfter;
for (var j = 0; myParas.length > j; j++) {
if (myParas[j].spaceBefore != mySBs[j] || myParas[j].spaceAfter != mySAs[j]) {
myParas[j].properties = {
spaceBefore:myParas[j].appliedParagraphStyle.spaceBefore,
spaceAfter:myParas[j].appliedParagraphStyle.spaceAfter
}
}
}
}
Ah well, back to work!
Saturday, January 05, 2008
Instructive Confusion
The other day, I went so far as to report a bug to Adobe only to discover that I was missing the obvious. It wasn't a bug I was experiencing, but it surely would make a nice feature request. I was working with a book and I had all the documents open. But one of the documents was of primary interest to me at that point in time, and I had two windows open into it, arranged to be side-by-side on my screen.
When I double-clicked that document in the book window, I expected both windows to come to the front. But only one did. And, as luck would have it, it was the one on the left that I had temporarily forgotten about. I was expecting the window on the right to come to the front. When it didn't after repeated tries, I fired off a bug report to Adobe, only to feel rather silly a few minutes later when I realized that the window at left was indeed a window of the document I was trying to wake up. So, I modified my report and made it a feature request instead.
Anyway, it being Saturday evening and I'm sitting here amusing myself messing around with scripts while listening to Mahler's Ninth Symphony, it occurred to me that I could write a script to bring all the windows of the active document to the front. I decided that I wanted them to retain whatever stacking order they already had, so I thought that all that meant was I should cycle through all the active document's windows and bring them to the front starting with the back one.
It came as quite a blow when this script didn't work:
Why is this? Because myWindows is pointing at the collection of windows owned by the active document, so each time I changed the order of the windows, the order of their references in in myWindows also changed. I've fallen into this trap so many times with objects of various sorts, you'd think I'd see it coming. The solution is to deploy getElements() to create an array that captures a snapshot of the order of the windows before we perform the loop, like this:
Note: app.windows[0].parent is equivalent to app.documents[0], but this is a script about windows, so I used the window-based construction.
When I double-clicked that document in the book window, I expected both windows to come to the front. But only one did. And, as luck would have it, it was the one on the left that I had temporarily forgotten about. I was expecting the window on the right to come to the front. When it didn't after repeated tries, I fired off a bug report to Adobe, only to feel rather silly a few minutes later when I realized that the window at left was indeed a window of the document I was trying to wake up. So, I modified my report and made it a feature request instead.
Anyway, it being Saturday evening and I'm sitting here amusing myself messing around with scripts while listening to Mahler's Ninth Symphony, it occurred to me that I could write a script to bring all the windows of the active document to the front. I decided that I wanted them to retain whatever stacking order they already had, so I thought that all that meant was I should cycle through all the active document's windows and bring them to the front starting with the back one.
It came as quite a blow when this script didn't work:
//DESCRIPTION: Bring all Windows of active document to the frontIn as much as it did bring all the active document's windows to the front, you could say it did work, but it reversed the order of the windows. That which was at the back was now at the front (I only had two windows open; with more the result would have been more muddled).
if (app.windows.length > 0) {
bringToFront(app.windows[0].parent);
}
function bringToFront(aDoc) {
var myWindows = aDoc.windows;
for (var j = myWindows.length - 1; j >= 0; j--) {
app.activeWindow = myWindows[j];
}
} // end bringToFront
Why is this? Because myWindows is pointing at the collection of windows owned by the active document, so each time I changed the order of the windows, the order of their references in in myWindows also changed. I've fallen into this trap so many times with objects of various sorts, you'd think I'd see it coming. The solution is to deploy getElements() to create an array that captures a snapshot of the order of the windows before we perform the loop, like this:
//DESCRIPTION: Bring all Windows of active document to the frontNow, the contents of myWindows is not affected by the changes made in the loop and so the windows end up in the order I wanted them, at the front of any other windows that might be open into other documents.
if (app.windows.length > 0) {
bringToFront(app.windows[0].parent);
}
function bringToFront(aDoc) {
var myWindows = aDoc.windows.everyItem().getElements();
for (var j = myWindows.length - 1; j >= 0; j--) {
app.activeWindow = myWindows[j];
}
} // end bringToFront
Note: app.windows[0].parent is equivalent to app.documents[0], but this is a script about windows, so I used the window-based construction.