首页 > 学院 > 开发设计 > 正文

TIFF文件解析

2019-11-06 06:22:56
字体:
来源:转载
供稿:网友

  TIF文件是一种标签标记文件,为什么这么说呢?它的文件的构成方式就是根据Tag来标记的。同时还可以记录地理信息,坐标、投影等信息,非常方便在GIS领域使用。网上关于TIFF文件的介绍也是不少,今天我主要是把我之前使用C++解析TIF文件的过程记录下来。 1.定义TIFF文件的结构体

//TIFF文件的数据结构typedef struct { FILE* pfile; //tiff文件 TIFF_UINT16_T tiff_byte_order; //字节序 TIFF_UINT16_T tiff_version; //文件版本 TIFF_UINT32_T tiff_dir_off; //DE位置 long tif_width; //宽度 long tif_height; //高度 long comPRession; //压缩 1:不压缩 long photo_metric_inter; //图像的色彩模式 2:RGB 3:索引图片 long bit_per_samples ; //像素的分量值 long samples_per_pixel; //每个象素的通道数 long rows_per_strip; //每个扫描行的图像数据行数 long bcount_strip_offset; //多少条扫描行 long planar_config; //图像数据存储方式 1 - RGBRGBRGB 2 - RRRGGGBBB TIFF_UINT32_T* strip_line; //扫描行的起始位置 long bcount_strip_byte_counts; // TIFF_UINT32_T* strip_byte_counts;//每条扫描行的字节数目 TIFF_UINT16_T* color_map; //颜色表 Tile tile; //瓦片数据 GeoTiff geo_tiff; //GeoTiff文件头}TiffFile;

2.定义在这个过程中使用到的宏

#define TIFF void*#define TIFF_VERSION_CLASSIC 42#define TIFF_BIGENDIAN 0x4d4d#define TIFF_LITTLEENDIAN 0x4949#define PI 3.14159265358979323846#define SIZEOF_INT 4/* Signed 8-bit type */#define TIFF_INT8_T signed char/* Unsigned 8-bit type */#define TIFF_UINT8_T unsigned char/* Signed 16-bit type */#define TIFF_INT16_T signed short/* Unsigned 16-bit type */#define TIFF_UINT16_T unsigned short/* Signed 32-bit type formatter */#define TIFF_INT32_FORMAT "%d"/* Signed 32-bit type */#define TIFF_INT32_T signed int/* Unsigned 32-bit type */#define TIFF_UINT32_T unsigned int/* Signed 64-bit type */#define TIFF_INT64_T signed __int64/* Unsigned 64-bit type formatter */#define TIFF_UINT64_FORMAT "%I64u"/* Unsigned 64-bit type */#define TIFF_UINT64_T unsigned __int64/* Signed size type */#if defined(_WIN64)#define TIFF_SSIZE_T signed __int64#else#define TIFF_SSIZE_T signed int#endif/* Signed size type formatter */#if defined(_WIN64)#define TIFF_SSIZE_FORMAT "%I64d"#else#define TIFF_SSIZE_FORMAT "%ld"#endif/* Pointer difference type */#define TIFF_PTRDIFF_T long#define TIFF_ERROR_PATH_SUCCESS 0 #define TIFF_ERROR_PATH_NULL -1#define TIFF_ERROR_OPEN_FAILED -2#define TIFF_ERROR_BYTE_ORDER -3#define TIFF_ERROR_TIFF_VER -4

如果里面使用到地理信息还会使用到以下定义:

#define TIFF_GEO_GeoTagPixelScale 33550#define TIFF_GEO_GeoTagTiePoint 33922#define TIFF_GEO_GeoTagTransMatrix 34264#define TIFF_GEO_GeoTagDirectory 34735#define TIFF_GEO_GeoTagDoubleParams 34736#define TIFF_GEO_GeoTagASCIIParams 34737

3.首先打开TIFF文件

int tif_open( const char* tiff_path , TiffFile* tf){ if ( tiff_path == NULL) { return -1; } //打开文件 FILE* ptiff = fopen( tiff_path , "rb" ); if ( ptiff == NULL ) { return -2; } tf->pfile = ptiff; fseek( ptiff ,0 ,SEEK_CUR ); //得到字节序 TIFF_UINT16_T byte_order; fread( &byte_order,1 , 2,ptiff ); tf->tiff_byte_order = byte_order; if ( !((byte_order ==TIFF_BIGENDIAN) || (byte_order ==TIFF_LITTLEENDIAN)) ) { fclose( ptiff ); return -3; } TIFF_UINT8_T s[2]={0}; //得到TIFF版本 fread( s ,2 , 1, ptiff ); TIFF_INT16_T byte_ver = sget2(s,byte_order); tf->tiff_version = byte_ver; if ( TIFF_VERSION_CLASSIC !=byte_ver ) { fclose( ptiff ); return -4; } //得到IFD的文件偏移量 TIFF_UINT32_T IFDoffset = get4( ptiff , byte_order ); tf->tiff_dir_off = IFDoffset; fseek( ptiff , IFDoffset-8 ,SEEK_CUR ); //得到IFD的数量 TIFF_UINT16_T IFDnum = get2( ptiff , byte_order ); int fs = fseek( ptiff ,2+IFDoffset , SEEK_SET ); TIFF_UINT16_T tdir_tag = 0 , tdir_type = 0 ; TIFF_UINT32_T tdir_count = 0 , toff_long = 0 ; for (TIFF_UINT16_T i=0x0000;i< IFDnum ;i++) { TIFF_UINT32_T file_offset = 2+IFDoffset+12*i; int fs = fseek( ptiff , 2+IFDoffset+12*i , SEEK_SET ); tdir_tag = get2( ptiff , byte_order ); if ( tdir_tag == 0x100 )//width { tdir_type = get2( ptiff , byte_order ); tdir_count = get4( ptiff , byte_order ); if ( ( tdir_type == 3 || tdir_type == 4 ) && byte_order == 0x4d4d/*Motor*/ && tdir_count == 1 ) { toff_long = (TIFF_UINT32_T)get2( ptiff , byte_order ); } else { toff_long = get4( ptiff , byte_order ); } tf ->tif_width = toff_long ; continue; } else if ( tdir_tag == 0x101 )//height { tdir_type = get2( ptiff , byte_order ); tdir_count = get4( ptiff , byte_order ); if ( ( tdir_type == 3 || tdir_type == 4 ) && byte_order == 0x4d4d/*Motor*/ && tdir_count == 1 ) { toff_long = (TIFF_UINT32_T)get2( ptiff , byte_order ); } else { toff_long = get4( ptiff , byte_order ); } tf ->tif_height = toff_long ; continue; } else if ( tdir_tag == 0x102 )//BitsPerSample { tdir_type = get2( ptiff , byte_order ); tdir_count = get4( ptiff , byte_order ); if ( tdir_count == 1 ) { if ( ( tdir_type == 3 || tdir_type == 4 ) && byte_order == 0x4d4d/*Motor*/ && tdir_count == 1 ) { toff_long = (TIFF_UINT32_T)get2( ptiff , byte_order ); } else { toff_long = get4( ptiff , byte_order ); } tf -> bit_per_samples = toff_long ; } else { toff_long = get4( ptiff , byte_order ); TIFF_UINT16_T* sl = (TIFF_UINT16_T*)get_byte_mem( ptiff , toff_long , tdir_count*sizeof(TIFF_UINT16_T) ); TIFF_UINT16_T* s2 = sl; for ( int i = 0 ; i < (int)tdir_count ; i++ ) { TIFF_UINT32_T s16 = sget2((TIFF_UINT8_T*)(s2 + i) , tf->tiff_byte_order ); tf -> bit_per_samples += s16 ; } } continue; } else if ( tdir_tag == 0x103 )//Compression { tdir_type = get2( ptiff , byte_order ); tdir_count = get4( ptiff , byte_order ); if ( ( tdir_type == 3 || tdir_type == 4 ) && byte_order == 0x4d4d/*Motor*/ && tdir_count == 1 ) { toff_long = (TIFF_UINT32_T)get2( ptiff , byte_order ); } else { toff_long = get4( ptiff , byte_order ); } tf ->compression = toff_long ; continue; } else if ( tdir_tag == 0x106 )//PhotometricInterpretation { tdir_type = get2( ptiff , byte_order ); tdir_count = get4( ptiff , byte_order ); if ( ( tdir_type == 3 || tdir_type == 4 ) && byte_order == 0x4d4d/*Motor*/ && tdir_count == 1 ) { toff_long = (TIFF_UINT32_T)get2( ptiff , byte_order ); } else { toff_long = get4( ptiff , byte_order ); } tf ->photo_metric_inter = toff_long ; continue; } else if ( tdir_tag == 0x111 )//StripOffsets { tdir_type = get2( ptiff , byte_order ); tdir_count = get4( ptiff , byte_order ); toff_long = get4( ptiff , byte_order ); tf ->bcount_strip_offset = tdir_count ; if ( tdir_count > 1 ) { TIFF_UINT32_T* sl = (TIFF_UINT32_T*)get_byte_mem( ptiff , toff_long , tdir_count * sizeof(TIFF_UINT32_T) ); TIFF_UINT32_T* sl2 = sl; //字节序的转换 for ( int i = 0 ; i < (int)tdir_count ; i++ ) { TIFF_UINT32_T s32 = sget4((TIFF_UINT8_T*)sl2 , tf->tiff_byte_order ); memcpy( sl2 , &s32 , 4 ); sl2+=1; } tf ->strip_line = sl ; } else { tf ->bcount_strip_offset = 1; tf ->strip_line = new TIFF_UINT32_T; *(tf ->strip_line) = toff_long; } continue; } else if ( tdir_tag == 0x115 )//SamplesPerPixel { tdir_type = get2( ptiff , byte_order ); tdir_count = get4( ptiff , byte_order ); if ( ( tdir_type == 3 || tdir_type == 4 ) && byte_order == 0x4d4d/*Motor*/ && tdir_count == 1 ) { toff_long = (TIFF_UINT32_T)get2( ptiff , byte_order ); } else { toff_long = get4( ptiff , byte_order ); } tf ->samples_per_pixel = toff_long ; continue; } else if ( tdir_tag == 0x116 )//RowsPerStrip { tdir_type = get2( ptiff , byte_order ); tdir_count = get4( ptiff , byte_order ); if ( ( tdir_type == 3 || tdir_type == 4 ) && byte_order == 0x4d4d/*Motor*/ && tdir_count == 1 ) { toff_long = (TIFF_UINT32_T)get2( ptiff , byte_order ); } else { toff_long = get4( ptiff , byte_order ); } tf ->rows_per_strip = toff_long; continue; } else if ( tdir_tag == 0x117 )//StripByteCounts { tdir_type = get2( ptiff , byte_order ); tdir_count = get4( ptiff , byte_order ); toff_long = get4( ptiff , byte_order ); tf ->bcount_strip_byte_counts = tdir_count ; if ( tf ->bcount_strip_byte_counts > 1 ) { TIFF_UINT32_T* sl = (TIFF_UINT32_T*)get_byte_mem( ptiff , toff_long , tdir_count*sizeof(TIFF_UINT32_T) ); TIFF_UINT32_T* sl2 = sl; //字节序的转换 for ( int i = 0 ; i < (int)tdir_count ; i++ ) { TIFF_UINT32_T s32 = sget4((TIFF_UINT8_T*)sl2 , tf->tiff_byte_order ); memcpy( sl2 , &s32 , 4 ); sl2+=1; } tf ->strip_byte_counts = sl ; } else { tf ->bcount_strip_byte_counts = 1; tf ->strip_byte_counts = new TIFF_UINT32_T; *(tf ->strip_byte_counts) = toff_long; } continue; } else if ( tdir_tag == 0x11c )//Planar Configuration { tdir_type = get2( ptiff , byte_order ); tdir_count = get4( ptiff , byte_order ); if ( ( tdir_type == 3 || tdir_type == 4 ) && byte_order == 0x4d4d/*Motor*/ && tdir_count == 1 ) { toff_long = (TIFF_UINT32_T)get2( ptiff , byte_order ); } else { toff_long = get4( ptiff , byte_order ); } tf->planar_config = toff_long ; continue; } else if ( tdir_tag== 0x140 )//Color map { tdir_type = get2( ptiff , byte_order ); tdir_count = get4( ptiff , byte_order ); toff_long = get4( ptiff , byte_order ); int pow1 = 0; if ( tf ->bit_per_samples == 1 ) { pow1 = 1<<1; } else if ( tf ->bit_per_samples == 4 ) { pow1 = 1<<4; } else if ( tf ->bit_per_samples == 8 ) { pow1 = 1<<8; } tf ->color_map = (TIFF_UINT16_T*)get_byte_mem( ptiff , toff_long , 3*pow1*2 ); } else if ( tdir_tag== 0x142 )//tile width { tf ->tile.is_tile = true ; tdir_type = get2( ptiff , byte_order ); tdir_count = get4( ptiff , byte_order ); toff_long = get4( ptiff , byte_order ); tf ->tile.tile_width = toff_long ; continue; } else if ( tdir_tag== 0x143 )//tile height { tdir_type = get2( ptiff , byte_order ); tdir_count = get4( ptiff , byte_order ); toff_long = get4( ptiff , byte_order ); tf ->tile.tile_height = toff_long ; continue; } else if ( tdir_tag== 0x144 )//tile offset { tdir_type = get2( ptiff , byte_order ); tdir_count = get4( ptiff , byte_order ); toff_long = get4( ptiff , byte_order ); tf ->tile.tile_offset_count = tdir_count ; if ( tdir_count > 1 ) { tf ->tile.tile_offset_list = (TIFF_UINT32_T*)get_byte_mem( ptiff , toff_long , tdir_count*sizeof(TIFF_UINT32_T) ); } continue; } else if ( tdir_tag== 0x145 )//tile byte count { tdir_type = get2( ptiff , byte_order ); tdir_count = get4( ptiff , byte_order ); toff_long = get4( ptiff , byte_order ); tf ->tile.tile_byte_num_count = tdir_count ; if ( tdir_count > 1 ) { tf ->tile.tile_byte_num_list = (TIFF_UINT32_T*)get_byte_mem( ptiff , toff_long , tdir_count*sizeof(TIFF_UINT32_T) ); } continue; } else if ( tdir_tag == 33550 ) //ModelPixelScaleTag { tf -> geo_tiff.is_geotiff = true ; tdir_type = get2( ptiff , byte_order ); tdir_count = get4( ptiff , byte_order ); toff_long = get4( ptiff , byte_order ); if ( tdir_count == 3 && tdir_type == 12 ) { TIFF_UINT8_T* ps = (TIFF_UINT8_T*)get_byte_mem( ptiff , toff_long , tdir_count*8*sizeof(TIFF_UINT8_T) ); tf -> geo_tiff.pixel_scale.scaleX = long_to_double( sget8( ps , byte_order)) ; tf -> geo_tiff.pixel_scale.scaleY = long_to_double( sget8( ps + 8 , byte_order)) ; tf -> geo_tiff.pixel_scale.scaleZ = long_to_double( sget8( ps + 16 , byte_order)) ; delete[] ps; ps = NULL; } continue; } else if ( tdir_tag == 33922 ) //ModelTiePointTag { tf -> geo_tiff.is_geotiff = true ; tdir_type = get2( ptiff , byte_order ); tdir_count = get4( ptiff , byte_order ); toff_long = get4( ptiff , byte_order ); if ( tdir_type == 12 && tdir_count >= 6 ) { TIFF_UINT8_T* ps = (TIFF_UINT8_T*)get_byte_mem( ptiff , toff_long , tdir_count*8*sizeof(TIFF_UINT8_T) ); tf -> geo_tiff.tie_point.SrcX = long_to_double( sget8( ps , byte_order)) ; tf -> geo_tiff.tie_point.SrcY = long_to_double( sget8( ps +8 , byte_order)) ; tf -> geo_tiff.tie_point.SrcZ = long_to_double( sget8( ps + 16 , byte_order)) ; tf -> geo_tiff.tie_point.DecX = long_to_double( sget8( ps + 24, byte_order)) ; tf -> geo_tiff.tie_point.DecY = long_to_double( sget8( ps + 32 , byte_order)) ; tf -> geo_tiff.tie_point.DecZ = long_to_double( sget8( ps + 40 , byte_order)) ; delete[] ps; ps = NULL; } continue; } else if ( tdir_tag == 34735 ) //GeoKeyDirectoryTag { tf -> geo_tiff.is_geotiff = true ; tf -> geo_tiff.is_geokeys = true ; tdir_type = get2( ptiff , byte_order ); tdir_count = get4( ptiff , byte_order ); toff_long = get4( ptiff , byte_order ); tf -> geo_tiff.geo_tag_directory = (TIFF_UINT16_T*)get_byte_mem( ptiff , toff_long , tdir_count*sizeof(TIFF_UINT16_T) ); continue; } else if ( tdir_tag == 34736 ) //GeoDoubleParamsTag { tf -> geo_tiff.is_geotiff = true ; tdir_type = get2( ptiff , byte_order ); tdir_count = get4( ptiff , byte_order ); toff_long = get4( ptiff , byte_order ); tf -> geo_tiff.double_param_count = tdir_count ; tf -> geo_tiff.geo_double = (double*)get_byte_mem( ptiff , toff_long , tdir_count*sizeof(double) ); continue; } else if ( tdir_tag == 34737 ) //GeoAsciiParamsTag { tf -> geo_tiff.is_geotiff = true ; tdir_type = get2( ptiff , byte_order ); tdir_count = get4( ptiff , byte_order ); toff_long = get4( ptiff , byte_order ); tf -> geo_tiff.ascii_param_count = tdir_count ; tf -> geo_tiff.geo_ascii = (char*)get_byte_mem( ptiff , toff_long , tdir_count*sizeof(char) ); break; } } return 0;}

4.TIFF文件在存储的图形数据有两种存储方式:一种是线性存储的,一种是块状存储的。在读取不同的数据结构时也是有不同的。 读取线性数据:

int read_tiff_file( int view_w ,int view_h , double sca , TiffFile* tiff_file , TIFF_UINT8_T* pbuf ){ double sc = 1 / sca ;//目标文件相对于源文件放大的倍数 FILE *pfile = tiff_file->pfile; int samples_per_pixel = tiff_file->samples_per_pixel; TIFF_UINT32_T* line_start = tiff_file->strip_line ; int SrcWidth = tiff_file->tif_width; for ( int i = view_h-1; i >=0 ; i-- )//上下颠倒 { //选取最邻近的点 int tSrcH = (int)( sc * i + 0.5); for ( int j = 0; j < view_w; j++) { int tSrcW = (int)( sc * j + 0.5); fseek ( pfile , line_start[tSrcH] + tSrcW * samples_per_pixel , SEEK_SET ); fread( pbuf ,samples_per_pixel ,1 , pfile ); TIFF_UINT8_T u; u = pbuf[0]; //************// pbuf[0] = pbuf[2]; // BGR -> RGB // pbuf[2] = u; //************// pbuf += 4/*samples_per_pixel*/; } } return 0;}

读取块状数据:

int read_tile_tiff_file( int view_w ,int view_h , double sca , TiffFile* tiff_file , TIFF_UINT8_T* pbuf ){ FILE *pfile = tiff_file->pfile; int samples_per_pixel = tiff_file->samples_per_pixel; TIFF_UINT32_T* line_start = tiff_file->strip_line ; int SrcWidth = tiff_file->tif_width; double sc = 1 / sca ;//目标文件相对于源文件放大的倍数 TIFF_UINT32_T*tile_offset = tiff_file->tile.tile_offset_list; //偏移量列表 int pos_h = 0 ,pos_w = 0; int table_w = (int)( tiff_file->tif_width/ tiff_file->tile.tile_width); if ( tiff_file->tif_width% tiff_file->tile.tile_width > 0 ) { table_w ++ ; } int table_h = (int)( tiff_file->tif_height/ tiff_file->tile.tile_height)+1; if ( tiff_file->tif_height% tiff_file->tile.tile_height > 0 ) { table_h ++ ; } int tile_H = tiff_file->tile.tile_height ; int tile_W = tiff_file->tile.tile_width ; //for ( int i = 0 ; i< desH ; i ++ ) for ( int i = view_h-1 ; i >= 0 ; i -- ) { int tSrcH = (int)( sc * i + 0.5); pos_h = tSrcH / tile_H; for ( int j = 0 ; j < view_w ; j ++ ) { int tSrcW = (int)( sc * j + 0.5); pos_w = tSrcW / tile_W; TIFF_UINT32_T file_offset_start = tile_offset[ pos_h*table_w + pos_w ]; to_client( tSrcW , tSrcH , tile_W , tile_H ); fseek ( pfile , file_offset_start+(tSrcH*tile_W+ tSrcW)*samples_per_pixel, SEEK_SET ); fread( pbuf ,samples_per_pixel ,1 , pfile ); TIFF_UINT8_T u; u = pbuf[0]; //************// pbuf[0] = pbuf[2]; // BGR -> RGB // pbuf[2] = u; //************// pbuf += 4/*samples_per_pixel*/; } } return 0;}

5.如果TIFF中包含地理信息,还需要把地理信息取出来

//通过像素坐标的范围确定地理坐标的范围void geo_coord( TiffFile* tf , geoRECT pixel_rect , geoRECT&geoRect ){ geoRect.left = tf->geo_tiff.tie_point.DecX + ( pixel_rect.left - tf->geo_tiff.tie_point.SrcX ) * tf->geo_tiff.pixel_scale.scaleX ; geoRect.top = tf->geo_tiff.tie_point.DecY + ( pixel_rect.top - tf->geo_tiff.tie_point.SrcY ) * tf->geo_tiff.pixel_scale.scaleY ; geoRect.right = tf->geo_tiff.tie_point.DecX + ( pixel_rect.right - tf->geo_tiff.tie_point.SrcX ) * tf->geo_tiff.pixel_scale.scaleX ; geoRect.botton = tf->geo_tiff.tie_point.DecY - ( pixel_rect.botton - tf->geo_tiff.tie_point.SrcY ) * tf->geo_tiff.pixel_scale.scaleY ;}

6.最后,如果是Google投影,则不需要proj4来转换,直接使用以下函数就可以实现地理坐标新(WGS84)和Google投影之间的坐标转换

#define PI 3.14159265358979323846void web_mercator_2_lonlat( coordPairs&ml ){ ml.x = ml.x / 20037508.3427892 * 180; double y = ml.y / 20037508.3427892 * 180; ml.y = 180 / PI * ( 2 * atan ( exp ( y * PI / 180 ) ) - PI / 2 );}void lonlat_2_web_mercator( coordPairs&ml ){ ml.x = ml.x * 20037508.3427892 / 180; double y = log ( tan ( ( 90 + ml.y ) * PI / 360 ) ) / ( PI / 180 ); ml.y = y * 20037508.3427892 / 180;}

好了,以上是读取TIFF文件的主要内容 源码下载


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表