C/C++

C 語言 TIFF 函式庫讀取 TIFF 影像與後設資料教學與範例

介紹如何使用 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)

參考資料:LIBTIFF Tutorial

Share
Published by
Office Guide

Recent Posts

Python 使用 PyAutoGUI 自動操作滑鼠與鍵盤

本篇介紹如何在 Python ...

1 年 ago

Ubuntu Linux 以 WireGuard 架設 VPN 伺服器教學與範例

本篇介紹如何在 Ubuntu ...

1 年 ago

Linux 網路設定 ip 指令用法教學與範例

本篇介紹如何在 Linux 系...

1 年 ago

Linux 以 Cryptsetup、LUKS 加密 USB 隨身碟教學與範例

介紹如何在 Linux 系統中...

1 年 ago