IMG格式详解
Img to Tif API下载:
Please Read detail info document with imagine file format at:http://home.gdal.org/projects/imagine/hfa_index.html
基本结构和基本对象
IMG文件的存储格式是HFA树,全称是Hierarchal File Format(层级文件结构),貌似是Erdas自己搞出来的东西……
总体来说,IMG文件是由头文件、节点存储结构和一系列节点组成,其中每个节点都有自己的头文件和存储的信息。
基本结构图:
Header 是整个文件的头文件,包括两部分内容,一个是Ehfa_HeaderTag,存储在文件最开头的地方,结构如下:
Ehfa_HeaderTag { char [16] label; //对象名,就是EHFA_HEADER_TAG long headerPtr; //对象Ehfa_File的位置 } |
另一个是Ehfa_File,开始位置可从上边的headerPtr 里读取,不过一般都是跟在Ehfa_HeaderTag 的后边,结构如下:
Ehfa_File { long version; //版本号,通常是1 long freelist; //不知道是神马 long rootEntryPtr; //根节点的位置 short entryHeaderLength; //每一个节点头文件的长度 long dictionaryPtr; //节点存储结构列表的位置 } |
通过这个对象里的信息,可以取得根节点和节点存储结构列表的位置。
节点
从根节点开始的各个节点存放了图像的内容,而各个节点之间的联系是通过Ehfa_Entry 对象来实现的,结构如下:
Ehfa_Entry { long next; //下一个节点的位置 long prev; //前一个节点的位置 long parent; //父节点的位置 long child; //第一个子节点的位置 long data; //数据的存放位置 long datasize; //数据大小 char [64] name; //节点的名字 char [32] type; //节点数据的存储结构 TIME modTime; //节点的修改时间 } |
通过next, prev, parent 和child 四个属性可以将节点联系成一棵树,而节点所存储的数据,可以通过data 属性来找到其位置。而数据的存储结构,需要在节点存储结构列表中去查找。
节点存储结构列表
Dictionary 是文件的节点存储结构列表,包括每个节点所存储的数据的结构,以及上边所说的头文件及节点本身的存储结构。比如Ehfa_Entry 对象,在列表中表述为
{1:Lnext,1:Lprev,1:Lparent,1:Lchild,1:Ldata,1:ldataSize,64:cname,32:ctype,1:tmodTime,}Ehfa_Entry |
每个存储结构之间用逗号隔开,存储结构中的变量也用逗号隔开。
在每个变量的表述中,比如1:Lnext,1代表一个变量,L表示是Long型的,next是变量名。
变量类型有很多种,可以确定的有L代表Long,C代表Char,T代表Time,S代表Short,E代表Enum,D代表Double,还有一些我也不确定的,比如B可能是指Bool, pc可能代表String,po和o可能都代表Object,表示嵌入另一个存储结构。
因为变量类型有的是一个字符有的是两个,并且Enum和Object等类型的存储格式和其他类型不太一样,如下
{1:e2:no compression,RLC compression,compressionType,0:poEdms_VirtualBlockInfo,blockinfo} |
除此之外还有这种我完全没能理解的存储格式
1:x{0:pcstring,}Emif_String,title |
由于不方便解析,而且每个文件的存储结构基本相同,因此我把要用到的一些节点直接写为了JSON 对象,没有直接解析文件来生成节点存储结构列表。在读取节点存储数据的时候,必须从列表中查找其存储结构,才能够读取所存储的信息。
节点存储数据
IMG 格式中一个重要的节点是Eimg_Layer,一般是根节点的子节点,每个节点对应图像的一个波段。数据存储结构如下:
Eimg_Layer { long width; //图层的宽度 Long height; //图层的长度 enum layerType; //图层的类型 enum pixelType; //图层像素的存储类型 long blockWidth; //图层块的宽度 long blockHeight; //图层块的长度 } |
IMG图像是二进制文件,并且采用的是Little-Endian模式存储。在各变量类型里,Char占一个字节,Short和Enum占两个字节,Long和Time占四个字节,Double占八个字节,String和Object的占用不固定。除了 这些变量之外,一个像素占的字节数就需要通过pixelType类型来确定。另外IMG图像的一个重要特点是分块存储,一幅图像按照行列数被分成N块,然后再分块存储,blockWidth和blockHeight就是存储了每块的大小。
由于一般各图层的宽高度等属性都是相同的,我在读取的时候只读取第一波段的Eimg_Layer信息。
在Eimg_Layer节点下,包括Edms_State(像素数据),Eprj_ProParameters(投影信息),Eprj_MapInfo(地理信息)等子节点。Edms_State节点保存的是图像像素的数据,也是非常重要的节点。结构如下:
Edms_State { long numvirtualblocks; //块的个数 long numobjectsperblock; //块的大小 long nextobjectnum; //不知道是神马 enum compressiontype; //是否压缩,0是不压缩,1是RLC压缩 edms_VirtualBlockInfo blockinfo; //块的信息 edms_FreelDList freelist; //仍然不知道是神马 TIME modTime; //修改时间 } |
其内嵌的两个子结构如下:
Edms_VirtualBlockInfo { short filecode; //一般是0 long offset; //块数据的存储地址 long size; //块的大小 enum logvalid; //代表什么不了解,但一般是1 enum compression; //是否压缩,0是不压缩,1是ESRI GRID压缩 } Edms_FreelDList { long min; //大概是最小值? long max; //大概是最大值? } |
在读取内嵌子结构的时候,需要先读取两个Long型的变量,一个是子结构的重复个数,另一个是子结构的地址。之后以重复个数为循环读取子结构内部的变量,如果子结构重复个数为0,则不读取。与其类似的是String型,其预读取的第一个变量不是重复个数而是字段的长度。
在读取完Edms_State节点之后,就可以通过其子结构Edms_VirtualBlockInfo的offset和size两个属性读取每个分块的图像数据。由于IMG文件是分块存储,还必须对所有读取出来的数据进行整理,才可以形成可以显示的数据流。