Robust File-writing from InDesign JavaScripts

Recently I've been scripting InDesign with JavaScript to parse an entire issue of the print version of the Boston Review and produce the files needed for the new Drupal site I am building for them.

After getting oriented in the Adobe ExtendScript scripting environment, I found that outputting all my debugging print statements to the JavaScript console with $.write() was really slowing things down. Since I was going to have to write files eventually anyway, I was thrilled to find Dave Saunder's code for logging from InDesign JavaScripts. Using this logging function sped up my code greatly versus writing everything to the console.

So, what is wrong with the code? Well, it makes the mistake of not checking for errors in file-handling calls. I know that I, for one, have made this "mistake" many times purposefully since it is just hard to write good error handling code without examples of failures to catch. And, after all, why worry about something failing when it has never failed? Maybe it will never fail on you and the coding-time will be wasted, or maybe the error-catching code itself will fail since you have no error examples to test it on.

Well, the original logging code failed seriously on me in a way that I just had to track done to keep my project on-track. So I thought I would share my experiences and my additions to the logging routine that make it report the error message when it fails. And with a real failure to test on, I had no excuse to not improve the code.

What I was noticing is that when I called the log() routine to see the contents of the array activeDocument.stories for a certain document the output for certain stories would always be mysteriously missing from the log file. So even though there was supposed to be one entry per story, occasionally output would just be missing for some stories.

When I tracked it down, I learned that the error message (from the File object) I needed to see was "Character conversion error." Here is my version of the log() routing that writes the error message to the JavaScript console once the error occurs:

function log(aFile, message, header, incDate) {
        var today = new Date();
        if (!aFile.exists) {
                // make new log file
                aFile.open("w");
                if (incDate) {
                        aFile.write(String(today));
                }
                if (header != null) {
                        aFile.write(header);
                }
                aFile.close();
        }

        if (aFile.open("e")) {
                if (aFile.seek(0,2)) {
                        if (aFile.write("\n" + message)) {
                                if (aFile.close()) {
                                        return true;
                                }
                        }
                }
        }
        $.writeln("ERROR='"+aFile.error+"', Log() failed to write '"+ message + "' to log file.");
        aFile.close();
        return false;
}

But why was this error happening? And why was it only happening only when trying to write the contents of certain stories? Well, it turns out that some of the stories are picture captions, or the name of the author, or other short things that have no exotic characters in them. But the longer entries, that are whole narratives written by someone all have some exotic characters in them, since they *all* end with a solid diamond character.

So when the File object's write method was passed certain strings to write to the file, it was trying to convert things like the solid diamond to some standard text characters in MACROMAN encoding and it had no instruction on how to convert them, so it failed with a "Character conversion error."

This is an interesting case, since I did not even imagine that character conversions were a possible source of failure in the File object's write method. I have to admit that if I had been writing the original logging routine, I probably would have reasoned wrongly that the only way a write can fail is that there is not enough disk space, and I'm never going to be close to that point, and not attempted error-catching code, either.

So how did I fix it? Easy, just tell the file object to use the UTF-16 encoding when it writes the file, rather than using the default encoding on my system. So my code, when opening the log file (or writing it for the first time) would read:

var filePath = "~/Desktop/tempLogFile.txt";
var logFile = new File(filePath);
logFile.encoding = "UTF-16";

This all ties into my next blog topic, which will be modular scripting for Adobe InDesign CS2. The most compelling reason for me to write exploratory output to a log file, came when I wanted break my process into separate scripts and simply append onto the end of one ongoing log file, and begin execution lower down (via the ExtendScript Toolkit) or call the top level script from In Design and still be able to check my single log file.

Drupal SEO