我是靠谱客的博主 暴躁金毛,最近开发中收集的这篇文章主要介绍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映像文件:

  #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 filen");
	    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);
    }
  

最后

以上就是暴躁金毛为你收集整理的SGI图像文件格式的全部内容,希望文章能够帮你解决SGI图像文件格式所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(42)

评论列表共有 0 条评论

立即
投稿
返回
顶部