488 lines
21 KiB
Plaintext
488 lines
21 KiB
Plaintext
"ILBM" IFF Interleaved Bitmap
|
||
Date: January 17, 1986
|
||
From: Jerry Morrison, Electronic Arts
|
||
Status: Released and in use
|
||
|
||
1. Introduction
|
||
|
||
"EA IFF 85" is Electronic Arts' standard for interchange format files.
|
||
"ILBM" is a format for a 2 dimensional raster graphics image, specifically
|
||
an InterLeaved bitplane BitMap image with color map. An ILBM is an
|
||
IFF "data section" or "FORM type", which can be an IFF file or a part
|
||
of one. (See the IFF reference.)
|
||
|
||
An ILBM is an archival representation designed for three uses. First,
|
||
a standalone image that specifies exactly how to display itself (resolution,
|
||
size, color map, etc.). Second, an image intended to be merged into
|
||
a bigger picture which has its own depth, color map, and so on. And
|
||
third, an empty image with a color map selection or "palette" for
|
||
a paint program. ILBM is also intended as a building block for composite
|
||
IFF FORMs like "animation sequence" and "structured graphics". Some
|
||
uses of ILBM will be to preserve as much information as possible across
|
||
disparate environments. Other uses will be to store data for a single
|
||
program or highly cooperative programs while maintaining subtle details.
|
||
So we're trying to accomplish a lot with this one format.
|
||
|
||
This memo is the IFF supplement for FORM ILBM. Section 2 defines the
|
||
purpose and format of property chunks bitmap header "BMHD", color
|
||
map "CMAP", hotspot "GRAB", destination merge data "DEST", sprite
|
||
information "SPRT", and Commodore Amiga viewport mode "CAMG". Section
|
||
3 defines the standard data chunk "BODY". These are the "standard"
|
||
chunks. Section 4 defines the nonstandard color range data chunk "CRNG".
|
||
Additional specialized chunks like texture pattern can be added later.
|
||
The ILBM syntax is summarized in Appendix A as a regular expression
|
||
and in Appendix B as a box diagram. Appendix C explains the optional
|
||
run encoding scheme. Appendix D names the committee responsible for
|
||
this FORM ILBM standard.
|
||
|
||
Details of the raster layout are given in part 3, "Standard Data Chunk".
|
||
Some elements are based on the Commodore Amiga hardware but generalized
|
||
for use on other computers. An alternative to ILBM would be appropriate
|
||
for computers with true color data in each pixel.
|
||
|
||
Reference:
|
||
|
||
"EA IFF 85" Standard for Interchange Format Files describes the underlying
|
||
conventions for all IFF files.
|
||
|
||
Amiga[tm] is a trademark of Commodore-Amiga, Inc.
|
||
Electronic Arts[tm] is a trademark of Electronic Arts.
|
||
Macintosh[tm] is a trademark licensed to Apple Computer, Inc.
|
||
MacPaint[tm] is a trademark of Apple Computer, Inc.
|
||
|
||
|
||
2. Standard Properties
|
||
|
||
The required property "BMHD" and any optional properties must appear
|
||
before any "BODY" chunk. (Since an ILBM has only one BODY chunk, any
|
||
following properties are superfluous.) Any of these properties may
|
||
be shared over a LIST of FORMs IBLM by putting them in a PROP ILBM.
|
||
(See the "EA IFF 85" memo.)
|
||
|
||
BMHD
|
||
|
||
The required property "BMHD" holds a BitMapHeader as defined in these
|
||
C declarations and following documentation. It describes the dimensions
|
||
and encoding of the image, including data necessary to understand
|
||
the BODY chunk to follow.
|
||
|
||
typedef UBYTE Masking; /* Choice of masking technique. */
|
||
|
||
#define mskNone 0
|
||
#define mskHasMask 1
|
||
#define mskHasTransparentColor 2
|
||
#define mskLasso 3
|
||
|
||
typedef UBYTE Compression;
|
||
/* Choice of compression algorithm applied to the rows of all
|
||
* source and mask planes. "cmpByteRun1" is the byte run encoding
|
||
* described in Appendix C. Do not compress across rows! */
|
||
#define cmpNone 0
|
||
#define cmpByteRun1 1
|
||
|
||
typedef struct {
|
||
UWORD w, h; /* raster width & height in pixels */
|
||
WORD x, y; /* pixel position for this image */
|
||
UBYTE nPlanes; /* # source bitplanes */
|
||
Masking masking;
|
||
Compression compression;
|
||
UBYTE pad1; /* unused; for consistency, put 0 here */
|
||
UWORD transparentColor; /* transparent "color number" (sort of) */
|
||
UBYTE xAspect, yAspect; /* pixel aspect, a ratio width : height */
|
||
WORD pageWidth, pageHeight; /* source "page" size in pixels */
|
||
} BitMapHeader;
|
||
|
||
Fields are filed in the order shown. The UBYTE fields are byte-packed.
|
||
|
||
The fields w and h indicate the size of the image rectangle in pixels.
|
||
Each row of the image is stored in an integral number of 16 bit words.
|
||
The number of words per row is Ceiling(w/16). The fields x and y indicate
|
||
the desired position of this image within the destination picture.
|
||
Some reader programs may ignore x and y. A safe default for writing
|
||
an ILBM is (x, y) = (0, 0).
|
||
|
||
The number of source bitplanes in the BODY chunk (see below) is stored
|
||
in nPlanes. An ILBM with a CMAP but no BODY and nPlanes = 0 is the
|
||
recommended way to store a color map.
|
||
|
||
Note: Color numbers are color map index values formed by pixels in
|
||
the destination bitmap, which may be deeper than nPlanes if a DEST
|
||
chunk calls for merging the image into a deeper image.
|
||
|
||
The field masking indicates what kind of masking is to be used for
|
||
this image. The value mskNone designates an opaque rectangular image.
|
||
The value mskHasMask means that a mask plane is interleaved with the
|
||
bitplanes in the BODY chunk (see below). The value mskHasTransparentColor
|
||
indicates that pixels in the source planes matching transparentColor
|
||
are to be considered "transparent". (Actually, transparentColor isn't
|
||
a "color number" since it's matched with numbers formed by the source
|
||
bitmap rather than the possibly deeper destination bitmap. Note that
|
||
having a transparent color implies ignoring one of the color registers.
|
||
See CMAP, below.) The value mskLasso indicates the reader may construct
|
||
a mask by lassoing the image as in MacPaint*. To do this, put a 1
|
||
pixel border of transparentColor around the image rectangle. Then
|
||
do a seed fill from this border. Filled pixels are to be transparent.
|
||
|
||
Issue: Include in an appendix an algorithm for converting a transparent
|
||
color to a mask plane, and maybe a lasso algorithm.
|
||
|
||
A code indicating the kind of data compression used is stored in compression.
|
||
Beware that using data compression makes your data unreadable by programs
|
||
that don't implement the matching decompression algorithm. So we'll
|
||
employ as few compression encodings as possible. The run encoding
|
||
byteRun1 is documented in Appendix C, below.
|
||
|
||
The field pad1 is a pad byte and must be set to 0 for consistency.
|
||
This field could get used in the future.
|
||
|
||
The transparentColor specifies which bit pattern means "transparent".
|
||
This only applies if masking is mskHasTransparentColor or mskLasso
|
||
(see above). Otherwise, transparentColor should be 0.
|
||
|
||
The pixel aspect ratio is stored as a ratio in the two fields xAspect
|
||
and yAspect. This may be used by programs to compensate for different
|
||
aspects or to help interpret the fields w, h, x, y, pageWidth, and
|
||
pageHeight, which are in units of pixels. The fraction xAspect/yAspect
|
||
represents a pixel's width/height. It's recommended that your programs
|
||
store proper fractions in BitMapHeaders, but aspect ratios can always
|
||
be correctly compared with the the test
|
||
|
||
xAspect%yDesiredAspect = yAspect%xDesiredAspect
|
||
|
||
Typical values for aspect ratio are width : height = 10 : 11 (Amiga
|
||
320 x 200 display) and 1 : 1 (Macintosh*).
|
||
|
||
The size in pixels of the source "page" (any raster device) is stored
|
||
in pageWidth and pageHeight, e.g. (320, 200) for a low resolution
|
||
Amiga display. This information might be used to scale an image or
|
||
to automatically set the display format to suit the image. (The image
|
||
can be larger than the page.)
|
||
|
||
CMAP
|
||
|
||
The optional (but encouraged) property "CMAP" stores color map data
|
||
as triplets of red, green, and blue intensity values. The n color
|
||
map entries ("color registers") are stored in the order 0 through
|
||
n-1, totaling 3n bytes. Thus n is the ckSize/3. Normally, n would
|
||
equal 2nPlanes.
|
||
|
||
A CMAP chunk contains a ColorMap array as defined below. (These typedefs
|
||
assume a C compiler that implements packed arrays of 3-byte elements.)
|
||
|
||
typedef struct {
|
||
UBYTE red, green, blue; /* color intensities 0..255 */
|
||
} ColorRegister; /* size = 3 bytes */
|
||
|
||
typedef ColorRegister ColorMap[n]; /* size = 3n bytes */
|
||
|
||
The color components red, green, and blue represent fractional intensity
|
||
values in the range 0 through 255 256ths. White is (255, 255, 255)
|
||
and black is (0, 0, 0). If your machine has less color resolution,
|
||
use the high order bits. Shift each field right on reading (or left
|
||
on writing) and assign it to (from) a field in a local packed format
|
||
like Color4, below. This achieves automatic conversion of images across
|
||
environments with different color resolutions. On reading an ILBM,
|
||
use defaults if the color map is absent or has fewer color registers
|
||
than you need. Ignore any extra color registers.
|
||
|
||
The example type Color4 represents the format of a color register
|
||
in working memory of an Amiga computer, which has 4 bit video DACs.
|
||
(The ":4" tells the C compiler to pack the field into 4 bits.)
|
||
|
||
typedef struct {
|
||
unsigned pad1 :4, red :4, green :4, blue :4;
|
||
} Color4; /* Amiga RAM format. Not filed. */
|
||
|
||
Remember that every chunk must be padded to an even length, so a color
|
||
map with an odd number of entries would be followed by a 0 byte, not
|
||
included in the ckSize.
|
||
|
||
GRAB
|
||
|
||
The optional property "GRAB" locates a "handle" or "hotspot" of the
|
||
image relative to its upper left corner, e.g. when used as a mouse
|
||
cursor or a "paint brush". A GRAB chunk contains a Point2D.
|
||
|
||
typedef struct {
|
||
WORD x, y; /* relative coordinates (pixels) */
|
||
} Point2D;
|
||
|
||
DEST
|
||
|
||
The optional property "DEST" is a way to say how to scatter zero or
|
||
more source bitplanes into a deeper destination image. Some readers
|
||
may ignore DEST.
|
||
|
||
The contents of a DEST chunk is DestMerge structure:
|
||
|
||
typedef struct {
|
||
UBYTE depth; /* # bitplanes in the original source */
|
||
UBYTE pad1; /* unused; for consistency put 0 here */
|
||
UWORD planePick; /* how to scatter source bitplanes into destination */
|
||
UWORD planeOnOff; /* default bitplane data for planePick */
|
||
UWORD planeMask; /* selects which bitplanes to store into */
|
||
} DestMerge;
|
||
|
||
The low order depth number of bits in planePick, planeOnOff, and planeMask
|
||
correspond one-to-one with destination bitplanes. Bit 0 with bitplane
|
||
0, etc. (Any higher order bits should be ignored.) "1" bits in planePick
|
||
mean "put the next source bitplane into this bitplane", so the number
|
||
of "1" bits should equal nPlanes. "0" bits mean "put the corresponding
|
||
bit from planeOnOff into this bitplane". Bits in planeMask gate writing
|
||
to the destination bitplane: "1" bits mean "write to this bitplane"
|
||
while "0" bits mean "leave this bitplane alone". The normal case (with
|
||
no DEST property) is equivalent to planePick = planeMask = 2nPlanesJ-
|
||
1.
|
||
|
||
Remember that color numbers are formed by pixels in the destination
|
||
bitmap (depth planes deep) not in the source bitmap (nPlanes planes
|
||
deep).
|
||
|
||
SPRT
|
||
|
||
The presence of an "SPRT" chunk indicates that this image is intended
|
||
as a sprite. It's up to the reader program to actually make it a sprite,
|
||
if even possible, and to use or overrule the sprite precedence data
|
||
inside the SPRT chunk:
|
||
|
||
typedef UWORD SpritePrecedence; /* relative precedence, 0 is the highest */
|
||
|
||
Precedence 0 is the highest, denoting a sprite that is foremost.
|
||
|
||
Creating a sprite may imply other setup. E.g. a 2 plane Amiga sprite
|
||
would have transparentColor = 0. Color registers 1, 2, and 3 in the
|
||
CMAP would be stored into the correct hardware color registers for
|
||
the hardware sprite number used, while CMAP color register 0 would
|
||
be ignored.
|
||
|
||
CAMG
|
||
|
||
A "CAMG" chunk is specifically for the Commodore Amiga computer. It
|
||
stores a LONG "viewport mode". This lets you specify Amiga display
|
||
modes like "dual playfield" and "hold and modify".
|
||
3. Standard Data Chunk
|
||
|
||
Raster Layout
|
||
|
||
Raster scan proceeds left-to-right (increasing X) across scan lines,
|
||
then top-to-bottom (increasing Y) down columns of scan lines. The
|
||
coordinate system is in units of pixels, where (0,0) is the upper
|
||
left corner.
|
||
|
||
The raster is typically organized as bitplanes in memory. The corresponding
|
||
bits from each plane, taken together, make up an index into the color
|
||
map which gives a color value for that pixel. The first bitplane,
|
||
plane 0, is the low order bit of these color indexes.
|
||
|
||
A scan line is made of one "row" from each bitplane. A row is one
|
||
planesU bits for one scan line, but padded out to a word (2 byte)
|
||
boundary (not necessarily the first word boundary). Within each row,
|
||
successive bytes are displayed in order and the most significant bit
|
||
of each byte is displayed first.
|
||
|
||
A "mask" is an optional "plane" of data the same size (w, h) as a
|
||
bitplane. It tells how to "cut out" part of the image when painting
|
||
it onto another image."One" bits in the mask mean "copy the corresponding
|
||
pixel to the destination" while "zero" mask bits mean "leave this
|
||
destination pixel alone". In other words, "zero" bits designate transparent
|
||
pixels.
|
||
|
||
The rows of the different bitplanes and mask are interleaved in the
|
||
file (see below). This localizes all the information pertinent to
|
||
each scan line. It makes it much easier to transform the data while
|
||
reading it to adjust the image size or depth. It also makes it possible
|
||
to scroll a big image by swapping rows directly from the file without
|
||
random-accessing to all the bitplanes.
|
||
|
||
BODY
|
||
|
||
The source raster is stored in a "BODY" chunk. This one chunk holds
|
||
all bitplanes and the optional mask, interleaved by row.
|
||
|
||
The BitMapHeader, in a BMHD property chunk, specifies the raster's
|
||
dimensions w, h, and nPlanes. It also holds the masking field which
|
||
indicates if there is a mask plane and the compression field which
|
||
indicates the compression algorithm used. This information is needed
|
||
to interpret the BODY chunk, so the BMHD chunk must appear first.
|
||
While reading an ILBM's BODY, a program may convert the image to another
|
||
size by filling (with transparentColor) or clipping.
|
||
|
||
The BODY's content is a concatenation of scan lines. Each scan line
|
||
is a concatenation of one row of data from each plane in order 0 through
|
||
nPlanes-1 followed by one row from the mask (if masking = hasMask
|
||
). If the BitMapHeader field compression is cmpNone, all h rows are
|
||
exactly Ceiling(w/16) words wide. Otherwise, every row is compressed
|
||
according to the specified algorithm and their stored widths depend
|
||
on the data compression.
|
||
|
||
Reader programs that require fewer bitplanes than appear in a particular
|
||
ILBM file can combine planes or drop the high-order (later) planes.
|
||
Similarly, they may add bitplanes and/or discard the mask plane.
|
||
|
||
Do not compress across rows and don't forget to compress the mask
|
||
just like the bitplanes. Remember to pad any BODY chunk that contains
|
||
an odd number of bytes.
|
||
4. Nonstandard Data Chunk
|
||
|
||
The following data chunk was defined after various programs began
|
||
using FORM ILBM so it's a "nonstandard" chunk. That means there's
|
||
some slight chance of name collisions.
|
||
|
||
CRNG
|
||
|
||
A "CRNG" chunk contains "color register range" information. It's used
|
||
by Electronic Arts' Deluxe Paint program to identify a contiguous
|
||
range of color registers for a "shade range" and color cycling. There
|
||
can be zero or more CRNG chunks in an ILBM, but all should appear
|
||
before the BODY chunk. Deluxe Paint normally writes 4 CRNG chunks
|
||
in an ILBM when the user asks it to "Save Picture".
|
||
|
||
typedef struct {
|
||
WORD pad1; /* reserved for future use; store 0 here */
|
||
WORD rate; /* color cycle rate */
|
||
WORD active; /* nonzero means cycle the colors */
|
||
UBYTE low, high; /* lower and upper color registers selected */
|
||
} CRange;
|
||
|
||
The fields low and high indicate the range of color registers (color
|
||
numbers) selected by this CRange.
|
||
|
||
The field active indicates whether color cycling is on or off. Zero
|
||
means off.
|
||
|
||
The field rate determines the speed at which the colors will step
|
||
when color cycling is on. The units are such that a rate of 60 steps
|
||
per second is represented as 214 = 16384. Slower rates can be obtained
|
||
by linear scaling: for 30 steps/second, rate = 8192; for 1 step/second,
|
||
rate = 16384/60 E 273.
|
||
|
||
CCRT
|
||
|
||
Commodore's Graphicraft program uses a similar chunk "CCRT" (for Color
|
||
Cyling Range and Timing). This chunk contains a CycleInfo structure.
|
||
|
||
typedef struct {
|
||
WORD direction; /* 0 = don't cycle. 1 = cycle forwards (1, 2, 3).
|
||
* -1 = cycle backwards (3, 2, 1) */
|
||
UBYTE start, end; /* lower and upper color registers selected */
|
||
LONG seconds; /* # seconds between changing colors */
|
||
LONG microseconds; /* # microseconds between changing colors */
|
||
WORD pad; /* reserved for future use; store 0 here */
|
||
} CycleInfo;
|
||
|
||
This is pretty similar to a CRNG chunk. A program would probably only
|
||
use one of these two methods of expressing color cycle data. You could
|
||
write out both if you want to communicate this information to both
|
||
Deluxe Paint and Graphicraft.
|
||
|
||
A CCRT chunk expresses the color cycling rate as a number of seconds
|
||
plus a number of microseconds.
|
||
|
||
|
||
|
||
Appendix A. ILBM Regular Expression
|
||
|
||
Here's a regular expression summary of the FORM ILBM syntax. This
|
||
could be an IFF file or a part of one.
|
||
|
||
ILBM ::= "FORM" #{ "ILBM" BMHD [CMAP] [GRAB] [DEST] [SPRT] [CAMG]
|
||
CRNG* CCRT* [BODY] }
|
||
|
||
BMHD ::= "BMHD" #{ BitMapHeader }
|
||
CMAP ::= "CMAP" #{ (red green blue)* } [0]
|
||
GRAB ::= "GRAB" #{ Point2D }
|
||
DEST ::= "DEST" #{ DestMerge }
|
||
SPRT ::= "SPRT" #{ SpritePrecendence }
|
||
CAMG ::= "CAMG" #{ LONG }
|
||
|
||
CRNG ::= "CRNG" #{ CRange }
|
||
CCRT ::= "CCRT" #{ CycleInfo }
|
||
BODY ::= "BODY" #{ UBYTE* } [0]
|
||
|
||
The token "#" represents a ckSize LONG count of the following {braced}
|
||
data bytes. E.g. a BMHD's "#" should equal sizeof(BitMapHeader). Literal
|
||
strings are shown in "quotes", [square bracket items] are optional,
|
||
and "*" means 0 or more repetitions. A sometimes-needed pad byte is
|
||
shown as "[0]".
|
||
|
||
The property chunks (BMHD, CMAP, GRAB, DEST, SPRT, and CAMG) and any
|
||
CRNG and CCRT data chunks may actually be in any order but all must
|
||
appear before the BODY chunk since ILBM readers usually stop as soon
|
||
as they read the BODY. If any of the 6 property chunks are missing,
|
||
default values are "inherited" from any shared properties (if the
|
||
ILBM appears inside an IFF LIST with PROPs) or from the reader program's
|
||
defaults. If any property appears more than once, the last occurrence
|
||
before the BODY is the one that counts since that's the one that modifies
|
||
the BODY.
|
||
|
||
|
||
|
||
Appendix B. ILBM Box Diagram
|
||
|
||
Here's a box diagram for a simple example: an uncompressed image 320
|
||
x 200 pixels x 3 bitplanes. The text to the right of the diagram shows
|
||
the outline that would be printed by the IFFCheck utility program
|
||
for this particular file.
|
||
|
||
|
||
+-----------------------------------+
|
||
|'FORM' 24070 | FORM 24070 IBLM
|
||
+-----------------------------------+
|
||
|'ILBM' |
|
||
+-----------------------------------+
|
||
| +-------------------------------+ |
|
||
| | 'BMHD' 20 | | .BMHD 20
|
||
| | 320, 200, 0, 0, 3, 0, 0, ... | |
|
||
| + ------------------------------+ |
|
||
| | 'CMAP' 21 | | .CMAP 21
|
||
| | 0, 0, 0; 32, 0, 0; 64,0,0; .. | |
|
||
| +-------------------------------+ |
|
||
| 0 |
|
||
+-----------------------------------+
|
||
|'BODY' 24000 | .BODY 24000
|
||
|0, 0, 0, ... |
|
||
+-----------------------------------+
|
||
|
||
|
||
|
||
The "0" after the CMAP chunk is a pad byte.
|
||
|
||
|
||
|
||
Appendix C. ByteRun1 Run Encoding
|
||
|
||
The run encoding scheme byteRun1 is best described by psuedo code
|
||
for the decoder Unpacker (called UnPackBits in the Macintosh* toolbox):
|
||
|
||
UnPacker:
|
||
LOOP until produced the desired number of bytes
|
||
Read the next source byte into n
|
||
SELECT n FROM
|
||
[0..127] => copy the next n+1 bytes literally
|
||
[-1..-127] => replicate the next byte -n+1 times
|
||
-128 => noop
|
||
ENDCASE;
|
||
ENDLOOP;
|
||
|
||
In the inverse routine Packer, it's best to encode a 2 byte repeat
|
||
run as a replicate run except when preceded and followed by a literal
|
||
run, in which case it's best to merge the three into one literal run.
|
||
Always encode 3 byte repeats as replicate runs.
|
||
|
||
Remember that each row of each scan line of a raster is separately
|
||
packed.
|
||
|
||
|
||
|
||
Appendix D. Standards Committee
|
||
|
||
The following people contributed to the design of this FORM ILBM standard:
|
||
|
||
Bob "Kodiak" Burns, Commodore-Amiga
|
||
R. J. Mical, Commodore-Amiga
|
||
Jerry Morrison, Electronic Arts
|
||
Greg Riker, Electronic Arts
|
||
Steve Shaw, Electronic Arts
|
||
Dan Silva, Electronic Arts
|
||
Barry Walsh, Commodore-Amiga
|