Steve Baker (sbaker++at++link.com)
Tue, 5 May 1998 07:39:05 -0500 (CDT)
> Does anyone know the exact format of a RGBA file? By this
> i mean both what ancillary information is written (e.g.,
> interleaved, sequential, separate) and how the RGBA values
> are written (e.g., 0-255, 0-1.0, other).
>
> A code snippet or a pointer to useful docs would be greatly
> appreciated!!!
Here you go ... everything you ever need to know.
==============================================================
The SGI Image File Format.
Draft version 0.9
Paul Haeberli (paul++at++sgi.com) Silicon Graphics Computer Systems
INTRODUCTION.
This is the definitive document describing the SGI image file format. This is a low level spec that
describes the actual byte level format of SGI image files. On SGI machines the preferred way of
reading and writing SGI image files is to use the image library -limage. This library provides a set
of functions that make it easy to read and write SGI images. If you are on an SGI workstation you
can get info on -limage by doing:
% man 4 rgb
A note on byte order of values in the SGI image files
In the following description a notation like bits[7..0] is used to denote a range of bits in a binary
value. Bit 0 is the lowest order bit in a the value.
All short values are represented by 2 bytes. The first byte stores the high order 8 bits of the value:
bits[15..8]. The second byte stores the low order 8 bits of the value: bits[7..0].
So, this function will read a short value from the file:
unsigned short getshort(inf)
FILE *inf;
{
unsigned char buf[2];
fread(buf,2,1,inf);
return (buf[0]<<8)+(buf[1]<<0);
}
All long values are represented by 4 bytes. The first byte stores the high order 8 bits of the value:
bits[31..24]. The second byte stores bits[23..16]. The third byte stores bits[15..8]. The forth byte
stores the low order 8 bits of the value: bits[7..0].
So, this function will read a long value from the file:
static long getlong(inf)
FILE *inf;
{
unsigned char buf[4];
fread(buf,4,1,inf);
return (buf[0]<<24)+(buf[1]<<16)+(buf[2]<<8)+(buf[3]<<0);
}
GENERAL STRUCTURE
The general structure of an SGI image file is as shown below:
The header indicates whether the image is run length encoded (RLE).
If the image is not run length encoded, this is the structure:
The Header
The Image Data
If the image is run length encoded, this is the structure:
The Header
The Offset Tables
The Image Data
The Header
The header consists of the following:
Size | Type | Name | Description
2 bytes | short | MAGIC | IRIS image file magic number
1 byte | char | STORAGE | Storage format
1 byte | char | BPC | Number of bytes per pixel channel
2 bytes | ushort | DIMENSION | Number of dimensions
2 bytes | ushort | XSIZE | X size in pixels
2 bytes | ushort | YSIZE | Y size in pixels
2 bytes | ushort | ZSIZE | Number of channels
4 bytes | long | PIXMIN | Minimum pixel value
4 bytes | long | PIXMAX | Maximum pixel value
4 bytes | char | DUMMY | Ignored
80 bytes | char | IMAGENAME | Image name
4 bytes | long | COLORMAP | Colormap ID
404 bytes | char | DUMMY | Ignored
Here is a description of each field in the image file header:
MAGIC - This is the decimal value 474 saved as a short. This identifies the file as an SGI
image file.
STORAGE - specifies whether the image is stored using run length encoding (RLE) or not
(VERBATIM). If RLE is used, the value of this byte will be 1. Otherwise the value of this
byte will be 0. The only allowed values for this field are 0 and 1.
BPC - describes the precision that is used to store each channel of an image. This is the
number of bytes per pixel component. The majority of SGI image files use 1 byte per pixel
component, giving 256 levels. Some SGI image files use 2 bytes per component. The only
allowed values for this field are 1 and 2.
DIMENSION - described the number of dimensions in the data stored in the image file. The
only allowed values are 1, 2, or 3. If this value is 1, the image file consists of only 1 channel
and only 1 scanline. The length of this scan line is given by the value of XSIZE below. If this
value is 2, the file consists of a single channel with a number of scan lines. The width and
height of the image are given by the values of XSIZE and YSIZE below. If this value is 3,
the file consists of a number of channels. The width and height of the image are given by the
values of XSIZE and YSIZE below. The number of channels is given by the value of ZSIZE
below.
XSIZE - The width of the image in pixels
YSIZE - The height of the image in pixels
ZSIZE - The number of channels in the image. B/W images are stored as 2 dimensional
images with a ZSIZE or 1. RGB color images are stored as 3 dimensional images with a
ZSIZE of 3. An RGB image with an ALPHA channel is stored as a 3 dimensional image
with a ZSIZE of 4. There are no inherent limitations in the SGI image file format that would
preclude the creation of image files with more than 4 channels.
PINMIN - The minimum pixel value in the image. The value of 0 may be used if no pixel
has a value that is smaller than 0.
PINMAX - The maximum pixel value in the image. The value of 255 may be used if no
pixel has a value that is greater than 255. This is the value that is considered to be full
brightness in the image.
DUMMY - This 4 bytes of data should be set to 0.
IMAGENAME - An null terminated ascii string of up to 79 characters terminated by a null
may be included here. This is not commonly used.
COLORMAP - This controls how the pixel values in the file should be interpreted. It can
have one of these four values:
0: NORMAL - The data in the channels represent B/W values for images with 1
channel, RGB values for images with 3 channels, and RGBA values for images with 4
channels. Almost all the SGI image files are of this type.
1: DITHERED - The image will have only 1 channel of data. For each pixel, RGB
data is packed into one 8 bit value. 3 bits are used for red and green, while blue uses 2
bits. Red data is found in bits[2..0], green data in bits[5..3], and blue data in bits[7..6].
This format is obsolete.
2: SCREEN - The image will have only 1 channel of data. This format was used to
store color-indexed pixels. To convert the pixel values into RGB values a colormap
must be used. The appropriate color map varies from image to image. This format is
obsolete.
3: COLORMAP - The image is used to store a color map from an SGI machine. In
this case the image is not displayable in the conventional sense.
DUMMY - This 404 bytes of data should be set to 0. This makes the header exactly 512
bytes.
The Image Data (if not RLE)
If the image is stored verbatim (without RLE), the image data directly follows the 512 byte header.
The data for each scanline in the first channel is written first. If the image has more than 1 channel
the remaining channels follow the first channel in numerical order. If the BPC value is 1, then each
scan line is written as XSIZE bytes. If the BPC value is 2, then each scanline is written as XSIZE
shorts. These shorts are stored in the byte order described above.
The Offset Tables (if RLE)
If the image is stored using run length encoding, offset tables follow the header that describe what
the file offsets are to the RLE for each scanline. This information only applies if the value for
STORAGE above is 1.
Size | Type | Name | Description
tablen longs | long | STARTTAB | Start table
tablen longs | long | LENGTHTAB | Length table
One entry in each table is needed for each scan line of RLE data. The total number of scanlines in
the image (tablen) is determined by the product of the YSIZE and ZSIZE. There are two tables of
longs that are written. Each consists of tablen longs of data. The first table has the file offsets to
the RLE data for each scan line in the image. In a file with more than 1 channel (ZSIZE > 1) this
table first has all the offsets for the scanlines in the first channel, followed be offsets for the
scanlines in the second channel, etc. The second table has the RLE data length for each scan line in
the image. In a file with more than 1 channel (ZSIZE > 1) this table first has all the RLE data
lengths for the scanlines in the first channel, followed be RLE data lengths for the scanlines in the
second channel, etc.
To find the the file offset, and the number of bytes in the RLE data for a particular scanline, these
two arrays may be read in and indexed as follows:
To read in the tables:
unsigned long *starttab, *lengthtab;
tablen = ysize*zsize*sizeof(long);
starttab = (unsigned long *)mymalloc(tablen);
lengthtab = (unsigned long *)mymalloc(tablen);
fseek(inf,512,SEEK_SET);
readlongtab(inf,starttab);
readlongtab(ing,lengthtab);
To find the file offset and RLE data length for a scanline:
rowno is an integer in the range 0 to YSIZE-1
channo is an integer in the range 0 to ZSIZE-1
rleoffset = starttab[rowno+channo*YSIZE]
rlelength = lengthtab[rowno+channo*YSIZE]
The Image Data (if RLE)
This information only applies if the value for STORAGE above is 1. If the image is stored using
run length encoding, the image data follows the offset tables above. The RLE data is not in any
particular order. The offset tables above are used to locate the rle data for any scanline.
The RLE data must be read in from the file and expanded into pixel data in the following manner:
If BPC is 1, then there is one byte per pixel. In this case the RLE data should be read into an array
of chars. To expand data, the low order seven bits of the first byte: bits[6..0] are used to form a
count. If the high order bit of the first byte is 1: bit[7], then the count is used to specify how many
bytes to copy from the RLE data buffer to the destination. Otherwise, if the high order bit of the
first byte is 0: bit[7], then the count is used to specify how many times to repeat the value of the
following byte, in the destination. This process continues until a count of 0 is found. This should
decompress exactly XSIZE pixels.
Here is example code to decompress a scanline:
expandrow(optr,iptr,z)
unsigned char *optr, *iptr;
int z;
{
unsigned char pixel, count;
optr += z;
while(1) {
pixel = *iptr++;
if ( !(count = (pixel & 0x7f)) )
return;
if(pixel & 0x80) {
while(count--) {
*optr = *iptr++;
optr+=4;
}
} else {
pixel = *iptr++;
while(count--) {
*optr = pixel;
optr+=4;
}
}
}
}
If BPC is 2, there is one short (2 bytes) per pixel. In this case the RLE data should be read into an
array of shorts. To expand data, the low order seven bits of the first short: bits[6..0] are used to
form a count. If bit[7] of the first short is 1, then the count is used to specify how many shorts to
copy from the RLE data buffer to the destination. Otherwise, if bit[7] of the first short is 0, then
the count is used to specify how many times to repeat the value of the following short, in the
destination. This process proceeds until a count of 0 is found. This should decompress exactly
XSIZE pixels. Note that the byte order of short data in on the input file should be observed, as
described above.
Implementation notes
Implementation of both RLE and VERBATIM format for images with BPC of 1 is required since
the great majority of SGI images are in this format. Support for images with a 2 BPC is
encouraged.
If the ZSIZE of an image is 1, it is assumed to represent B/W values. If the ZSIZE is 3, it is
assumed to represent RGB data, and if ZSIZE is 4, it is assumed to contain RGB data with alpha.
Naming Conventions
On SGI systems, SGI image files end with the extension .bw if they are B/W images, they end in
.rgb if they contain RGB image data, and end in .rgba if they are RGB images with alpha channel.
Sometimes the .sgi extension is used as well.
An example: This program will write out a valid B/W SGI image file:
#include "stdio.h"
#define IXSIZE (23)
#define IYSIZE (15)
putbyte(outf,val)
FILE *outf;
unsigned char val;
{
unsigned char buf[1];
buf[0] = val;
fwrite(buf,1,1,outf);
}
putshort(outf,val)
FILE *outf;
unsigned short val;
{
unsigned char buf[2];
buf[0] = (val>>8);
buf[1] = (val>>0);
fwrite(buf,2,1,outf);
}
static int putlong(outf,val)
FILE *outf;
unsigned long val;
{
unsigned char buf[4];
buf[0] = (val>>24);
buf[1] = (val>>16);
buf[2] = (val>>8);
buf[3] = (val>>0);
return fwrite(buf,4,1,outf);
}
main()
{
FILE *of;
char iname[80];
unsigned char outbuf[IXSIZE];
int i, x, y;
of = fopen("example.rgb","w");
if(!of) {
fprintf(stderr,"sgiimage: can't open output file\n");
exit(1);
}
putshort(of,474); /* MAGIC */
putbyte(of,0); /* STORAGE is VERBATIM */
putbyte(of,1); /* BPC is 1 */
putshort(of,2); /* DIMENSION is 2 */
putshort(of,IXSIZE); /* XSIZE */
putshort(of,IYSIZE); /* YSIZE */
putshort(of,1); /* ZSIZE */
putlong(of,0); /* PIXMIN is 0 */
putlong(of,255); /* PIXMAX is 255 */
for(i=0; i<4; i++) /* DUMMY 4 bytes */
putbyte(of,0);
strcpy(iname,"No Name");
fwrite(iname,80,1,of); /* IMAGENAME */
putlong(of,0); /* COLORMAP is 0 */
for(i=0; i<404; i++) /* DUMMY 404 bytes */
putbyte(of,0);
for(y=0; y < IYSIZE; y++) {
for(x=0; x < IXSIZE; x++)
outbuf[x] = (255*x)/(IXSIZE-1);
fwrite(outbuf,IXSIZE,1,of);
}
fclose(of);
}
========================================================================
Steve Baker (817)619-8776 (Vox/Vox-Mail)
Raytheon Systems Inc. (817)619-4028 (Fax)
Work: SBaker++at++link.com http://www.hti.com
Home: SJBaker1++at++airmail.net http://web2.airmail.net/sjbaker1
=======================================================================
List Archives, FAQ, FTP: http://www.sgi.com/Technology/Performer/
Submissions: info-performer++at++sgi.com
Admin. requests: info-performer-request++at++sgi.com
This archive was generated by hypermail 2.0b2 on Mon Aug 10 1998 - 17:57:22 PDT