介紹如何使用 libtiff 函式庫讀取 TIFF 檔案內的影像與後設資料。
安裝 TIFF 函式庫
若在 Ubuntu Linux 中,可以使用 apt 來安裝 TIFF 函式庫:
# 安裝 TIFF 函式庫
sudo apt install libtiff-dev
讀取 TIFF 影像轉為 RGBA 格式
libtiff 函式庫中提供了一個 TIFFReadRGBAImage 高階函數,可以自動讀取 TIFF 影像並轉為 8 位元的 RGBA 格式,以下是一個簡單的範例:
#include <stdio.h>
#include <tiffio.h>
int main(int argc, char* argv[]) {
// 開啟 TIFF 檔案
TIFF* tif = TIFFOpen("myfile.tif", "r");
if (tif) {
uint32 imageLength, imageWidth;
size_t nPixels;
uint32* raster;
uint8 r, g, b, a;
// 取得影像長度、寬度
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &imageLength);
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &imageWidth);
printf("Image Size = %d x %d\n", imageLength, imageWidth);
// 影像像素數
nPixels = imageLength * imageWidth;
// 配置記憶體
raster = (uint32*) _TIFFmalloc(nPixels * sizeof (uint32));
if (raster != NULL) {
// 讀取影像,轉為 RGBA 格式
if (TIFFReadRGBAImage(tif, imageWidth, imageLength, raster, 0)) {
// 讀取每一點像素值
for (int y = 0; y < imageLength; ++y) {
for (int x = 0; x < imageWidth; ++x) {
int i = y * imageWidth + x;
r = TIFFGetR(raster[i]);
g = TIFFGetG(raster[i]);
b = TIFFGetB(raster[i]);
a = TIFFGetA(raster[i]);
printf("raster[%d, %d] = (%d, %d, %d, %d)\n", x, y, r, g, b, a);
}
}
}
_TIFFfree(raster);
}
TIFFClose(tif);
}
return 0;
}
將這段程式碼儲存為 read_tiff.c,並使用以下指令進行編譯,然後執行編譯好的程式:
# 編譯使用 TIFF 函式庫的應用程式
gcc read_tiff.c -o read_tiff -ltiff
./read_tiff
執行後的輸出訊息會類似這樣:
Image Size = 2 x 3 raster[0, 0] = (255, 0, 0, 255) raster[1, 0] = (96, 96, 0, 255) raster[2, 0] = (255, 255, 255, 255) raster[0, 1] = (255, 255, 255, 255) raster[1, 1] = (255, 255, 255, 255) raster[2, 1] = (255, 255, 255, 255)
TIFFReadRGBAImage 函數在讀取影像資料時,會以影像的左下角作為原點,若需要將原點設定在其它位置,可以改用 TIFFReadRGBAImageOriented 函數。
TIFFReadRGBAImage 函數若遇到非 8 位元的影像,則會自動進行縮放(scaling)轉換,對於灰階、CMYK、YCbCr 等影像格式,也會自動轉為 RGB 格式。
掃描線讀取 TIFF 影像資料
以下是一個讀取 TIFF 圖檔的基本範例,先取得 TIFF 檔案的一些基本後設資料(metadata),接著再以掃描線(scan line)的方式讀取影像資料:
#include <stdio.h>
#include <tiffio.h>
int main() {
// 開啟 TIFF 檔案
TIFF* tif = TIFFOpen("myfile.tif", "r");
if (tif) {
uint32 imageLength, imageWidth;
uint16 bitsPerSample, samplesPerPixel;
tdata_t buf;
uint32 row;
uint8 r, g, b, a;
// 取得影像長度、寬度
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &imageLength);
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &imageWidth);
printf("Image Size = %d x %d\n", imageLength, imageWidth);
// 取得影像像素資訊
TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bitsPerSample);
TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesPerPixel);
printf("Bits per sample = %d\n", bitsPerSample);
printf("Samples per pixel = %d\n", samplesPerPixel);
// 取得每一條 row 的位元組數
tsize_t bufSize = TIFFScanlineSize(tif);
printf("Buffer Size = %ld\n", bufSize);
// 配置緩衝區
buf = _TIFFmalloc(bufSize);
// 逐列讀取影像
for (row = 0; row < imageLength; row++) {
TIFFReadScanline(tif, buf, row, 0);
for (int col = 0; col < imageWidth; ++col) {
r = ((uint8*) buf)[col * 4];
g = ((uint8*) buf)[col * 4 + 1];
b = ((uint8*) buf)[col * 4 + 2];
a = ((uint8*) buf)[col * 4 + 3];
printf("image[%d, %d] = (%d, %d, %d, %d)\n", row, col, r, g, b, a);
}
}
// 釋放緩衝區
_TIFFfree(buf);
// 關閉 TIFF 檔案
TIFFClose(tif);
}
}
將這段程式碼儲存為 scan_tiff.c,並使用以下指令進行編譯,然後執行編譯好的程式:
# 編譯使用 TIFF 函式庫的應用程式
gcc scan_tiff.c -o scan_tiff -ltiff
./scan_tiff
執行後的輸出訊息會類似這樣:
Image Size = 2 x 3 Bits per sample = 8 Samples per pixel = 4 Buffer Size = 12 image[0, 0] = (255, 255, 255, 255) image[0, 1] = (255, 255, 255, 255) image[0, 2] = (255, 255, 255, 255) image[1, 0] = (255, 0, 0, 255) image[1, 1] = (96, 96, 0, 255) image[1, 2] = (255, 255, 255, 255)
