home *** CD-ROM | disk | FTP | other *** search
-
-
-
-
- EXPANDING IMAGEFX
-
- Developer Documentation
- for the ImageFX Image Processing System
- by Thomas Krehbiel
-
-
-
- WARNING: This document assumes that you are familiar with programming on the
- Amiga, especially in the 'C' language. It also assumes that you are at least
- somewhat familiar with the ImageFX program itself.
-
-
-
-
-
- 0. CONTENTS
-
- 0. Contents
- 1. Introduction
- 2. Basics
- 2.1. Compiling Conventions
- 2.2. ScanBase
- 3. Modules
- 3.1. Theory
- 3.2. Standard Module Startup Code
- 3.3. Module Caveats
- 3.4. Types of Modules
- 3.2.1. Loader
- 3.2.2. Saver
- 3.2.3. Render
- 3.2.4. Scanner
- 3.2.5. Printer
- 3.2.6. Preview
- 3.5. Language
- 3.6. Preferences
- 3.7. Modules and Arexx
- 4. Hooks
- 4.1. Theory
- 4.2. Hook Construction
- 4.3. Language
- 4.4. Hooks and Arexx
-
-
-
-
-
- 1. INTRODUCTION
-
-
- ImageFX was designed to be expandable by anyone with an inclination
- towards programming, through the use of Modules and Hooks. What are Modules
- and Hooks you ask? Well, sit back and I'll explain:
-
- A "Module" is like an Amiga shared library. ImageFX loads the module into
- memory and calls functions in it to get things done. Every effort was made to
- make "black boxes" of these modules, thus it is possible to update or even
- replace modules without bothering ImageFX. Modules are broken down into
- several types, each one designed to do a specific thing. They are: Loader,
- Saver, Preview, Scanner, Render, Printer, Quantize, and Dither modules. Each
- module type is explained in more detail below.
-
- A "Hook" is a more free-form type of expansion for ImageFX. It is
- essentially just a program that is able to access much of the internal "stuff"
- of ImageFX, including image buffers and the like. ImageFX launches the Hook,
- waits for it to complete, and then continues as normal. Thus a Hook has
- virtually unlimited application, ranging from adding simple effects to adding
- whole new interfaces to the program.
-
-
-
-
-
-
-
- 2. BASICS
-
- This section describes some things you should know that are common to both
- the Modules and Hooks.
-
-
- 2.1. Compiling Conventions
-
- This document assumes you are using the SAS/C compiler. All examples and
- code were compiled with SAS/C 5.10b, and all object modules provided are in the
- standard Amiga link library format. They may require some modification to
- compile under other systems (especially Aztec).
-
- 32-bit int's are assumed throughout this document.
-
- All example source code assumes you are using at least the V37 include
- files. If you don't have them, I strongly suggest you get them along with the
- 2.0 enhancer kit. The sooner we stamp out 1.3, the better off we'll all be...
- :)
-
- 2.2. ScanBase
-
- When ImageFX is loaded, it creates a shared library in memory. This
- library contains a plethora of useful functions for dealing with ImageFX. The
- library structure (struct ScanBase) itself also contains a lot of useful
- information, like Screen pointers, drawing mode state information, and things
- like that. For details on the functions, consult the appropriate autodoc file.
-
- Since more than one ImageFX may be running at once, the name of the
- library has to also be different for each copy of the program. The convention
- used is as follows: For the first copy of ImageFX loaded, the library is
- called "scan1.library"; for the second copy of ImageFX, the library is called
- "scan2.library"; and so on.
-
- Normally, you will not need to worry about opening the library yourself.
- Modules are passed a pointer to ScanBase which they can use directly. Standard
- initialization code provided for writing Hooks also takes care of getting the
- right ScanBase pointer. You generally only need to know that there is a global
- ScanBase pointer available, and thus all the functions of that library are
- available.
-
- The library function calls are all registerized, so it should be possible
- to call scan.library from just about any language. The developer distribution
- uses pragmas for the library calls, so you may need to adjust this for your
- particular setup. An FD file is included so you can build your own stub
- library if necessary.
-
- A link-time library ("scan.lib") is included which contains varargs
- versions of some of the functions in scan.library, as well as few other handy
- functions not included in scan.library.
-
-
-
-
- 3. MODULES
-
- 3.1. Theory
-
- ImageFX Modules are strongly based on Amiga shared libraries. They are
- built in almost exactly the same way. If you aren't familiar with how to
- create a shared library, I strongly suggest that you review the subject (check
- the RKMs) before delving into this.
-
- A Module has the 4 standard library vectors of OPEN, CLOSE, EXPUNGE, and
- RESERVED. In addition, each type of module has additional vectors which must
- be provided (see individual descriptions below).
-
- Each Module has a ModuleBase structure associated with it (see
- "scan/mod.h"), which is based on the standard Exec Library structure. The
- ModuleBase structure is allocated by ImageFX and passed to the Module's OPEN
- vector, where the Module's job is to fill in the fields of the structure and
- return it. This is also where the module does any pre-use initialization
- required (such as opening libraries, etc.). By "pre-use" I mean any
- initialization that will cause the Module open to fail if something goes wrong
- (for example, if a module depends on some kind of hardware and the hardware is
- not found). For most modules there is another function to do less critical
- initializations such as initializing variables and such.
-
- ImageFX will fill in a few fields in the ModuleBase structure before
- passing it to the Module, most notably the SysLib and ScanBase pointers. These
- may be copied to the Module's global SysBase and ScanBase pointers
- respectively, to give access to those libraries. ScanBase also contains
- pointers to IntuitionBase and GfxBase, so those may also be copied if needed.
-
- Some of the common fields of ModuleBase that the Module OPEN vector should
- fill in are described below:
-
- NewGad: Points to an array of NewGad structures, which describes the GUI
- (gadgets, text, etc.) for this module (if it has one).
-
- Language: A string representing the "tag" to look for to find all the
- text associated with this module. A NULL indicates this module has no text, or
- you're not bothering with internationalizing the module. See the section below
- on internationalizing ImageFX modules.
-
- LangCount: The total number of text strings to look for.
-
- CmdTable: Pointer to an array of RXCMD structures, which describes the
- Arexx commands that this module understands. Loaders and Savers only use the
- first entry. If NULL, this module has no Arexx commands.
-
- PrefID: Four-byte ID "tag" used to locate and store preferences settings
- for this module. Each module MUST have a unique 4-byte ID, or disaster could
- result (or at least mixed-up preferences settings). If 0, this module has no
- preferences.
-
- PrefLen: Length of the structure that contains the module's preferences
- settings. ImageFX will ask the module to fill in a structure of this size,
- which it will then write to disk when the user wants to Save Prefs. Similarly,
- when the user Loads Prefs, a structure of this size which has been read from
- disk will be presented to the module.
-
-
-
-
-
- NewWin: Pointer to a NewWindow structure. Only used for Preview modules
- so that ImageFX can open the Preview Options window. May be NULL if there are
- no preview options.
-
- All other fields of the ModuleBase structure should be considered read
- only. Tampering with them may be dangerous.
-
-
- 3.2. Standard Module Startup Code
-
- I have provided a link-time module which does 99% of the grunt work of
- creating a module. You need only provide a function table, the name and type
- of your module, and special initialization and cleanup functions. The library
- does the rest.
-
- This wonderous achievement is called "lib.o", and should be the first
- module in your link list.
-
- Here are the things you need to specify:
-
- LibraryID: A pointer to a string which gives pertinant information about
- your module. It should be in the form of a standard 2.0 version string:
-
- "$VER: name version.revision (dd.mm.yy)"
-
- LibraryType: A byte indicating the type of module this is. Should be one
- of the NT_* constants defined in "scan/mod.h".
-
- FuncTable: A LONG array, where each element is a pointer to a function.
- This is the library vector table, and the first four functions should always be
- LibOpen, LibClose, LibExpunge, and LibNull (they are defined in lib.o). The
- remaining functions depend on the type of module (see below). The function
- table must be terminated with a -1 entry.
-
- UserOpen: Initialization function called within the OPEN vector. This is
- where you should take the time to initialize the appropriate fields of the
- ModuleBase structure, which is passed to you in A6 (a good place to use SAS's
- __asm register parameters). The ModuleBase parameter is also placed on the
- stack.
-
- UserClose: Cleanup function called within the CLOSE vector. This should
- cleanup anything that you (and only you) allocated in the UserOpen() function
- above. This is also passed a pointer to struct ModuleBase in A6 and on the
- stack.
-
- The startup code will fill in the SysBase, ScanBase, IntuitionBase,
- GfxBase, and ModuleBase (pointing to the module's own ModuleBase structure)
- global pointers.
-
-
- 3.3. Module Caveats
-
- Generally the same things that are not possible in an Amiga shared library
- are not possible in a Module. Most notably, you cannot use any of the stdio
- functions. Fortunately, however, there are similar buffered file I/O routines
- provided in ScanBase (see Scan.autodoc for details).
-
- While it is possible to use floating point math, you can only use the
-
-
-
-
- inline FPU math (-f8/lcm881) or the SAS floating point (-fl/lcm) routines. You
- may NOT use either of the Amiga floating point libraries (-fi/lcmieee or
- -ff/lcmffp) for reasons better left unsaid. For obvious reasons, I'd recommend
- staying away from the floating point altogether unless it's absolutely
- necessary (most of the time it isn't).
-
- It is generally a good idea to compile without stack depth checking (-v in
- SAS) on.
-
- If your module uses the small data model, you should make sure that any
- functions in your module that get called by ImageFX (directly or indirectly)
- load the A4 register to point to your data base. With SAS/C, you can use
- __saveds for all such functions or take the lazy way out (like me :) and just
- compile with the -y flag. I always do it the latter way so I'm not entirely
- sure the former way will work -- it should though. If you're really lazy you
- can just compile with -b0 and use the large data model.
-
- Modules always run in the ImageFX task context, using ImageFX's stack.
- Modules do not have to be reentrant.
-
-
- 3.4. Types of Modules
-
- Well, on to the nitty-gritty details of the modules.
-
-
- 3.4.1. Loader Modules
-
- Loader modules convert image files on disk into 8- or 24-bit buffers
- suitable for use in ImageFX. They are also used for extracting palette
- information from files (assuming the file format in question supports a
- palette).
-
- Generally speaking, each Loader module will handle one file format.
- However, it is possible to allow a single Loader to be able to read one of
- several file formats, or more commonly several variations of one file format.
- This is done by passing back an array of structures indicating the types of
- files the loader can read. Each file format must have its own unique ID number
- associated with it; this ID value is passed to the module's load vector so it
- knows which format was matched.
-
- ImageFX was designed to automatically detect the file format of the image
- the user is attempting to load, so that he doesn't have to know what it is
- beforehand. It was also designed to retain this ability no matter how many
- loader modules were added to the system. In order for ImageFX to know what to
- look for, it scans the modules/loaders/ directory (at startup time) and calls
- each loader module in turn. The loader module reports what "signature" bytes
- that a file must have in order to be considered as the file format that this
- loader expects. ImageFX takes this information and stores it in a list and
- continues on to the next loader until all of them have been queried.
-
- When the user asks to load a file, ImageFX reads the first few bytes of
- the file and compares those bytes to all the entries in its list. If it
- matches one of the entries, the approprate Loader module is loaded and control
- passes to it to read the image into memory.
-
- Another method of file format detection exists. If a file format does not
- have any "magic" constants at the beginning of the file, a Loader module may
-
-
-
-
- elect to do "custom file identification." This means that ImageFX will call
- your Loader with the name of the file in question. You loader module may then
- do whatever is necessary to determine whether this file is in the format
- expected by this module. If it is not, ImageFX carries the search on to other
- loader modules. If it is, control passes to your loader module to read the
- file into memory. A Loader module indicates that it wants to do custom file
- identification by returning NULL in the function that would normally indicate
- what signature bytes to look for.
-
- ImageFX also provides a method of automatically using a 68000 or 68030
- version of a loader module. The 68000 version of the loader module should have
- a file extension of ".000" and the 68030 version of the loader module should
- have a file extension of ".030". ImageFX will determine which loader module to
- use based on the CPU in the current system. Loader modules without any
- extensions can be used on any system.
-
- There are four functions that you need to provide in your Loader module.
- They (in order) are LM_Load(), LM_LoadPalette(), LM_Signatures(), and
- LM_CheckFile(). For detailed information about these function, consult the
- loader module autodoc and the sample loader skeleton source code.
-
-
- 3.4.2. Saver Modules
-
- Saver modules are responsible for storing 8- or 24-bit image buffers onto
- disk in a particular file format. They also handle saving rendered (color
- mapped) images.
-
- Generally speaking, each Saver module will handle one file format.
- However, it is possible to allow a single Saver to be able to write one of
- several file formats, or more commonly several variations of one file format.
- This is done by passing back an array of structures indicating the types of
- files the saver can write. Each file format must have its own unique ID number
- associated with it; this ID value is passed to the module's save vectors so it
- knows which format was matched.
-
- Similar to Loader modules, ImageFX will scan the entire
- modules/savers/directory at startup time to record the names of all available
- save formats.
-
- When the user chooses to save a file, he is presented with a list of all
- available file formats. After the user selects one, ImageFX decides on the
- appropriate Saver module to call, and calls one of its save vectors to write
- the file to disk (which vector depends on whether the user is saving a 24-bit
- file or a rendered image).
-
- Like Loader modules, ImageFX also provides a method of automatically using
- a 68000 or 68030 version of a saver module. The 68000 version of the saver
- module should have a file extension of ".000" and the 68030 version of the
- saver module should have a file extension of ".030". ImageFX will determine
- which saver module to use based on the CPU in the current system. Saver
- modules without any extensions can be used on any system.
-
- There are four functions that you need to provide in your Saver module.
- They (in order) are SM_SaveTrue(), SM_SaveMapped(), SM_SavePalette(), and
- SM_Signatures(). For detailed information about these functions, consult the
- saver module autodoc and the source code for the saver module skeleton.
-
-
-
-
-
-
- 3.4.3. Render Modules
-
- Render modules are responsible for displaying 24-bit image data on various
- display devices. Generally this process involves quantizing (reducing the
- colors in) a 24-bit buffer down to some fewer number of colors (16 or 256, for
- example). Render modules are not interactive, that is, they simple the display
- the image data. The user may choose to save the rendered image from the Save
- gadget on the main menu.
-
- Render modules are somewhat more complex than either Loader or Saver
- modules because of the introduction of a GUI. The user must be able to have
- some gadgets to click on when he chooses your render module, even if it is
- nothing more than a "GO" gadget. Your render module should also follow the
- convention of having a button in the upper left corner for changing the current
- module.
-
- ImageFX uses a somewhat unorthadox method of creating GUIs, which is
- something that you'll have to learn to create Render (as well as Scanner,
- Print, and Preview) modules. The system is loosely based on the 2.0
- gadTools.library, but goes about things in a different way. Basically, you
- hand ImageFX an array of structures describing the GUI; each element of the
- array describes a gadget, bevel box, image, or bit of text. The gadgets in the
- list may be given functions to call when they are "fiddled" with (buttons
- pressed, sliders slid, etc.). ImageFX handles all of the event processing for
- you. For further details of ImageFX's GUI system, refer to the Ged autodoc and
- "scan/ged.h".
-
- Render modules are loaded only when they are first accessed by the user
- (when he first clicks on the Render gadget). The module segment is then loaded
- into memory, and the standard module initialization is performed. Render
- modules also have additional initialization steps to go through (the functions
- RM_Init and RM_Show).
-
- <more to come - see example skeleton render module>
-
-
- 3.4.5. Printer Modules
-
- <more to come>
-
-
- 3.4.6. Preview Modules
- <more to come - see example skeleton preview module>
-
- 3.5. Language
-
- ImageFX was designed as an internationally-aware program. All the text
- used in the main program may be translated by the use of an external text file.
- If this text file exists, ImageFX reads the text into an array in memory, and
- all text references within the program are made as indexes into this array.
- Otherwise, internal (English) defaults are used. This allows for easy
- translation of the program into other languages.
-
- ImageFX also provides a way for modules to use the same technique of
- storing text in an external text file. Modules should be designed to take
-
-
-
-
- advantage of this, so that they may be translated to other languages as well
- (remember that the majority of Amigas are in Europe).
-
- If you want your module to be internationally-aware, there are a couple
- things you need to do:
-
- In your module's Open() vector, you should fill in the "Language" and
- "LangCount" fields of the ModuleBase structure. ImageFX will then try to
- locate the text of your module in a text file based on your language tag and
- return a pointer to the resulting array of text strings in ModuleBase->Text.
- If the language text is found, you should get your text strings from this array
- only.
-
- The standard module startup code contains a helpful function for use in
- internationalizing your modules: GetStr(). You should use this function for
- all your text references. The format of the function call is as follows:
-
- char *text = GetStr (int index, char *default_text)
-
- This function will examine your ModuleBase->Text field to see if an
- external text file was successfully read. If so, it will return the text at
- the given index to you. If the text was not read in, then the default text
- string will be returned.
-
- The name of the external text file depends on the type of module you are
- creating and the language tag you specify in ModuleBase->Language. ImageFX
- will use a template like this: "%ls_%ls.text", where the first argument is the
- *type* of module (eg. Loader, Render, Saver, etc.) and the second argument is
- the language tag you specify. For example, a scanner module with the language
- tag "Fuji" would reference the text file "Scanner_Fuji.text".
-
- A quick, fragmented example of a render module follows:
-
- /*******************************************************
- * In the module, you should define your text as indexes
- * into an array instead of as strings. This is the
- * index array:
- */
- enum {
- TXT_Hello,
- TXT_Goodbye,
- TXT_Yikes,
- TXT_COUNT /* 3 entries */
- };
-
- /*******************************************************
- * In the module Open() vector, setup the ModuleBase
- * Language and LangCount fields:
- */
- ModuleBase->Language = "MyModuleText";
- ModuleBase->LangCount = TXT_COUNT;
-
- /*******************************************************
- * Now whenever you want to use text, you reference it using
- * the GetStr() function.
- */
- Errorf(GetStr(TXT_Yikes, "Yikes!"));
-
-
-
-
-
-
- ;********************************************************
- ;* And in the ImageFX Text/ directory, you create a file
- ;* called "Render_MyModuleText.text" with the following lines:
- ;*
- !MyModuleText
- Hello
- Goodbye
- Yikes - an error!
- #
-
-
- 3.6. Preferences
-
- <more to come>
-
- 3.7. Modules and Arexx
-
- <more to come>
-
-
-
-
-
-
- 4. HOOKS
-
- 4.1. Theory
-
- ImageFX Hooks are nothing more than executable programs. When ImageFX
- launches a hook, it passes the name of the ImageFX function library to it as
- the first argument on the command line. Once the hook program has opened this
- library, it can access all of the functions in ImageFX, allowing it to get to
- the image buffers, or whatever. Additional command line arguments may be
- passed if the hook invocation came from Arexx.
-
-
- 4.2. Hook Construction
-
- A link-time startup module is provided to make building your hooks easier.
- It takes care of all the "grunt" work of opening the function library and
- making sure everything is setup properly. In addition, it copies certain
- library pointers (IntuitionBase and GfxBase) into global variables for your
- immediate use.
-
- The hook startup code calls the function "hook_main()" to invoke your hook
- code. This is the only function you need to provide.
-
- There are also three global variables you need to set so that the hook
- startup code knows what to do. They are described below:
-
- HookName: (char *) The name of your hook program.
-
- HookText: (char *) Language tag to search for for this hook program (see
- "Language" below).
-
- HookTextCount: (int) Number of text entries to read for this hook program
- (see "Language" below).
-
- Failure to set these will probably result in a link error.
-
-
- 4.3. Language
-
- Hook programs may also be designed to take advantage of ImageFX's
- internationality.
-
- The standard hook startup code contains a helpful function for use in
- internationalizing your modules: GetStr(). You should use this function for
- all your text references. The format of the function call is as follows:
-
- char *text = GetStr (int index, char *default_text)
-
- This function will check to see if an external text file was successfully
- read. If so, it will return to you the text at the given index. If the text
- was not read in, then the default text string will be returned.
-
- A quick, fragmented example follows:
-
- /*******************************************************
- * In the hook, you should define your text as indexes
- * into an array instead of as strings. This is the
- * index array:
-
-
-
-
- */
- enum {
- TXT_Hello,
- TXT_Goodbye,
- TXT_Yikes,
- TXT_COUNT /* 3 entries */
- };
-
- /*******************************************************
- * Use the following globals to tell the hook startup
- * code what to look for:
- */
- HookText = "MyHookText";
- HookTextCount = TXT_COUNT;
-
- /*******************************************************
- * Now whenever you want to use text, you reference it using
- * the GetStr() function.
- */
- Errorf(GetStr(TXT_Yikes, "Yikes!"));
-
-
- ;********************************************************
- ;* And in the ImageFX Text/ directory, you create a file
- ;* called "Hook_MyHookText.text" with the following lines:
- ;*
- !MyHookText
- Hello
- Goodbye
- Yikes - an error!
- #
-
-
- 4.4. Hooks and Arexx
-
- When a hook is invoked via. Arexx, arguments may be passed to your hook
- code via. the command line.
-
- The hook_main() function has two arguments just like a standard main()
- function; 'argc' and 'argv'. You can use these to peruse any arguments that
- were sent to your hook program via. Arexx.
-
- For example, suppose the user issued the command:
-
- "Hook YourHook 1 4 Cookies"
-
- Your hook_main() function will get the following:
-
- argc = 4
- argv[0] = <ignored>
- argv[1] = "1"
- argv[2] = "4"
- argv[3] = "Cookies"
-
- Why is the first one ignored? To keep the same conventions as standard C
- main() functions.
-
- If you need to get to the RexxMsg that invoked your hook program (for
-
-
-
-
- example, to setup result strings or set variables), you can look in the field
- ScanBase->sb_HookMsg. If this field is NULL, then your hook was not invoked by
- Arexx (ie. the user could have just typed something in the command shell).
- Otherwise, it points to a RexxMsg structure which you can use for whatever
- purpose.
-
- A handy function contained in ScanBase is called SetResult(). It lets you
- set the result string to return to an Arexx program in a fairly easy fashion.
- It's prototype is:
-
- BOOL SetResult (struct RexxMsg *msg, char *fmt, ...);
-
- The result string to pass back to the Arexx program associated with the
- given RexxMsg will be set to the formatted string passed in. It is safe to
- pass a NULL for the RexxMsg, in which case nothing is done.
-
-
-