Photoshop Plug-Ins Part 1
Volume Number: 15
Issue Number: 4
Column Tag: Plugging In
How to Write a Photoshop Plug-In, Part 1
by Kas Thomas
How to harness the awesome power of Adobe's
800-lb graphics gorilla
Over the years, Adobe Photoshop has become such a staple of desktop graphics that
people tend to lose sight of what may well be this program's most significant
contribution to the world of desktop computing: namely, the popularization of
plug-ins. External code resources were nothing new in Photoshop's early days, of
course; Silicon Beach already had a plug-in service in SuperPaint, for example (and
before that, HyperCard developers championed XCMDs). But Photoshop was the first
bonafide "killer app" to make extensive use of third-party plug-ins, leveraging the
efforts of outside programmers to expand the host program's core functionality. It was
a brilliant maneuver, ensuring Photoshop's hegemony in the graphics-software
market. Thanks to Photoshop, user expectations have been raised to the point where,
today, no developer of a major software title - of any kind - can afford to neglect to
provide a plug-in architecture. It's hard to find a compiler, web browser,
data-compression utility, page-layout program, video editing suite, or 3D modelling
or animation program that doesn't rely on a plug-in architecture for much (if not
most) of its functionality.
The graphics programmer benefits tremendously from a plug-in mechanism, for the
simple reason that more time can be spent implementing image-manipulation code
while less time is wasted on event-loop code, file I/O, format conversion issues, and
other extraneous matters. If you're interested in simply trying out some new
graphics-programming ideas, it's a lot easier to write and compile a small plug-in
than it is to whip up a standalone test program. Consider these advantages of writing
plug-ins:
• File I/O is handled by the host program.
• No format conversions are necessary; Photoshop will open almost any
graphics file.
• No user-interface code. (Actually, you will probably want to have a
parameter-setup dialog, although some plug-ins, like Blur and Blur More,
don't have one.)
• Buffer pre-fetch is handled by the host program.
• Writing to the screen is handled by the host. No need to get involved with
GWorlds, PixMaps, monitor modes, etc.; in fact, you'll seldom use Color
Quickdraw.
• No need for error-handling related to file I/O, format conversions, buffer
operations, blitting, or user interface code.
• "Undo" is handled by the host.
Another nice thing about writing Photoshop plug-ins is that most of them will work
"as is" with other programs - for example, with Adobe PhotoDeluxe. Many non-Adobe
programs also support Photoshop plug-ins. Thus, an image filter that you write for
Photoshop may turn out to be quite useful to someone working with another product
entirely.
Most of us think "image filter" when we think of Photoshop plug-ins, but the fact is,
there's almost nothing you can't do inside a plug-in. For example, your plug-in code
can make use of Quickdraw 3D, QuickTime, Open Transport, the Sound Manager, or any
other code you'd normally access from a standalone program. In theory, there's no
reason you couldn't implement a game, OCR program, or even a word processor as a
Photoshop plug-in, if you wanted to. What you decide to do with all this power is up to
you.
The first thing you'll need to do if you intend to write plug-ins for Photoshop is obtain
the most current version of the Adobe Photoshop Software Developer's Kit (SDK).
Generally, you can get everything you need from <http://www.adobe.com>, but if you
want to obtain up-to-the-minute pre-release or beta versions of SDKs, you need to
join the Adobe Developer's Association (ADA). Membership in ADA is a good idea for
several reasons. First, you get the most current versions of all of the Adobe Graphics
and Publishing SDKs (for Photoshop, Premiere, After Effects, PageMaker, and
Illustrator) mailed to you on one CD, which is a lot more convenient than trying to
download everything off the Web. The Photoshop SDK alone, for example, contains over
17 megabytes of sample code and around 10 megs of documentation in .pdf format.
That's a lot to try to download.
Another reason to consider joining ADA is that you get developer technical support
(i.e., answers to your development questions), and discounts on Adobe products. For
example, as an ADA member, you can buy a full version of any Adobe product for $99.
(There is a limit of one purchase per year per member, however; and you have to sign
an affadavit affirming that your purchase will be used for development purposes
only.) You have to admit, this makes the $199-per-year membership fee look much
more attractive. Where else are you going to get a full version of After Effects for
$99?
ADA members can also subscribe to the Graphics and Publishing SDK Discussion List
and can receive Adobe Technical Notes automatically via e-mail. Visit
<http://www.adobe.com/supportservice/devrelations/sdks.html> to learn more
details.
Documentation
Version 5.0 of the Photoshop SDK comes with around 1,000 pages of .pdf
documentation contained in a dozen files. Fortunately, you won't need to read most of
this material, although you definitely will want to become well acquainted with the
168-page Photoshop API Guide Additional doc files talk about the TIFF and EPS
formats, the all-new Adobe Dialog Manager, and the Plug-In Component Architecture
API (otherwise known as PICA), which is a device-independent meta-API through
which plug-ins can be invoked - and controlled - either by various hosts or by other
plug-ins. Not only can your plug-in use PICA to pipeline its input or output through
other plug-ins, but you can use PICA to implement daemon-like "service provider
modules (which Adobe calls "Suite PEA" plug-ins). The new Adobe Dialog Manager is
implemented this way, for example. The idea behind ADM is to provide
platform-independent support for dialogs, so that - as with Java - you just write
generic dialog code once, and then it runs, works, looks, and smells the same on any
host. (Newtek's Lightwave 3D - the popular cross-platform 3D tool - handles dialogs
for plug-ins in exactly this fashion, via its Panel Services plug-in.) Thanks to PICA,
you could very easily create custom math libraries, DSP transform engines, fractal
generators, expression parsers, or any number of other sophisticated utilities as
"Suite PEA" modules. The possibilities here are limitless.
In the future, all Adobe host programs (Illustrator, Photoshop, PhotoDeluxe,
Premiere, After Effects, etc.) will go through PICA to find, load, invoke, and control
plug-ins. If you want your plug-ins to be fully PICA aware, be sure to check out the
PICA Guide.
Types of Plug-Ins
At this writing, Photoshop supports nine core types of plug-ins:
1. Image Filter. This is the most familiar kind of plug-in, since it operates
directly on images to change their appearance. The familiar Noise and Blur
plug-ins (and dozens of others) that ship with Photoshop are image filters.
2. Import. Prior to Photoshop 4.0, these were called Acquire modules.
Import modules basically open an image in a new window. They can provide an
interface to scanners or frame grabbers, read images in unsupported or
compressed file formats, or generate synthetic images (e.g., gradients or
fills), among other possibilities.
3. Export. There really is little need for this category of plug-in, since
"Save As" operations involving format conversions can be dealt with via the
Format plug-in type (below). The most appropriate use for Export plug-ins
is to support unorthodox (non-disk) types of export operations, such as
exporting data to a printer or other peripheral.
4. Parser. This is not a category you should worry about, since the interface
is not public. Adobe uses it for importing and exporting Illustrator files.
5. Extension. You also won't be writing any of these, since the interface is
not public. Adobe uses this plug-in type for certain low-level tasks like
custom cursor-drawing and enabling asynchronous I/O.
6. Format. Plug-ins of this type are also called File Format or Image Format modules, since they provide support for reading and writing additional image
formats. They show up as new options in the pop-up menu in "Open," "Save
As," and "Save a Copy" dialogs.
7. Color Picker. This facility allows the user to substitute a custom color-picker (implemented as a plug-in) as part of the Preferences setup so
that when the user pops the "Choose a Color" dialog, your custom color-picker
appears instead of Apple's or Adobe's.
8. Selection. Modules of this type, which show up at the bottom of the
"Select" menu in PS 5.0 or later, enable the plug-in writer to generate
custom selections, paths, or layers on the fly. Good examples of this class of
plug-in are given in Adobe's SDK. (No examples of this kind ship in the
standard Photoshop retail distribution suite.)
9. Automation. This category, like the Selection category (above), is new
with Photoshop version 5.0. It implements a very powerful class of plug-in
based on Actions. Basically, any menu action or tool operation that a user can
apply to an image (or to a layer, selection, or channel), including plug-in
invocation, can be done from inside an Automation plug-in. The organizational
paradigm underlying Actions is object-oriented, with many layers of
abstraction, inheritance, etc. To harness the full power of Automation
requires an understanding of OOP concepts, familiarity with the Actions
scripting API, and a working knowledge of PICA (Adobe's meta-API for
communicating between plug-ins; see above). Space doesn't permit a full
discussion of Automation plug-in programming here. To do the subject justice
would require a book-length treatment. Fortunately, such a book already
exists: the 223-page Actions Guide in the Photoshop SDK docs.
Unless your primary need is to implement a new image format or compression
scheme, chances are you'll be spending most of your time writing image filters, so
that's what we'll talk about for the rest of this article. Adobe provides CodeWarrior
Pro 1 and/or Pro 2 projects for 19 different plug-ins in the current SDK, covering
all seven major categories for which public interfaces are available. Most of the
projects are still implemented in C, although the newer ones (for example, the
Automation plug-ins) are done in C++.
The SDK example projects, incidentally, contain a great deal of legacy code (for 680x0
processor Macs), with discussion of "fat" binaries, register A4 setup, etc. But since
Photoshop 5.0 and up requires a PowerPC processor, it doesn't really make sense any
more to compile plug-ins as anything but PPC-native code. If you're writing plug-ins
for Photoshop 5.0 or higher, compile them as PPC-native. This will streamline your
code, speed up compilation, give smaller executables, and make it possible for you to
use global and static variables in your code (which you normally can't, in a 680x0
plug-in).
Plug-In Resources
When Photoshop launches, it scans plug-ins for 'PiPL' (plug-in property list)
resources. This is how Photoshop knows what category your plug-in falls in (Filter,
Automation, Import, Export, or whatever). In years gone by, this info was determined
by the plug-in's filetype, but that's not how it works any more. If the PiPL resource
says your plug-in is a filter, Photoshop will treat your plug-in as (and expect it to
be) a filter, no matter what the filetype of the module on disk.
Prior to version 3.0 of Photoshop, plug-ins had 'PiMI' ("pimmy") resources to
inform the host of various plug-in properties. The PiMI resource is no longer needed,
however, unless you want your plug-in to work under Photoshop 2.0 or 2.5.
Accordingly, it should be dropped in favor of the 'PiPL'.
The 'PiPL' resource has grown to be a sophisticated, flexible, extensible structure
containing many property lists, so that plug-ins can fine-tune their relationship with
various hosts (not only Photoshop but After Effects, Premiere, Illustrator, and
others). For example, in a 'PiPL' you can inform Photoshop of the specific image types
(RGB, CMYK, grayscale, etc.) your plug-in is designed to operate on, so that your
plug-in's name will be grayed out in the Filters menu when the user is working in an
inappropriate image format. You can also communicate preferences involving layer
handling, transparency, buffering, and many other properties. To learn more, consult
the Plug-In Resource Guide that comes with the SDK.
The SDK sample code projects contain templates for compiling PiPL resources. One
thing you should be aware of is that no version of ResEdit (as of this writing) is
PiPL-aware, so the best tool for graphic editing of PiPL resources remains
Resorcerer. If you insist on using ResEdit, you can open the resource forks of the
compiled plug-ins that come with the SDK, copy any PiPLs you need, and paste them
into your own plug-ins. Then you can hack away at the individual PiPL field values
using ResEdit's hex-editor option.
Very important: Remember that it's the 'name' field in the 'PiPL' resource (not the
name of the module on disk!) that determines what name your plug-in has in the Filter
menu when Photoshop is running. Also, it's the 'catg' field of the 'PiPL' that determines
which submenu (Noise, Pixelate, Other, etc.) your plug-in shows up in. Be sure to set
these fields up correctly if you want your plug-in to "show up" properly at runtime.
How Plug-Ins Work
When Photoshop invokes a plug-in, it calls the plug-in's entry point - which, on the
Mac, must be named "main()" and must occur as the first function in the module -
with a selector value indicating the type of action the plug-in is expected to perform.
The prototype for main() looks like:
pascal void main (const short selector,
FilterRecord *filterParamBlock,
long *data,
short *result);
The filterParamBlock will contain image data appropriate to the selector value as well
as hooks to a variety of host callbacks.
The data pointer is for the plug-in's use; normally, you set this to a Handle to the
plug-in's own global data. The host maintains the data value across calls to main().
Obviously, if you stuff a Handle here, you should lock it down at plug-in invocation and
unlock it when the plug-in returns control to the host, so that the data can be relocated
in memory as need be during host operation.
The result parameter is where the plug-in passes back a result code to indicate to the
host whether the operation in question (i.e., the one requested via the selector value)
encountered an error or returned normally (with noErr). See "Error Reporting,
below.
The FilterRecord data structure is an enormous, 200-field structure containing
references to a bewildering amount of state information about the current image (or
selection), plus hooks to various callback services. An entire article (or small book!)
could be devoted to explaining the various fields in this colossal data structure.
Fortunately, you'll seldom need to use very many of the fields of this structure,