一 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#endiftypedef 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
這個代碼這是對特定的TIF進行讀取,在儲存時不知道為什麼,不能再windows下正常顯示,期待大俠解決呀