• SGI图像文件格式


    介绍

    这是描述SGI图像文件格式的权威文档。这是一个低级规范,描述了 SGI 图像文件的实际字节级格式。在 SGI 机器上,读取和写入 SGI 图像文件的首选方法是使用图像库 -limage。此库提供了一组函数,使读取和写入 SGI 图像变得容易。如果您使用的是 SGI 工作站,您可以通过以下方式获取有关 -limage 的信息:

    % man 4 rgb
    

    关于 SGI 图像文件中值的字节顺序的说明

    在下面的描述中,像 bits[7..0] 这样的表示法用于表示二进制值中的位范围。位 0 是值中的最低位。

    所有短值均由 2 个字节表示。第一个字节存储高阶 8 位的值:bits[15..8]。第二个字节存储值的低阶 8 位:bits[7..0]。

    因此,此函数将从文件中读取一个短值:

        unsigned short getshort(inf)
        FILE *inf;
        {
    	unsigned char buf[2];
    
    	fread(buf,2,1,inf);
    	return (buf[0]<<8)+(buf[1]<<0);
        }
    

    所有长值都由 4 个字节表示。第一个字节存储高阶 8 位的值:bits[31..24]。第二个字节存储位[23..16]。第三个字节存储位[15..8]。第四个字节存储值的低阶 8 位:bits[7..0]。

    此函数将从文件中读取一个长值:

        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);
        }
    

    SGI 图像文件的一般结构

    标头指示图像是否为运行长度编码 (RLE)。

    如果图像未进行运行长度编码,则结构如下:

     	The Header
     	The Image Data
    

    如果图像是运行长度编码的,则结构如下:

     	The Header
     	The Offset Tables
     	The Image Data
    

    页眉

    标头包含以下内容:

            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
    

    以下是图像文件头中每个字段的说明:

    魔术 - 这是保存为短整型的十进制值 474。这会将文件标识为 SGI 映像文件。

    存储 - 指定是否使用运行长度编码 (RLE) 或不使用 (逐字) 存储图像。如果使用 RLE,则此字节的值将为 1。否则,此字节的值将为 0。此字段唯一允许的值为 0 或 1。

    BPC - 描述用于存储图像的每个通道的精度。这是每个像素分量的字节数。大多数 SGI 图像文件使用每像素 1 个字节的分量,给出 256 个级别。某些 SGI 映像文件每个组件使用 2 个字节。此字段唯一允许的值为 1 或 2。

    维度 - 描述存储在图像文件中的数据中的维度数。唯一允许的值为 1、2 或 3。如果此值为 1,则图像文件仅包含 1 个通道和 1 条扫描线(行)。此扫描线的长度由下面的 XSIZE 值给出。如果此值为 2,则文件由具有多个扫描线的单个通道组成。图像的宽度和高度由下面的 XSIZE 和 YSIZE 值给出。如果此值为 3,则文件由多个通道组成。图像的宽度和高度由下面的 XSIZE 和 YSIZE 值给出。通道数由下面的 ZSIZE 值给出。

    XSIZE - 图像的宽度(以像素为单位)

    YSIZE - 图像的高度(以像素为单位)

    ZSIZE - 图像中的通道数。黑白(灰度)图像存储为 ZSIZE 或 1 的二维图像。RGB 彩色图像存储为 ZSIZE 为 3 的三维图像。具有 ALPHA 通道的 RGB 图像存储为 ZSIZE 为 4 的三维图像。SGI图像文件格式并无固有限制,无法创建超过4个通道的图像文件。

    PINMIN - 图像中的最小像素值。如果没有像素的值小于 0,则可以使用 0 的值。

    PINMAX - 图像中的最大像素值。如果没有像素的值大于 255,则可以使用 255 的值。这是图像中被视为全亮度的值。

    虚拟 - 这 4 个字节的数据应设置为 0。

    图像名称 - 此处可能包含以空结尾的 ASCII 字符串,该字符串最多包含 79 个字符,以空结尾。这不常用。

    颜色映射表 - 这控制应如何解释文件中的像素值。它可以具有以下四个值之一:

    0:正常 - 通道中的数据表示具有 1 个通道的图像的黑白值、具有 3 个通道的图像的 RGB 值和具有 4 个通道的图像的 RGBA 值。几乎所有的SGI图像文件都是这种类型的。

    1:抖动 - 图像将只有 1 个数据通道。对于每个像素,RGB 数据被打包到一个 8 位值中。3 位用于红色和绿色,而蓝色使用 2 位。红色数据以位[2..0]为单位,绿色数据以位[5..3]为单位,蓝色数据以位[7..6]为单位。此格式已过时。

    2:屏幕 - 图像将只有 1 个数据通道。此格式用于存储颜色索引像素。要将像素值转换为 RGB 值,必须使用颜色图。适当的颜色映射因图像而异。此格式已过时。

    3:颜色图 - 图像用于存储来自SGI机器的色彩映射。在这种情况下,图像在传统意义上不可显示。

    虚拟 - 此 404 字节的数据应设置为 0。这使得标头正好为 512 字节。

    图像数据(如果不是 RLE)

    如果图像是逐字存储的(没有 RLE),则图像数据直接跟在 512 字节标头之后。首先写入第一个通道的每个扫描线的数据。如果映像具有 1 个以上的通道,则写入第一个通道的所有数据,然后写入其余通道。如果 BPC 值为 1,则每个扫描线都写入为 XSIZE 字节。如果 BPC 值为 2,则每条扫描线都写为 XSIZE 短裤。这些短裤按上述字节顺序存储。

    偏移表(如果是 RLE)

    如果使用运行长度编码存储图像,则偏移表跟在标题后面,该标头描述了每个扫描线的文件偏移量对 RLE 的偏移量。仅当上述存储的值为 1 时,此信息才适用。

             Size  | Type   | Name      | Description   
    
      tablen longs | long   | STARTTAB  | Start table
      tablen longs | long   | LENGTHTAB | Length table
    

    RLE 数据的每个扫描行都需要每个表中的一个条目。图像(表n)中的扫描线总数由YSIZE和ZSIZE的乘积决定。写了两个长头表。每个都由表长的数据组成。第一个表具有图像中每条扫描线的 RLE 数据的文件偏移量。在具有 1 个以上通道(ZSIZE > 1)的文件中,此表首先包含第一个通道中扫描线的所有偏移量,然后是第二个通道中扫描线的偏移量,依此类推。第二个表包含图像中每条扫描线的 RLE 数据长度。在具有 1 个以上通道(ZSIZE > 1)的文件中,此表首先包含第一个通道中扫描线的所有 RLE 数据长度,然后是第二个通道中扫描线的 RLE 数据长度,依此类推。

    要查找文件偏移量以及特定扫描线的 RLE 数据中的字节数,可以按如下方式读取这两个数组并编制索引:

    要在表格中阅读:

        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);
    

    要查找扫描线的文件偏移量和 RLE 数据长度:

    rowno 是 0 到 YSIZE-1 范围内的整数 channo 是 0 到 ZSIZE-1 范围内的整数

        rleoffset = starttab[rowno+channo*YSIZE]
        rlelength = lengthtab[rowno+channo*YSIZE]
    

    两个相同的行(扫描线)可以共享压缩数据。可以将完全白色的图像写入单个压缩行,并使所有表条目都指向该行。另一个应该有效的小技巧是,如果您正在写出RGB RLE文件,并且特定的扫描线是消色差的(灰度),则可以使r,g和b行指向相同的数据!

    图像数据(如果是 RLE)

    仅当上述存储的值为 1 时,此信息才适用。如果使用运行长度编码存储图像,则图像数据遵循上面的偏移表。RLE 数据不按任何特定顺序排列。上面的偏移表用于定位任何扫描线的 rle 数据。

    必须按以下方式从文件中读入 RLE 数据并将其扩展为像素数据:

    如果 BPC 为 1,则每个像素有一个字节。在这种情况下,应将 RLE 数据读入字符数组。为了扩展数据,第一个字节的低阶七位:bits[6..0]用于形成计数。如果第一个字节的高阶位为 1: bit[7],则计数用于指定要从 RLE 数据缓冲区复制到目标的字节数。否则,如果第一个字节的高阶位为 0: bit[7],则计数用于指定在目标中重复下一个字节的值的次数。此过程一直持续到找到计数 0。这应该完全解压缩 XSIZE 像素。

    以下是解压缩扫描线的示例代码:

        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++;
    	    } else {
    		pixel = *iptr++;
    		while(count--) 
    		    *optr++ = pixel;
    	    }
    	}
        }
    

    如果 BPC 为 2,则每个像素有一个短(2 个字节)。在这种情况下,RLE 数据应读入短路数组。为了扩展数据,使用第一个短:bits[6..0]的低阶七位来形成计数。如果第一个短路的 bit[7] 为 1,则计数用于指定要从 RLE 数据缓冲区复制到目标的短路数。否则,如果第一个短裤的 bit[7] 为 0,则计数用于指定在目标中重复下一个短指令的值的次数。此过程将继续,直到找到计数 0。这应该完全解压缩 XSIZE 像素。请注意,应使用输入文件中短数据的字节顺序,如上所述。

    实施说明

    对于 BPC 为 1 的图像,需要同时实现 RLE 和 VERBATIM 格式,因为绝大多数 SGI 图像都是这种格式。鼓励支持具有 2 BPC 的图像。

    如果图像的 ZSIZE 为 1,则假定它表示黑白值。如果 ZSIZE 为 3,则假定它表示 RGB 数据,如果 ZSIZE 为 4,则假定它包含带有 alpha 的 RGB 数据。

    所有SGI图像的原点都是左下角。第一条扫描线(第 0 行)始终是图像的底行。

    命名约定

    在 SGI 系统上,如果 SGI 图像文件是黑白图像,则以扩展名 .bw 结尾,如果包含 RGB 图像数据,则以 .rgb 结尾,如果是带有 alpha 通道的 RGB 图像,则以 .rgba 结尾。

    有时也会使用.sgi扩展名。

    一个例子

    此程序将写出有效的黑白SGI映像文件:

    1. #include "stdio.h"
    2. #define IXSIZE (23)
    3. #define IYSIZE (15)
    4. putbyte(outf,val)
    5. FILE *outf;
    6. unsigned char val;
    7. {
    8. unsigned char buf[1];
    9. buf[0] = val;
    10. fwrite(buf,1,1,outf);
    11. }
    12. putshort(outf,val)
    13. FILE *outf;
    14. unsigned short val;
    15. {
    16. unsigned char buf[2];
    17. buf[0] = (val>>8);
    18. buf[1] = (val>>0);
    19. fwrite(buf,2,1,outf);
    20. }
    21. static int putlong(outf,val)
    22. FILE *outf;
    23. unsigned long val;
    24. {
    25. unsigned char buf[4];
    26. buf[0] = (val>>24);
    27. buf[1] = (val>>16);
    28. buf[2] = (val>>8);
    29. buf[3] = (val>>0);
    30. return fwrite(buf,4,1,outf);
    31. }
    32. main()
    33. {
    34. FILE *of;
    35. char iname[80];
    36. unsigned char outbuf[IXSIZE];
    37. int i, x, y;
    38. of = fopen("example.rgb","w");
    39. if(!of) {
    40. fprintf(stderr,"sgiimage: can't open output file\n");
    41. exit(1);
    42. }
    43. putshort(of,474); /* MAGIC */
    44. putbyte(of,0); /* STORAGE is VERBATIM */
    45. putbyte(of,1); /* BPC is 1 */
    46. putshort(of,2); /* DIMENSION is 2 */
    47. putshort(of,IXSIZE); /* XSIZE */
    48. putshort(of,IYSIZE); /* YSIZE */
    49. putshort(of,1); /* ZSIZE */
    50. putlong(of,0); /* PIXMIN is 0 */
    51. putlong(of,255); /* PIXMAX is 255 */
    52. for(i=0; i<4; i++) /* DUMMY 4 bytes */
    53. putbyte(of,0);
    54. strcpy(iname,"No Name");
    55. fwrite(iname,80,1,of); /* IMAGENAME */
    56. putlong(of,0); /* COLORMAP is 0 */
    57. for(i=0; i<404; i++) /* DUMMY 404 bytes */
    58. putbyte(of,0);
    59. for(y=0; y<IYSIZE; y++) {
    60. for(x=0; x<IXSIZE; x++)
    61. outbuf[x] = (255*x)/(IXSIZE-1);
    62. fwrite(outbuf,IXSIZE,1,of);
    63. }
    64. fclose(of);
    65. }
      
    
  • 相关阅读:
    Java版企业电子招标采购系统源码—企业战略布局下的采购寻源
    C++模板编程与泛型编程之函数模板
    TypeScript基础类型(day2)
    Matlab 如何把频谱图的纵坐标设置为分贝刻度
    【双目视觉】 立体匹配算法原理之“代价空间与聚合、视差计算”
    【Java】学习日记 Day21
    C++入门知识
    Mysql设置open_files_limit
    【SpringMVC】Controller中映射方法的参数解析过程
    ▲ Android 签到打卡效果
  • 原文地址:https://blog.csdn.net/whl0071/article/details/127773548