TIFF文件解析

来源:互联网 发布:逆袭网络剧百度云网盘 编辑:程序博客网 时间:2024/06/09 16:55

  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文件的主要内容
源码下载

0 0