I want to convert some images to GIFs. Why do Corel want me not to be able to do this?
The problem
I have several dozen files in Corel Painter's format RIFF. I can use Painter to convert images one at a time to GIF by opening the image and doing File → Clone followed by File → Save As. But with several dozen images this gets tedious. Why can't I automate this?
How it should work
Suppose my images were PNGs and I wanted GIFs. Then I could write a Python program to do this along these lines:
for name in os.listdir(inDir):
im = Image.open(os.path.join(inDir, name))
im.save(os.path.join(outDir, name[:-4] + '.gif'), 'GIF')
Too bad PIL does not support RIFF, because RIFF is a closed, proprietary format (NOTE: not to be confused with other formats called RIFF).
Too bad there is no standard format for images that includes layers and suchlike that Corel could have Painter support. (Actually you could represent images with layers pretty well using SVG if you wanted.)
Corel could supply a library for working with RIFF images. Failing that, Corel could publish a description of the format so someone else could write a library for working with RIFF images. Sadly there is no commerical reason for Corel to do this. All it would do is make their software more useful; since usefulness is not what really sells software, there is no reason for them to do this.
Another solution that would have been lousy but better than nothing
Corel could have made Painter scriptable. On the Mac, 'scriptable' means it exposes a dictionary of commands to AppleScript's voodoo. Writing programs in AppleScript is about the worst imaginable way to spend my time I can actually imagine doing; AppleScript is one of the worst-designed programming languages I have ever tried to do actual work in. I mean, I hate Visual Basic, but AppleScript is worse.
Despite this, if Corel had exposed open file
and save as
commands, I
could probably have cobbled together a script that did one coversion.
From there you can plug in to Automater and folder actions to make it
keep your GIFs up-to-date with respect to the master copies in RIFF
format. Automated workflow! It would be great. Too bad I can't have
it.
What Corel's software does expose is a command cryptically named
DoScript
. What does it do? I don't know. It takes a parameter that
is a string. A string of what? Special Corel commands? I have done
some digging, and it appears that when you save what Painter calls a
script to a file, it is in some sort of text format. Perhaps these can
be fed in to the DoScript
command, but if so I have yet to make it
work. Maybe it is supposed to be a file name? Who knows? Nobody
knows, that's who.
Digression on the subject of file names in AppleScript
I started writing this article after attempting to make an AppleScript program that opens a file in Corel Painter. The following works
tell application "Finder"
open file "Macintosh HD:Users:pdc:foo:bar:baz.riff"
end tell
Note the use of the obsolete 'file path' notation (using colons). I can also make it work with the file name as a variable:
tell application "Finder"
set file_name to "Macintosh HD:Users:pdc:foo:bar:baz.riff"
open file file_name
end tell
Fine. But what if I want to use a Unix file name rather than a Mac OS 9 file path? It turns out that if I type this in to a script:
tell application "Finder"
open POSIX file "/Users/pdc/foo/bar/baz.riff"
end tell
then the AppleScript compiler rewrites it as a file path! It replaces my code with
tell application "Finder"
open file "Macintosh HD:Users:pdc:foo:bar:baz.riff"
end tell
That is seriously fucked up. If I try using a variable to hold the file name, it fails: I get an error message
Finder got an error: Can't get POSIX file "/Users/pdc/foo/bar/baz.riff"
So opening files via the Finder also seems to be out, unless I fancy learning enough about AppleScript's crappy string manipulation expressions to convert my file names in to file paths myself.
The light at the end of the tunnel is an illusion caused by excessive blood pressure
There is another emergency backup approach to scripting non-scriptable applications: GUI scripting. This is so great that Apple devote a couple of paragraphs to it on the web site. The idea is that you can send events direct to the buttons and text fields of the application, driving it more or less as the user would. Here is an example:
tell application "Corel Painter 8"
activate
end tell
tell application "System Events"
tell process "Corel Painter 8"
tell menu 1 of menu bar item "File" of menu bar 1
click menu item "Clone"
end tell
end tell
end tell
This clicks the File → Clone menu item, creating a flattened version of the frontmost image. Since the user interface of Painter is undocumented, producing even the above script takes hours of fiddling with Apple's GUI spy program and guessing what the names of this actually are (since it does not go so far as telling you).
With a similar incantation I can make the Save As dialogue box appear. Now I want to change the file type from RIFF to GIF in the drop-down list. Unfortunately its expression in AppleScript is
pop up button 1 of ??? of window "Open"
where the question marks need to be replaced with a name I cannot type: the GUI
element that is a child of window "Open"
and a parent of the pop up button
is listed as 'Unknown', but unknown
is an AppleScript keyword of some sort. In
the end I could not find a way to make this work. After spotting something in
one of Apple's code samples, I came up with a different appoach:
repeat 14 times
keystroke tab
end repeat
keystroke space
keystroke "g"
delay 1
keystroke return
The existence of the keystroke
command I had to infer from one of the
code samples on Apple's page; it is not documented anywhere.
These seven lines do the same work as the seven characters
, "GIF"
in my hypothetical Python program.
String manipulation by drunken fairy trolls
The expression
name[:-4] + '.gif'
replaces the file-name suffix. This happens automatically when yoiu
change file types in the Save As dialogue, but you do also need to strip
off the words Clone of
from the front of the name (added because you
are saving a clone of the original image). Here's the AppleScript
equivalent:
set the_file_name to value of text field 1
if the_file_name starts with "Clone of " then
set the_file_name to text 10 thru (length of the_file_name) of the_file_name
end if
set the value of text field 1 to the_file_name
The text ... thru ...
expression comes from the O'Reilly AppleScript
book. I can't think how someone is supposed to guess it. The
array-slicing notation used in Python is also something you have to
learn, of course, but the difference is that, in Python, you will use it
often, and for many different things, because slices apply to lists, and
lists are used for listing things in Python, instead of haveing unique
and special keywords to learn for every object in the system.
Now for the output directory
The Python program uses
os.path.join(outDir, ...)
to arrange that the GIF files are stored in a different directory from where they came from. To set the directory the file will be saved to in the Save As dialogue, I ended up (after an eternity of hacking) with this monstrosity:
keystroke "/" using control down
delay 1
repeat with the_char in every character of the_dir_name
keystroke the_char
end repeat
keystroke return
The first part invokes an obscure feature of Mac OS X file dialogues: Ctrl /
shows a sheet that lets you enter the directory name using your keyboard. The
sample code I nicked this idea from sets a text field to the directory name;
Corel's pop-up window unhelpfully is nameless, so I can't work out how to get at
its fields. So I resorted to feeding it the characters one at a time.
I would also like to point out that 'repeat with the_char in every character of the_dir_name' is no more English-like than 'for char in name' would be. I hate the way every review of AppleScript manuals says something like
AppleScript is a scripting language that mimics the syntax of English. As such, it's extremely similar to how sentences are structured and, as a result, is very intuitive and simple to use.
AppleScript is not intuitive. Its syntax mimics English in the same way a cargo cultist mimics an airport. The supposedly English-like syntax is more complex, and therefore harder to use, than almost any other programming language apart from Perl.
Status
So far I have managed to get Corel Painter to save a file as a GIF, once it is loaded. The bit where I set the directiory name sort of works, but seems to be flakey; luckily I don't need it if I don't mind all my files going to the same directory. I am still stuck when it comes to opening all the files in a directory. Maybe I should look in to how Automater does its stuff; perhaps I can get it to take care of the file names for me...