various bits and pieces of documentation
[imager.git] / fileformatdocs / sgiimage-1.00.html
1 <html><head><title>SGI Image File Format Specification</title></head><body bgcolor="#ffffff">\r
2 <font face="Helvetica, Arial, sans-serif" size="-1">\r
3 </font><center>\r
4 <h3><font face="Helvetica, Arial, sans-serif" size="-1">The SGI Image File Format</font></h3>\r
5 <p>\r
6 <font face="Helvetica, Arial, sans-serif" size="-1">Version 1.00\r
7 </font></p><p>\r
8 <font face="Helvetica, Arial, sans-serif" size="-1">Paul Haeberli<br>\r
9 Silicon Graphics Computer Systems<br>\r
11 </font></p></center>\r
12 <h3><font face="Helvetica, Arial, sans-serif" size="-1">Introduction</font></h3>\r
13 <p>\r
14 <font face="Helvetica, Arial, sans-serif" size="-1">This is the definitive document describing the SGI image file format.  This \r
15 is a low level spec that describes the actual byte level format of SGI image\r
16 files.  On SGI machines the preferred way of reading and writing SGI image\r
17 files is to use the image library -limage.  This library provides a set\r
18 of functions that make it easy to read and write SGI images.  If you are \r
19 on an SGI workstation you can get info on -limage by doing:\r
20 </font></p><blockquote><pre><font face="Helvetica, Arial, sans-serif" size="-1">% man 4 rgb\r
21 </font></pre></blockquote>\r
22 <h3><font face="Helvetica, Arial, sans-serif" size="-1">A note on byte order of values in the SGI image files</font></h3>\r
23 <p>\r
24 <font face="Helvetica, Arial, sans-serif" size="-1">In the following description a notation like bits[7..0] is used to denote\r
25 a range of bits in a binary value.   Bit 0 is the lowest order bit in\r
26 the value.\r
27 </font></p><p>\r
28 <font face="Helvetica, Arial, sans-serif" size="-1">All short values are represented by 2 bytes.  The first byte stores the\r
29 high order 8 bits of the value: bits[15..8].  The second byte stores\r
30 the low order 8 bits of the value: bits[7..0].  \r
31 </font></p><p>\r
32 <font face="Helvetica, Arial, sans-serif" size="-1">So this function will read a short value from the file:\r
33 </font></p><pre><font face="Helvetica, Arial, sans-serif" size="-1">    unsigned short getshort(inf)\r
34     FILE *inf;\r
35     {\r
36         unsigned char buf[2];\r
37 \r
38         fread(buf,2,1,inf);\r
39         return (buf[0]&lt;&lt;8)+(buf[1]&lt;&lt;0);\r
40     }\r
41 </font></pre>\r
42 <p>\r
43 <font face="Helvetica, Arial, sans-serif" size="-1">All long values are represented by 4 bytes.  The first byte stores the\r
44 high order 8 bits of the value: bits[31..24].  The second byte stores\r
45 bits[23..16].  The third byte stores bits[15..8]. The forth byte stores\r
46 the low order 8 bits of the value: bits[7..0].  \r
47 </font></p><p>\r
48 <font face="Helvetica, Arial, sans-serif" size="-1">And this function will read a long value from the file:\r
49 </font></p><pre><font face="Helvetica, Arial, sans-serif" size="-1">    static long getlong(inf)\r
50     FILE *inf;\r
51     {\r
52         unsigned char buf[4];\r
53 \r
54         fread(buf,4,1,inf);\r
55         return (buf[0]&lt;&lt;24)+(buf[1]&lt;&lt;16)+(buf[2]&lt;&lt;8)+(buf[3]&lt;&lt;0);\r
56     }\r
57 </font></pre>\r
58 <font face="Helvetica, Arial, sans-serif" size="-1"> \r
59 </font><p>\r
60 </p><h3><font face="Helvetica, Arial, sans-serif" size="-1">The general structure of an SGI image file</font></h3>\r
61 <font face="Helvetica, Arial, sans-serif" size="-1">     The header indicates whether the image is run length encoded (RLE).\r
62 </font><p>\r
63 <font face="Helvetica, Arial, sans-serif" size="-1">     If the image is not run length encoded, this is the structure:\r
64 </font></p><blockquote>\r
65 <font face="Helvetica, Arial, sans-serif" size="-1">    The Header<br>\r
66         The Image Data\r
67 </font></blockquote>\r
68 <font face="Helvetica, Arial, sans-serif" size="-1"> \r
69      If the image is run length encoded, this is the structure:\r
70 </font><blockquote>\r
71 <font face="Helvetica, Arial, sans-serif" size="-1">    The Header<br>\r
72         The Offset Tables<br>\r
73         The Image Data\r
74 </font></blockquote>\r
75 <font face="Helvetica, Arial, sans-serif" size="-1"> \r
76 </font><h3><font face="Helvetica, Arial, sans-serif" size="-1">The Header</font></h3>\r
77 <p>\r
78 <font face="Helvetica, Arial, sans-serif" size="-1">The header consists of the following:\r
79 </font></p><pre><font face="Helvetica, Arial, sans-serif" size="-1">        Size  | Type   | Name      | Description   \r
80  \r
81       2 bytes | short  | MAGIC     | IRIS image file magic number\r
82       1 byte  | char   | STORAGE   | Storage format\r
83       1 byte  | char   | BPC       | Number of bytes per pixel channel \r
84       2 bytes | ushort | DIMENSION | Number of dimensions\r
85       2 bytes | ushort | XSIZE     | X size in pixels \r
86       2 bytes | ushort | YSIZE     | Y size in pixels \r
87       2 bytes | ushort | ZSIZE     | Number of channels\r
88       4 bytes | long   | PIXMIN    | Minimum pixel value\r
89       4 bytes | long   | PIXMAX    | Maximum pixel value\r
90       4 bytes | char   | DUMMY     | Ignored\r
91      80 bytes | char   | IMAGENAME | Image name\r
92       4 bytes | long   | COLORMAP  | Colormap ID\r
93     404 bytes | char   | DUMMY     | Ignored\r
94 </font></pre>\r
95 <blockquote>\r
96 <p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
97 Here is a description of each field in the image file header:\r
98 </font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
99         MAGIC - This is the decimal value 474 saved as a short. This\r
100         identifies the file as an SGI image file.\r
101 </font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
102         STORAGE - specifies whether the image is stored using run\r
103         length encoding (RLE) or not (VERBATIM).   If RLE is used, the value \r
104         of this byte will be 1.  Otherwise the value of this byte will be 0.\r
105         The only allowed values for this field are 0 or 1.\r
106 </font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
107         BPC - describes the precision that is used to store each\r
108         channel of an image.  This is the number of bytes per pixel\r
109         component.  The majority of SGI image files use 1 byte per \r
110         pixel component, giving 256 levels.  Some SGI image files use \r
111         2 bytes per component.  The only allowed values for this field \r
112         are 1 or 2.\r
113  \r
114 </font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
115         DIMENSION - described the number of dimensions in the data stored\r
116         in the image file.  The only allowed values are 1, 2, or 3.  If\r
117         this value is 1, the image file consists of only 1 channel and \r
118         only 1 scanline (row).  The length of this scanline is given by the \r
119         value of XSIZE below.  If this value is 2, the file consists of a \r
120         single channel with a number of scanlines. The width and height\r
121         of the image are given by the values of XSIZE and YSIZE below.\r
122         If this value is 3, the file consists of a number of channels.\r
123         The width and height of the image are given by the values of \r
124         XSIZE and YSIZE below.  The number of channels is given by the \r
125         value of ZSIZE below.  \r
126 </font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
127         XSIZE - The width of the image in pixels\r
128 </font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
129  \r
130         YSIZE - The height of the image in pixels\r
131 </font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
132  \r
133         ZSIZE - The number of channels in the image.  B/W (greyscale) images \r
134         are stored as 2 dimensional images with a ZSIZE or 1.  RGB color \r
135         images are stored as 3 dimensional images with a ZSIZE of 3.  An RGB \r
136         image with an ALPHA channel is stored as a 3 dimensional image with \r
137         a ZSIZE of 4.  There are no inherent limitations in the SGI image \r
138         file format that would preclude the creation of image files with more \r
139         than 4 channels.\r
140  \r
141 </font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
142         PINMIN - The minimum pixel value in the image.  The value of\r
143         0 may be used if no pixel has a value that is smaller than 0.\r
144 </font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
145  \r
146         PINMAX - The maximum pixel value in the image.  The value of\r
147         255 may be used if no pixel has a value that is greater than 255.\r
148         This is the value that is considered to be full brightness in \r
149         the image.  \r
150  \r
151 </font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
152         DUMMY - This 4 bytes of data should be set to 0. \r
153 </font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
154  \r
155         IMAGENAME - An null terminated ascii string of up to 79 characters \r
156         terminated by a null may be included here.  This is not commonly\r
157         used.\r
158  \r
159 </font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
160         COLORMAP - This controls how the pixel values in the file should be\r
161         interpreted.  It can have one of these four values:\r
162  \r
163 </font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
164             0:  NORMAL - The data in the channels represent B/W values\r
165                 for images with 1 channel, RGB values for images with 3\r
166                 channels, and RGBA values for images with 4 channels.\r
167                 Almost all the SGI image files are of this type. \r
168  \r
169 </font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
170             1:  DITHERED - The image will have only 1 channel of data.\r
171                 For each pixel, RGB data is packed into one 8 bit value.\r
172                 3 bits are used for red and green, while blue uses 2 bits.\r
173                 Red data is found in bits[2..0], green data in bits[5..3],\r
174                 and blue data in bits[7..6].  This format is obsolete.\r
175  \r
176 </font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
177             2:  SCREEN - The image will have only 1 channel of data.\r
178                 This format was used to store color-indexed pixels.\r
179                 To convert the pixel values into RGB values a colormap\r
180                 must be used.  The appropriate color map varies from\r
181                 image to image.  This format is obsolete.\r
182  \r
183 </font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
184             3:  COLORMAP - The image is used to store a color map from\r
185                 an SGI machine.  In this case the image is not displayable\r
186                 in the conventional sense.\r
187  \r
188 </font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
189         DUMMY - This 404 bytes of data should be set to 0. This makes the\r
190         header exactly 512 bytes. \r
191 </font></p></blockquote>\r
192 <font face="Helvetica, Arial, sans-serif" size="-1"> \r
193 </font><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
194 </font></p><h3><font face="Helvetica, Arial, sans-serif" size="-1">The Image Data (if not RLE)</font></h3>\r
195 <p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
196      If the image is stored verbatim (without RLE), then image data directly\r
197      follows the 512 byte header.  The data for each scanline of the first\r
198      channel is written first.  If the image has more than 1 channel, all\r
199      the data for the first channel is written, followed by the remaining\r
200      channels.  If the BPC value is 1, then each scanline is written as XSIZE\r
201      bytes.  If the BPC value is 2, then each scanline is written as XSIZE \r
202      shorts.  These shorts are stored in the byte order described above.\r
203 </font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
204 </font></p><h3><font face="Helvetica, Arial, sans-serif" size="-1">The Offset Tables (if RLE)</font></h3>\r
205 <p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
206      If the image is stored using run length encoding, offset tables\r
207      follow the header that describe what the file offsets are to the \r
208      RLE for each scanline.  This information only applies if the value \r
209      for STORAGE above is 1.\r
210 </font></p><pre><font face="Helvetica, Arial, sans-serif" size="-1">         Size  | Type   | Name      | Description   \r
211 \r
212   tablen longs | long   | STARTTAB  | Start table\r
213   tablen longs | long   | LENGTHTAB | Length table\r
214 </font></pre><font face="Helvetica, Arial, sans-serif" size="-1"> \r
215 </font><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
216      One entry in each table is needed for each scanline of RLE data.  The \r
217      total number of scanlines in the image (tablen) is determined by the\r
218      product of the YSIZE and ZSIZE.  There are two tables of longs that \r
219      are written. Each consists of tablen longs of data.  The first\r
220      table has the file offsets to the RLE data for each scanline in the\r
221      image.  In a file with more than 1 channel (ZSIZE &gt; 1) this table first \r
222      has all the offsets for the scanlines in the first channel, followed\r
223      be offsets for the scanlines in the second channel, etc.  The second \r
224      table has the RLE data length for each scanline in the image.  In a \r
225      file with more than 1 channel (ZSIZE &gt; 1) this table first has all the \r
226      RLE data lengths for the scanlines in the first channel, followed\r
227      be RLE data lengths for the scanlines in the second channel, etc.\r
228  \r
229 </font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
230      To find the the file offset, and the number of bytes in the RLE data \r
231      for a particular scanline, these two arrays may be read in and indexed as\r
232      follows: \r
233  \r
234 </font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
235         To read in the tables:\r
236 </font></p><pre><font face="Helvetica, Arial, sans-serif" size="-1">    unsigned long *starttab, *lengthtab;\r
237 \r
238     tablen = YSIZE*ZSIZE*sizeof(long);\r
239     starttab = (unsigned long *)mymalloc(tablen);\r
240     lengthtab = (unsigned long *)mymalloc(tablen);\r
241     fseek(inf,512,SEEK_SET);\r
242     readlongtab(inf,starttab);\r
243     readlongtab(ing,lengthtab);\r
244 </font></pre><font face="Helvetica, Arial, sans-serif" size="-1"> \r
245 \r
246 </font><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
247         To find the file offset and RLE data length for a scanline:\r
248 </font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
249             rowno is an integer in the range 0 to YSIZE-1\r
250             channo is an integer in the range 0 to ZSIZE-1\r
251 </font></p><pre><font face="Helvetica, Arial, sans-serif" size="-1">    rleoffset = starttab[rowno+channo*YSIZE]\r
252     rlelength = lengthtab[rowno+channo*YSIZE]\r
253 </font></pre>\r
254 <p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
255      It is possible for two identical rows (scanlines) to share compressed \r
256      data.  A completely white image could be written as a single compressed \r
257      row and having all table entries point to that row.  Another little hack \r
258      that should work is if you are writing out a RGB RLE file, and a \r
259      particular scanline is achromatic (greyscale), you could just make the \r
260      r, g and b rows point to the same data!!\r
261 </font></p><h3><font face="Helvetica, Arial, sans-serif" size="-1">The Image Data (if RLE)</font></h3>\r
262 <p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
263      This information only applies if the value for STORAGE above is 1.  If\r
264      the image is stored using run length encoding, the image data follows\r
265      the offset tables above.  The RLE data is not in any particular order.\r
266      The offset tables above are used to locate the rle data for any scanline.\r
267 </font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
268      The RLE data must be read in from the file and expanded into pixel \r
269      data in the following manner:\r
270 </font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
271      If BPC is 1, then there is one byte per pixel.  In this case the \r
272      RLE data should be read into an array of chars.  To expand\r
273      data, the low order seven bits of the first byte: bits[6..0]\r
274      are used to form a count.  If the high order bit of the first\r
275      byte is 1: bit[7], then the count is used to specify how many\r
276      bytes to copy from the RLE data buffer to the destination.\r
277      Otherwise, if the high order bit of the first byte is 0: bit[7],\r
278      then the count is used to specify how many times to repeat the \r
279      value of the following byte, in the destination.  This process\r
280      continues until a count of 0 is found.  This should decompress\r
281      exactly XSIZE pixels.  \r
282 </font></p><p><font face="Helvetica, Arial, sans-serif" size="-1"> \r
283         Here is example code to decompress a scanline:\r
284 </font></p><pre><font face="Helvetica, Arial, sans-serif" size="-1">    expandrow(optr,iptr,z)\r
285     unsigned char *optr, *iptr;\r
286     int z;\r
287     {\r
288         unsigned char pixel, count;\r
289     \r
290         optr += z;\r
291         while(1) {\r
292             pixel = *iptr++;\r
293             if ( !(count = (pixel &amp; 0x7f)) )\r
294                 return;\r
295             if(pixel &amp; 0x80) {\r
296                 while(count--) \r
297                     *optr++ = *iptr++;\r
298             } else {\r
299                 pixel = *iptr++;\r
300                 while(count--) \r
301                     *optr++ = pixel;\r
302             }\r
303         }\r
304     }\r
305 </font></pre><font face="Helvetica, Arial, sans-serif" size="-1"> \r
306 </font><p>\r
307 <font face="Helvetica, Arial, sans-serif" size="-1">     If BPC is 2, there is one short (2 bytes) per pixel.  In this \r
308      case the RLE data should be read into an array of shorts.  To \r
309      expand data, the low order seven bits of the first short: bits[6..0]\r
310      are used to form a count.  If bit[7] of the first short is 1, then \r
311      the count is used to specify how many shorts to copy from the RLE \r
312      data buffer to the destination.  Otherwise, if bit[7] of the first \r
313      short is 0, then the count is used to specify how many times to \r
314      repeat the value of the following short, in the destination.  This \r
315      process proceeds until a count of 0 is found.  This should decompress\r
316      exactly XSIZE pixels.  Note that the byte order of short data in\r
317      the input file should be used, as described above.\r
318 </font></p><h3><font face="Helvetica, Arial, sans-serif" size="-1">Implementation notes</font></h3>\r
319 <p>\r
320 <font face="Helvetica, Arial, sans-serif" size="-1">     Implementation of both RLE and VERBATIM format for images with\r
321      BPC of 1 is required since the great majority of SGI images are in\r
322      this format.  Support for images with a 2 BPC is encouraged.\r
323 </font></p><p>\r
324 <font face="Helvetica, Arial, sans-serif" size="-1">     If the ZSIZE of an image is 1, it is assumed to represent B/W\r
325      values.  If the ZSIZE is 3, it is assumed to represent RGB data,\r
326      and if ZSIZE is 4, it is assumed to contain RGB data with alpha.\r
327 </font></p><p>\r
328 <font face="Helvetica, Arial, sans-serif" size="-1">     The origin for all SGI images is the lower left hand corner.  The\r
329      first scanline (row 0) is always the bottom row of the image.   \r
330 </font></p><h3><font face="Helvetica, Arial, sans-serif" size="-1">Naming Conventions</font></h3>\r
331 <p>\r
332 <font face="Helvetica, Arial, sans-serif" size="-1">     On SGI systems, SGI image files end with the extension .bw if\r
333      they are B/W images, they end in .rgb if they contain RGB image\r
334      data, and end in .rgba if they are RGB images with alpha channel.\r
335 </font></p><p>\r
336 <font face="Helvetica, Arial, sans-serif" size="-1">     Sometimes the .sgi extension is used as well.\r
337 </font></p><h3><font face="Helvetica, Arial, sans-serif" size="-1">An example</font></h3>\r
338 <p>\r
339 <font face="Helvetica, Arial, sans-serif" size="-1">This program will write out a valid B/W SGI image file:\r
340 </font></p><pre><font face="Helvetica, Arial, sans-serif" size="-1">    #include "stdio.h"\r
341      \r
342     #define IXSIZE      (23)\r
343     #define IYSIZE      (15)\r
344      \r
345     putbyte(outf,val)\r
346     FILE *outf;\r
347     unsigned char val;\r
348     {\r
349         unsigned char buf[1];\r
350      \r
351         buf[0] = val;\r
352         fwrite(buf,1,1,outf);\r
353     }\r
354      \r
355     putshort(outf,val)\r
356     FILE *outf;\r
357     unsigned short val;\r
358     {\r
359         unsigned char buf[2];\r
360      \r
361         buf[0] = (val&gt;&gt;8);\r
362         buf[1] = (val&gt;&gt;0);\r
363         fwrite(buf,2,1,outf);\r
364     }\r
365      \r
366     static int putlong(outf,val)\r
367     FILE *outf;\r
368     unsigned long val;\r
369     {\r
370         unsigned char buf[4];\r
371      \r
372         buf[0] = (val&gt;&gt;24);\r
373         buf[1] = (val&gt;&gt;16);\r
374         buf[2] = (val&gt;&gt;8);\r
375         buf[3] = (val&gt;&gt;0);\r
376         return fwrite(buf,4,1,outf);\r
377     }\r
378      \r
379     main()\r
380     {\r
381         FILE *of;\r
382         char iname[80];\r
383         unsigned char outbuf[IXSIZE];\r
384         int i, x, y;\r
385      \r
386         of = fopen("example.rgb","w");\r
387         if(!of) {\r
388             fprintf(stderr,"sgiimage: can't open output file\n");\r
389             exit(1);\r
390         }\r
391         putshort(of,474);       /* MAGIC               */\r
392         putbyte(of,0);          /* STORAGE is VERBATIM */\r
393         putbyte(of,1);          /* BPC is 1            */\r
394         putshort(of,2);         /* DIMENSION is 2      */\r
395         putshort(of,IXSIZE);    /* XSIZE               */\r
396         putshort(of,IYSIZE);    /* YSIZE               */\r
397         putshort(of,1);         /* ZSIZE               */\r
398         putlong(of,0);          /* PIXMIN is 0         */\r
399         putlong(of,255);        /* PIXMAX is 255       */\r
400         for(i=0; i&lt;4; i++)      /* DUMMY 4 bytes       */\r
401             putbyte(of,0);\r
402         strcpy(iname,"No Name");\r
403         fwrite(iname,80,1,of);  /* IMAGENAME           */\r
404         putlong(of,0);          /* COLORMAP is 0       */\r
405         for(i=0; i&lt;404; i++)    /* DUMMY 404 bytes     */\r
406             putbyte(of,0);\r
407      \r
408         for(y=0; y&lt;IYSIZE; y++) {\r
409             for(x=0; x&lt;IXSIZE; x++) \r
410             outbuf[x] = (255*x)/(IXSIZE-1);\r
411             fwrite(outbuf,IXSIZE,1,of);\r
412         }\r
413         fclose(of);\r
414     }\r
415 </font></pre>\r
416 \r
417 </body></html>