]> git.imager.perl.org - imager.git/commitdiff
various bits and pieces of documentation
authorTony Cook <tony@develop=help.com>
Sat, 12 May 2007 05:19:27 +0000 (05:19 +0000)
committerTony Cook <tony@develop=help.com>
Sat, 12 May 2007 05:19:27 +0000 (05:19 +0000)
announce/0.57.txt [new file with mode: 0644]
fileformatdocs/SGIIMAGESPEC.txt [new file with mode: 0644]
fileformatdocs/sgiimage-1.00.html [new file with mode: 0644]

diff --git a/announce/0.57.txt b/announce/0.57.txt
new file mode 100644 (file)
index 0000000..adc205c
--- /dev/null
@@ -0,0 +1,9 @@
+<p>Imager 0.57 is a security fix release.</p>
+
+<p>After following up on a <a
+href="http://www.securityfocus.com/archive/1/archive/1/464726/100/0/threaded">buqtraq
+message</a> describing BMP issues in some viewers I <a href="https://rt.cpan.org/Public/Bug/Display.html?id=26107">decided to test Imager</a> against the test images.</p>
+
+<p>Unfortunately Imager failed on some of the test images.</p>
+
+<p>Imager 0.57 corrects this.</p>
diff --git a/fileformatdocs/SGIIMAGESPEC.txt b/fileformatdocs/SGIIMAGESPEC.txt
new file mode 100644 (file)
index 0000000..4782f1f
--- /dev/null
@@ -0,0 +1,417 @@
+
+For Version 1.00 of this spec see:
+
+http://reality.sgi.com/grafica/sgiimage.html
+
+
+
+                           Draft version  0.97
+                       The SGI Image File Format
+                            Paul Haeberli
+                             paul@sgi.com
+                   Silicon Graphics Computer Systems
+ 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
+     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);
+           }
+ 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 or 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 or 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 (row).  The length of this scanline is given by the 
+       value of XSIZE below.  If this value is 2, the file consists of a 
+       single channel with a number of scanlines. 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 (greyscale) 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), then image data directly
+     follows the 512 byte header.  The data for each scanline of the first
+     channel is written first.  If the image has more than 1 channel, all
+     the data for the first channel is written, followed by the remaining
+     channels.  If the BPC value is 1, then each scanline 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 scanline 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 scanline 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 scanline 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]
+     
+     It is possible for two identical rows (scanlines) to share compressed 
+     data.  A completely white image could be written as a single compressed 
+     row and having all table entries point to that row.  Another little hack 
+     that should work is if you are writing out a RGB RLE file, and a 
+     particular scanline is achromatic (greyscale), you could just make the 
+     r, g and b rows point to the same data!!
+ 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
+     the input file should be used, 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.
+     The origin for all SGI images is the lower left hand corner.  The
+     first scanline (row 0) is always the bottom row of the image.   
+ 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);
+}
diff --git a/fileformatdocs/sgiimage-1.00.html b/fileformatdocs/sgiimage-1.00.html
new file mode 100644 (file)
index 0000000..c26094a
--- /dev/null
@@ -0,0 +1,417 @@
+<html><head><title>SGI Image File Format Specification</title></head><body bgcolor="#ffffff">\r
+<font face="Helvetica, Arial, sans-serif" size="-1">\r
+</font><center>\r
+<h3><font face="Helvetica, Arial, sans-serif" size="-1">The SGI Image File Format</font></h3>\r
+<p>\r
+<font face="Helvetica, Arial, sans-serif" size="-1">Version 1.00\r
+</font></p><p>\r
+<font face="Helvetica, Arial, sans-serif" size="-1">Paul Haeberli<br>\r
+Silicon Graphics Computer Systems<br>\r
+paulhaeberli@yahoo.com<br>\r
+</font></p></center>\r
+<h3><font face="Helvetica, Arial, sans-serif" size="-1">Introduction</font></h3>\r
+<p>\r
+<font face="Helvetica, Arial, sans-serif" size="-1">This is the definitive document describing the SGI image file format.  This \r
+is a low level spec that describes the actual byte level format of SGI image\r
+files.  On SGI machines the preferred way of reading and writing SGI image\r
+files is to use the image library -limage.  This library provides a set\r
+of functions that make it easy to read and write SGI images.  If you are \r
+on an SGI workstation you can get info on -limage by doing:\r
+</font></p><blockquote><pre><font face="Helvetica, Arial, sans-serif" size="-1">% man 4 rgb\r
+</font></pre></blockquote>\r
+<h3><font face="Helvetica, Arial, sans-serif" size="-1">A note on byte order of values in the SGI image files</font></h3>\r
+<p>\r
+<font face="Helvetica, Arial, sans-serif" size="-1">In the following description a notation like bits[7..0] is used to denote\r
+a range of bits in a binary value.   Bit 0 is the lowest order bit in\r
+the value.\r
+</font></p><p>\r
+<font face="Helvetica, Arial, sans-serif" size="-1">All short values are represented by 2 bytes.  The first byte stores the\r
+high order 8 bits of the value: bits[15..8].  The second byte stores\r
+the low order 8 bits of the value: bits[7..0].  \r
+</font></p><p>\r
+<font face="Helvetica, Arial, sans-serif" size="-1">So this function will read a short value from the file:\r
+</font></p><pre><font face="Helvetica, Arial, sans-serif" size="-1">    unsigned short getshort(inf)\r
+    FILE *inf;\r
+    {\r
+       unsigned char buf[2];\r
+\r
+       fread(buf,2,1,inf);\r
+       return (buf[0]&lt;&lt;8)+(buf[1]&lt;&lt;0);\r
+    }\r
+</font></pre>\r
+<p>\r
+<font face="Helvetica, Arial, sans-serif" size="-1">All long values are represented by 4 bytes.  The first byte stores the\r
+high order 8 bits of the value: bits[31..24].  The second byte stores\r
+bits[23..16].  The third byte stores bits[15..8]. The forth byte stores\r
+the low order 8 bits of the value: bits[7..0].  \r
+</font></p><p>\r
+<font face="Helvetica, Arial, sans-serif" size="-1">And this function will read a long value from the file:\r
+</font></p><pre><font face="Helvetica, Arial, sans-serif" size="-1">    static long getlong(inf)\r
+    FILE *inf;\r
+    {\r
+       unsigned char buf[4];\r
+\r
+       fread(buf,4,1,inf);\r
+       return (buf[0]&lt;&lt;24)+(buf[1]&lt;&lt;16)+(buf[2]&lt;&lt;8)+(buf[3]&lt;&lt;0);\r
+    }\r
+</font></pre>\r
+<font face="Helvetica, Arial, sans-serif" size="-1"> \r
+</font><p>\r
+</p><h3><font face="Helvetica, Arial, sans-serif" size="-1">The general structure of an SGI image file</font></h3>\r
+<font face="Helvetica, Arial, sans-serif" size="-1">     The header indicates whether the image is run length encoded (RLE).\r
+</font><p>\r
+<font face="Helvetica, Arial, sans-serif" size="-1">     If the image is not run length encoded, this is the structure:\r
+</font></p><blockquote>\r
+<font face="Helvetica, Arial, sans-serif" size="-1">   The Header<br>\r
+       The Image Data\r
+</font></blockquote>\r
+<font face="Helvetica, Arial, sans-serif" size="-1"> \r
+     If the image is run length encoded, this is the structure:\r
+</font><blockquote>\r
+<font face="Helvetica, Arial, sans-serif" size="-1">   The Header<br>\r
+       The Offset Tables<br>\r
+       The Image Data\r
+</font></blockquote>\r
+<font face="Helvetica, Arial, sans-serif" size="-1"> \r
+</font><h3><font face="Helvetica, Arial, sans-serif" size="-1">The Header</font></h3>\r
+<p>\r
+<font face="Helvetica, Arial, sans-serif" size="-1">The header consists of the following:\r
+</font></p><pre><font face="Helvetica, Arial, sans-serif" size="-1">        Size  | Type   | Name      | Description   \r
\r
+      2 bytes | short  | MAGIC     | IRIS image file magic number\r
+      1 byte  | char   | STORAGE   | Storage format\r
+      1 byte  | char   | BPC       | Number of bytes per pixel channel \r
+      2 bytes | ushort | DIMENSION | Number of dimensions\r
+      2 bytes | ushort | XSIZE     | X size in pixels \r
+      2 bytes | ushort | YSIZE     | Y size in pixels \r
+      2 bytes | ushort | ZSIZE     | Number of channels\r
+      4 bytes | long   | PIXMIN    | Minimum pixel value\r
+      4 bytes | long   | PIXMAX    | Maximum pixel value\r
+      4 bytes | char   | DUMMY     | Ignored\r
+     80 bytes | char   | IMAGENAME | Image name\r
+      4 bytes | long   | COLORMAP  | Colormap ID\r
+    404 bytes | char   | DUMMY     | Ignored\r
+</font></pre>\r
+<blockquote>\r
+<p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
+Here is a description of each field in the image file header:\r
+</font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
+       MAGIC - This is the decimal value 474 saved as a short. This\r
+       identifies the file as an SGI image file.\r
+</font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
+       STORAGE - specifies whether the image is stored using run\r
+       length encoding (RLE) or not (VERBATIM).   If RLE is used, the value \r
+        of this byte will be 1.  Otherwise the value of this byte will be 0.\r
+       The only allowed values for this field are 0 or 1.\r
+</font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
+       BPC - describes the precision that is used to store each\r
+       channel of an image.  This is the number of bytes per pixel\r
+       component.  The majority of SGI image files use 1 byte per \r
+       pixel component, giving 256 levels.  Some SGI image files use \r
+       2 bytes per component.  The only allowed values for this field \r
+       are 1 or 2.\r
\r
+</font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
+       DIMENSION - described the number of dimensions in the data stored\r
+       in the image file.  The only allowed values are 1, 2, or 3.  If\r
+       this value is 1, the image file consists of only 1 channel and \r
+       only 1 scanline (row).  The length of this scanline is given by the \r
+       value of XSIZE below.  If this value is 2, the file consists of a \r
+       single channel with a number of scanlines. The width and height\r
+       of the image are given by the values of XSIZE and YSIZE below.\r
+       If this value is 3, the file consists of a number of channels.\r
+       The width and height of the image are given by the values of \r
+       XSIZE and YSIZE below.  The number of channels is given by the \r
+       value of ZSIZE below.  \r
+</font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
+       XSIZE - The width of the image in pixels\r
+</font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
\r
+       YSIZE - The height of the image in pixels\r
+</font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
\r
+       ZSIZE - The number of channels in the image.  B/W (greyscale) images \r
+       are stored as 2 dimensional images with a ZSIZE or 1.  RGB color \r
+       images are stored as 3 dimensional images with a ZSIZE of 3.  An RGB \r
+       image with an ALPHA channel is stored as a 3 dimensional image with \r
+       a ZSIZE of 4.  There are no inherent limitations in the SGI image \r
+       file format that would preclude the creation of image files with more \r
+       than 4 channels.\r
\r
+</font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
+       PINMIN - The minimum pixel value in the image.  The value of\r
+       0 may be used if no pixel has a value that is smaller than 0.\r
+</font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
\r
+       PINMAX - The maximum pixel value in the image.  The value of\r
+       255 may be used if no pixel has a value that is greater than 255.\r
+       This is the value that is considered to be full brightness in \r
+       the image.  \r
\r
+</font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
+       DUMMY - This 4 bytes of data should be set to 0. \r
+</font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
\r
+       IMAGENAME - An null terminated ascii string of up to 79 characters \r
+       terminated by a null may be included here.  This is not commonly\r
+       used.\r
\r
+</font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
+       COLORMAP - This controls how the pixel values in the file should be\r
+       interpreted.  It can have one of these four values:\r
\r
+</font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
+           0:  NORMAL - The data in the channels represent B/W values\r
+               for images with 1 channel, RGB values for images with 3\r
+               channels, and RGBA values for images with 4 channels.\r
+               Almost all the SGI image files are of this type. \r
\r
+</font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
+           1:  DITHERED - The image will have only 1 channel of data.\r
+               For each pixel, RGB data is packed into one 8 bit value.\r
+               3 bits are used for red and green, while blue uses 2 bits.\r
+               Red data is found in bits[2..0], green data in bits[5..3],\r
+               and blue data in bits[7..6].  This format is obsolete.\r
\r
+</font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
+           2:  SCREEN - The image will have only 1 channel of data.\r
+               This format was used to store color-indexed pixels.\r
+               To convert the pixel values into RGB values a colormap\r
+               must be used.  The appropriate color map varies from\r
+               image to image.  This format is obsolete.\r
\r
+</font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
+           3:  COLORMAP - The image is used to store a color map from\r
+               an SGI machine.  In this case the image is not displayable\r
+               in the conventional sense.\r
\r
+</font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
+       DUMMY - This 404 bytes of data should be set to 0. This makes the\r
+       header exactly 512 bytes. \r
+</font></p></blockquote>\r
+<font face="Helvetica, Arial, sans-serif" size="-1"> \r
+</font><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
+</font></p><h3><font face="Helvetica, Arial, sans-serif" size="-1">The Image Data (if not RLE)</font></h3>\r
+<p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
+     If the image is stored verbatim (without RLE), then image data directly\r
+     follows the 512 byte header.  The data for each scanline of the first\r
+     channel is written first.  If the image has more than 1 channel, all\r
+     the data for the first channel is written, followed by the remaining\r
+     channels.  If the BPC value is 1, then each scanline is written as XSIZE\r
+     bytes.  If the BPC value is 2, then each scanline is written as XSIZE \r
+     shorts.  These shorts are stored in the byte order described above.\r
+</font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
+</font></p><h3><font face="Helvetica, Arial, sans-serif" size="-1">The Offset Tables (if RLE)</font></h3>\r
+<p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
+     If the image is stored using run length encoding, offset tables\r
+     follow the header that describe what the file offsets are to the \r
+     RLE for each scanline.  This information only applies if the value \r
+     for STORAGE above is 1.\r
+</font></p><pre><font face="Helvetica, Arial, sans-serif" size="-1">         Size  | Type   | Name      | Description   \r
+\r
+  tablen longs | long   | STARTTAB  | Start table\r
+  tablen longs | long   | LENGTHTAB | Length table\r
+</font></pre><font face="Helvetica, Arial, sans-serif" size="-1"> \r
+</font><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
+     One entry in each table is needed for each scanline of RLE data.  The \r
+     total number of scanlines in the image (tablen) is determined by the\r
+     product of the YSIZE and ZSIZE.  There are two tables of longs that \r
+     are written. Each consists of tablen longs of data.  The first\r
+     table has the file offsets to the RLE data for each scanline in the\r
+     image.  In a file with more than 1 channel (ZSIZE &gt; 1) this table first \r
+     has all the offsets for the scanlines in the first channel, followed\r
+     be offsets for the scanlines in the second channel, etc.  The second \r
+     table has the RLE data length for each scanline in the image.  In a \r
+     file with more than 1 channel (ZSIZE &gt; 1) this table first has all the \r
+     RLE data lengths for the scanlines in the first channel, followed\r
+     be RLE data lengths for the scanlines in the second channel, etc.\r
\r
+</font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
+     To find the the file offset, and the number of bytes in the RLE data \r
+     for a particular scanline, these two arrays may be read in and indexed as\r
+     follows: \r
\r
+</font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
+       To read in the tables:\r
+</font></p><pre><font face="Helvetica, Arial, sans-serif" size="-1">    unsigned long *starttab, *lengthtab;\r
+\r
+    tablen = YSIZE*ZSIZE*sizeof(long);\r
+    starttab = (unsigned long *)mymalloc(tablen);\r
+    lengthtab = (unsigned long *)mymalloc(tablen);\r
+    fseek(inf,512,SEEK_SET);\r
+    readlongtab(inf,starttab);\r
+    readlongtab(ing,lengthtab);\r
+</font></pre><font face="Helvetica, Arial, sans-serif" size="-1"> \r
+\r
+</font><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
+       To find the file offset and RLE data length for a scanline:\r
+</font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
+           rowno is an integer in the range 0 to YSIZE-1\r
+           channo is an integer in the range 0 to ZSIZE-1\r
+</font></p><pre><font face="Helvetica, Arial, sans-serif" size="-1">    rleoffset = starttab[rowno+channo*YSIZE]\r
+    rlelength = lengthtab[rowno+channo*YSIZE]\r
+</font></pre>\r
+<p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
+     It is possible for two identical rows (scanlines) to share compressed \r
+     data.  A completely white image could be written as a single compressed \r
+     row and having all table entries point to that row.  Another little hack \r
+     that should work is if you are writing out a RGB RLE file, and a \r
+     particular scanline is achromatic (greyscale), you could just make the \r
+     r, g and b rows point to the same data!!\r
+</font></p><h3><font face="Helvetica, Arial, sans-serif" size="-1">The Image Data (if RLE)</font></h3>\r
+<p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
+     This information only applies if the value for STORAGE above is 1.  If\r
+     the image is stored using run length encoding, the image data follows\r
+     the offset tables above.  The RLE data is not in any particular order.\r
+     The offset tables above are used to locate the rle data for any scanline.\r
+</font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
+     The RLE data must be read in from the file and expanded into pixel \r
+     data in the following manner:\r
+</font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
+     If BPC is 1, then there is one byte per pixel.  In this case the \r
+     RLE data should be read into an array of chars.  To expand\r
+     data, the low order seven bits of the first byte: bits[6..0]\r
+     are used to form a count.  If the high order bit of the first\r
+     byte is 1: bit[7], then the count is used to specify how many\r
+     bytes to copy from the RLE data buffer to the destination.\r
+     Otherwise, if the high order bit of the first byte is 0: bit[7],\r
+     then the count is used to specify how many times to repeat the \r
+     value of the following byte, in the destination.  This process\r
+     continues until a count of 0 is found.  This should decompress\r
+     exactly XSIZE pixels.  \r
+</font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
+       Here is example code to decompress a scanline:\r
+</font></p><pre><font face="Helvetica, Arial, sans-serif" size="-1">    expandrow(optr,iptr,z)\r
+    unsigned char *optr, *iptr;\r
+    int z;\r
+    {\r
+       unsigned char pixel, count;\r
+    \r
+       optr += z;\r
+       while(1) {\r
+           pixel = *iptr++;\r
+           if ( !(count = (pixel &amp; 0x7f)) )\r
+               return;\r
+           if(pixel &amp; 0x80) {\r
+               while(count--) \r
+                   *optr++ = *iptr++;\r
+           } else {\r
+               pixel = *iptr++;\r
+               while(count--) \r
+                   *optr++ = pixel;\r
+           }\r
+       }\r
+    }\r
+</font></pre><font face="Helvetica, Arial, sans-serif" size="-1"> \r
+</font><p>\r
+<font face="Helvetica, Arial, sans-serif" size="-1">     If BPC is 2, there is one short (2 bytes) per pixel.  In this \r
+     case the RLE data should be read into an array of shorts.  To \r
+     expand data, the low order seven bits of the first short: bits[6..0]\r
+     are used to form a count.  If bit[7] of the first short is 1, then \r
+     the count is used to specify how many shorts to copy from the RLE \r
+     data buffer to the destination.  Otherwise, if bit[7] of the first \r
+     short is 0, then the count is used to specify how many times to \r
+     repeat the value of the following short, in the destination.  This \r
+     process proceeds until a count of 0 is found.  This should decompress\r
+     exactly XSIZE pixels.  Note that the byte order of short data in\r
+     the input file should be used, as described above.\r
+</font></p><h3><font face="Helvetica, Arial, sans-serif" size="-1">Implementation notes</font></h3>\r
+<p>\r
+<font face="Helvetica, Arial, sans-serif" size="-1">     Implementation of both RLE and VERBATIM format for images with\r
+     BPC of 1 is required since the great majority of SGI images are in\r
+     this format.  Support for images with a 2 BPC is encouraged.\r
+</font></p><p>\r
+<font face="Helvetica, Arial, sans-serif" size="-1">     If the ZSIZE of an image is 1, it is assumed to represent B/W\r
+     values.  If the ZSIZE is 3, it is assumed to represent RGB data,\r
+     and if ZSIZE is 4, it is assumed to contain RGB data with alpha.\r
+</font></p><p>\r
+<font face="Helvetica, Arial, sans-serif" size="-1">     The origin for all SGI images is the lower left hand corner.  The\r
+     first scanline (row 0) is always the bottom row of the image.   \r
+</font></p><h3><font face="Helvetica, Arial, sans-serif" size="-1">Naming Conventions</font></h3>\r
+<p>\r
+<font face="Helvetica, Arial, sans-serif" size="-1">     On SGI systems, SGI image files end with the extension .bw if\r
+     they are B/W images, they end in .rgb if they contain RGB image\r
+     data, and end in .rgba if they are RGB images with alpha channel.\r
+</font></p><p>\r
+<font face="Helvetica, Arial, sans-serif" size="-1">     Sometimes the .sgi extension is used as well.\r
+</font></p><h3><font face="Helvetica, Arial, sans-serif" size="-1">An example</font></h3>\r
+<p>\r
+<font face="Helvetica, Arial, sans-serif" size="-1">This program will write out a valid B/W SGI image file:\r
+</font></p><pre><font face="Helvetica, Arial, sans-serif" size="-1">    #include "stdio.h"\r
+     \r
+    #define IXSIZE      (23)\r
+    #define IYSIZE      (15)\r
+     \r
+    putbyte(outf,val)\r
+    FILE *outf;\r
+    unsigned char val;\r
+    {\r
+       unsigned char buf[1];\r
+     \r
+       buf[0] = val;\r
+       fwrite(buf,1,1,outf);\r
+    }\r
+     \r
+    putshort(outf,val)\r
+    FILE *outf;\r
+    unsigned short val;\r
+    {\r
+       unsigned char buf[2];\r
+     \r
+       buf[0] = (val&gt;&gt;8);\r
+       buf[1] = (val&gt;&gt;0);\r
+       fwrite(buf,2,1,outf);\r
+    }\r
+     \r
+    static int putlong(outf,val)\r
+    FILE *outf;\r
+    unsigned long val;\r
+    {\r
+       unsigned char buf[4];\r
+     \r
+       buf[0] = (val&gt;&gt;24);\r
+       buf[1] = (val&gt;&gt;16);\r
+       buf[2] = (val&gt;&gt;8);\r
+       buf[3] = (val&gt;&gt;0);\r
+       return fwrite(buf,4,1,outf);\r
+    }\r
+     \r
+    main()\r
+    {\r
+       FILE *of;\r
+       char iname[80];\r
+       unsigned char outbuf[IXSIZE];\r
+       int i, x, y;\r
+     \r
+       of = fopen("example.rgb","w");\r
+       if(!of) {\r
+           fprintf(stderr,"sgiimage: can't open output file\n");\r
+           exit(1);\r
+       }\r
+       putshort(of,474);       /* MAGIC               */\r
+       putbyte(of,0);          /* STORAGE is VERBATIM */\r
+       putbyte(of,1);          /* BPC is 1            */\r
+       putshort(of,2);         /* DIMENSION is 2      */\r
+       putshort(of,IXSIZE);    /* XSIZE               */\r
+       putshort(of,IYSIZE);    /* YSIZE               */\r
+       putshort(of,1);         /* ZSIZE               */\r
+       putlong(of,0);          /* PIXMIN is 0         */\r
+       putlong(of,255);        /* PIXMAX is 255       */\r
+       for(i=0; i&lt;4; i++)      /* DUMMY 4 bytes       */\r
+           putbyte(of,0);\r
+       strcpy(iname,"No Name");\r
+       fwrite(iname,80,1,of);  /* IMAGENAME           */\r
+       putlong(of,0);          /* COLORMAP is 0       */\r
+       for(i=0; i&lt;404; i++)    /* DUMMY 404 bytes     */\r
+           putbyte(of,0);\r
+     \r
+       for(y=0; y&lt;IYSIZE; y++) {\r
+           for(x=0; x&lt;IXSIZE; x++) \r
+            outbuf[x] = (255*x)/(IXSIZE-1);\r
+           fwrite(outbuf,IXSIZE,1,of);\r
+       }\r
+       fclose(of);\r
+    }\r
+</font></pre>\r
+\r
+</body></html>
\ No newline at end of file