TIFF圖像文件格式詳解


1 什么是TIFF?
TIFF是Tagged Image File Format的縮寫。在現在的標准中,只有TIFF存在, 其他的提法已經舍棄不用了。做為一種標記語言,TIFF與其他文件格式最大的不同在於除了圖像數據,它還可以記錄很多圖像的其他信息。它記錄圖像數據的方式也比較靈活, 理論上來說, 任何其他的圖像格式都能為TIFF所用, 嵌入到TIFF里面。比如JPEG, Lossless JPEG, JPEG2000和任意數據寬度的原始無壓縮數據都可以方便的嵌入到TIFF中去。由於它的可擴展性, TIFF在數字影響、遙感、醫學等領域中得到了廣泛的應用。TIFF文件的后綴是.tif或者.tiff

2 TIFF文件結構 
TIFF文件中的三個關鍵詞是:圖像文件頭Image File Header(IFH), 圖像文件目錄Image File Directory(IFD)和目錄項Directory Entry(DE)。每一幅圖像是以8字節的IFH開始的, 這個IFH指向了第一個IFD。IFD包含了圖像的各種信息, 同時也包含了一個指向實際圖像數據的指針。
IFH的構成:
Byte 0-1: 字節順序標志位, 值為II或者MM。II表示小字節在前, 又稱為little-endian。MM表示大字節在前,又成為big-endian。
Byte 2-3: TIFF的標志位,一般都是42
Byte 4-7: 第一個IFD的偏移量。可以在任意位置, 但必須是在一個字的邊界,也就是說必須是2的整數倍。
IFD的構成(0代表此IFD的起始位置):
Byte 0-1: 表示此IFD包含了多少個DE,假設數目為n
Byte 2-(n*12+1): n個DE
Byte (n*12+2)-(n*12+5): 下一個IFD的偏移量,如果沒有則置為0
DE的構成:
Byte 0-1: 此TAG的唯一標識
Byte 2-3: 數據類型。
Byte 4-7: 數量。通過類型和數量可以確定存儲此TAG的數據需要占據的字節數
Byte 8-11: 如果占用的字節數少於4, 則數據直接存於此。 如果超過4個,則這里存放的是指向實際數據的指針

可以用以下的圖來表示(圖來自http://www.cppblog.com/windcsn/archive/2009/03/12/1158.html)

在TIFF6.0中,定義了12種數據類型,分別是:

1 = BYTE 8-bit unsigned integer.
2 = ASCII 8-bit byte that contains a 7-bit ASCII code; the last byte
must be NUL (binary zero).
3 = SHORT 16-bit (2-byte) unsigned integer.
4 = LONG 32-bit (4-byte) unsigned integer.
5 = RATIONAL Two LONGs: the first represents the numerator
6 = SBYTE An 8-bit signed (twos-complement) integer.
7 = UNDEFINED An 8-bit byte that may contain anything, depending on
the definition of the field.
8 = SSHORT A 16-bit (2-byte) signed (twos-complement) integer.
9 = SLONG A 32-bit (4-byte) signed (twos-complement) integer.
10 = SRATIONAL Two SLONG’s: the first represents the numerator of a
fraction, the second the denominator.
11 = FLOAT Single precision (4-byte) IEEE format.
12 = DOUBLE Double precision (8-byte) IEEE format.

-個TIFF文件可能包含多個IFD,每一個IFD都是一個子文件。Baseline解碼器只要求解第一個IFD所對應的圖像數據。擴展的TIFF圖像經常包含多個IFD,每一個IFD都包含了不同的信息。

TIF圖一般由三個部分組成:文件頭(簡稱IFH)、文件目錄(簡稱IFD)、圖像數據。
一、圖像文件頭(Image File Header)
  IFH數據結構包含3個成員共計8個字節(見表一):
表一 IFH結構描述
------------------------------------------------------------
名稱        字節數 數據類型 說明
------------------------------------------------------------
Byteorder       2  Integer  TIF標記,其值為4D4D或4949
Version        2  Integer  版本號,其值恆為2A00
Offset to first IFD  4  Long    第一個IFD的偏移量
------------------------------------------------------------
表一說明
  1.Byteorder:可能是H4D4D或H4949,H4D4D表示該圖是摩托羅拉整數格式,H4949表示該圖是Intel整數格式。
  2.Version:總是H2A00,它可能是tif文件的版本,也可能用於進一步校驗該文件是否為TIF格式。
  3.Offset to first IFD:第一個IFD相對文件開始處的偏移量(因為可能會有多個順序排列的IFD)。
  IFD數據結構並不一定緊跟在IFH后面,相反,它常常位於第三部分圖像數據的后面,即TIF圖像文件的一般組織形式是:IFH——圖像數據——IFD。
  二、圖像文件目錄(Image File Directory)
  IFD是TIF圖像文件中重要的數據結構,它包含了三個成員。由於一個TIF文件中可以有多個圖像,而一個IFD只標識一個圖像的所有屬性(有的文章把“屬性”稱之為“標簽”),所以,一個TIF文件中有幾個圖像,就會有幾個IFD。IFD的結構見表二:
表二 IFD結構描述
-----------------------------------------------------------------
名稱         字節數 數據類型 說明
-----------------------------------------------------------------
Directory Entry Count  2  Integer  本IFD中DE的數量
Directory Entry(1)   12       簡稱DE,中文譯義“目錄項”
Directory Entry(2)   12
……
Directory Entry(N)   12
Offset to next IFD   4  Long    下一個IFD的偏移量
-----------------------------------------------------------------
表二說明
  1.Directory Entry Count:指出在該IFD中DE的個數;
  2.Directory Entry:共12個字節,結構見表三。需要指出的是,DE的個數是不定的,因為每個DE只標識了圖像的一個屬性,那么這幅圖像有N個屬性就會有N個DE,用戶甚至可添加自定義的標記屬性,這就是為什么稱TIF格式文件為“可擴充標記的文件”的原因。
  3.Offset to next IFD Or NULL:下一個IFD相對於文件開始處的位置,這是一個鏈式構成。如果該數字為0,表示已經是最后一個IFD。當然,如果該TIF文件只包含了一幅圖像,那么就只有一個IFD,顯然這個偏移量也會等於0。
表三 DE結構描述
--------------------------------------------------
名稱     字節數  數據類型 說明
--------------------------------------------------
tag       2   Integer  本屬性的標簽編號
type       2   Integer  本屬性值的數據類型
length      4   Long    該類型數據的數量
valueOffset   4   Long    屬性值的存放偏移量
--------------------------------------------------
表三說明
  由DE標識的圖像屬性有:圖像的大小、分辨率、是否壓縮、像素的行列數、顏色深度(單色、16色、256色、真彩色)等等。其中:
  ①tag:是該屬性的標簽編號(TagID),在圖像文件目錄中,它是按照升序排列的(但不一定是連續的)。這些編號在TIF格式官方白皮書中可以查到相應的含義,但遺憾的是,我們到哪兒可以找到官方白皮書呢?所以,筆者只能把網上能找得到資料(再結合自己的實驗結果)羅列出來,見表四。
  ②type:表示該屬性數據的類型,一般認為TIF官方指定的有5種數據類型(但也有說12種數據類型的)。見表五。
  ③length:該種類型的數據的個數,而不是某個數據的長度。
  ④valueOffset:是tagID代表的變量值相對文件開始處的偏移量,但如果變量值占用的空間不多於4個字節(例如只有1個Integer類型的值),那么該值就直接存放在valueOffset中,沒必要再另外指向一個地方了。
表四 DE中標簽編號的含義
-------------------------------------------------------------------------
TagID 屬性名稱 type 說明
-------------------------------------------------------------------------
0100 圖像寬       0003
0101 圖像高       0003
0102 顏色深度      0003  值=1為單色,=4為16色,=8為256色。
                 如果該類型數據個數>2個,說明是真彩圖像
0103 圖像數據是否壓縮  0003  值=05表示壓縮
0106 圖像是否采用反色顯示0003  值=01表示反色,否則表示不反色
0111 圖像掃描線偏移量  0004  圖像數據起始字節相對於文件開始處的位置
0116 圖像掃描線的數量  0004  表示圖像有幾行掃描線,實際上等於圖像高度
0117 圖像數據字節總數  0003  如果不是偶數,那么實際存放時會在后面加0
011A 水平分辯率偏移量  0005  常用計量單位是:像素/英寸
011B 垂直分辯率 偏移量  0005  常用計量單位是:像素/英寸
0131 生成該圖像的軟件名 0002  文本類型
0132 生成該圖像的時間  0002  文本類型
0140 調色板偏移量    0003  256色和16色圖像才有此屬性,而且有連續2個
                 調色板,但屬性的length值只表示出1個調色板
-------------------------------------------------------------------------
表四說明
  ①“水平(垂直)分辯率”是分數型的屬性,其值要占用8個字節,所以在valueOffset中存放的肯定是它的具體數值的偏移量,而不是數值本身。
  ②“生成圖像的軟件名稱”和“生成圖像的時間”這兩個字符型屬性,它們的值所占用的空間也會大於4字節,所以在valueOffset中存放的也是它們的值的偏移量,而不是值本身。
  ③“圖像數據字節總數”一般是個偶數,如果是奇數,那么實際存放時會在后面加一個0,但這個0不會計算在字節總數之內。
表五 DE中的數據類型
--------------------------------------------------------------------
type值 數據類型  說明
--------------------------------------------------------------------
0001  Byte
0002  Ascii   文本類型,7位Ascii碼加1位二進制0
0003  Integer
0004  Long
0005  RATIONAL  分數類型,由兩個Long組成,第1個是分子,第2個是分母
--------------------------------------------------------------------
  三、圖像數據。這些數據可能是壓縮的,也可能是未壓縮的。如果經過壓縮,那么壓縮算法又有許多種,所以,圖像數據是TIF文件中最為復雜的部分,暫還沒有哪個軟件能譯出所有的壓縮算法。

 

TIFF圖片可以存儲坐標信息,但是如何對這些坐標信息進行轉換,然后生成新的圖片呢?首先需要知道現在TIFF圖片中的坐標系,然后要知道被轉換的坐標系。現在我們只支持WGS84、西安80、北京54等中國常用的坐標系。
坐標系轉換的頭文件:

頭文件

#pragma once
#include "proj_api.h"

#define PROJ4_COUNT 1024
#define coord_wgs84 "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"
#define coord_google "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs"
/*
北京54 +proj=tmerc +a=6378245.000000 +b=6356863.018800 +x_0=39500000.000000 +y_0=0.000000 +lat_0=0.000000 +lon_0=117.000000 +units=m +k=1.000000  +towgs84=0,-0,0,0,0,0,0
西安80 +proj=tmerc +a=6378140.000000 +b=6356755.288158 +x_0=39500000.000000 +y_0=0.000000 +lat_0=0.000000 +lon_0=117.000000 +units=m +k=1.000000  +towgs84=0,-0,0,0,0,0,0
國家2000 +proj=tmerc +a=6378137.000000 +b=6356752.314140 +x_0=39500000.000000 +y_0=0.000000 +lat_0=0.000000 +lon_0=117.000000 +units=m +k=1.000000  +towgs84=0,-0,0,0,0,0,0
*/


class CoordTrans
{
public:
    CoordTrans();
public:

    void define_coord_sys( const int coord_sys );
    void define_ellps( const int ellps );
    void define_proj_zone( const int maj_zone );
    void define_7_trans( double dx , double dy , double dz , double rx , double ry , double rz , double k );
    void trans_2_des( double&left , double&top , double&right , double&bottom );
    void trans_2_des( double&left , double&top );

    void trans_back_src( double&left , double&top );
public:

    bool init_proj( const char* src_ ,const char* des_ = coord_google );

    void xy_2_latlong( double&x , double&y );
    void xy_2_xy( double&x , double&y );
    void longlat_2_xy( double&x , double&y );

private:
    void deinit();
private:
    void* _source;
    void* _des;

    char* _sz_source;
    char* _sz_des;

private:
    int _coord_sys;
    int _ellps;
    int _maj_zone;

    double _dx;
    double _dy;
    double _dz;
    double _rx;
    double _ry;
    double _rz;
    double _k;
};

坐標轉換cpp文件

#include "coord_trans.h"
#include <string.h>
#include <stdio.h>
#include "windows.h"
#include <string>
using namespace std;

struct _ellps_type_data_
{
    TCHAR* name;
    double a;
    double b;
};

const _ellps_type_data_ ellps_list[]=
{
    {L"WGS84"   , 6378137.0 , 6356752.3142 },
    {L"西安80"    , 6378140.0 , 6356755.288157528},
    {L"北京54"    , 6378245.0 , 6356863.0188 },
    {L"國家2000", 6378137.0 , 6356752.31414},
    {L"web墨卡托",6378137.0 , 6378137.0},
    {NULL           , 0         , 0 }
};

typedef struct _proj_type_data_
{
    TCHAR* name;
    int zome_number;
    double pl;
    double pb;
    double pfe;
    double pfn;
    double pk;
} ProjData;

ProjData theProj[]=
{
    {L"(6度帶)13-中央經線 75"   ,13,75,0,13500000,0,1},
    {L"(6度帶)14-中央經線 81"   ,14,81,0,14500000,0,1},
    {L"(6度帶)15-中央經線 87"   ,15,87,0,15500000,0,1},
    {L"(6度帶)16-中央經線 93"   ,16,93,0,16500000,0,1},
    {L"(6度帶)17-中央經線 99" ,17,99,0,17500000,0,1},
    {L"(6度帶)18-中央經線 105"    ,18,105,0,18500000,0,1},
    {L"(6度帶)19-中央經線 111"    ,19,111,0,19500000,0,1},
    {L"(6度帶)20-中央經線 117"    ,20,117,0,20500000,0,1},
    {L"(6度帶)21-中央經線 123"    ,21,123,0,21500000,0,1},
    {L"(6度帶)22-中央經線 129"    ,22,129,0,22500000,0,1},
    {L"(6度帶)23-中央經線 135"    ,23,135,0,23500000,0,1},

    {L"(3度帶)25-中央經線 75" ,25,75,0,25500000,0,1},
    {L"(3度帶)26-中央經線 78" ,26,78,0,26500000,0,1},
    {L"(3度帶)27-中央經線 81" ,27,81,0,27500000,0,1},
    {L"(3度帶)28-中央經線 84" ,28,84,0,28500000,0,1},
    {L"(3度帶)29-中央經線 87" ,29,87,0,29500000,0,1},
    {L"(3度帶)30-中央經線 90" ,30,90,0,30500000,0,1},
    {L"(3度帶)31-中央經線 93" ,31,93,0,31500000,0,1},
    {L"(3度帶)32-中央經線 96" ,32,96,0,32500000,0,1},
    {L"(3度帶)33-中央經線 99" ,33,99,0,33500000,0,1},
    {L"(3度帶)34-中央經線 102"    ,34,102,0,34500000,0,1},
    {L"(3度帶)35-中央經線 105"    ,35,105,0,35500000,0,1},
    {L"(3度帶)36-中央經線 108"    ,36,108,0,36500000,0,1},
    {L"(3度帶)37-中央經線 111"    ,37,111,0,37500000,0,1},
    {L"(3度帶)38-中央經線 114"    ,38,114,0,38500000,0,1},
    {L"(3度帶)39-中央經線 117"    ,39,117,0,39500000,0,1},
    {L"(3度帶)40-中央經線 120"    ,40,120,0,40500000,0,1},
    {L"(3度帶)41-中央經線 123"    ,41,123,0,41500000,0,1},
    {L"(3度帶)42-中央經線 126"    ,42,126,0,42500000,0,1},
    {L"(3度帶)43-中央經線 129"    ,43,129,0,43500000,0,1},
    {L"(3度帶)44-中央經線 132"    ,44,132,0,44500000,0,1},
    {L"(3度帶)45-中央經線 135"    ,45,135,0,45500000,0,1},
    /*{L"自定義",39,117,0,500000,0,1},*/
    {NULL   ,0,0,0,0,1}
};

CoordTrans::CoordTrans()
{
    _source = NULL;
    _des = NULL;

    _sz_source = new char[PROJ4_COUNT];
    memset( _sz_source , 0 , PROJ4_COUNT );

    _sz_des = new char[PROJ4_COUNT];
    memset( _sz_des , 0 , PROJ4_COUNT );
}

void CoordTrans::define_coord_sys( const int coord_sys )
{
    _coord_sys = coord_sys;

}

void CoordTrans::define_ellps( const int ellps )
{
    _ellps = ellps;
}

void CoordTrans::define_proj_zone( const int maj_zone )
{
    _maj_zone = maj_zone;
}
void CoordTrans::define_7_trans( double dx , double dy , double dz , double rx , double ry , double rz , double k )
{
    _dx = dx;
    _dy = -dy;
    _dz = dz;
    _rx = rx;
    _ry = ry;
    _rz = rz;
    _k = k;
}

void CoordTrans::trans_2_des( double&left , double&top , double&right , double&bottom )
{
    double left2 = left;
    double right2 = right;
    double top2 = top;
    double bottom2 = bottom;

    string proj ;
    if ( _coord_sys == 0 )
    {
        proj = "+proj=longlat ";
    }
    else if ( _coord_sys == 1 )
    {
        proj = "+proj=tmerc ";
    }

    //橢球體
    char ch_ellps[128];
    memset( ch_ellps , 0 , 128 );
    sprintf( ch_ellps , "+a=%f +b=%f " , ellps_list[_ellps].a , ellps_list[_ellps].b );
    string ellps( ch_ellps );

    //投影帶
    char ch_zone[512];
    memset( ch_zone , 0 , 512 );
    sprintf ( ch_zone ,"+x_0=%f +y_0=0.000000 +lat_0=0.000000 +lon_0=%f +units=m +k=1.000000 "
        , theProj[_maj_zone].pfe , theProj[_maj_zone].pl );
    string zone( ch_zone );

    //towgs84
    char ch_wgs84[128];
    memset( ch_wgs84 , 0 , 128 );
    sprintf( ch_wgs84 , "+towgs84=%f,%f,%f,%f,%f,%f,%f" , _dx , _dy , _dz , _rx , _ry , _rz , _k );
    string towgs84( ch_wgs84 );

    sprintf ( _sz_source ,"%s%s%s%s" , proj.c_str() , ellps.c_str() , zone.c_str() , towgs84.c_str() );


    init_proj( _sz_source );

    if ( _coord_sys == 0 )
    {
        longlat_2_xy( left , top );
        longlat_2_xy( right , bottom );
    }
    else
    {
        xy_2_xy( left , top );
        xy_2_xy( right , bottom );
    }


    /*init_proj( _sz_source , coord_wgs84 );
    xy_2_latlong( left2 , top2 );
    xy_2_latlong( right2 , bottom2 );
    init_proj( coord_wgs84 , coord_google );
    longlat_2_xy( left2 , top2 );
    longlat_2_xy( right2 , bottom2  );*/
}

void CoordTrans::trans_2_des( double&left , double&top )
{
    double left2 = left;
    double top2 = top;

    string proj ;
    if ( _coord_sys == 0 )
    {
        proj = "+proj=longlat ";
    }
    else if ( _coord_sys == 1 )
    {
        proj = "+proj=tmerc ";
    }

    //橢球體
    char ch_ellps[128];
    memset( ch_ellps , 0 , 128 );
    sprintf( ch_ellps , "+a=%f +b=%f " , ellps_list[_ellps].a , ellps_list[_ellps].b );
    string ellps( ch_ellps );

    //投影帶
    char ch_zone[512];
    memset( ch_zone , 0 , 512 );
    sprintf ( ch_zone ,"+x_0=%f +y_0=0.000000 +lat_0=0.000000 +lon_0=%f +units=m +k=1.000000 "
        , theProj[_maj_zone].pfe , theProj[_maj_zone].pl );
    string zone( ch_zone );

    //towgs84
    char ch_wgs84[128];
    memset( ch_wgs84 , 0 , 128 );
    sprintf( ch_wgs84 , "+towgs84=%f,%f,%f,%f,%f,%f,%f" , _dx , _dy , _dz , _rx , _ry , _rz , _k );
    string towgs84( ch_wgs84 );

    sprintf ( _sz_source ,"%s%s%s%s" , proj.c_str() , ellps.c_str() , zone.c_str() , towgs84.c_str() );


    init_proj( _sz_source );

    if ( _coord_sys == 0 )
    {
        longlat_2_xy( left , top );
    }
    else
    {
        xy_2_xy( left , top );
    }
}

void CoordTrans::trans_back_src( double&left , double&top )
{
    double left2 = left;
    double top2 = top;

    string proj ;
    if ( _coord_sys == 0 )
    {
        proj = "+proj=longlat ";
    }
    else if ( _coord_sys == 1 )
    {
        proj = "+proj=tmerc ";
    }

    //橢球體
    char ch_ellps[128];
    memset( ch_ellps , 0 , 128 );
    sprintf( ch_ellps , "+a=%f +b=%f " , ellps_list[_ellps].a , ellps_list[_ellps].b );
    string ellps( ch_ellps );

    //投影帶
    char ch_zone[512];
    memset( ch_zone , 0 , 512 );
    sprintf ( ch_zone ,"+x_0=%f +y_0=0.000000 +lat_0=0.000000 +lon_0=%f +units=m +k=1.000000 "
        , theProj[_maj_zone].pfe , theProj[_maj_zone].pl );
    string zone( ch_zone );

    //towgs84
    char ch_wgs84[128];
    memset( ch_wgs84 , 0 , 128 );
    sprintf( ch_wgs84 , "+towgs84=%f,%f,%f,%f,%f,%f,%f" , _dx , _dy , _dz , _rx , _ry , _rz , _k );
    string towgs84( ch_wgs84 );

    sprintf ( _sz_des ,"%s%s%s%s" , proj.c_str() , ellps.c_str() , zone.c_str() , towgs84.c_str() );


    init_proj( coord_google , _sz_des );

    if ( _coord_sys == 0 )
    {
        longlat_2_xy( left , top );
    }
    else
    {
        xy_2_xy( left , top );
    }
}

bool CoordTrans::init_proj( const char* src_ ,const char* des_ )
{
    deinit();

    _source = pj_init_plus( src_ );
    if ( !_source )
    {
        return false;
    }
    _des = pj_init_plus( des_ );
    if ( !_des )
    {
        return false;
    }

    return true;
}

void CoordTrans::xy_2_latlong( double&x , double&y )
{
    pj_transform(  _source,_des, 1, 0, &x , &y , 0 );

    x *= RAD_TO_DEG;
    y *= RAD_TO_DEG;
}

void CoordTrans::xy_2_xy( double&x , double&y )
{
    pj_transform(  _source,_des, 1, 0, &x , &y , 0 );
}
void CoordTrans::longlat_2_xy( double&x , double&y )
{
    x *= DEG_TO_RAD;
    y *= DEG_TO_RAD;
    pj_transform(  _source ,_des ,  1, 0, &x , &y , 0 );

}

void CoordTrans::deinit()
{
    if ( _source )
    {
        pj_free( _source );
        _source = NULL;
    }

    if ( _des )
    {
        pj_free( _des );

        _des= NULL;
    }
}

tiff處理的頭文件

#pragma once
#include "tiflib.h"
#include "coord_trans.h"
#include <math.h>
#include <string>
#include <vector>
using namespace std;

#include<Windows.h>

#define TIFF_HEADER_SIZE 8    //文件頭字節數
#define DE_START 10           //tiff TAG開始的位置
#define ONE_DE_SIZE 12        //每個TAG的大小
#define IDF_END_FLAG_SIZE 4   //IFD最后結尾的4個空字節
typedef struct
{
    int i_tag;
    const char* text;
}TagText;

typedef struct
{
    TIFF_UINT16_T type;
    char* type_name;
    TIFF_UINT16_T type_size;
}DataType;
typedef struct
{
    TIFF_UINT16_T tag;
    TIFF_UINT16_T type;
    TIFF_UINT32_T count;
    TIFF_UINT32_T offset;
}DirectoryEntry;

typedef struct
{
    DirectoryEntry de;
    int data_source; //0 - offset本身值 1 - offset對應的源文件偏移量 2 - 來自內存
    TIFF_UINT8_T* mem_data; //當 data_soure = 2 時 ,指向內存
}deInfo;

typedef struct
{
    int diff_x ;
    int diff_y ;
}DiffValue;

class tiffDeform
{
public:
    tiffDeform();
    tiffDeform( string tiff_path , string proj4_str );
    ~tiffDeform();

public:
    int open( string tiff_path , string proj4_str  , int coord_type );
    bool arrangement();
    void save( string src_file , string save_name = "" );
private:
    void src_coord_box( );
    double zone_number( double left_right );
    int get_zone_num( string proj4_str );
    double src_geo_xy( double left_right );
    void to_web_mector( geoRECT&rect , bool b );//b - true 取最內側的范圍 false - 取最外側范圍
    void to_web_mector( geoRECT&rect , bool b , double&x1 , double&y1, double&x2 , double&y2, double&x3 , double&y3, double&x4 , double&y4 );
    void get_pixel_scale();
    int get_src_tag_list();
    int cts_new_tag_list();
    void print_tag_info_list();
    const char* tag_text( int i_tag );

    deInfo* cts_strip_offsets();  
    deInfo* cts_rows_per_strip();
    deInfo* cts_strip_byte_counts();
    deInfo* cts_line_tag();
    void mix_proj_de_list( deInfo* coord_list );

    void write_file_header( );
    string new_tiff_name();
    void modify_strip_offset();
    void sort_byte_order( TIFF_UINT8_T* buf , TIFF_UINT16_T data_type , TIFF_UINT16_T data_count );
    TIFF_UINT64_T file_disk_data( DirectoryEntry de , TIFF_UINT64_T buffer_size );
    void write_tag_list();

    void write_img_data();       //單個像素寫入
    void write_img_data_ex();    //提高寫入像素的速度,整行寫入
    void write_img_data_th();    //采用多行讀取當行寫入來提高效率
    void write_img_data_th_ex(); //采用多行讀取當行寫入來提高效率,並且記錄TXT像素差值
    void write_img_data_mul_th();//采用多線程
    void write_img_by_record();  //通過事先記錄好的規則填寫數據
    void write_img_by_block_record();//分塊計算規則
    void write_img_by_sin();     //通過斜率填寫數據
    TIFF_UINT64_T double_to_long( double d_ );
    void point_to_by_geo( double x , double y , int&pt_x , int&pt_y );
    void point_to_by_geo_ex( double x , double y , int&pt_x , int&pt_y );

    void cs_coord( deInfo* coord_list );
    void cs_tie_point( double x , double y );
    void cs_pixel_scale( double cx , double cy );

    void des_geo_to_src_range( geoRECT des_geo , geoRECT&src_range );//通過目標地理范圍獲得原圖片的像素范圍
    void to_src_proj( geoRECT&des_geo , bool b );//b - true 取最內側的范圍 false - 取最外側范圍

    void des_geo_to_src_range_first( geoRECT des_geo , geoRECT&src_range , int&first_x , int&first_y );//通過目標地理范圍獲得原圖片的像素范圍,並得到第一個點坐標值
    void to_src_proj_first( geoRECT&des_geo , bool b , double&first_x , double&first_y );//b - true 取最內側的范圍 false - 取最外側范圍

private:
    HANDLE m_htiff_write;
    static DWORD WINAPI tiff_write_thread( LPVOID lpParameter );

private:
    TiffFile* _tiff_file;
    string _tiff_path;
    string _proj4_str;

    CoordTrans _coord_trans;
    int _coord_type;
    geoRECT _geo_rect_src , _geo_rect_des; //圖片的邊界
    double _scaleX_src,_scaleY_src;
    double _scaleX_des,_scaleY_des;

    int _new_tiff_width;
    int _new_tiff_height;

    FILE* _line_tiff;
    deInfo* de_list;
    TIFF_UINT16_T _de_num;             //標簽的數量

    TIFF_UINT32_T _strip_offset_pos;   //TAG StripOffset的文件偏移位置


    TIFF_UINT64_T pixel_scale[3];//像元比例
    TIFF_UINT64_T tie_point[6];//控制點坐標對

    TIFF_UINT32_T* _height_start;
    TIFF_UINT32_T _file_size;

    HANDLE _hMutex;
};

tiff處理的cpp

#include "tiffDeform.h"

TagText tag_text_list[] =
{
    { 254 , "NewSubfileType" },
    { 256 , "ImageWidth" },
    { 257 , "ImageLength" },
    { 258 , "BitsPerSample" },
    { 259 , "Compression" },
    { 262 , "PhotometricInterpretation" },
    { 273 , "StripOffsets" },
    { 274 , "相對於圖像的行和列的方向" },
    { 277 , "SamplesPerPixel" },
    { 278 , "RowsPerStrip" },
    { 279 , "StripByteCounts" },
    { 282 , "XResolution" },
    { 283 , "YResolution" },
    { 284 , "PlanarConfiguration" },
    { 296 , "ResolutionUnit" },
    { 305 , "Software" },
    { 306 , "DateTime" },
    { 322 , "TileWidth" },
    { 323 , "TileLength" },
    { 324 , "TileOffsets" },
    { 325 , "TileByteCounts" },
    { 339 , "SampleFormat" },
    { 33550 , "ModelPixelScaleTag" },
    { 33922 , "ModelTiepointTag" },
    { 34264 , "ModelTransformationTag" },
    { 34735 , "GeoKeyDirectoryTag" },
    { 34736 , "GeoDoubleParamsTag" },
    { 34737 , "GeoAsciiParamsTag" },
    { -1 , "" }
};

DataType data_type_list[] =
{
    { 0  , "NULL"     , 0 },//NULL
    { 1  , "BYTE"     , 1 },//BYTE 8-bit unsigned integer
    { 2  , "ASCII"    , 1 },//ASCII 8-bit byte that contains a 7-bit ASCII code; the last byte must be NUL (binary zero)
    { 3  , "SHORT"    , 2 },//SHORT 16-bit (2-byte) unsigned integer
    { 4  , "LONG"     , 4 },//LONG 32-bit (4-byte) unsigned integer
    { 5  , "RATIONAL" , 8 },//RATIONAL Two LONGs: the first represents the numerator
    { 6  , "SBYTE"    , 1 },//SBYTE An 8-bit signed (twos-complement) integer.
    { 7  , "UNDEFINED", 1 },//UNDEFINED An 8-bit byte that may contain anything, depending on the definition of the field.
    { 8  , "SSHORT"   , 2 },//SSHORT A 16-bit (2-byte) signed (twos-complement) integer
    { 9  , "SLONG"    , 4 },//SLONG A 32-bit (4-byte) signed (twos-complement) integer
    { 10 , "SRATIONAL", 8 },//SRATIONAL Two SLONG’s: the first represents the numerator of afraction, the second the denominator
    { 11 , "FLOAT"    , 4 },//FLOAT Single precision (4-byte) IEEE format
    { 12 , "DOUBLE"   , 8 } //DOUBLE Double precision (8-byte) IEEE format.

};

/*
Geo Key : 1024 = 1 
Geo Key : 1025 = 1 
Geo Key : 1026 = Popular Visualisation CRS / Mercator 
Geo Key : 2048 = 32767 
Geo Key : 2049 = Popular Visualisation CRS 
Geo Key : 2050 = 32767 
Geo Key : 2054 = 9102 
Geo Key : 2056 = 32767 
Geo Key : 2057 = 6378137.000000 
Geo Key : 2058 = 6378137.000000 
Geo Key : 3072 = 32767 
Geo Key : 3074 = 32767 
Geo Key : 3075 = 7 
Geo Key : 3076 = 9001 
Geo Key : 3080 = 0.000000 
Geo Key : 3081 = 0.000000 
Geo Key : 3082 = 0.000000 
Geo Key : 3083 = 0.000000 
Geo Key : 3092 = 1.000000 
*/
unsigned char geotiff_web_mercator_tag_dir[]=
{
    /*目錄版本號(2 bytes),修訂版本號(2 bytes),副版本號(2 bytes),地理鍵的個數(2 bytes)*/
    0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x13, 0x00, //
    /*地理鍵ID(2 bytes),存放位置(2 bytes),元素的個數(2 bytes),值/索引(2 bytes) */
    0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 
    0x01, 0x04, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 
    0x02, 0x04, 0xb1, 0x87, 0x25, 0x00, 0x00, 0x00, 
    0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0xff, 0x7f, 
    0x01, 0x08, 0xb1, 0x87, 0x1a, 0x00, 0x25, 0x00,
    0x02, 0x08, 0x00, 0x00, 0x01, 0x00, 0xff, 0x7f, 
    0x06, 0x08, 0x00, 0x00, 0x01, 0x00, 0x8e, 0x23, 
    0x08, 0x08, 0x00, 0x00, 0x01, 0x00, 0xff, 0x7f, 
    0x09, 0x08, 0xb0, 0x87, 0x01, 0x00, 0x05, 0x00, 
    0x0a, 0x08, 0xb0, 0x87, 0x01, 0x00, 0x06, 0x00, 
    0x00, 0x0c, 0x00, 0x00, 0x01, 0x00, 0xff, 0x7f, 
    0x02, 0x0c, 0x00, 0x00, 0x01, 0x00, 0xff, 0x7f,
    0x03, 0x0c, 0x00, 0x00, 0x01, 0x00, 0x07, 0x00,
    0x04, 0x0c, 0x00, 0x00, 0x01, 0x00, 0x29, 0x23,
    0x08, 0x0c, 0xb0, 0x87, 0x01, 0x00, 0x01, 0x00, 
    0x09, 0x0c, 0xb0, 0x87, 0x01, 0x00, 0x00, 0x00, 
    0x0a, 0x0c, 0xb0, 0x87, 0x01, 0x00, 0x03, 0x00, 
    0x0b, 0x0c, 0xb0, 0x87, 0x01, 0x00, 0x04, 0x00,
    0x14, 0x0c, 0xb0, 0x87, 0x01, 0x00, 0x02, 0x00
};

unsigned char geotiff_double_param[]=
{
    0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , //0.0
    0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , //0.0
    0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xf0 , 0x3f , //1.0
    0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , //0.0
    0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , //0.0
    0x00 , 0x00 , 0x00 , 0x40 , 0xa6 , 0x54 , 0x58 , 0x41 , //6378137.0000000000
    0x00 , 0x00 , 0x00 , 0x40 , 0xa6 , 0x54 , 0x58 , 0x41   //6378137.0000000000
};

unsigned char geotiff_ascii_param[]= /*Popular Visualisation CRS / Mercator|Popular Visualisation CRS|*/
{
    0x50 , 0x6f , 0x70 , 0x75 , 0x6c , 0x61 , 0x72 , 0x20 , 
    0x56 , 0x69 , 0x73 , 0x75 , 0x61 , 0x6c , 0x69 , 0x73 , 
    0x61 , 0x74 , 0x69 , 0x6f , 0x6e , 0x20 , 0x43 , 0x52 , 
    0x53 , 0x20 , 0x2f , 0x20 , 0x4d , 0x65 , 0x72 , 0x63 , 
    0x61 , 0x74 , 0x6f , 0x72 , 0x7c , 0x50 , 0x6f , 0x70 , 
    0x75 , 0x6c , 0x61 , 0x72 , 0x20 , 0x56 , 0x69 , 0x73 , 
    0x75 , 0x61 , 0x6c , 0x69 , 0x73 , 0x61 , 0x74 , 0x69 , 
    0x6f , 0x6e , 0x20 , 0x43 , 0x52 , 0x53 , 0x7c , 0x00
};

tiffDeform::tiffDeform()
{
    _tiff_file = NULL;
    _tiff_file = new TiffFile;
    memset( _tiff_file , 0 , sizeof(TiffFile) );
}

tiffDeform::tiffDeform( string tiff_path , string proj4_str )
{
    _tiff_path = tiff_path ;
    _proj4_str = proj4_str ;

    _tiff_file = new TiffFile;
    memset( _tiff_file , 0 , sizeof(TiffFile) );
}

tiffDeform::~tiffDeform()
{
    if( _tiff_file == NULL )
    {
        delete _tiff_file;
        _tiff_file = NULL;
    }
}

bool tiffDeform::arrangement()
{
    return _tiff_file->tile.is_tile;
}

int tiffDeform::open( string tiff_path , string proj4_str , int coord_type )
{
    _tiff_path = tiff_path ;
    _proj4_str = proj4_str ;
    _coord_type = coord_type;
    return tif_open ( tiff_path.c_str() , _tiff_file );
}

void tiffDeform::save(  string src_file , string save_name )
{
    delete _tiff_file;
    _tiff_file = NULL;

    _tiff_path = src_file;
    _tiff_file = new TiffFile;
    memset( _tiff_file , 0 , sizeof(TiffFile) );
    tif_open( _tiff_path.c_str() , _tiff_file );

    //1.獲得原始圖片的范圍坐標
    src_coord_box( );

    //2.計算轉換為WebMector的坐標范圍
    _geo_rect_des = _geo_rect_src;
    _geo_rect_des.left = zone_number( _geo_rect_des.left ) ;
    _geo_rect_des.right = zone_number( _geo_rect_des.right ) ;
    double x1,y1,x2,y2,x3,y3,x4,y4;
    to_web_mector( _geo_rect_des , true ,x1,y1,x2,y2,x3,y3,x4,y4 );

    //3.獲得像元比例
    get_pixel_scale();

    //4.計算新生成的圖片的長度和寬度
    _new_tiff_width = (int)(( _geo_rect_des.right - _geo_rect_des.left )/_scaleX_des + 0.5 );
    _new_tiff_height= (int)(( _geo_rect_des.top - _geo_rect_des.botton )/_scaleY_des + 0.5 );

    //5.獲得原圖片的TAG列表
    get_src_tag_list();


    //6.構造新的TAG列表
    cts_new_tag_list();


    string temp_path;
    if (  save_name == "" )
    {
        temp_path = new_tiff_name() ;
    }
    else
    {
        temp_path = save_name;
    }

    _line_tiff = fopen( temp_path.c_str() , "wb" );
    if ( _line_tiff == NULL )
    {
        return ;
    }
    //7.寫入文件頭
    write_file_header( );

    //8.寫入tag的數量
    fwrite( &( _de_num ) , 1 , 2 , _line_tiff );
    //9.寫入空的DE占位空間
    TIFF_UINT8_T* place_holder = new TIFF_UINT8_T[ _de_num * ONE_DE_SIZE + IDF_END_FLAG_SIZE ];
    memset( place_holder , 0 , _de_num * ONE_DE_SIZE + IDF_END_FLAG_SIZE );
    fwrite( place_holder , 1 , _de_num * ONE_DE_SIZE + IDF_END_FLAG_SIZE , _line_tiff );

    TIFF_UINT64_T write_file_size = ftell( _line_tiff );
    //10.寫入具體的TAG內容和對應的偏移量
    write_tag_list();

    //11.修改圖像數據的偏移量
    modify_strip_offset();

    //12.寫入圖像數據
    //write_img_data();
    //write_img_data_ex();
    //write_img_data_th();
    //write_img_data_th_ex();
    //write_img_data_mul_th( );
    write_img_by_record();
    //write_img_by_sin();
    //write_img_by_block_record();

    //13.關閉文件
    //Sleep( 1000 );
    fclose( _line_tiff );
}

void tiffDeform::write_img_data()
{
    TIFF_UINT32_T* height_start = new TIFF_UINT32_T[ _new_tiff_height *  sizeof(TIFF_UINT32_T) ];
    memset( height_start , 0 ,  _new_tiff_height *  sizeof(TIFF_UINT32_T) );
    int bits =  _tiff_file->bit_per_samples ;
    if ( bits >= 24 )
    {
        if ( !_tiff_file->tile.is_tile )//不是瓦片數據
        {
            fresh_line_start( _tiff_file , height_start );
        }
    }

    fseek( _line_tiff , 0 , SEEK_END );

    _coord_trans.init_proj( coord_google , _proj4_str.c_str() );

    for ( int i_height = 0 ; i_height < _new_tiff_height ; i_height++ )
    {
        system("cls");
        printf( " %s \n Coord Trans %d / %d \n" , _tiff_path.c_str() , i_height + 1 , _new_tiff_height  );
        for ( int i_width = 0 ; i_width < _new_tiff_width ; i_width++ )
        {
            double new_y = _geo_rect_des.top;
            new_y -= ( i_height * _scaleY_des ); 
            double new_x = _geo_rect_des.left;
            new_x += ( i_width * _scaleX_des );

            if ( _coord_type == 0 )
            {
                _coord_trans.xy_2_latlong( new_x , new_y );
            }
            else
            {
                _coord_trans.xy_2_xy( new_x , new_y );
            }

            new_x = src_geo_xy( new_x );

            int pixel_x = 0 , pixel_y = 0 ;
            point_to_by_geo( new_x , new_y , pixel_x , pixel_y );

            TIFF_UINT8_T* buf = new TIFF_UINT8_T[ _tiff_file->samples_per_pixel ];
            memset( buf , 0 , _tiff_file->samples_per_pixel );
            if ( !( pixel_y == -1 || pixel_x == -1 ) )
            {   
                TIFF_UINT32_T pos = height_start[pixel_y] + pixel_x*_tiff_file->samples_per_pixel;
                fseek( _tiff_file->pfile , height_start[pixel_y] + pixel_x*_tiff_file->samples_per_pixel , SEEK_SET );
                fread( buf , _tiff_file->samples_per_pixel , 1 , _tiff_file->pfile );

                fwrite( buf , _tiff_file->samples_per_pixel , 1 , _line_tiff );
            }
            else
            {
                fwrite( buf , _tiff_file->samples_per_pixel , 1 , _line_tiff );
            }
            delete[] buf;
            buf = NULL;
        }
    }
}

void tiffDeform::write_img_data_ex()
{
    TIFF_UINT32_T* height_start = new TIFF_UINT32_T[ _new_tiff_height *  sizeof(TIFF_UINT32_T) ];
    memset( height_start , 0 ,  _new_tiff_height *  sizeof(TIFF_UINT32_T) );
    int bits =  _tiff_file->bit_per_samples ;
    if ( bits >= 24 )
    {
        if ( !_tiff_file->tile.is_tile )//不是瓦片數據
        {
            fresh_line_start( _tiff_file , height_start );
        }
    }

    fseek( _line_tiff , 0 , SEEK_END );

    _coord_trans.init_proj( coord_google , _proj4_str.c_str() );

    printf( "轉換中請稍后... \n" );

    for ( int i_height = 0 ; i_height < _new_tiff_height ; i_height++ )
    {
        //system("cls");
        //printf( " %s \n Coord Trans %d / %d \n" , _tiff_path.c_str() , i_height + 1 , _new_tiff_height  );

        TIFF_UINT8_T* buf = new TIFF_UINT8_T[ _tiff_file->samples_per_pixel * _new_tiff_width ];
        memset( buf , 0 , _tiff_file->samples_per_pixel * _new_tiff_width );
        TIFF_UINT8_T* temp_buf = buf ;

        for ( int i_width = 0 ; i_width < _new_tiff_width ; i_width++ )
        {
            double new_y = _geo_rect_des.top;
            new_y -= ( i_height * _scaleY_des ); 
            double new_x = _geo_rect_des.left;
            new_x += ( i_width * _scaleX_des );

            if ( _coord_type == 0 )
            {
                _coord_trans.xy_2_latlong( new_x , new_y );
            }
            else
            {
                _coord_trans.xy_2_xy( new_x , new_y );
            }

            new_x = src_geo_xy( new_x );//添加帶號

            int pixel_x = 0 , pixel_y = 0 ;
            point_to_by_geo( new_x , new_y , pixel_x , pixel_y );

            //TIFF_UINT8_T* buf = new TIFF_UINT8_T[ _tiff_file->samples_per_pixel ];
            //memset( buf , 0 , _tiff_file->samples_per_pixel );
            if ( !( pixel_y == -1 || pixel_x == -1 ) )
            {   
                TIFF_UINT32_T pos = height_start[pixel_y] + pixel_x*_tiff_file->samples_per_pixel;
                fseek( _tiff_file->pfile , height_start[pixel_y] + pixel_x*_tiff_file->samples_per_pixel , SEEK_SET );
                fread( temp_buf , _tiff_file->samples_per_pixel , 1 , _tiff_file->pfile );

                //fwrite( buf , _tiff_file->samples_per_pixel , 1 , _line_tiff );
                temp_buf += _tiff_file->samples_per_pixel ;
            }
            else
            {
                //fwrite( buf , _tiff_file->samples_per_pixel , 1 , _line_tiff );
                temp_buf += _tiff_file->samples_per_pixel ;
            }
            //delete[] buf;
            //buf = NULL;
        }
        fwrite( buf , _tiff_file->samples_per_pixel * _new_tiff_width , 1 , _line_tiff );
        delete[] buf;
        buf = NULL;
    }

    printf( "轉換完成! \n" );
}

void tiffDeform::to_src_proj_first( geoRECT&des_geo , bool b , double&first_x , double&first_y )
{
/*
      (1)     (2)
        +-----+
        |     |
        |     |
        +-----+
      (3)     (4) 
    */
    //_coord_trans.init_proj( coord_google , _proj4_str.c_str() );
    double x1,y1,x2,y2,x3,y3,x4,y4;
    x1 = des_geo.left;  y1 = des_geo.top;
    x2 = des_geo.right; y2 = des_geo.top;
    x3 = des_geo.left ; y3 = des_geo.botton;
    x4 = des_geo.right; y4 = des_geo.botton;

    if ( _coord_type == 0 )
    {
        _coord_trans.xy_2_latlong( x1 , y1 );
    }
    else
    {
        _coord_trans.xy_2_xy( x1 , y1 );
    }

    first_x = x1 ;
    first_y = y1 ;

    if ( _coord_type == 0 )
    {
        _coord_trans.xy_2_latlong( x2 , y2 );
    }
    else
    {
        _coord_trans.xy_2_xy( x2 , y2 );
    }

    if ( _coord_type == 0 )
    {
        _coord_trans.xy_2_latlong( x3 , y3 );
    }
    else
    {
        _coord_trans.xy_2_xy( x3 , y3 );
    }

    if ( _coord_type == 0 )
    {
        _coord_trans.xy_2_latlong( x4 , y4 );
    }
    else
    {
        _coord_trans.xy_2_xy( x4 , y4 );
    }

    if ( b )
    {
        des_geo.left = x1 < x3 ? x3 : x1;
        des_geo.top = y1 > y2 ? y2 : y1;
        des_geo.right = x2 > x4 ? x4 : x2;
        des_geo.botton = y3 < y4 ? y4 : y3;
    }
    else
    {
        des_geo.left = x1 > x3 ? x3 : x1;
        des_geo.top = y1 < y2 ? y2 : y1;
        des_geo.right = x2 < x4 ? x4 : x2;
        des_geo.botton = y3 > y4 ? y4 : y3;
    }
}

void tiffDeform::to_src_proj( geoRECT&des_geo , bool b )
{
    /*
      (1)     (2)
        +-----+
        |     |
        |     |
        +-----+
      (3)     (4) 
    */
    //_coord_trans.init_proj( coord_google , _proj4_str.c_str() );
    double x1,y1,x2,y2,x3,y3,x4,y4;
    x1 = des_geo.left;  y1 = des_geo.top;
    x2 = des_geo.right; y2 = des_geo.top;
    x3 = des_geo.left ; y3 = des_geo.botton;
    x4 = des_geo.right; y4 = des_geo.botton;

    if ( _coord_type == 0 )
    {
        _coord_trans.xy_2_latlong( x1 , y1 );
    }
    else
    {
        _coord_trans.xy_2_xy( x1 , y1 );
    }

    if ( _coord_type == 0 )
    {
        _coord_trans.xy_2_latlong( x2 , y2 );
    }
    else
    {
        _coord_trans.xy_2_xy( x2 , y2 );
    }

    if ( _coord_type == 0 )
    {
        _coord_trans.xy_2_latlong( x3 , y3 );
    }
    else
    {
        _coord_trans.xy_2_xy( x3 , y3 );
    }

    if ( _coord_type == 0 )
    {
        _coord_trans.xy_2_latlong( x4 , y4 );
    }
    else
    {
        _coord_trans.xy_2_xy( x4 , y4 );
    }

    if ( b )
    {
        des_geo.left = x1 < x3 ? x3 : x1;
        des_geo.top = y1 > y2 ? y2 : y1;
        des_geo.right = x2 > x4 ? x4 : x2;
        des_geo.botton = y3 < y4 ? y4 : y3;
    }
    else
    {
        des_geo.left = x1 > x3 ? x3 : x1;
        des_geo.top = y1 < y2 ? y2 : y1;
        des_geo.right = x2 < x4 ? x4 : x2;
        des_geo.botton = y3 > y4 ? y4 : y3;
    }
}

void tiffDeform::des_geo_to_src_range( geoRECT des_geo , geoRECT&src_range )
{
    to_src_proj( des_geo , false );
    src_range.left = ( des_geo.left - _geo_rect_src.left ) / _scaleX_src - 0.5 ;
    if ( src_range.left < 0 )
    {
        //src_range.left = 0 ;
    }

    src_range.right = ( des_geo.right - _geo_rect_src.left ) / _scaleX_src + 0.5 ;
    if ( src_range.right > _tiff_file->tif_width )
    {
        //src_range.right = _tiff_file->tif_width ;
    }

    src_range.top = ( _geo_rect_src.top - des_geo.top ) / _scaleY_src - 0.5;
    if ( src_range.top < 0 )
    {
        src_range.top = 0;
    }
    src_range.botton = ( _geo_rect_src.top - des_geo.botton ) / _scaleY_src + 0.5;
    if ( src_range.botton > _tiff_file->tif_height )
    {
        src_range.botton = _tiff_file->tif_height ;
    }
}

void tiffDeform::des_geo_to_src_range_first( geoRECT des_geo , geoRECT&src_range , int&first_x , int&first_y )
{
    double fx = 0.0 , fy = 0.0 ;
    to_src_proj_first( des_geo , false , fx , fy );

    first_x = (int)(( fx - _geo_rect_src.left ) / _scaleX_src - 0.5 ) ;
    first_y = (int)(( _geo_rect_src.top - fy ) / _scaleY_src - 0.5); 

    src_range.left = ( des_geo.left - _geo_rect_src.left ) / _scaleX_src - 0.5 ;
    if ( src_range.left < 0 )
    {
        src_range.left = 0 ;
    }

    src_range.right = ( des_geo.right - _geo_rect_src.left ) / _scaleX_src + 0.5 ;
    if ( src_range.right > _tiff_file->tif_width )
    {
        src_range.right = _tiff_file->tif_width ;
    }

    src_range.top = ( _geo_rect_src.top - des_geo.top ) / _scaleY_src - 0.5;
    if ( src_range.top < 0 )
    {
        src_range.top = 0;
    }
    src_range.botton = ( _geo_rect_src.top - des_geo.botton ) / _scaleY_src + 0.5;
    if ( src_range.botton > _tiff_file->tif_height )
    {
        src_range.botton = _tiff_file->tif_height ;
    }
}

void tiffDeform::write_img_data_th()
{
    TIFF_UINT32_T* height_start = new TIFF_UINT32_T[ _new_tiff_height *  sizeof(TIFF_UINT32_T) ];
    memset( height_start , 0 ,  _new_tiff_height *  sizeof(TIFF_UINT32_T) );
    int bits =  _tiff_file->bit_per_samples ;
    if ( bits >= 24 )
    {
        if ( !_tiff_file->tile.is_tile )//不是瓦片數據
        {
            fresh_line_start( _tiff_file , height_start );
        }
    }

    fseek( _line_tiff , 0 , SEEK_END );

    printf( "轉換中請稍后... \n" );

    _coord_trans.init_proj( coord_google , _proj4_str.c_str() );

    for ( int i_height = 0 ; i_height < _new_tiff_height ; i_height++ )
    {
        double line_y = _geo_rect_des.top;
        line_y -= ( i_height * _scaleY_des ); 

        geoRECT new_line_rect ;
        new_line_rect.left = _geo_rect_des.left ;
        new_line_rect.right = _geo_rect_des.right ;
        new_line_rect.top = line_y ;
        new_line_rect.botton = line_y ;
        geoRECT src_range;
        des_geo_to_src_range( new_line_rect , src_range );

        int src_top = ( int )src_range.top;
        int src_bottom = ( int )src_range.botton;
        TIFF_UINT32_T src_buf_size = _tiff_file->samples_per_pixel * _tiff_file->tif_width * ( src_bottom - src_top + 1 ); 
        TIFF_UINT8_T* src_buf = new TIFF_UINT8_T[ src_buf_size ];
        memset( src_buf , 0 , src_buf_size );

        fseek( _tiff_file->pfile , height_start[src_top] , SEEK_SET );
        fread( src_buf ,src_buf_size , 1 , _tiff_file->pfile );

        TIFF_UINT8_T* buf = new TIFF_UINT8_T[ _tiff_file->samples_per_pixel * _new_tiff_width ];
        memset( buf , 0 , _tiff_file->samples_per_pixel * _new_tiff_width );
        TIFF_UINT8_T* temp_buf = buf ;

        for ( int i_width = 0 ; i_width < _new_tiff_width ; i_width++ )
        {
            double new_y = _geo_rect_des.top;
            new_y -= ( i_height * _scaleY_des ); 
            double new_x = _geo_rect_des.left;
            new_x += ( i_width * _scaleX_des );
#if 1
            if ( _coord_type == 0 )
            {
                _coord_trans.xy_2_latlong( new_x , new_y );
            }
            else
            {
                _coord_trans.xy_2_xy( new_x , new_y );
            }

            new_x = src_geo_xy( new_x );//添加帶號

            int pixel_x = 0 , pixel_y = 0 ;
            point_to_by_geo( new_x , new_y , pixel_x , pixel_y );

            if ( !( pixel_y == -1 || pixel_x == -1 ) )
            {   
                memcpy ( temp_buf 
                    , src_buf + ( pixel_y - src_top ) * _tiff_file->samples_per_pixel * _tiff_file->tif_width + pixel_x * _tiff_file->samples_per_pixel 
                    , _tiff_file->samples_per_pixel );

                temp_buf += _tiff_file->samples_per_pixel ;
            }
            else
            {
                temp_buf += _tiff_file->samples_per_pixel ;
            }
#else
            int pixel_x = 0 , pixel_y = 0 ;

            if ( !( pixel_y == -1 || pixel_x == -1 ) )
            {   
                temp_buf += _tiff_file->samples_per_pixel ;
            }
            else
            {
                temp_buf += _tiff_file->samples_per_pixel ;
            }
#endif

        }
        fwrite( buf , _tiff_file->samples_per_pixel * _new_tiff_width , 1 , _line_tiff );
        delete[] buf;
        buf = NULL;

        delete[] src_buf;
        src_buf = NULL ;
    }

    printf( "轉換完成! \n" );
}

void tiffDeform::write_img_data_th_ex()
{
    TIFF_UINT32_T* height_start = new TIFF_UINT32_T[ _new_tiff_height *  sizeof(TIFF_UINT32_T) ];
    memset( height_start , 0 ,  _new_tiff_height *  sizeof(TIFF_UINT32_T) );
    int bits =  _tiff_file->bit_per_samples ;
    if ( bits >= 24 )
    {
        if ( !_tiff_file->tile.is_tile )//不是瓦片數據
        {
            fresh_line_start( _tiff_file , height_start );
        }
    }

    fseek( _line_tiff , 0 , SEEK_END );

    printf( "轉換中請稍后... \n" );

    TIFF_UINT8_T* buf = new TIFF_UINT8_T[ _tiff_file->samples_per_pixel * _new_tiff_width ];
    memset( buf , 0 , _tiff_file->samples_per_pixel * _new_tiff_width );
    _coord_trans.init_proj( coord_google , _proj4_str.c_str() );

    geoRECT new_line_rect ;
    new_line_rect.left = _geo_rect_des.left ;
    new_line_rect.right = _geo_rect_des.right ;

    TIFF_UINT32_T LineBytes = _tiff_file->samples_per_pixel * _tiff_file->tif_width;

    FILE* pf = fopen( "1.txt" , "w" );
    char* pwrite = new char[128];
    int first_x = 0 , first_y = 0;
    for ( int i_height = 0 ; i_height < _new_tiff_height ; i_height++ )
    {
        double line_y = _geo_rect_des.top;
        line_y -= ( i_height * _scaleY_des ); 

        new_line_rect.top = line_y ;
        new_line_rect.botton = line_y ;

        geoRECT src_range;
        des_geo_to_src_range( new_line_rect , src_range );

        int src_top = ( int )src_range.top;
        int src_bottom = ( int )src_range.botton;

        TIFF_UINT32_T src_buf_size =  LineBytes * ( src_bottom - src_top + 1 ); 
        TIFF_UINT8_T* src_buf = new TIFF_UINT8_T[ src_buf_size ];
        memset( src_buf , 0 , src_buf_size );

        fseek( _tiff_file->pfile , height_start[src_top] , SEEK_SET );
        fread( src_buf ,src_buf_size , 1 , _tiff_file->pfile );


        TIFF_UINT8_T* temp_buf = buf ;


        memset( pwrite , 0 , 128 );
        sprintf( pwrite , "第 %d 行\n" , i_height );
        fwrite( pwrite , strlen(pwrite) , 1 , pf );

        for ( int i_width = 0 ; i_width < _new_tiff_width ; i_width++ )
        {
            double new_y = _geo_rect_des.top;
            new_y -= ( i_height * _scaleY_des ); 
            double new_x = _geo_rect_des.left;
            new_x += ( i_width * _scaleX_des );

            if ( _coord_type == 0 )
            {
                _coord_trans.xy_2_latlong( new_x , new_y );
            }
            else
            {
                _coord_trans.xy_2_xy( new_x , new_y );
            }

            new_x = src_geo_xy( new_x );//添加帶號

            int pixel_x = 0 , pixel_y = 0 ;
            point_to_by_geo( new_x , new_y , pixel_x , pixel_y );

            if ( i_width == 0 )
            {
                first_x = pixel_x;
                first_y = pixel_y;
            }
            memset( pwrite , 0 , 128 );
            sprintf( pwrite , "(%d,%d)" , pixel_x - first_x , pixel_y - first_y );
            fwrite( pwrite , strlen(pwrite) , 1 , pf );

            if ( !( pixel_y == -1 || pixel_x == -1 ) )
            {   
                memcpy ( temp_buf 
                    , src_buf + ( pixel_y - src_top ) * LineBytes + pixel_x * _tiff_file->samples_per_pixel 
                    , _tiff_file->samples_per_pixel );

                temp_buf += _tiff_file->samples_per_pixel ;
            }
            else
            {
                temp_buf += _tiff_file->samples_per_pixel ;
            }
        }
        fwrite( buf , _tiff_file->samples_per_pixel * _new_tiff_width , 1 , _line_tiff );

        fwrite( "\n" , 1 , 1 , pf );

        delete[] src_buf;
        src_buf = NULL ;
    }

    delete[] buf;
    buf = NULL;

    printf( "轉換完成! \n" );
}

void tiffDeform::write_img_data_mul_th()
{
    _height_start = new TIFF_UINT32_T[ _new_tiff_height *  sizeof(TIFF_UINT32_T) ];
    memset( _height_start , 0 ,  _new_tiff_height *  sizeof(TIFF_UINT32_T) );
    int bits =  _tiff_file->bit_per_samples ;
    if ( bits >= 24 )
    {
        if ( !_tiff_file->tile.is_tile )//不是瓦片數據
        {
            fresh_line_start( _tiff_file , _height_start );
        }
    }

    fseek( _line_tiff , 0 , SEEK_END );
    _file_size = ftell( _line_tiff );

    printf( "轉換中請稍后... \n" );

    TIFF_UINT8_T* buf = new TIFF_UINT8_T[ _tiff_file->samples_per_pixel * _new_tiff_width ];
    memset( buf , 0 , _tiff_file->samples_per_pixel * _new_tiff_width );
    _coord_trans.init_proj( coord_google , _proj4_str.c_str() );

    geoRECT new_line_rect ;
    new_line_rect.left = _geo_rect_des.left ;
    new_line_rect.right = _geo_rect_des.right ;

    TIFF_UINT32_T LineBytes = _tiff_file->samples_per_pixel * _tiff_file->tif_width;
    TIFF_UINT32_T new_line_bytes = _tiff_file->samples_per_pixel * _new_tiff_width;

    _hMutex = CreateMutex( NULL,FALSE,L"MyFileMutex" );
    m_htiff_write = CreateThread( NULL , 0 , tiff_write_thread , this , 0 , NULL );//啟動新線程

    for ( int i_height = 0 ; i_height < _new_tiff_height / 2  ; i_height++ )
    {
        double line_y = _geo_rect_des.top;
        line_y -= ( i_height * _scaleY_des ); 

        new_line_rect.top = line_y ;
        new_line_rect.botton = line_y ;

        geoRECT src_range;
        des_geo_to_src_range( new_line_rect , src_range );

        int src_top = ( int )src_range.top;
        int src_bottom = ( int )src_range.botton;

        TIFF_UINT32_T src_buf_size =  LineBytes * ( src_bottom - src_top + 1 ); 
        TIFF_UINT8_T* src_buf = new TIFF_UINT8_T[ src_buf_size ];
        memset( src_buf , 0 , src_buf_size );

        fseek( _tiff_file->pfile , _height_start[src_top] , SEEK_SET );
        fread( src_buf ,src_buf_size , 1 , _tiff_file->pfile );


        TIFF_UINT8_T* temp_buf = buf ;

        for ( int i_width = 0 ; i_width < _new_tiff_width ; i_width++ )
        {
            double new_y = _geo_rect_des.top;
            new_y -= ( i_height * _scaleY_des ); 
            double new_x = _geo_rect_des.left;
            new_x += ( i_width * _scaleX_des );

            if ( _coord_type == 0 )
            {
                _coord_trans.xy_2_latlong( new_x , new_y );
            }
            else
            {
                _coord_trans.xy_2_xy( new_x , new_y );
            }

            new_x = src_geo_xy( new_x );//添加帶號

            int pixel_x = 0 , pixel_y = 0 ;
            point_to_by_geo( new_x , new_y , pixel_x , pixel_y );

            if ( !( pixel_y == -1 || pixel_x == -1 ) )
            {   
                memcpy ( temp_buf 
                    , src_buf + ( pixel_y - src_top ) * LineBytes + pixel_x * _tiff_file->samples_per_pixel 
                    , _tiff_file->samples_per_pixel );

                temp_buf += _tiff_file->samples_per_pixel ;
            }
            else
            {
                temp_buf += _tiff_file->samples_per_pixel ;
            }
        }

        TIFF_UINT64_T temp_file_size = _file_size ;
        temp_file_size += /*_tiff_file->samples_per_pixel * _new_tiff_width*/new_line_bytes * i_height ; 


        WaitForSingleObject( _hMutex ,INFINITE );// //等待臨界資源,即鎖定文件
        TIFF_UINT64_T ret = /*fseek*/_fseeki64( _line_tiff , temp_file_size , SEEK_SET );
        int write_ret = fwrite( buf , /*_tiff_file->samples_per_pixel * _new_tiff_width*/new_line_bytes , 1 , _line_tiff );
        ReleaseMutex( _hMutex );//釋放互斥量,解除鎖定

        delete[] src_buf;
        src_buf = NULL ;
    }

    delete[] buf;
    buf = NULL;

    printf( "轉換完成! \n" );
}

DWORD WINAPI tiffDeform::tiff_write_thread( LPVOID lpParameter ) 
{
    tiffDeform* pApp=( tiffDeform* )lpParameter;


    printf( "轉換中請稍后... \n" );

    TIFF_UINT8_T* buf = new TIFF_UINT8_T[ pApp->_tiff_file->samples_per_pixel * pApp->_new_tiff_width ];
    memset( buf , 0 , pApp->_tiff_file->samples_per_pixel * pApp->_new_tiff_width );
    //pApp->_coord_trans.init_proj( coord_google , pApp->_proj4_str.c_str() );

    geoRECT new_line_rect ;
    new_line_rect.left = pApp->_geo_rect_des.left ;
    new_line_rect.right = pApp->_geo_rect_des.right ;

    TIFF_UINT32_T LineBytes = pApp->_tiff_file->samples_per_pixel * pApp->_tiff_file->tif_width ;
    TIFF_UINT32_T new_line_bytes = pApp->_tiff_file->samples_per_pixel * pApp->_new_tiff_width;

    for ( int i_height = pApp->_new_tiff_height / 2 ; i_height < pApp->_new_tiff_height  ; i_height++ )
    {
        double line_y = pApp->_geo_rect_des.top;
        line_y -= ( i_height * pApp->_scaleY_des ); 

        new_line_rect.top = line_y ;
        new_line_rect.botton = line_y ;

        geoRECT src_range;
        pApp->des_geo_to_src_range( new_line_rect , src_range );

        int src_top = ( int )src_range.top;
        int src_bottom = ( int )src_range.botton;

        TIFF_UINT32_T src_buf_size =  LineBytes * ( src_bottom - src_top + 1 ); 
        TIFF_UINT8_T* src_buf = new TIFF_UINT8_T[ src_buf_size ];
        memset( src_buf , 0 , src_buf_size );

        fseek( pApp->_tiff_file->pfile , pApp->_height_start[src_top] , SEEK_SET );
        fread( src_buf ,src_buf_size , 1 , pApp->_tiff_file->pfile );


        TIFF_UINT8_T* temp_buf = buf ;

        for ( int i_width = 0 ; i_width < pApp->_new_tiff_width ; i_width++ )
        {
            double new_y = pApp->_geo_rect_des.top;
            new_y -= ( i_height * pApp->_scaleY_des ); 
            double new_x = pApp->_geo_rect_des.left;
            new_x += ( i_width * pApp->_scaleX_des );

            if ( pApp->_coord_type == 0 )
            {
                pApp->_coord_trans.xy_2_latlong( new_x , new_y );
            }
            else
            {
                pApp->_coord_trans.xy_2_xy( new_x , new_y );
            }

            new_x = pApp->src_geo_xy( new_x );//添加帶號

            int pixel_x = 0 , pixel_y = 0 ;
            pApp->point_to_by_geo( new_x , new_y , pixel_x , pixel_y );

            if ( !( pixel_y == -1 || pixel_x == -1 ) )
            {   
                memcpy ( temp_buf 
                    , src_buf + ( pixel_y - src_top ) * LineBytes + pixel_x * pApp->_tiff_file->samples_per_pixel 
                    , pApp->_tiff_file->samples_per_pixel );

                temp_buf += pApp->_tiff_file->samples_per_pixel ;
            }
            else
            {
                temp_buf += pApp->_tiff_file->samples_per_pixel ;
            }
        }

        TIFF_UINT64_T temp_file_size = pApp->_file_size ;
        temp_file_size += /*pApp->_tiff_file->samples_per_pixel * pApp->_new_tiff_width*/new_line_bytes * i_height ; 

        WaitForSingleObject( pApp->_hMutex ,INFINITE );// //等待臨界資源,即鎖定文件
        TIFF_UINT64_T ret = /*fseek*/_fseeki64( pApp->_line_tiff , temp_file_size , SEEK_SET );
        int write_ret = fwrite( buf , /*pApp->_tiff_file->samples_per_pixel * pApp->_new_tiff_width*/ new_line_bytes , 1 , pApp->_line_tiff );
        ReleaseMutex( pApp->_hMutex );//釋放互斥量,解除鎖定

        delete[] src_buf;
        src_buf = NULL ;
    }

    delete[] buf;
    buf = NULL;

    return 0;
}

void tiffDeform::write_img_by_record()
{
    TIFF_UINT32_T* height_start = new TIFF_UINT32_T[ _new_tiff_height *  sizeof(TIFF_UINT32_T) ];
    memset( height_start , 0 ,  _new_tiff_height *  sizeof(TIFF_UINT32_T) );
    int bits =  _tiff_file->bit_per_samples ;
    if ( bits >= 8 )
    {
        if ( !_tiff_file->tile.is_tile )//不是瓦片數據
        {
            fresh_line_start( _tiff_file , height_start );
        }
    }

    _fseeki64( _line_tiff , 0 , SEEK_END );

    printf( "轉換中請稍后... \n" );

    TIFF_UINT8_T* buf = new TIFF_UINT8_T[ _tiff_file->samples_per_pixel * _new_tiff_width ];
    memset( buf , 0 , _tiff_file->samples_per_pixel * _new_tiff_width );
    _coord_trans.init_proj( coord_google , _proj4_str.c_str() );

    geoRECT new_line_rect ;
    new_line_rect.left = _geo_rect_des.left ;
    new_line_rect.right = _geo_rect_des.right ;

    TIFF_UINT32_T LineBytes = _tiff_file->samples_per_pixel * _tiff_file->tif_width;

    //計算中間行的斜率
    double line_y = _geo_rect_des.top;
    line_y -= ( _tiff_file->tif_height / 2 * _scaleY_des ); 
    new_line_rect.top = line_y ;
    new_line_rect.botton = line_y ;

    geoRECT src_range;
    des_geo_to_src_range( new_line_rect , src_range );
    int src_top = ( int )src_range.top;
    int src_bottom = ( int )src_range.botton;

    TIFF_UINT32_T src_buf_size =  LineBytes * ( src_bottom - src_top + 1 ); 
    TIFF_UINT8_T* src_buf = new TIFF_UINT8_T[ src_buf_size ];
    memset( src_buf , 0 , src_buf_size );

    _fseeki64( _tiff_file->pfile , height_start[src_top] , SEEK_SET );
    fread( src_buf ,src_buf_size , 1 , _tiff_file->pfile );

    int *diff_x = new int[ _new_tiff_width ] ;memset( diff_x , 0 , _new_tiff_width );
    int *diff_y = new int[ _new_tiff_width ] ;memset( diff_y , 0 , _new_tiff_width );
    int first_x = 0 , first_y = 0;
    for ( int i_width = 0 ; i_width < _new_tiff_width ; i_width++ )
    {
        double new_y = new_line_rect.top;
        double new_x = _geo_rect_des.left;
        new_x += ( i_width * _scaleX_des );

        if ( _coord_type == 0 )
        {
            _coord_trans.xy_2_latlong( new_x , new_y );
        }
        else
        {
            _coord_trans.xy_2_xy( new_x , new_y );
        }

        new_x = src_geo_xy( new_x );//添加帶號

        int pixel_x = 0 , pixel_y = 0 ;
        point_to_by_geo_ex( new_x , new_y , pixel_x , pixel_y );

        if ( i_width == 0 )
        {
            diff_x[0] = 0 ;
            diff_y[0] = 0 ;
            first_x = pixel_x ;
            first_y = pixel_y ;
        }
        else
        {
            diff_x[ i_width ] = pixel_x - first_x;
            diff_y[ i_width ] = pixel_y - first_y;
        }
    }

    for ( int i_height = 0 ; i_height < _new_tiff_height ; i_height++ )
    {

        int pixel_first_x = 0 , pixel_first_y = 0 ;

        double line_y = _geo_rect_des.top;
        line_y -= ( i_height * _scaleY_des ); 

        new_line_rect.top = line_y ;
        new_line_rect.botton = line_y ;

        geoRECT src_range;
        des_geo_to_src_range_first( new_line_rect , src_range , pixel_first_x , pixel_first_y );

        int src_top = ( int )src_range.top;
        int src_bottom = ( int )src_range.botton;

        TIFF_UINT32_T src_buf_size =  LineBytes * ( src_bottom - src_top + 1 ); 
        TIFF_UINT8_T* src_buf = new TIFF_UINT8_T[ src_buf_size ];
        memset( src_buf , 0 , src_buf_size );

        _fseeki64( _tiff_file->pfile , height_start[src_top] , SEEK_SET );
        fread( src_buf ,src_buf_size , 1 , _tiff_file->pfile );

        TIFF_UINT8_T* temp_buf = buf ;

        for ( int i_width = 0 ; i_width < _new_tiff_width ; i_width++ )
        {
            int pixel_x = 0 , pixel_y = 0 ;

            pixel_x = /*( int )src_range.left*/pixel_first_x + diff_x[ i_width ];
            pixel_y = /*( int )src_range.top*/pixel_first_y + diff_y[ i_width ];

            if ( pixel_y <  (int)src_range.top || pixel_y > (int) src_range.botton )
            {
                pixel_y = -1;
            }
            if ( pixel_x < 0 || pixel_x > _tiff_file->tif_width )
            {
                pixel_x = 0;
            }
            if ( !( pixel_y == -1 || pixel_x == -1 ) )
            {   
                memcpy ( temp_buf 
                    , src_buf + ( pixel_y - src_top ) * LineBytes + pixel_x * _tiff_file->samples_per_pixel 
                    , _tiff_file->samples_per_pixel );

                temp_buf += _tiff_file->samples_per_pixel ;
            }
            else
            {
                temp_buf += _tiff_file->samples_per_pixel ;
            }
        }
        fwrite( buf , _tiff_file->samples_per_pixel * _new_tiff_width , 1 , _line_tiff );

        delete[] src_buf;
        src_buf = NULL ;
    }

    delete[] buf;
    buf = NULL;

    //printf( "轉換完成! \n" );
}

void tiffDeform::write_img_by_block_record( )
{
    TIFF_UINT32_T* height_start = new TIFF_UINT32_T[ _new_tiff_height *  sizeof( TIFF_UINT32_T ) ];
    memset( height_start , 0 ,  _new_tiff_height *  sizeof(TIFF_UINT32_T) );
    int bits =  _tiff_file->bit_per_samples ;
    if ( bits >= 24 )
    {
        if ( !_tiff_file->tile.is_tile )//不是瓦片數據
        {
            fresh_line_start( _tiff_file , height_start );
        }
    }

    fseek( _line_tiff , 0 , SEEK_END );

    int bc = 0;
    int blockCount = 64;
    DiffValue** diff = (DiffValue **)malloc(blockCount * sizeof(DiffValue *));;
    for(bc=0; bc<blockCount; bc++){
        diff[bc] = new DiffValue[ _new_tiff_width ];
        memset( diff[bc] , 0 , sizeof( DiffValue ) );
    }

    //分成四部分分別計算差值
/*  DiffValue* diff1 = new DiffValue[ _new_tiff_width ];
    memset( diff1 , 0 , sizeof( DiffValue ) );
    DiffValue* diff2 = new DiffValue[ _new_tiff_width ];
    memset( diff2 , 0 , sizeof( DiffValue ) );
    DiffValue* diff3 = new DiffValue[ _new_tiff_width ];
    memset( diff3 , 0 , sizeof( DiffValue ) );
    DiffValue* diff4 = new DiffValue[ _new_tiff_width ];
    memset( diff4 , 0 , sizeof( DiffValue ) );*/

    int block_interval = _new_tiff_height / blockCount ;

/*  TIFF_UINT16_T height_pos[4] = { 0 , 0 , 0 , 0 } ;         //每部分的中間位置
    height_pos[0] = block_interval / 2;                       //第一部分的中間行
    height_pos[1] = block_interval + block_interval / 2;      //第二部分的中間位置
    height_pos[2] = _new_tiff_height / 2 + block_interval / 2;//第三部分的中間位置行
    height_pos[3] = _new_tiff_height - block_interval / 2;    //第四部分的中間位置行*/

    TIFF_UINT16_T *height_pos = (TIFF_UINT16_T *)malloc(sizeof(TIFF_UINT16_T) * blockCount);
    for(bc=0; bc<blockCount; bc++)
    {
        height_pos[bc] = block_interval / 2 + block_interval * bc;                       //第一部分的中間行
    }
    _coord_trans.init_proj( coord_google , _proj4_str.c_str() );//初始化proj4

/*  geoRECT temp_geo2 , temp_geo1 , temp_geo3 , temp_geo4 ;
    memset( &temp_geo1 , 0 , sizeof( geoRECT ) );
    memset( &temp_geo2 , 0 , sizeof( geoRECT ) );
    memset( &temp_geo3 , 0 , sizeof( geoRECT ) );
    memset( &temp_geo4 , 0 , sizeof( geoRECT ) );

    temp_geo1.left = _geo_rect_des.left ;
    temp_geo1.top = _geo_rect_des.top ;
    temp_geo1.top -= ( height_pos[0] * _scaleY_des );

    temp_geo2.left = _geo_rect_des.left ;
    temp_geo2.top = _geo_rect_des.top ;
    temp_geo2.top -= ( height_pos[1] * _scaleY_des ); 

    temp_geo3.left = _geo_rect_des.left ;
    temp_geo3.top = _geo_rect_des.top ;
    temp_geo3.top -= ( height_pos[2] * _scaleY_des ); 

    temp_geo4.left = _geo_rect_des.left ;
    temp_geo4.top = _geo_rect_des.top ;
    temp_geo4.top -= ( height_pos[3] * _scaleY_des ); 

    int first1_x = 0 , first1_y = 0 ;
    int first2_x = 0 , first2_y = 0 ;
    int first3_x = 0 , first3_y = 0 ;
    int first4_x = 0 , first4_y = 0 ;*/

    geoRECT *temp_geo = (geoRECT *)malloc(sizeof(geoRECT) * blockCount);
    int *first_x = (int *)malloc(sizeof(int) * blockCount);
    int *first_y = (int *)malloc(sizeof(int) * blockCount);
    for(bc=0; bc<blockCount; bc++)
    {
        memset( &temp_geo[bc] , 0 , sizeof( geoRECT ) );

        temp_geo[bc].left = _geo_rect_des.left ;
        temp_geo[bc].top = _geo_rect_des.top ;
        temp_geo[bc].top -= ( height_pos[bc] * _scaleY_des );

        first_x[bc] = 0;
        first_y[bc] = 0;
    }

    TIFF_UINT32_T LineBytes = _tiff_file->samples_per_pixel * _tiff_file->tif_width;

    for ( int i_new_w = 0 ; i_new_w < _new_tiff_width ; i_new_w ++ )
    {
        for( bc = 0 ; bc < blockCount ; bc ++ )
        {
            double new_y = temp_geo[bc].top;
            double new_x = _geo_rect_des.left;
            new_x += ( i_new_w * _scaleX_des );

            if ( _coord_type == 0 )
            {
                _coord_trans.xy_2_latlong( new_x , new_y );
            }
            else
            {
                _coord_trans.xy_2_xy( new_x , new_y );
            }

            new_x = src_geo_xy( new_x );//添加帶號

            int pixel_x = 0 , pixel_y = 0 ;
            point_to_by_geo( new_x , new_y , pixel_x , pixel_y );

            if ( i_new_w == 0 )
            {
                double new_y = temp_geo[bc].top;
                double new_x = _geo_rect_des.left;
                new_x += ( _new_tiff_width /2 * _scaleX_des );
                if ( _coord_type == 0 )
                {
                    _coord_trans.xy_2_latlong( new_x , new_y );
                }
                else
                {
                    _coord_trans.xy_2_xy( new_x , new_y );
                }

                new_x = src_geo_xy( new_x );//添加帶號

                int pixel_x = 0 , pixel_y = 0 ;
                point_to_by_geo( new_x , new_y , pixel_x , pixel_y );

                diff[bc][_new_tiff_width /2].diff_x = 0 ;
                diff[bc][_new_tiff_width /2].diff_y = 0 ;
                first_x[bc] = pixel_x ;
                first_y[bc] = pixel_y ;
            }
            else
            {
                diff[bc][ i_new_w ].diff_x = pixel_x - first_x[bc] ;
                diff[bc][ i_new_w ].diff_y = pixel_y - first_y[bc] ;
            }
        }
/*      //第一部分
        double new_y = temp_geo1.top;
        double new_x = _geo_rect_des.left;
        new_x += ( i_new_w * _scaleX_des );

        if ( _coord_type == 0 )
        {
            _coord_trans.xy_2_latlong( new_x , new_y );
        }
        else
        {
            _coord_trans.xy_2_xy( new_x , new_y );
        }

        new_x = src_geo_xy( new_x );//添加帶號

        int pixel_x = 0 , pixel_y = 0 ;
        point_to_by_geo( new_x , new_y , pixel_x , pixel_y );

        if ( i_new_w == 0 )
        {
            diff1[0].diff_x = 0 ;
            diff1[0].diff_y = 0 ;
            first1_x = pixel_x ;
            first1_y = pixel_y ;
        }
        else
        {
            diff1[ i_new_w ].diff_x = pixel_x - first1_x ;
            diff1[ i_new_w ].diff_y = pixel_y - first1_y ;
        }

        //第二部分
        new_y = temp_geo2.top;
        new_x = _geo_rect_des.left;
        new_x += ( i_new_w * _scaleX_des );

        if ( _coord_type == 0 )
        {
            _coord_trans.xy_2_latlong( new_x , new_y );
        }
        else
        {
            _coord_trans.xy_2_xy( new_x , new_y );
        }

        new_x = src_geo_xy( new_x );//添加帶號

        pixel_x = 0 , pixel_y = 0 ;
        point_to_by_geo( new_x , new_y , pixel_x , pixel_y );

        if ( i_new_w == 0 )
        {
            diff2[0].diff_x = 0 ;
            diff2[0].diff_y = 0 ;
            first2_x = pixel_x ;
            first2_y = pixel_y ;
        }
        else
        {
            diff2[ i_new_w ].diff_x = pixel_x - first2_x ;
            diff2[ i_new_w ].diff_y = pixel_y - first2_y ;
        }

        //第三部分
        new_y = temp_geo3.top;
        new_x = _geo_rect_des.left;
        new_x += ( i_new_w * _scaleX_des );

        if ( _coord_type == 0 )
        {
            _coord_trans.xy_2_latlong( new_x , new_y );
        }
        else
        {
            _coord_trans.xy_2_xy( new_x , new_y );
        }

        new_x = src_geo_xy( new_x );//添加帶號

        pixel_x = 0 , pixel_y = 0 ;
        point_to_by_geo( new_x , new_y , pixel_x , pixel_y );

        if ( i_new_w == 0 )
        {
            diff3[0].diff_x = 0 ;
            diff3[0].diff_y = 0 ;
            first3_x = pixel_x ;
            first3_y = pixel_y ;
        }
        else
        {
            diff3[ i_new_w ].diff_x = pixel_x - first3_x ;
            diff3[ i_new_w ].diff_y = pixel_y - first3_y ;
        }

        //第四部分
        new_y = temp_geo4.top;
        new_x = _geo_rect_des.left;
        new_x += ( i_new_w * _scaleX_des );

        if ( _coord_type == 0 )
        {
            _coord_trans.xy_2_latlong( new_x , new_y );
        }
        else
        {
            _coord_trans.xy_2_xy( new_x , new_y );
        }

        new_x = src_geo_xy( new_x );//添加帶號

        pixel_x = 0 , pixel_y = 0 ;
        point_to_by_geo( new_x , new_y , pixel_x , pixel_y );

        if ( i_new_w == 0 )
        {
            diff4[0].diff_x = 0 ;
            diff4[0].diff_y = 0 ;
            first4_x = pixel_x ;
            first4_y = pixel_y ;
        }
        else
        {
            diff4[ i_new_w ].diff_x = pixel_x - first4_x ;
            diff4[ i_new_w ].diff_y = pixel_y - first4_y ;
        }*/
    }

    geoRECT new_line_rect ;
    memset( &new_line_rect , 0 , sizeof( geoRECT ) );
    new_line_rect.left = _geo_rect_des.left ;
    new_line_rect.right = _geo_rect_des.right ;

    TIFF_UINT8_T* buf = new TIFF_UINT8_T[ _tiff_file->samples_per_pixel * _new_tiff_width ];
    memset( buf , 0 , _tiff_file->samples_per_pixel * _new_tiff_width );

    for ( int i_height = 0 ; i_height < _new_tiff_height ; i_height++ )
    {
        double line_y = _geo_rect_des.top;
        line_y -= ( i_height * _scaleY_des ); 

        new_line_rect.top = line_y ;
        new_line_rect.botton = line_y ;

        geoRECT src_range;
        des_geo_to_src_range( new_line_rect , src_range );

        int src_top = ( int )src_range.top;
        int src_bottom = ( int )src_range.botton;

        TIFF_UINT32_T src_buf_size =  LineBytes * ( src_bottom - src_top + 1 ); 
        TIFF_UINT8_T* src_buf = new TIFF_UINT8_T[ src_buf_size ];
        memset( src_buf , 0 , src_buf_size );

        fseek( _tiff_file->pfile , height_start[src_top] , SEEK_SET );
        fread( src_buf ,src_buf_size , 1 , _tiff_file->pfile );

        TIFF_UINT8_T* temp_buf = buf ;

        DiffValue* ptemp = NULL ;

        for(bc=0; bc<blockCount; bc++)
        {
            if(i_height <= block_interval * (bc+1) && i_height >= block_interval * (bc))
            {
                ptemp = diff[bc];
            }
        }
        if(!ptemp) break;
/*      if ( i_height <= block_interval )
        {
            ptemp = diff1;
        }
        else if ( i_height > block_interval && i_height <= _new_tiff_height/2 )
        {
            ptemp = diff2;
        }
        else if ( i_height > _new_tiff_height/2 && i_height < ( _new_tiff_height/2 + block_interval ) )
        {
            ptemp = diff3 ;
        }
        else if ( i_height >= ( _new_tiff_height/2 + block_interval ) )
        {
            ptemp = diff4;
        }*/

        for ( int i_width = 0 ; i_width < _new_tiff_width ; i_width++ )
        {
            int pixel_x = 0 , pixel_y = 0 ;
            //if( i_width <= _new_tiff_width/2 )
            /*{
                pixel_x = ( int )src_range.left - ptemp[i_width].diff_x ;
                pixel_y = ( int )src_range.botton - ptemp[i_width].diff_y ;
            }*/
            /*else*/
            {
                pixel_x = ( int )src_range.left + ptemp[i_width].diff_x ;
                pixel_y = ( int )src_range.botton + ptemp[i_width].diff_y ;
            }

            if ( pixel_y <  (int)src_range.top || pixel_y > (int) src_range.botton )
            {
                pixel_y = -1;
            }
            if ( pixel_x < 0 || pixel_x > _tiff_file->tif_width )
            {
                pixel_x = 0;
            }
            if ( !( pixel_y == -1 || pixel_x == -1 ) )
            {   
                memcpy ( temp_buf 
                    , src_buf + ( pixel_y - src_top ) * LineBytes + pixel_x * _tiff_file->samples_per_pixel 
                    , _tiff_file->samples_per_pixel );

                temp_buf += _tiff_file->samples_per_pixel ;
            }
            else
            {
                temp_buf += _tiff_file->samples_per_pixel ;
            }
        }
        fwrite( buf , _tiff_file->samples_per_pixel * _new_tiff_width , 1 , _line_tiff );

        delete[] src_buf;
        src_buf = NULL ;
    }

/*  delete[] diff1;
    diff1 = NULL ;
    delete[] diff2;
    diff2 = NULL ;
    delete[] diff3;
    diff3 = NULL ;
    delete[] diff4;
    diff4 = NULL ;*/
}

void tiffDeform::write_img_by_sin()
{
    TIFF_UINT32_T* height_start = new TIFF_UINT32_T[ _new_tiff_height *  sizeof(TIFF_UINT32_T) ];
    memset( height_start , 0 ,  _new_tiff_height *  sizeof(TIFF_UINT32_T) );
    int bits =  _tiff_file->bit_per_samples ;
    if ( bits >= 24 )
    {
        if ( !_tiff_file->tile.is_tile )//不是瓦片數據
        {
            fresh_line_start( _tiff_file , height_start );
        }
    }

    fseek( _line_tiff , 0 , SEEK_END );

    printf( "轉換中請稍后... \n" );

    TIFF_UINT8_T* buf = new TIFF_UINT8_T[ _tiff_file->samples_per_pixel * _new_tiff_width ];
    memset( buf , 0 , _tiff_file->samples_per_pixel * _new_tiff_width );
    _coord_trans.init_proj( coord_google , _proj4_str.c_str() );

    geoRECT new_line_rect ;
    new_line_rect.left = _geo_rect_des.left ;
    new_line_rect.right = _geo_rect_des.right ;

    TIFF_UINT32_T LineBytes = _tiff_file->samples_per_pixel * _tiff_file->tif_width;

    //計算中間行的斜率
    double line_y = _geo_rect_des.top;
    line_y -= ( _tiff_file->tif_height / 2 * _scaleY_des ); 
    new_line_rect.top = line_y ;
    new_line_rect.botton = line_y ;

    geoRECT new_line_rect_2 = new_line_rect ;
    to_src_proj( new_line_rect_2 , /*true*/false );
    //傾斜角的正切值
    double slope_tan = ( new_line_rect_2.top - new_line_rect_2.botton ) / ( new_line_rect_2.right - new_line_rect_2.left );

    //傾斜角的正弦值
    double hypotenuse_line = sqrt( ( new_line_rect_2.top - new_line_rect_2.botton )*( new_line_rect_2.top - new_line_rect_2.botton ) 
        + ( new_line_rect_2.right - new_line_rect_2.left )*( new_line_rect_2.right - new_line_rect_2.left ) );
    double slope_sin = ( new_line_rect_2.top - new_line_rect_2.botton ) / hypotenuse_line ;
    //傾斜角的余弦值
    double slope_cos = ( new_line_rect_2.right - new_line_rect_2.left ) / hypotenuse_line;
    //X方向上的放大比例
    double scale_x = ( double )_tiff_file->tif_width / _new_tiff_width ;

    geoRECT src_range;
    des_geo_to_src_range( new_line_rect , src_range );
    int src_top = ( int )src_range.top;
    int src_bottom = ( int )src_range.botton;

    TIFF_UINT32_T src_buf_size =  LineBytes * ( src_bottom - src_top + 1 ); 
    TIFF_UINT8_T* src_buf = new TIFF_UINT8_T[ src_buf_size ];
    memset( src_buf , 0 , src_buf_size );

    fseek( _tiff_file->pfile , height_start[src_top] , SEEK_SET );
    fread( src_buf ,src_buf_size , 1 , _tiff_file->pfile );

    for ( int i_height = 0 ; i_height < _new_tiff_height ; i_height++ )
    {
        double line_y = _geo_rect_des.top;
        line_y -= ( i_height * _scaleY_des ); 

        new_line_rect.top = line_y ;
        new_line_rect.botton = line_y ;

        geoRECT src_range;
        des_geo_to_src_range( new_line_rect , src_range );

        int src_top = ( int )src_range.top;
        int src_bottom = ( int )src_range.botton;

        TIFF_UINT32_T src_buf_size =  LineBytes * ( src_bottom - src_top + 1 ); 
        TIFF_UINT8_T* src_buf = new TIFF_UINT8_T[ src_buf_size ];
        memset( src_buf , 0 , src_buf_size );

        fseek( _tiff_file->pfile , height_start[src_top] , SEEK_SET );
        fread( src_buf ,src_buf_size , 1 , _tiff_file->pfile );

        //計算第一個點坐標
        int pixel_first_x = 0 , pixel_first_y = 0 ;
        {
            double new_y = _geo_rect_des.top;
            new_y -= ( i_height * _scaleY_des ); 
            double new_x = _geo_rect_des.left;

            if ( _coord_type == 0 )
            {
                _coord_trans.xy_2_latlong( new_x , new_y );
            }
            else
            {
                _coord_trans.xy_2_xy( new_x , new_y );
            }

            new_x = src_geo_xy( new_x );


            point_to_by_geo_ex( new_x , new_y , pixel_first_x , pixel_first_y );
        }

        TIFF_UINT8_T* temp_buf = buf ;

        for ( int i_width = 0 ; i_width < _new_tiff_width ; i_width ++ )
        {
            int pixel_x = 0 , pixel_y = 0 ;
            pixel_x = /*( int )src_range.left*/( int )( pixel_first_x + ( i_width * scale_x + 0.5 )) ;
            pixel_y = /*( int )src_range.botton*/( int )( pixel_first_y - ( pixel_x * slope_tan + 0.5 )) ;

            if ( pixel_y <  (int)src_range.top || pixel_y > (int) src_range.botton )
            {
                pixel_y = -1;
            }
            if ( pixel_x < 0 || pixel_x > _tiff_file->tif_width )
            {
                pixel_x = 0;
            }
            if ( !( pixel_y == -1 || pixel_x == -1 ) )
            {   
                memcpy ( temp_buf 
                    , src_buf + ( pixel_y - src_top ) * LineBytes + pixel_x * _tiff_file->samples_per_pixel 
                    , _tiff_file->samples_per_pixel );

                temp_buf += _tiff_file->samples_per_pixel ;
            }
            else
            {
                temp_buf += _tiff_file->samples_per_pixel ;
            }
        }
        fwrite( buf , _tiff_file->samples_per_pixel * _new_tiff_width , 1 , _line_tiff );

        delete[] src_buf;
        src_buf = NULL ;
    }

    delete[] buf;
    buf = NULL;

    //printf( "轉換完成! \n" );
}

void tiffDeform::point_to_by_geo( double x , double y , int&pt_x , int&pt_y )
{
    pt_x = (int)(( x - _geo_rect_src.left )/_scaleX_src + 0.5 );//計算像素點的在原始圖片的范圍
    pt_y = (int)( ( _geo_rect_src.top - y ) / _scaleY_src + 0.5 );

    if ( !(pt_x <= _tiff_file->tif_width && pt_x >= 0) )//像素點出了范圍
    {
        pt_x = -1;
    }

    if( !(pt_y <= _tiff_file->tif_height && pt_y >= 0 ) )//像素點出了范圍
    {
        pt_y = -1;
    }

}

void tiffDeform::point_to_by_geo_ex( double x , double y , int&pt_x , int&pt_y )
{
    pt_x = (int)(( x - _geo_rect_src.left )/_scaleX_src + 0.5 );//計算像素點的在原始圖片的范圍
    pt_y = (int)( ( _geo_rect_src.top - y ) / _scaleY_src + 0.5 );
}

string tiffDeform::new_tiff_name()
{
    int pos = _tiff_path.rfind( '\\' );
    string tiff_name = _tiff_path.substr( pos + 1 );
    string dir = _tiff_path.substr( 0 , pos + 1 );
    string temp_name = "line_";
    temp_name += tiff_name ;
    return ( dir + temp_name ) ;
}

void tiffDeform::write_tag_list()
{
    for ( int i = 0 ; i < _de_num ; i++ )
    {
        fseek( _line_tiff , DE_START + ONE_DE_SIZE * i , SEEK_SET );
        fwrite( &( de_list[i].de.tag ) , 2 , 1 , _line_tiff );   //TAG 2字節
        fwrite( &( de_list[i].de.type ) , 2 , 1 , _line_tiff );  //數據類型 2字節
        fwrite( &( de_list[i].de.count ) , 4 , 1 , _line_tiff ); //count 4字節    

        if( de_list[i].de.tag == 273 )//Strip offset
        {
            fseek( _line_tiff , 0 , SEEK_END );
            _strip_offset_pos = ftell( _line_tiff );
        }

        //寫入offset
        if( de_list[i].data_source == 0 )//直接寫入值
        {
            fwrite( &( de_list[i].de.offset ) , 4 , 1 , _line_tiff );
        }
        else if ( de_list[i].data_source == 1 )//文件對應的偏移量
        {
            fseek( _line_tiff , 0 , SEEK_END );

            TIFF_UINT32_T pos = ftell( _line_tiff );

            TIFF_UINT64_T buffer_size = data_type_list[de_list[i].de.type].type_size * de_list[i].de.count;
            file_disk_data( de_list[i].de , buffer_size );

            //修改TAG對應的數據存放的地址
            fseek( _line_tiff , DE_START + ONE_DE_SIZE * i + 8 , SEEK_SET );
            fwrite( &pos , 1 , 4 , _line_tiff );
        }
        else if ( de_list[i].data_source == 2 )//內存
        {
            fseek( _line_tiff , 0 , SEEK_END );
            TIFF_UINT32_T pos = ftell( _line_tiff );
            fwrite ( de_list[i].mem_data , 1 ,  data_type_list[de_list[i].de.type].type_size * de_list[i].de.count  , _line_tiff );

            //修改TAG對應的數據存放的地址
            fseek( _line_tiff , DE_START + ONE_DE_SIZE * i + 8 , SEEK_SET );
            fwrite( &pos , 1 , 4 , _line_tiff );

            if ( de_list[i].de.tag == 33550 
                || de_list[i].de.tag == 33922
                || de_list[i].de.tag == 34735
                || de_list[i].de.tag == 34736
                || de_list[i].de.tag == 34737)//這些屬於靜態內存不需要釋放
            {
                continue;
            }
            delete[] de_list[i].mem_data;
        }
    }
}

TIFF_UINT64_T tiffDeform::file_disk_data( DirectoryEntry de , TIFF_UINT64_T buffer_size )
{
    fseek( _tiff_file->pfile , de.offset , SEEK_SET );

    TIFF_UINT8_T* buf = new TIFF_UINT8_T[1024];
    memset( buf , 0 , 1024 );

    TIFF_UINT64_T fs = 0;
    TIFF_UINT16_T read_size = 0;
    if ( buffer_size <= 1024 )//若小於1024字節,則讀取之后直接寫入即可
    {
        read_size = fread( buf , 1 , buffer_size , _tiff_file->pfile );

        if( _tiff_file->tiff_byte_order == TIFF_BIGENDIAN && data_type_list[de.type].type_size != 1 )
        {
            sort_byte_order( buf , de.type , de.count );
        }

        fs += fwrite ( buf , 1 , read_size , _line_tiff );
    }
    else//若大於1024字節,則分批寫入1024字節,最后寫入不足1024的字節
    {
        TIFF_UINT16_T tile_num = ( int )(buffer_size / 1024) ;
        TIFF_UINT16_T last_num = buffer_size % 1024;
        for ( int i = 0 ; i < tile_num ; i++ )
        {
            read_size = fread( buf , 1 , 1024 , _tiff_file->pfile );//注意參數的順序
            if( _tiff_file->tiff_byte_order == TIFF_BIGENDIAN && data_type_list[de.type].type_size != 1 )
            {
                sort_byte_order( buf , de.type , de.count );
            }
            fs += fwrite ( buf , 1 , read_size , _line_tiff );
        }

        read_size = fread( buf , 1 , last_num , _tiff_file->pfile );
        if( _tiff_file->tiff_byte_order == TIFF_BIGENDIAN && data_type_list[de.type].type_size != 1 )
        {
            sort_byte_order( buf , de.type , de.count );
        }
        fs += fwrite ( buf , 1 , last_num , _line_tiff );
    }
    delete[] buf;
    buf = NULL;
    return fs;
}

void tiffDeform::sort_byte_order( TIFF_UINT8_T* buf , TIFF_UINT16_T data_type , TIFF_UINT16_T data_count )
{
    TIFF_UINT8_T* p = buf;

    for ( TIFF_UINT16_T i = 0 ; i < data_count ; i++ )
    {
        if ( data_type == 3 || data_type == 8 )//SHORT
        {
            TIFF_UINT16_T ret = sget2( p , TIFF_BIGENDIAN );
            memcpy( p , &ret , 2 );
            p += 2;
        }
        else if ( data_type == 4 ||  data_type == 9 ||  data_type == 11 )//LONG
        {
            TIFF_UINT32_T ret = sget4( p , TIFF_BIGENDIAN );
            memcpy( p , &ret , 4 );
            p += 4;
        }
        if ( data_type == 5 || data_type == 10 )
        {
            TIFF_UINT32_T ret = sget4( p , TIFF_BIGENDIAN );
            memcpy( p , &ret , 4 );
            p += 4;

            ret = sget4( p , TIFF_BIGENDIAN );
            memcpy( p , &ret , 4 );
            p += 4;
        }
        else if ( data_type == 12 )//DOUBLE
        {
            TIFF_UINT64_T ret = sget8( p , TIFF_BIGENDIAN );
            memcpy( p , &ret , 8 );
            p += 8;
        }
    }
}

//修改strip offset所對應的值
void tiffDeform::modify_strip_offset()
{
    fseek( _line_tiff , 0 , SEEK_END );
    TIFF_UINT32_T current_size = ftell( _line_tiff );
    fseek( _line_tiff , _strip_offset_pos , SEEK_SET );

    TIFF_UINT32_T width_bytes = _new_tiff_width * _tiff_file->samples_per_pixel ;
    for ( int i = 0 ; i < _new_tiff_height ; i++ )
    {
        TIFF_UINT32_T height_start = current_size + i * width_bytes;
        fwrite( &height_start , 1 , 4 , _line_tiff );
    }
}

void tiffDeform::write_file_header( )
{
    //字節序   
    fwrite( "II" , 2 , 1 , _line_tiff );

    //版本號
    TIFF_UINT16_T ver = 0x002a;
    fwrite( &ver , 2 , 1 , _line_tiff );

    //Tag偏移量
    TIFF_UINT32_T offset = 0x00000008;
    fwrite( &offset , 4 , 1 , _line_tiff );
}

void tiffDeform::src_coord_box( )
{
    geoRECT pixel_rect;
    pixel_rect.left = 0 ;
    pixel_rect.top = 0;
    pixel_rect.right = _tiff_file->tif_width;
    pixel_rect.botton = _tiff_file->tif_height ;
    geo_coord( _tiff_file , pixel_rect , _geo_rect_src );
}

double tiffDeform::zone_number( double left_right )
{
    if( _coord_type == 0 )
    {
        return left_right;
    }

    if( left_right/10000000 > 1 )
    {
        return left_right;
    }
    else
    {
        int zone_n = get_zone_num( _proj4_str );
        left_right += ( zone_n * 1000000 );
        return left_right;
    }
}

int tiffDeform::get_zone_num( string proj4_str )
{
    int pos = proj4_str.find("+x_0=");
    string str = proj4_str.substr( pos + 5 );
    return atoi( str.substr( 0 , 2 ).c_str() );
}

double tiffDeform::src_geo_xy( double left_right )
{
    if( _coord_type == 0 )
    {
        return left_right;
    }
    if ( _geo_rect_src.left / 10000000 > 1 )
    {
        return left_right;
    }
    else
    {
        int zone_n = get_zone_num( _proj4_str );
        left_right -= ( zone_n * 1000000 );
        return left_right;
    }
}

void tiffDeform::get_pixel_scale()
{
    if( _coord_type == 0 )//經緯度坐標
    {
        _scaleX_src = _tiff_file->geo_tiff.pixel_scale.scaleX;
        _scaleY_src = _tiff_file->geo_tiff.pixel_scale.scaleY;

        _scaleX_des = ( _geo_rect_des.right - _geo_rect_des.left )/_tiff_file->tif_width;
        _scaleY_des = ( _geo_rect_des.top - _geo_rect_des.botton ) / _tiff_file->tif_height;
    }
    else//平面投影坐標
    {
        _scaleX_src = _tiff_file->geo_tiff.pixel_scale.scaleX;
        _scaleY_src = _tiff_file->geo_tiff.pixel_scale.scaleY;

        _scaleX_des = _scaleX_src;
        _scaleY_des = _scaleY_src;
    }
}

void tiffDeform::to_web_mector( geoRECT&rect , bool b )
{
    /*
      (1)     (2)
        +-----+
        |     |
        |     |
        +-----+
      (3)     (4) 
    */
    _coord_trans.init_proj( _proj4_str.c_str() );

    double x1 ,y1,x2 ,y2,x3 ,y3,x4 ,y4;
    x1 = rect.left;
    y1 = rect.top;
    if ( _coord_type == 0 )
    {
        _coord_trans.longlat_2_xy( x1 , y1 );
    }
    else
    {
        _coord_trans.xy_2_xy( x1 , y1 );
    }

    x2 = rect.right;
    y2 = rect.top;
    if ( _coord_type == 0 )
    {
        _coord_trans.longlat_2_xy( x2 , y2 );
    }
    else
    {
        _coord_trans.xy_2_xy( x2 , y2 );
    }

    x3 = rect.left;
    y3 = rect.botton;
    if ( _coord_type == 0 )
    {
        _coord_trans.longlat_2_xy( x3 , y3 );
    }
    else
    {
        _coord_trans.xy_2_xy( x3 , y3 );
    }

    x4 = rect.right;
    y4 = rect.botton;
    if ( _coord_type == 0 )
    {
        _coord_trans.longlat_2_xy( x4 , y4 );
    }
    else
    {
        _coord_trans.xy_2_xy( x4 , y4 );
    }

    if ( b )
    {
        rect.left = x1 < x3 ? x3 : x1;
        rect.top = y1 > y2 ? y2 : y1;
        rect.right = x2 > x4 ? x4 : x2;
        rect.botton = y3 < y4 ? y4 : y3;
    }
    else
    {
        rect.left = x1 > x3 ? x3 : x1;
        rect.top = y1 < y2 ? y2 : y1;
        rect.right = x2 < x4 ? x4 : x2;
        rect.botton = y3 > y4 ? y4 : y3;
    }
}

void tiffDeform::to_web_mector( geoRECT&rect , bool b , double&x1 , double&y1, double&x2 , double&y2, double&x3 , double&y3, double&x4 , double&y4)
{
    /*
      (1)     (2)
        +-----+
        |     |
        |     |
        +-----+
      (3)     (4) 
    */
    _coord_trans.init_proj( _proj4_str.c_str() );

    //double x1 ,y1,x2 ,y2,x3 ,y3,x4 ,y4;
    x1 = rect.left;
    y1 = rect.top;
    if ( _coord_type == 0 )
    {
        _coord_trans.longlat_2_xy( x1 , y1 );
    }
    else
    {
        _coord_trans.xy_2_xy( x1 , y1 );
    }

    x2 = rect.right;
    y2 = rect.top;
    if ( _coord_type == 0 )
    {
        _coord_trans.longlat_2_xy( x2 , y2 );
    }
    else
    {
        _coord_trans.xy_2_xy( x2 , y2 );
    }

    x3 = rect.left;
    y3 = rect.botton;
    if ( _coord_type == 0 )
    {
        _coord_trans.longlat_2_xy( x3 , y3 );
    }
    else
    {
        _coord_trans.xy_2_xy( x3 , y3 );
    }

    x4 = rect.right;
    y4 = rect.botton;
    if ( _coord_type == 0 )
    {
        _coord_trans.longlat_2_xy( x4 , y4 );
    }
    else
    {
        _coord_trans.xy_2_xy( x4 , y4 );
    }

    if ( b )
    {
        rect.left = x1 < x3 ? x3 : x1;
        rect.top = y1 > y2 ? y2 : y1;
        rect.right = x2 > x4 ? x4 : x2;
        rect.botton = y3 < y4 ? y4 : y3;
    }
    else
    {
        rect.left = x1 > x3 ? x3 : x1;
        rect.top = y1 < y2 ? y2 : y1;
        rect.right = x2 < x4 ? x4 : x2;
        rect.botton = y3 > y4 ? y4 : y3;
    }
}

int tiffDeform::get_src_tag_list()
{
    TIFF_UINT32_T ifd_offset;      //第一個IFD的偏移量
    fseek( _tiff_file->pfile , 0 , SEEK_SET );
    fseek( _tiff_file->pfile ,4 ,SEEK_SET );
    ifd_offset = get4( _tiff_file->pfile , _tiff_file->tiff_byte_order ) ;

    //定位到IFD的位置
    fseek( _tiff_file->pfile , ifd_offset , SEEK_SET );
    //得到IFD的數量
    _de_num = get2( _tiff_file->pfile , _tiff_file->tiff_byte_order );

    de_list = new deInfo[ _de_num ];
    memset( de_list , 0 , _de_num * sizeof( deInfo ) );

    //循環得到DE
    for ( TIFF_UINT16_T i = 0x0000 ; i < _de_num ; i++ )
    {
        fseek( _tiff_file->pfile , ifd_offset + ONE_DE_SIZE * i + 2 , SEEK_SET );//文件指針復原指向

        de_list[i].de.tag = get2( _tiff_file->pfile , _tiff_file->tiff_byte_order );
        de_list[i].de.type = get2( _tiff_file->pfile , _tiff_file->tiff_byte_order );
        de_list[i].de.count = get4( _tiff_file->pfile , _tiff_file->tiff_byte_order );

        //如果是大端字節序並且是short類型,則只會讀取四個字節中的前兩個字節
        if ( de_list[i].de.type == 3 && _tiff_file->tiff_byte_order == 0x4d4d/*Motor*/ && de_list[i].de.count == 1 )
        {
            de_list[i].de.offset = (TIFF_UINT32_T)get2( _tiff_file->pfile , _tiff_file->tiff_byte_order );
        }
        else
        {
            de_list[i].de.offset = get4( _tiff_file->pfile , _tiff_file->tiff_byte_order );
        }

        //如果是 SHORT 或者 LONG 並且數量為1,則直接存儲在Offset中,並不存儲地址
        if( ( de_list[i].de.type == 3 || de_list[i].de.type == 4 ) && de_list[i].de.count == 1 )
        {
            de_list[i].data_source = 0 ;
        }
        else
        {
            de_list[i].data_source = 1 ;
        }
    }

    print_tag_info_list();
    return _de_num ;
}

void tiffDeform::print_tag_info_list()
{
    printf( "\n" );
    for ( int i = 0 ; i < _de_num ; i++ )
    {
        char outStr[1024];
        memset( outStr , 0 , 1024 * sizeof( char ) );
        sprintf( outStr , "0x%04x[ %5d %-26s ] , 0x%02x , 0x%04x( %5d ) , 0x%08x , %d \n" 
            , de_list[i].de.tag 
            , de_list[i].de.tag
            , tag_text( de_list[i].de.tag )
            , de_list[i].de.type 
            , de_list[i].de.count
            , de_list[i].de.count
            , de_list[i].de.offset 
            , de_list[i].data_source ) ;
        printf( outStr );
    }
}

const char* tiffDeform::tag_text( int i_tag )
{
    int i = 0 ;
    while ( tag_text_list[i].i_tag != -1 )
    {
        if ( tag_text_list[i].i_tag == i_tag )
        {
            return tag_text_list[i].text;
        }
        i++;
    }

    return "";
}

deInfo* tiffDeform::cts_strip_offsets()
{
    deInfo* temp_de = new deInfo;
    temp_de->de.tag = 273;
    temp_de->de.type = 4;//long
    temp_de->de.count = _new_tiff_height;
    temp_de->de.offset = 0;
    temp_de->data_source = 2;
    TIFF_UINT32_T* mem = new TIFF_UINT32_T[_new_tiff_height];
    memset( mem , 0 , sizeof(TIFF_UINT32_T)*_new_tiff_height );
    temp_de->mem_data = (TIFF_UINT8_T*)mem;
    return temp_de;
}

deInfo* tiffDeform::cts_rows_per_strip()
{
    deInfo* temp_de = new deInfo;
    temp_de->de.tag = 278;
    temp_de->de.type = 3;//short
    temp_de->de.count = 1;
    temp_de->de.offset = 1;
    temp_de->data_source = 0;
    temp_de->mem_data = NULL;
    return temp_de;
}

deInfo* tiffDeform::cts_strip_byte_counts()
{
    deInfo* temp_de = new deInfo;
    temp_de->de.tag = 279;
    temp_de->de.type = 4;//short
    temp_de->de.count = _new_tiff_height;
    temp_de->de.offset = 0;
    temp_de->data_source = 2;
    TIFF_UINT32_T* mem = new TIFF_UINT32_T[_new_tiff_height];
    memset( mem , 0 , sizeof(TIFF_UINT32_T)*_new_tiff_height );
    for ( int i = 0 ; i < _new_tiff_height ; i++ )
    {
        mem[i] = _new_tiff_width * _tiff_file->samples_per_pixel;
    }
    temp_de->mem_data = (TIFF_UINT8_T*)mem;
    return temp_de;
}

deInfo* tiffDeform::cts_line_tag()
{
    deInfo* temp_line_tag_list = new deInfo[3];
    memset( temp_line_tag_list , 0 , sizeof(deInfo) * 3 );
    deInfo* temp = cts_strip_offsets();
    memcpy( temp_line_tag_list , temp , sizeof(deInfo) ) ;
    delete temp;
    temp = cts_rows_per_strip();
    memcpy( temp_line_tag_list + 1 , temp , sizeof(deInfo));
    delete temp;
    temp = cts_strip_byte_counts();
    memcpy( temp_line_tag_list + 2 , temp , sizeof(deInfo));
    delete temp;
    temp = NULL;
    return temp_line_tag_list;
}

int tiffDeform::cts_new_tag_list( )
{
    deInfo* temp_line = cts_line_tag();

    deInfo* temp_de_list = new deInfo[ _de_num ];//tile 4個標簽 line 只需要3個標簽
    memset( temp_de_list , 0 , sizeof(deInfo)*( _de_num ) );

    int tag_num = 0;
    int j = 0 , k = 0 ;
    for ( int i = 0 ; i < _de_num ; i++ )
    {
        if (   de_list[i].de.tag == 33550 
            || de_list[i].de.tag == 33922
            || de_list[i].de.tag == 34735
            || de_list[i].de.tag == 34736
            || de_list[i].de.tag == 34737)
        {
            continue;
        }

        tag_num ++;
        if ( k < 3 )//line只有三個標簽
        {
            if ( de_list[i].de.tag < temp_line[k].de.tag )
            {
                memcpy( temp_de_list + j , de_list + i , sizeof( deInfo ) );
                j++;
            }
            else
            {
                memcpy( temp_de_list + j , temp_line + k , sizeof( deInfo ) );
                j++;
                k++;
                //i--;
            }
        }
        else
        {
            memcpy( temp_de_list + j , de_list + i , sizeof( deInfo ) );
            j++;
        }
        int n = j - 1;
        if ( temp_de_list[n].de.tag == 256 )//ImageWidth
        {
            temp_de_list[n].de.offset = _new_tiff_width;
        }

        if ( temp_de_list[n].de.tag == 257 )//ImageHeight
        {
            temp_de_list[n].de.offset = _new_tiff_height;
        }
    }

    delete[] de_list;
    de_list = NULL;
    de_list = temp_de_list;

    _de_num = tag_num;

    cs_pixel_scale( _scaleX_des , _scaleY_des );
    cs_tie_point( _geo_rect_des.left , _geo_rect_des.top );
    deInfo geo_coord_list[5];
    memset( geo_coord_list , 0 , 5 * sizeof( deInfo ) );
    cs_coord( geo_coord_list );

    mix_proj_de_list( geo_coord_list );

    print_tag_info_list();
    return _de_num;
}

void tiffDeform::mix_proj_de_list( deInfo* coord_list )
{
    deInfo* new_de_list = new deInfo[ _de_num + 5 ];
    memset( new_de_list , 0 , sizeof( deInfo ) * ( _de_num + 5 ) );


    int i_des = 0 ; 
    int i_coord = 0 ;
    if ( _de_num < 5 )
    {
        return ;
    }

    int count = 0;
    for( int i = 0 ; i < _de_num ; i++ )
    {
        if ( de_list[i].de.tag < coord_list[i_coord].de.tag )
        {
            new_de_list[i_des] = de_list[i];
            i_des ++;
            count ++;
        }
        else if ( de_list[i].de.tag >= coord_list[i_coord].de.tag )
        {
            new_de_list[i_des] = coord_list[i_coord];
            i_des++;
            i_coord++;
            count++;
        }
    }

    if ( i_coord < 5 )
    {
        int temp = i_coord;
        for ( int i = temp ; i < 5 ; i++ )
        {
            new_de_list[ i_des ] = coord_list[ i_coord ];
            i_des ++;
            i_coord ++;
            count++;
        }
    }

    delete[] de_list;
    de_list = NULL;

    de_list = new_de_list;
    _de_num = count;
}

TIFF_UINT64_T tiffDeform::double_to_long( double d_ )
{
    union { TIFF_UINT64_T i; double f; } u;
    u.f = d_ ;
    return u.i ;
}

void tiffDeform::cs_pixel_scale( double cx , double cy )
{
    pixel_scale[0] = double_to_long ( cx );
    pixel_scale[1] = double_to_long ( cy );
    pixel_scale[2] = 0 ;
}

void tiffDeform::cs_tie_point( double x , double y )
{
    tie_point[0] = 0;
    tie_point[1] = 0;
    tie_point[2] = 0;

    tie_point[3] = double_to_long( x ) ;
    tie_point[4] = double_to_long( y ) ;
    tie_point[5] = 0;
}

void tiffDeform::cs_coord( deInfo* coord_list )
{
    coord_list[0].de.tag = 33550;//GeoTagPixelScale
    coord_list[0].de.type = 12;//double
    coord_list[0].de.count = 3 ;
    coord_list[0].data_source = 2;//內存數據
    coord_list[0].mem_data = ( TIFF_UINT8_T* )pixel_scale;

    coord_list[1].de.tag = 33922;//GeoTagTiePoint
    coord_list[1].de.type = 12;//double
    coord_list[1].de.count = 6 ;
    coord_list[1].data_source = 2;//內存數據
    coord_list[1].mem_data = ( TIFF_UINT8_T* )tie_point;

    coord_list[2].de.tag = 34735;//GeoTagDirectory
    coord_list[2].de.type = 3;//short
    coord_list[2].de.count = 80;
    coord_list[2].data_source = 2;//內存數據
    coord_list[2].mem_data = ( TIFF_UINT8_T* )geotiff_web_mercator_tag_dir;

    coord_list[3].de.tag = 34736;//GeoDoubleParamsTag
    coord_list[3].de.type = 12;//double
    coord_list[3].de.count = 7;
    coord_list[3].data_source = 2;//內存數據
    coord_list[3].mem_data = ( TIFF_UINT8_T* )geotiff_double_param;

    coord_list[4].de.tag = 34737;//GeoAsciiParamsTag
    coord_list[4].de.type = 2;//ascii
    coord_list[4].de.count = 64;
    coord_list[4].data_source = 2;//內存數據
    coord_list[4].mem_data = ( TIFF_UINT8_T* )geotiff_ascii_param;
}

main

#include <stdio.h>
#include <stdlib.h>
#include "MainH.h"
#include "tiffDeform.h"

int main( int argc, char* argv[] )
{
    if ( argc < 4 )
    {
        print_help_info();
        return -1;
    }

    string tiff_path( argv[1] );
    int coord_type = 0;
    string proj4_str = parse_proj4 ( argc , argv , coord_type );

    tiffDeform tiff_deform;
    tiff_deform.open( tiff_path , proj4_str , coord_type );

    string src_tiff = tiff_path;
    string save_name;
    if ( tiff_deform.arrangement() )
    {
        string cmd_sz = get_exe_dir( argv[0] );
        cmd_sz += "Tile2Line.exe \"-t\" ";
        cmd_sz += "\"";
        cmd_sz += tiff_path ;
        cmd_sz += "\"";
        cmd_sz += " ";
        cmd_sz += "\"";
        cmd_sz += argv[2];
        cmd_sz += "\"";
        system( cmd_sz.c_str() );
        src_tiff = deal_tiff_name( argv[2] , tiff_path );
    }

    save_name = new_tiff_name( argv[2] , tiff_path );

    tiff_deform.save( src_tiff  , save_name );

    printf( "轉換完成!" );

    return 0;
}

string new_tiff_name( string save_dir ,string src_name )
{
    int pos = src_name.rfind( '\\' );
    string tiff_name = src_name.substr( pos + 1 );
    string temp_name = "\\new_";
    temp_name += tiff_name ;
    return ( save_dir + temp_name ) ;
}

string deal_tiff_name( string save_dir ,string src_name )
{
    int pos = src_name.rfind( '\\' );
    string tiff_name = src_name.substr( pos + 1 );
    string temp_name = "\\line_";
    temp_name += tiff_name ;
    return ( save_dir + temp_name ) ;
}

string get_exe_dir( char* argv )
{
    string str( argv );
    int pos = str.rfind('\\') ;
    return str.substr( 0 , pos + 1 );
}

void print_help_info()
{
    printf("-?/H/h 顯示幫助信息 \n");
    printf("參數:[tiff圖片完整的路徑][保存TIFF的文件夾] [坐標類型 0-經緯度坐標 1-平面投影坐標] [當前tiff圖片坐標信息的proj4字符串] \n");
    printf(" 例 :D:\\beijing.tif D:\\xxx 0 +proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs\n" );
}

string parse_proj4( int argc , char* argv[] ,int&coord_type )
{
    coord_type = atoi( argv[3] );
    string temp_sz;
    for ( int i = 4 ; i < argc ; i++ )
    {
        temp_sz += argv[i];
        temp_sz+=" ";
    }
    return temp_sz.substr( 0 , temp_sz.size() -1 );
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM