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 ...

9 個月 ago

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

本篇介紹如何在 Ubuntu ...

10 個月 ago

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

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

10 個月 ago

Windows 使用 TPM 虛擬智慧卡保護 SSH 金鑰教學與範例

本篇介紹如何在 Windows...

11 個月 ago

Linux 以 Shamir’s Secret Sharing 分割保存金鑰教學與範例

介紹如何在 Linux 中使用...

11 個月 ago

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

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

11 個月 ago