SWAPPING
                                   ART
                                   WITH
                             OTHER COMPUTERS
                         IFF STANDARDS FOR THE ST

                              By Tom Hudson

  The Interchange File Format (IFF), originally developed for the Amiga
  computer, is now a vailable on the ST. Graphics block transfers-true
  "'clip art"- and Amiga picture compatibility are provided, courtesy of
  Tom Hudson. The author of DEGAS Elite and CAD-3D explains how to use
  this new graphics standard. Folder IFF.STQ on your START disk contains
  all necessary source code for the routines, two sample programs to
  read and write your own IFF picture blocks, and some sample picture
  segments.

  While developing DEGAS Elite, the full-featured version of DEGAS, I
  decided the program should have true "clip art" capability, such as
  that found on the Macintosh. This ability to transfer portions of a
  graphics display (bit-blocks) from one program to another has been
  missing from the Atari ST. It's not that it hasn't been done, it's
  just that ST developers have not agreed upon a standard file format.

  Originally, I created a very simple bit-block format for DEGAS Elite
  pictures that would work fine for Atari users. But what if someone
  wanted to import images from, say, the Commodore Amiga computer? A
  simple Atari-only format just wouldn't do.

  I consulted several prominent ST developers for their opinions, and we
  decided that Atari bit-block images should be stored to disk in the
  Electronic Arts Interchange File Format (IFF).

  The Interchange File Format is a set of file standards developed by
  Electronic Arts so that computers of all types can easily exchange a
  variety of files: graphics, music, text, and so forth. Originally
  implemented on the Amiga, this format will be the perfect way for the
  ST to communicate with any other computer that supports IFF.

  Why support IFF files? Take a look at the computer industry. Every
  computer manufacturer has a different notion of how things should be
  done. You can't use an Amiga or Macintosh disk in an ST drive-they use
  different formats to store their data. You can't plug an IBM graphics
  card into an Apple II. The major drawing programs on the ST alone use
  different picture storage formats! The computer industry needs
  standards, and the IFF file is a move in the right direction. With it,
  we take an important step toward computer compatibility.

  With a proper standard defined and adhered to by the many ST software
  developers, we will have a uniform method for exchanging graphics
  information between applications such as paint programs, page-layout
  programs, charting programs, or word processors. One program can
  create a graphic image and write it to a disk file, then another
  program can use that image in whatever way is required. In addition,
  it will be much easier to port software from one computer to another
  because they will use the same file-handling routines!

  This article will describe a uniform method of storing graphic
  bit-blocks in IFF disk files, and provide commented C source listings
  demonstrating the reading and writing of the files. In addition, the
  START disk contains example block image files along with the
  ready-to-use source code, so that START readers can begin supporting
  the file format immediately.

  (Editor's note: START agrees with Tom Hudson and the developers
  supporting him on this. We urge all ST developers to adopt the IFF
  format as an ST graphics standard. Non programmers and others who just
  want to use the IFF programs on their START disk will find
  instructions near the end of this article. We advise reading the
  article for information that will make the instructions clearer.)

  MEMORY FORMS

  Before examining IFF and adapting it to the ST, we must understand how
  the ST itself transfers bit blocks. Whenever the ST's graphics
  routines perform a bit-block transfer, they must be informed how the
  graphic information is laid out in the system memory. This is known as
  a memory form, and may be in several formats depending upon the
  image's resolution and how the program created the image.

  Typically, the ST programmer uses the GEM VDI bit-block manipulation
  functions, vro_cpyfm() and vrt_cpyfm(), to move image blocks around.
  These functions are passed the format of the bit-mapped image with an
  array of values known as a Memory Form Definition Block (MFDB). Most
  applications will require the use of the vro_cpyfm() function (opaque
  color form to color form operation) rather than the vrt_cpyfm()
  function (transparent, single-plane form to color form) because the
  latter is mainly used to turn a monochrome image (such as a block of
  text) into a color image. We will only work with the vro_cpyfm()
  function in this article.

  An MFDB is a ten-word array of values in which each word entry is a
  part of the information defining the bit-block. Its format is as
  follows:

  MFDB[0]-High word of memory form starting address
  MFDB[1]-Low word of memory form starring address
  MFDB[2]-Form width in pixels
  MFDB[3]-Form height in pixels
  MFDB[4]-Form width in words
  MFDB[5]-Form format flag
  MFDB[6]-Number of memory planes
  MFDB[7]-Reserved (0)
  MFDB[8]-Reserved (0)
  MFDB[9]-Reserved (0)

  The first two entries of the MFDB array are the longword address of
  the start of the bit-block broken into high and low words. These two
  word values tell the VDI where the bit-block memory form is located in
  memory. For memory forms that are standard ST screens, this value will
  be the base address of the screen RAM.

  The third entry in the MFDB array is the form width in pixels. This is
  quickly calculated as:

  Rightmost pixel number - Leftmost pixel number + 1

  For an entire ST screen, this value will be either 320 (low-resolution
  mode) or 640 (medium- and high-resolution modes).

  The fourth entry in the MFDB array, the form height in pixels, is
  equally easy to calculate:

  Bottommost pixel number -Topmost pixel number +1

  For an entire ST screen, the height in pixels will be either 200 (low-
  and medium-resolution modes) or 400 (high-resolution mode).
                            _________________

                                 What if
                            someone wanted to
                           import images from,
                            say, the Commodore
                                  Amiga?
                            _________________

  The fifth entry tells the VDI in which format the bit-block image is
  stored. There are two formats supported by the VDI: standard form (1)
  and device-specific form (0). For our purposes, we will use only the
  device-specific form, since this is the format used in ST screen image
  data.

  The sixth MFDB value, the form width in words, is the number of 16-bit
  words required to hold one line of pixels. In C, this value can be
  calculated as:

  (Width in pixels + 15)>>4

  Finally, the number of memory planes is either 4 (low-resolution), 2
  (medium-resolution) or 1 (high-resolution monochrome).

  The last three entries in the MFDB array are reserved for future use
  in the VDI. Set them to zero, to avoid unexpected results in future
  versions of the VDI.

  Once you have properly defined the MFDBs for the source form (where
  the bit-block is being moved from) and destination form (where the
  bit-block is being moved to), you can use vro_cpyfm() to move a
  bit-block from one memory form to another You can use the same MFDB
  for both the source and the destination if needed, but it's best to
  perform a bit-block transfer (bitblt) using two separate memory forms
  to avoid overlap conflicts.

  MOVING A BIT BLOCK

  Moving a block around is actually very simple, but you must know where
  the block is and where you want it to go. To do this, you must set up
  two MFDB arrays, one for the source form and one for the destination
  form. Normally, one of the memory forms will be a screen RAM area, and
  the other will be a user-defined holding buffer for the bit-block.

  Setting up a user-defined portion of RAM for the image buffer is quite
  easy. Calculate the size of the picture in bytes.

  Number of planes * Width in words * 2 * Height in pixels

  This value is then used as a parameter for the memory allocation
  function, Malloc(). Note that it isn't necessary to allocate an entire
  32000 bytes (the full size of an ST screen) for your bit image. For a
  low-resolution (4 bit planes) bit-block 33 pixels wide (3 words) and
  12 pixels high, the RAM required is only (4 * 3 * 2*12), or 288 bytes.
  Calculate the RAM needed, allocate it, and plug the starting address
  of the allocated RAM into the first two entries of the MFDB. (Well
  look at an example of this later)

  Once you have both MFDBs defined with properly allocated sections of
  RAM, you need to set up another array which tells vro_cpyfm() which
  part of the source form you want to move, as well as where to place it
  in the destination memory form. This is an eight-entry array with the
  first four words defining the source rectangle, and the last four
  words defining the destination rectangle. For example, to move the
  rectangle with upper-left coordinates 30,40 and lower-right
  coordinates 50,45 to a rectangle on the destination form with
  upper-left coordinates 0,0 and lower-right coordinates 20,5 (be sure
  the two rectangles are the same size), the coordinate array (well call
  it COORD) will look like this:

  COORD[0] = 30
  COORD[1] = 40
  COORD[2] = 50
  COORD[3] = 45

  COORD[4] = 0
  COORD[5] = 0
  COORD[6] = 20
  COORD[7] = 5

  Now all the preliminary data is set up. We have properly described the
  memory forms and the portion of the source form we want to move. We're
  ready to do the bitblt operation with the vro_cpyfm() call. It is
  structured as follows:

  vro_cpyfm(handle, wr_mode, COORD array, source MFDB, destination MFDB)

  The handle is the device handle of the graphics workstation you are
  using, assigned when you open the virtual workstation with the
  v_opnvwk() function.
                            _________________

                             This format will
                          be the perfect way for
                                the ST to
                             communicate with
                            any other computer
                              that supports
                                   IFF.
                            _________________

  The wr_mode is the writing mode to use in the bitblt operation,
  numbered from 0-15, and described in the GEM VDI manual, page 6-6. For
  our purposes, we will always use mode 3 (replace mode), where the
  source block is copied into the destination form exactly as it appears
  in the source form. The other 15 writing modes can be used for special
  masking effects, and you can experiment with them to see what they do.

  The COORD array is the eight-word array described earlier which tells
  the VDI the coordinates of the bit-block to move.

  The source MFDB is the pointer to the MFDB of the form we're moving
  the block from.

  The destination MFDB is the pointer to the MFDB of the form we're
  moving the block to.

  When vro_cpyfm() is called, the bit-block will be copied from the
  source form to the destination form, and if the two MFDBs are
  different formats (as in the source form being a standard ST screen
  and the destination form being just the size of the bit-block), the
  VDI will convert the form's format accordingly.

  INTERCHANGE FILE FORMAT

  Now that you know the basics of setting up a memory form and copying a
  bit-block from one form to another, let's see how to store bit-blocks
  in a disk file for later use. This is where the IFF file format comes
  in.

  The IFF routines on your START disk are a subset of the full IFF
  specification. These routines can handle bit-mapped images of various
  resolutions quite well but do not handle text or any of the other IFF
  file types. They are easy for the ST programmer to use because they
  take standard GEM VDI Memory Form Definition Blocks and ST palettes as
  input; the programmer doesn't have to deal directly with the IFF
  files. When reading the IFF file, the routines take care of most
  conditions that can occur, and return palette information in both a
  system palette table and a GEM color format. In short, the routines
  make reading and writing IFF files a quick and painless task for the
  ST programmer.

  The IFF bit-block files we'll be using have a standard format, shown
  below. For ST IFF bit-block files, I suggest three standard extenders:
  For low-resolution (16-color) images, use BL1; for medium-resolution
  (4-color) images, use .BL2; and for high-resolution (monochrome)
  images, use .BL3. These correspond to the .P11/.P12/.P13 extenders
  used by the DEGAS paint program, which allow users to quickly identify
  the resolution of the image contained in the file. This will become
  important when images begin to appear on bulletin board systems with
  little documentation.

  Each IFF bit-block file begins with the four-character identifier FORM
  followed by a four-byte longword indicating the length of the file
  (not counting the FORM header and length code). The program reading
  the IFF file should check for this header to be sure the file is in
  the proper IFF format.

  Following the FORM header is the four-character code ILBM, which
  stands for InterLeaved Bit Map (not to be confused with ST Bit-Plane
  Interleaving). This code lets the reading program know the file
  contains an IFF bit-block image.

  Next comes another four-character identifier, BMHD, which stands for
  Bit Map HeaDer It is followed by a four-byte longword indicating the
  length of the header. The length is expected to be 20 bytes with the
  following structure:

Byte
Offset
 0   word - Width of form in pixels
 2   word - Height of form in pixels
 4   word - X pixel location (assumed to be 0)
 6   word - Y pixel position (assumed to be 0)
 8   byte - Number of bit planes
 9   byte - Masking flag- unused in our routines
10   byte - Compression flag-0=No compression, 1=RLE
11   byte - Unused filler byte
12   word - Transparent color pixel value (normally 0)
14   byte - X Aspect ratio (unused by our routines)
15   byte - Y Aspect ratio (unused by our routines)
16   word - Page width
18   word - Page height

  Following the BMHD data chunk is the color palette information. This
  is another four-character identifier, CMAP (Color MAP), and it is also
  followed by a four-byte longword indicating the number of bytes in
  this data chunk. The data in this chunk is a group of three-byte
  structures, as shown below. Each three-byte RGB value represents one
  color:

  byte - Red value for color
  byte - Green value for color
  byte - Blue value for color

  The color information in each of these bytes must be aligned with the
  most significant bit. For example, the ST's palette registers contain
  red, green and blue settings ranging from 0-7, which requires three
  bits to store. In a byte, these bits are stored like so:

  00000XXX

  To make the value conform to the IFF format, we shift the
  color-register value to the left five bits, so that the most
  significant bit of the byte contains the most significant bit of the
  color data, like so:

  XXX00000

  For a low-resolution image, the color map contains 16 three-byte
  entries; for a medium-resolution image, it contains four three-byte
  entries; for a high-resolution image, it contains two three-byte
  entries.

  One problem arises at this point. When transporting bit-block files
  from the Amiga (which allows up to 32 colors) to the ST (which allows
  only 16 colors), the ST routine must drop some of the colors and their
  corresponding bit planes. When this happens, the first 16 colors are
  used, and the rest are discarded. The same applies for the extra
  bit-planes. The IFF routines supplied here can read one resolution
  bit-block and turn it into another resolution, but be warned that
  reading a bit-block image file into a memory form with fewer bit
  planes (such as reading a BL1 file into monochrome mode) will probably
  render the image useless. You can read blocks with fewer bit planes
  into a form with more bit planes with no trouble-the colors will show
  up properly.

  After the color map, the last data chunk in the IFF file is the
  bit-mapped image itself. This is preceded by a four-character
  identifier BODY and a four-byte longword specifying the length of the
  bit-block data.

  The BODY can be written in two different forms: uncompressed and
  compressed. The compressed format uses a simple Run-Length Encoding
  RLE scheme (see Reference 2). Note that the IFF Reader on your START
  disk will read both uncompressed and RLE-format bit-block data, but,
  for simplicity's sake, the write routines will only write uncompressed
  data. If you like, you can modify the write routine so that it
  supports the RLE option.

  This is a simple overview of the IFF bit-block format. As I said
  earlier, the IFF routines do most of the work for the programmer and a
  detailed knowledge of IFF format is not needed to use them. However,
  if you would like to get full information on compression format and
  other details, you should read the Electronic Arts "EA IFF 85 Standard
  for Interchange Format Files" document (see Reference 1).

  IFF FILE HANDLING ROUTINES

  The file IFFRTNS.C on your START disk is the C source code for the
  actual IFF I/O routines. To use this in your programs, compile it into
  a .O (object) file and place it on your linker disk. Whenever you want
  to use the IFF routines, link the IFFRTNS.O file with your program,
  and you're ready to go.

  There are three routines in the IFFRTNS.C file that you will be
  concerned with: iff__rdl(), iff_rd2() and iff_wrt(). All these
  routines and their support functions are documented for your use.

  The IFF I/O routines make several items available. The Syspal[] array
  is a 16-word array which holds the color-palette information as used
  by the Setpallete() call. That is, each entry ranges from $0000-0777,
  where $0000 is black and $0777 is white.

  The Gempal[16][3] array is an array of color values used by the GEM
  vs_color() function. This array has 16 groups of three values, where
  Gempal[][0] is a value from 0-1000 for the red portion of the color,
  Gempal[][1] is the green component, and Gempal[][2] is the blue
  component.

  Finally, the xparent variable is an INT value that tells which color
  is assumed to be transparent. This will typically be the background
  color index, 0.

  The colors in a block file may differ from the color palette that your
  program is using. Because of this, the block images may not look
  correct when loaded. With the color-palette information supplied with
  each block, you can do what is termed a "color re-map" - that is, you
  can process the pixels in the block image and replace the old pixels
  with the color from the current palette which most closely matches the
  original pixel color. This rather complex operation requires
  specialized assembly language and is beyond the scope of this article.

  IFF I/O FUNCTIONS

  The iff_id() function, used internally in the IFF I/O routines, reads
  a four-character data ID and the four-byte length into the chk
  structure.

  The proc_CMAP() function is used after the color map (CMAP) chunk has
  been located. It reads the color values from the block file and
  transforms them into both the ST BIOS format (in the Syspal[] array)
  and the GEM format (in the Gempal[][] array).

  The decompress() function takes care of reading bit-block images which
  were written using the RLE compression scheme. Decompression is done
  one scan line at a time.

  The rawread() function does the same thing as decompress(), but with
  block image data that is not compressed.

  The rawwrite() function writes a scan line of uncompressed data to a
  disk file. As mentioned, there is no corresponding compress() function
  here, but you can add one to write image data in a compressed form, if
  you like. The Read routines can handle either format. Compression on
  writing was not supported primarily because small block files benefit
  little from RLE compression.

  The toraster() function does the job of converting the raw,
  uncompressed scan line data into the ST's device-specific
  "interleaved" bit-map format. This screen data format is discussed in
  the article "GRAFCON ST' in the July, 1986 issue of Antic magazine.

  The fmraster() function does the opposite of the toraster() function.
  That is, it takes a scan line of device-specific data and converts it
  into the form required by the IFF data file. After this routine, the
  data is ready for writing (or compression, if you choose to install
  RLE compression).

  The iff_rdl() and iff_rd2() functions are the actual functions called
  to read an IFF file. This is a two-phase operation: You furnish an
  MFDB array and the handle of a file opened for input, and call
  iff_rdl(). This function reads the starting portion of an IFF file,
  sets up the MFDB array to let you know how the block is laid out, and
  returns. Using the information in the returned MFDB, you allocate the
  amount of RAM the block needs and call iff__rd2() to complete the read
  process. This operation is shown in detail below.

  The iff__wrt() function is used to write a bit-block to disk. You
  furnish the handle of a file opened for output, the MFDB of the block,
  a color palette in the ST BIOS format, and the resolution of the
  image. This process is also shown in detail below.

  READING IFF FILES

  As mentioned, the IFF file-read process is a two-stage process.
  IFFREAD.PRG, on your START disk, is a program demonstrating the
  reading of IFF block files. Sample block files of the three different
  resolutions are supplied on the START disk. Files with .BL1 extensions
  are for low-resolution, .BL2 files are for medium-resolution, and .BL3
  files are for monochrome. Try reading various resolution block files
  in the ST's three graphics modes to see how each looks. The following
  is an explanation of the source code found in IFFREAD.C.

  IFFREAD starts by opening a virtual workstation and requesting the
  screen's location in memory and its resolution. The color palette is
  also placed in the oldpaI[] array for later restoration. Important:
  always restore the color palette after your program is done so that
  when the system returns to the Desktop, it is the same as it was
  before your program executed. This is not only considerate to the
  user, but it insures that the Desktop screen will be readable!

  Next, the program builds the screen's MFDB array This is a fairly
  straightforward operation. As you can see, it plugs the appropriate
  values into all ten scrnmfdb[] array locations. Be sure to always
  place zeroes into the last three MFDB locations to insure
  compatibility with future GEM VDI releases.

  Now we bring up the GEM file-selector dialog and let the user select
  the IFF block file to load. Once the filename is entered, the program
  displays the whichfm dialog to ask the user where to load the block
  image.

  The whichfm dialog lets you choose how the block file will be loaded.
  If SCREEN is chosen, the block will be loaded into the screen's MFDB,
  regardless of the block's size. In this case, the block is read into
  the upper-left corner of the screen, showing that a block can be read
  into any size memory form. Of course, the only usable portion of the
  form is the block itself.

  If FORM is chosen in the dialog, the program will allocate the amount
  of RAM required for the bit-block in a part of RAM separate from the
  screen, read the block into that RAM, then do a bitblt to copy the
  block to the center of the screen. This is a triple-edged
  demonstration, showing how to allocate RAM, bring in a bit-block to a
  special buffer, and how a bitblt operation works.

  After SCREEN or FORM is chosen, the program attempts to open the file
  requested by the user. If it is opened successfully, the program
  attempts a first-stage IFF read using the iff_rdl() function. The
  program passes the file's handle (fhand) to the function along with a
  10-entry MFDB array (workmfdb) which the function will set up
  according to the block's size.

  The iff_rdl() function returns a value of zero if the first-stage IFF
  read was successful. If the value is negative, an error has occurred.
  The error numbers and meanings are found in the #defines of the
  IFFRTNS.C file:

  After iff_rdl() executes successfully, Syspal[] and Gempal[][] will be
  filled with the color values found in the IFF file. The MFDB array you
  specified in the iff_rdl() function call will be filled with the data
  for the bit-block except for the first two array entries. These
  entries, you should recall, contain the address of the memory form
  block, which the IFF Reader routines cannot determine. This is up to
  you, and we'll see how to do it in a moment.
                            _________________

                            The routine makes
                           reading and writing
                          IFF files a quick and
                          painless task for the
                              ST programmer.
                            _________________

  The first thing IFFREAD does is check to see if either the width or
  height of the image is too large for the ST screen. If so, the MFDB
  values for these settings are adjusted to the maximum size of the ST
  screen. Excess size conditions can occur if you try to read a large
  monochrome image into a low-resolution screen (since monochrome images
  are 640X400 pixels and low-resolution images are 320X200 pixels). This
  operation will truncate the block to a usable size.

  Next, we set the number of bitplanes in the form to the same number as
  the resolution that is in use. If the form has excess bitplanes, they
  are ignored. In the demonstration program, this is accomplished by:

  workmfdb[6] = scrnmfdb[6];

  If the user requested that the block be loaded into the screen
  (formtype= =1), the address of the memory form is set to that of the
  current screen, which is in the scrnmfdb[] form entries [0] and [1] To
  read the block into the screen, we must also make sure the block's
  width parameter (workmfdb[4]) matches that of the screen.

  If the block is to be read into a memory form separate from the screen
  (formtype= =2), we have to do a little more work. Specifically, we
  need to ask the operating system to allocate enough RAM for the
  bit-block's form. Fortunately, we can allocate just the right amount
  of RAM required for the bit-block-which can be as few as two bytes or
  as many as 32000 bytes. This prevents wasted memory.

  To determine the amount of RAM needed to hold a bit-block, we do the
  calculation:

  blocksize = MFDB[3] * MFDB[4] * MFDB[6] * 2;

  This value is then used as input to the GEMDOS Malloc() (memory
  allocation) call, which sets aside the RAM we need and returns the
  address of the allocated RAM. If the allocation is successful, we plug
  the RAM's address into locations [0] and [1] of the workmfdb[] array.
  The rest of the MFDB is left as is.

  Now that the MFDB is set up with the address of the memory form and
  the number of bit planes we intend to use, we call iff_rd2(). This
  function actually reads the bit-block into the area we defined via
  workmfdb[]. If the read is successful, a zero is returned, otherwise,
  a negative value is returned (see the error code #defines in the
  IFFRTNS.C file).

  After the phase 2 IFF file read has executed, the file we opened
  should be closed, since we're done with it.

  If it is necessary to set the colors to those of the block, you can do
  it in two ways, as shown in the example program. The Setpallete() call
  is the easiest, but you can also use the vs_color() function to do the
  job. The result is the same in either case-it's a matter of personal
  preference. In the IFFREAD demo, we go ahead and set the colors in
  both ways so that you can see the block as it was stored.

  If the block was read into the screen RAM, no further action is
  necessary, since the block is in view already.

  If the block was read into a memory form other than the screen
  (formtyp = = 2), we'll have to copy it to the screen to view it. To do
  this, we set up the blit[] array with the coordinates of the block in
  its source form in blit[0] through blit[3]. We also set up the
  coordinates of where we want the block to be copied in the destination
  form (the screen) in blit[4] through blit[7]. For proper results, make
  sure the source block size and the destination block sizes are the
  same. IFFREAD copies the block to the screen so that it is centered
  horizontally and vertically. The actual instruction to do the bitblt
  operation is vro_cpyfm(), described earlier. It uses the workmfdb[]
  array for the source form, scrnmfdb[] for the destination form and the
  blit[] array for the coordinates to copy. Try changing the coordinate
  values to see how the bitblt operation works.

  After you have viewed the loaded bit-block image, press any key to
  return to the Desktop.

  WRITING BLOCK FILES

  The IFFWRITE.C file on the START disk is the C source file for the
  IFFWRITE.PRG example program. With it, you can load any DEGAS-format
  picture and save portions of the picture to disk in a standard
  IFF-format block file. These files will be compatible with DEGAS
  Elite's block-handling capability and any other program that supports
  the IFF-format block files.

  This program is quite straightforward. It is similar to IFFREAD in
  many places, so we'll cover mainly the important differences.

  The program begins like IFFREAD by opening a virtual workstation,
  setting up the screen's MFDB, and so on. It does, however, perform an
  extra setup function. In order to prepare to write one of our block
  files, we must have a section of memory reserved to hold up to a
  screenful of data-or 32000 bytes. This is done with the Malloc()
  function. We ask the system for 32000 bytes of RAM, and it returns the
  starting address of the RAM. If this fails, the program informs the
  user with a dialog. Otherwise, we set the pointer workarea to the
  address of the RAM buffer.

  Like IFFREAD, IFFWRITE displays the file-selector dialog. This time,
  however, it wants a DEGAS-format picture file as input, and
  automatically searches for a file with a P11, P12, or P13 extender,
  depending on the current system resolution. After the user enters the
  filename, the picture file is read into the current screen memory for
  the user to see. The 16-entry INT array picpal[] contains the color
  information for the picture.

  After the picture appears, the user points the mouse to the upper-left
  corner of the area to be saved, presses and holds the button, dragging
  it to the lower-right corner of the block. A "rubber box" appears to
  define the rectangle that will be saved.

  When the button is released, the program calculates the size of the
  bit-block and uses vro_cpyfm() to copy the block to the 32000-byte
  work area that was allocated at the start of the program. Before the
  bitblt operation can be executed, however, the program must set up the
  MFDB for the rectangle. This MFDB will be used to tell the IFF write
  routine where the block is and what its format is.

  Now the program displays a second file selector dialog, this time
  expecting a block file name. When entering the filename, be sure to
  add the .BL1/.BL2/.BL3 extender so that you can identify the
  resolution of the block file later.

  After the block filename is entered, the program creates the file and
  instructs the IFF write routine iff__wrt(), to write the file. This is
  a simple one-stage process. The programmer furnishes the handle of the
  file that is opened as output, along with the MFDB for the block, the
  color palette that is to be used for the block, and the block's
  resolution (0, 1, or 2). The IFF write routine does all the rest and
  returns a 0 to indicate success or a -1 to indicate failure. After the
  write call returns, the program closes the file and the write process
  is complete! What could be easier?

  An interesting side-benefit of this program is that if you "grab" the
  entire screen with the rubber box and write it, the resulting block
  file is directly usable by all Amiga paint programs that support IFF,
  making the program a handy DEGAS-to-IFF converter! Aren't standards
  wonderful?

  FINAL NOTES

  Remember: though these routines are flexible and will allow you to use
  any bit-block image regardless of resolution, loading an image with
  more bit planes than are used in your particular graphics mode may
  make the image unusable. If in doubt, just force the user to use BL1,
  .BL2 or .BL3 files, depending upon the resolution. This way, the
  images will always be usable.

  Using the IFF file-read routines shown in this example, you can load
  many different bit-block images into separate areas of computer memory
  for use by your own programs. Whether you are an ST developer or an
  involved programming hobbyist, these routines should prove valuable
  for using bit-block files in your own programs.

  REFERENCE:

  EA IFF 85 Standard for Interchange Format Files from Jerry Morrison,
  Electronic Arts. Available through Commodore-Amiga, 1200 Wilson Drive,
  West Chester, PA 19380.

  GRAFCON ST, Universal Graphics Converter by Patrick Bass, Antic
  Magazine, July 1986, pp. 67-72.

  GEM VDI Manual, Digital Research, Inc., pp. 6-1 through 6-8.

  Atari ST GEM Programmer's Reference by Norbert Szczepanowski and Bernd
  Gunther, Abacus Software, pp. 157-161.
    _________________________________________________________________