一 TIF圖像介紹
??? TIFF是最復雜的一種位圖文件格式。TIFF是基于標記的文件格式,它廣泛地應用于對圖像質量要求較高的圖像的存儲與轉換。由于它的結構靈活和包容性大,它已成為圖像文件格式的一種標準,絕大多數圖像系統都支持這種格式。
?? TIFF 是一個靈活適應性強的文件格式,通過在文件頭中包含“標簽”它能夠在一個文件中處理多幅圖像和數據。標簽能夠標明圖像的如圖像大小這樣的基本幾何尺寸或者定義圖像數據是如何排列的并且是否使用了各種各樣的圖像壓縮選項。例如,TIFF可以包含JPEG和行程長度編碼壓縮的圖像。TIFF文件也可以包含基于矢量的裁剪區域(剪切或者構成主體圖像的輪廓)。使用無損格式存儲圖像的能力使TIFF文件成為圖像存檔的有效方法。與JPEG不同,TIFF文件可以編輯然后重新存儲而不會有壓縮損失。其它的一些TIFF文件選項包括多層或者多頁。
盡管現今它是一種被廣泛接受的標準格式,當TIFF最初出現的時候,它的可擴展性帶來了很多兼容問題。程序員可以隨意定義新的標簽和選項,但是并不是所有的實現程序都能支持這些所有這些創造出的標簽。作為結果,它的一個最小特性集成為了“這個”TIFF,即使是在今天大量的TIFF文件和讀取它們的代碼都是基于簡單的32位非壓縮圖像。
TIFF有一個使用LZW壓縮的選項,這是一種減小文件大小的無損技術,但是這項技術在不同的司法權限內為幾個專利所涵蓋。到了2005年,除了一個之外這些專利都已經到期,其中包括Unisys所擁有的廣為人知又有很多爭議的專利。另外一個著名的專利是IBM擁有的將在2006年8月11日到期的專利,IBM也沒有要加強它的意思(who has shown no interest to date in enforcing it)。
每個TIFF文件都是從指示字節順序的兩個字節開始的。“II”表示小字節在先、“MM”表示大字節在先字節順序。后面的兩個字節表示數字42。數字42是“為了其深刻的哲學意義"而選擇的。 42的讀法取決于頭兩個字節所表示的字節順序。整個文件根據所指出的字節順序進行讀取。
字節順序在Apple Macintosh和微軟視窗程序之間可能產生兼容性的問題,它們通常為TIFF文件使用不同的字節順序。一些程序提供了保存為Mac或者是Windows字節順序的選項以使文件能在交叉平臺使用。
二TIF圖像的讀取
??? 1.TIF的存儲結構
?????? TIFF文件以.tif為擴展名。其數據格式是一種3級體系結構,從高到低依次為:文件頭、一個或多個稱為IFD的包含標記指針的目錄和數據。
??? 1.文件頭(IFH)
在每一個TIFF文件中第一個數據結構稱為圖像文件頭或IFH,它是圖像文件體系結構的最高層。這個結構在一個TIFF文件中是惟一的,有固定的位置。它位于文件的開始部分,包含了正確解釋TIFF文件的其他部分所需的必要信息。
???
??????? IFH數據結構包含3個成員共計8個字節,Byte order成員可能是“MM”(0x4d4d)或“II”(0x4949),0x4d4d表示該TIFF圖是摩托羅拉整數格式 0x4949表示該圖是Intel整數格式;Version成員總是包含十進制42(0x2a),它用于進一步校驗該文件是否為TIF格式,42這個數并 不是一般人 想象中的那樣認為是tif軟件的版本,實際上,42這個數大概永遠不會變化;第三個成員是IFD(接下來要說的第二個數據結構)相對文件開始處的偏移量。
??? 2.圖像文件目錄(IFD)
IFD是TIFF文件中第2個數據結構,它是一個名為標記(tag)的用于區分一個或多個可變長度數據塊的表,標記中包含了有關于圖像的所有信息。IFD提供了一系列的指針(索引),這些指針告訴我們各種有關的數據字段在文件中的開始位置,并給出每個字段的數據類型及長度。這種方法允許數據字段定位在文件的任何地方,且可以是任意長度,因此文件格式十分靈活。
???? IFD是TIF圖中最重要的數據結構,它包含了一個TIF文件中最重要的信息,一個TIF圖可能有多個IFD,這說明文件中有多個圖像,每個IFD標 識1個圖像的基本屬性。 IFD結構中包含了三類成員,Directory Entry Count指出該結構里面有多少個目錄入口;接下來就是N個線性排列的DE序列,數量不定(這就是 為什么稱TIF格式文件為可擴充標記的文件,甚至用戶可以添加自定義的標記屬性),每個DE標識了圖像的某一個屬性;最后就是一個偏移量, 標識下一個文件目錄相對于文件開始處的位置,當然,如果該TIF文件只包含了一幅圖像,那么就只有一個IFD,顯然,這個偏移量就等于0;
共12個字節,見圖二。簡單說,一個DE就是一幅圖像的某一個屬性。例如圖像的大小、分辨率、是否壓縮、像素的行列數、一個像素由幾位 表示(1位代表黑白兩色,8位代表256色等等)等。其中:tag成員是該屬性的編號,在圖像文件目錄中,它是按照升序排列的。我們可以通過讀 這些編號,然后到TIF格式官方白皮書中查找相應的含義。屬性是用數據來表示的,那么type就是代表著該數據的類型,TIF官方指定的有5種數據類型。type=1就是BYTE類型(8位無標記整數)、type=2是ASCII類型(7位ASCII碼加1位二進制0)、type=3是SHORT類型 (16位無標記整數)、type=4是LONG 類型(32位無標記整數)、type=5是RATIONAL類型(2個LONG,第一個是分子,第二個是分母)。length成員是數據的數量而不是數據類型的長度。 第4個成員valueOffset很重要,它是tag標識的屬性代表的變量值相對文件開始處的偏移量。如果變量值占用的空間小于4個字節,那么該值就存放在 valueOffset中即可,沒必要再另外指向一個地方了。
????? 3.圖像數據
根據IFD所指向的地址.存儲相關的圖像信息
以下是在6.0下運行的代碼
- #ifndef?TIFREADER_H???
- #define?TIFREADER_H???
- ??
- #include?<stdio.h>??
- #include?<string.h>??
- ??
- #ifndef?NULL??
- #define?NULL???0??
- #endif??
- ??
- #ifndef?TRUE??
- #define?TRUE???1??
- #define?FALSE??0??
- #endif??
- ??
- ??
- typedef?struct????
- {??
- ??unsigned?short?Byte_order;//??
- ??unsigned?short?Version;//校驗文件是否是TIF文件??
- ??unsigned???int?OffsetToFirstFID;//相對對文件開始處的偏移量??
- ?//?unsigned?short?wDECount;//多少目錄入口??
- }IFH;??
- ??
- typedef?struct??
- {??
- ????unsigned?short?tag;//屬性的編號??
- ????unsigned?short?type;//數據類型??
- ????unsigned?long?length;//數據的數量??
- ????unsigned?long?valueOffset;//tag標識的屬性代表的變量值相對文件開始處的偏移量??
- }DE;??
- typedef?struct????
- {??
- ????int?width;??
- ????int?height;??
- ??????
- }Size;??
- typedef?struct???
- ?{??
- ????int?*data;??
- }DATA;??
- typedef?struct???
- {??
- ????DE?*pde;??
- ????int?wDECount;??
- }PDE;??
- bool?readTIF(char*?path,IFH?&ifh,PDE?&de,Size?&size,DATA?&Data)??
- {??
- ????unsigned?char?*data;??
- ????int?*dat;??
- ????unsigned?short?wDECount;//多少目錄入口??
- ??????
- //??ZeroMemory(&ifh,?sizeof(IFH));??
- //??ZeroMemory(&de,?sizeof(DE));??
- ??
- ????FILE?*fp;??
- ????fp=fopen(path,"rb");??
- ????if(fp?==?NULL)??
- ????{??
- ????????cout<<"open?file?error"<<endl;??
- ????????return?false;??
- ????}??
- ????if(sizeof(IFH)?!=?fread(&ifh,?1,sizeof(IFH),fp))??
- ????{??
- ????????cout<<"讀TIF文件頭失敗";??
- ????????return?FALSE;??
- ????}??
- ?????if(0x2a?!=?ifh.Version)??
- ?????{??
- ??????????cout<<"該文件不是TIF格式,讀文件失敗";??
- ??????????return?FALSE;??
- ?????}??
- ??
- ?????if(0x4949?!=?ifh.Byte_order)??
- ?????{??
- ??????????cout<<"該TIF文件不是IBMPC字節序,讀文件失敗";??
- ??????????return?FALSE;??
- ?????}??
- ??
- ?????fseek(fp,ifh.OffsetToFirstFID,SEEK_SET);//將文件指針定位到IFD??
- ?????//讀文件有多少個目錄入口???
- ????if(2?!=?fread(&wDECount,1,sizeof(unsigned?short),fp))??
- ?????{??
- ??????????cout<<"無法獲得TIF文件目錄入口數量";??
- ??????????return?FALSE;??
- ?????}??
- ????cout<<"該TIF文件有"<<wDECount<<"個目錄入口"<<endl;??
- ????//創建DE數組,接收信息,數組中有wDECount個元素???
- ????de.pde?=?new?DE[wDECount];??
- ????DE*?pTemp?=?de.pde;??
- ????de.wDECount?=?wDECount;??
- ????memset(de.pde,?0,?sizeof(DE)*wDECount);??
- ?????if(sizeof(DE)*wDECount?!=?fread(de.pde,1,?sizeof(DE)*wDECount,fp))??
- ?????{??
- ??????????cout<<"讀圖象文件目錄失敗";??
- ??????????delete?[]de.pde;??
- ??????????return?false?;??
- ?????}??
- ????//把圖像的大小和圖像數據的容量保存到成員變量中??
- ?????int?m_size_x;??
- ?????int?m_size_y;??
- ?????int?m_size;??
- ?????int?i;??
- ????for(i=0;?i<wDECount;?i++)??
- ?????{??
- ??????????pTemp?=de.pde?+?i;??
- ??????????if(256?==?pTemp->tag)?//tag為256的目錄入口中的變量標識了圖象寬度??
- ??????????{??
- ??????????????m_size_x?=?pTemp->valueOffset;??
- ??????????}??
- ??????????if(257?==?pTemp->tag)?//圖象高度??
- ??????????{??
- ??????????????m_size_y?=?pTemp->valueOffset;??
- ??????????}??
- ??????????if(273?==?pTemp->tag)?//計算圖象數據占用字節數??
- ??????????{??
- ???????????//m_dwBmSize?=?pTemp->valueOffset?-?sizeof(IFH);??
- ???????????//或者把tag=256的valueOffset乘以tag=257的valueOffset??
- ??????????????m_size?=?m_size_x?*?m_size_y;??
- ??????????}??
- ????}??
- ????//填充所有像素數據,?顛倒圖象數據從最后一行開始讀起??
- ?????int?j?=?0;??
- ????//?int?i?=?0;??
- ?????data?=?(unsigned?char*)malloc(m_size*sizeof(BYTE));??
- ?????dat?=?(int*)malloc(m_size*sizeof(int));??
- ?????for(i=m_size_y-1;?i>=0;?i--)??
- ?????{??
- ?????????fseek(fp,sizeof(IFH)?+?i*m_size_x,?SEEK_SET);??
- ?????????fread((BYTE*)(data?+?1)?+?j*m_size_x,sizeof(BYTE),?m_size_x,fp);??
- ??????????j++;??
- ?????}??
- ?????cout<<"width:"<<m_size_x<<endl;??
- ?????cout<<"height:"<<m_size_y<<endl;??
- ?????unsigned?char*?p;??
- ?????p?=?data;??
- ?????int?*ptr;??
- ?????ptr?=?dat;??
- ?????for?(i=0;i<m_size;i++,p++,ptr++)??
- ?????{??
- ?????????*ptr?=?(int)(*p);??
- ?????????int??h=?*ptr;??
- ????????//?cout<<h<<"?";??
- ?????}??
- ?????size.width?=?m_size_x;??
- ?????size.height?=?m_size_y;??
- ?????Data.data?=?dat;??
- ?????return?TRUE;??
- ????
- }??
- bool?saveTIF(char*?path,IFH?ifh,PDE?de,Size?size,DATA?Data)??
- {??
- ????unsigned?char?*data;??
- //????unsigned?short?wDECount;//多少目錄入口??
- ??????
- //??ZeroMemory(&ifh,?sizeof(IFH));??
- //??ZeroMemory(&de,?sizeof(DE));??
- ??
- ????FILE?*fp;??
- ????fp=fopen(path,"wb");??
- ????if(fp?==?NULL)??
- ????{??
- ????????cout<<"open?file?error"<<endl;??
- ????????return?false;??
- ????}??
- ????if(sizeof(IFH)?!=?fwrite(&ifh,?1,sizeof(IFH),fp))??
- ????{??
- ????????cout<<"寫TIF文件頭失敗";??
- ????????return?FALSE;??
- ????}??
- ?????fseek(fp,ifh.OffsetToFirstFID,SEEK_SET);//將文件指針定位到IFD??
- ?????//讀文件有多少個目錄入口???
- ????if(2?!=?fwrite(&de.wDECount,1,sizeof(unsigned?short),fp))??
- ?????{??
- ??????????cout<<"無法獲得TIF文件目錄入口數量";??
- ??????????return?FALSE;??
- ?????}??
- ????//創建DE數組,接收信息,數組中有wDECount個元素???
- ???
- ?????if(sizeof(DE)*de.wDECount?!=?fwrite(de.pde,1,?sizeof(DE)*de.wDECount,fp))??
- ?????{??
- ??????????cout<<"讀圖象文件目錄失敗";??
- ??????????return?false?;??
- ?????}??
- ????//填充所有像素數據,?顛倒圖象數據從最后一行開始讀起??
- ?????int?j?=?0;??
- ?????int?i?=?0;??
- ?????data?=?(unsigned?char*)malloc(size.width*size.height*sizeof(BYTE));??
- ?????int?*ptr?=?Data.data;??
- ??
- ?????unsigned?char*?p;??
- ?????p?=?data;??
- ?????for?(i=0;i<size.width*size.height;i++,p++,ptr++)??
- ?????{??
- ?????????*p?=?(unsigned?char)(*ptr);??
- ????????//?int??h=?*ptr;??
- ????????//?cout<<h<<"?";??
- ?????}????
- ?????for(i=size.height-1;?i>=0;?i--)??
- ?????{??
- ?????????fseek(fp,sizeof(IFH)?+?i*size.width,?SEEK_SET);??
- ?????????fwrite((BYTE*)(data?+?1)?+?j*size.width,sizeof(BYTE),?size.width,fp);??
- ??????????j++;??
- ?????}??
- ??
- ?????return?TRUE;??
- ????
- }??
- #endif??