BIGTIFF圖檔解析

BIGTIFF圖檔解析
BIGTIFF圖檔解析

高解像度『TIFF』圖片, 加入『BIGTIFF』規范,使用64bit支緩4GB以上圖片. 支緩『ZIP』壓縮.擴展名『.tf8』『.btf』『.tiff』.

『BIGTIFF』圖檔頭Image File Header(IFH)

typedef struct BIGTIFF_HEAD_TYP { BIGTIFF圖檔頭
        WORD ByteOrder; 字節順序  ‘II’ / ‘MM’
        WORD version; BIGTIFF圖檔版本  0x002B
        WORD     ReservedOffset; 保留
        WORD     Reserved; 保留
DWORD64  offset; 首個IFD偏移量64BIT,邊界對齊4
}BIGTIFF_HEAD, * BIGTIFF_HEAD_PTR;  

區分『BIGTIFF』仝『TIFF

#define TIFF_VERSION          0x002A TIFF圖檔版本
#define BIGTIFF_VERSION       0x002B BIGTIFF圖檔版本

『BIGTIFF』新增三個數據類型

#define BIGTIFF_TYPE_LONG8     16 冇符號8字節(64位)整数
#define BIGTIFF_TYPE_SLONG8    17 有符號8字節(64 位)整数
#define BIGTIFF_TYPE_IFD8       18 无符号8字節(64位)IFD偏移。

『BIGTIFF』新增ZIP壓縮類型 8

#define TIFF_Compression_ZIP  8 ZIP壓縮, MAX_WBITS帶 zlib 頭和尾

『BIGTIFF』目錄入口 Directory Entry(DE)

typedef struct BIGTIFF_ENTER_TYP { 即係數值
WORD  tag; 標識
        WORD  type; 數據類型 1~12 16~17
        DWORD64 count; 數量64BIT
        union {

DWORD64 data;

數值64BIT
                DWORD64 offset;

};

偏移64BIT
}BIGTIFF_ENTER, * BIGTIFF_ENTER_PTR;  

『BIGTIFF』目錄 Image File Directory(IFD)

typedef struct BIGTIFF_DIRECTORY_TYP {  
        DWORD64  count; 目錄數量64BIT
        BIGTIFF_ENTER enter_array[1]; 目錄,即係數值
        // DWORD64 offset; 64BIT下壹個偏移-BIGIFD
}BIGTIFF_DIRECTORY, * BIGTIFF_DIRECTORY_PTR;  

『高解像圖片』組織成『Tiled瓦片』而非『條帶Strip』, 低中解像圖像用標準『TIFF』『條帶Strip』.『高解像圖片』切割成大致方正塊狀,而非長條『條帶Strip』.壓縮效果更佳.

『Tiled瓦片』取代『StripOffsets』、『StripByteCounts』『RowsPerStrip』. 切忽仝時用『Tiled瓦片』仝『條帶Strip』.

『TileWidth』仝『TileLength』『瓦片』定義寬高. 所有『瓦片』『寬高』相同, 『瓦片』邊界填充.

當『ImageWidth』=129, 『TileWidth』= 64.則分割3個『Tiled瓦片』, 最後一個填充63個像素.

平鋪邊界代價需要浪費一定空間,但係壓縮可以將填充區壓縮到接近0.

即使數據冇壓縮,『Tiled瓦片』祗适用於『高解像圖片』. 『高解像圖片』分割大量『Tiled瓦片』, 填充區祈浪費百分之幾空間,

『Tiled瓦片』被單獨壓縮, 仝『條帶Strip』壓縮一樣. 即每個『Tiled瓦片』數據被視為單獨『條帶Strip』.

『Tiled瓦片』欄位:

『Tiled瓦片』欄位:    
TileWidth SHORT or LONG 瓦片寬度, 必須16倍數
TileHeight SHORT or LONG 瓦片高度, 必須16倍數
TileOffsets LONG or LONG8 瓦片(數據)偏移, 從左到右從上到下的順序排列.
TileByteCounts SHORT or LONG or LONG8 瓦片數據字節量, 從左到右從上到下的順序排列.

載入瓦片數據

bool Load_Tile_TIFF(TIFF_PTR tiff){
PBYTE  tile_buffer; // 瓦片圖像

DWORD64    tile_size; // 瓦片數據字節量

DWORD64    tile_offset;// 瓦片数据偏移

DWORD64 tiles_countX;// 瓦片橫跨

DWORD64 tiles_countY;  // 瓦片縱跨

DWORD64 line_size;

DWORD64 index, i, j; // 索引

DWORD64 offset;// (數據)偏移.

DWORD64 count;// 數據字節量

DWORD64 size;// 寫入量

DWORD64 buffer_offset;// 圖像数据偏移

DWORD64 buffer_size;// 圖像数据字節

tiles_countX = (tiff->ImageWidth + tiff->TileWidth – 1) / tiff->TileWidth;// 瓦片橫跨
tiles_countY = (tiff->ImageHeight + tiff->TileHeight – 1) / tiff->TileHeight;// 瓦片縱跨
tile_size = tiff->TileWidth * tiff->TileHeight * tiff->SamplesPerPixel; // 瓦片數據字節量
tile_buffer = (PBYTE)malloc(tile_size);// 分配記憶體
size = 0;// 寫入量
// 計算圖像所占長度

buffer_size = (tiff->ImageWidth * tiff->ImageHeight) * tiff->SamplesPerPixel;

// 定位平鋪/瓦片图像数据

for (j = 0; j < tiles_countY; ++j){

for (i = 0; i < tiles_countX; ++i){
index = j * tiles_countX + i;
offset = tiff->TileOffsets[index]; // (數據)偏移.

count = tiff->TileByteCounts[index]; // 數據字節量

// 讀瓦片數據

if (tiff->Compression == TIFF_Uncompressed)

{// 未壓縮

memcpy(tile_buffer, tiff->data + offset, count);// 复制图像数据

size = size + count;// 累積寫入量

}else

if (tiff->Compression == TIFF_Compression_LZW)

{// LZW 解壓縮

tile_size = ((tiff->TileWidth * tiff->TileHeight) * tiff->SamplesPerPixel);

UnCompress_Data_LZW(&_lzw, tile_buffer, &tile_size, tiff->data + offset, count);

size = size + tile_size;// 累積寫入量

}

else

if (tiff->Compression == TIFF_Compression_ZIP)

{// ZIP 解壓縮

DWORD _tile_size = ((tiff->TileWidth * tiff->TileHeight) * tiff->SamplesPerPixel);

Uncompress_Data_ZIP(tile_buffer, &_tile_size, tiff->data + offset, (DWORD)count, MAX_WBITS);

size = size + _tile_size;// 累積寫入量

}

// 寫入瓦片數據

for (DWORD tindex = 0; tindex < tiff->TileHeight; ++tindex)

{

if ( (j * tiff->TileHeight + tindex)  >= tiff->ImageHeight )

break;// 超出

buffer_offset = ( ((j * tiff->TileHeight + tindex) * tiff->ImageWidth) + (i * tiff->TileWidth)) * tiff->SamplesPerPixel;// 圖像数据偏移
tile_offset = tindex * tiff->TileWidth * tiff->SamplesPerPixel;// 瓦片数据偏移
if ((tiff->TileWidth * i) > tiff->ImageWidth)

line_size = (tiff->ImageWidth – (tiff->TileWidth * (i – 1))) * tiff->SamplesPerPixel;

else

line_size = tiff->TileWidth * tiff->SamplesPerPixel;

if (buffer_offset >= buffer_size)

break;// 截斷填充區

                                memcpy(tiff->buffer + buffer_offset, tile_buffer + tile_offset, line_size);

}

}

}

        free(tile_buffer);// 释放

return true;

}

發佈留言