介紹如何使用 libtiff
函式庫讀取 TIFF 檔案內的影像與後設資料。
若在 Ubuntu Linux 中,可以使用 apt 來安裝 TIFF 函式庫:
# 安裝 TIFF 函式庫
sudo apt install libtiff-dev
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 檔案的一些基本後設資料(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)
參考資料:LIBTIFF Tutorial