このページでは Mac に LibTIFF をインストールする手順と LibTIFF を用いたプログラムの例を紹介します。
試したOSは下記の通りです
他の環境では試せていませんのでご了承ください。
- macOS HighSierra(バージョン10.13.4)
ダウンロードされるフォルダ違うなどの違いがありますが、LINUX 環境でも手順は参考になると思います。
Contents
LibTIFF とは
LibTIFF は TIFF 画像ファイルを扱うためのライブラリです。
この LibTIFF を利用することで、C言語などのプログラムから簡単に TIFF 画像を読み込んだり、TIFF 画像を作成したりできるようになります。
LibTIFF のインストール
それでは LibTIFF のインストール方法について解説していきます。
このインストールの基本的な流れは下記になります。
- ダウンロード
- 設定
- ライブラリ生成
- インストール
- インストールの確認
スポンサーリンク
LibTIFF のダウンロード
まず LibTIFF をダウンロードするためにhttp://download.osgeo.org/libtiff/にアクセスしましょう。
上のような画面が表示されると思いますので、最新の .zip ファイルをダウンロードします。2018/07/29現在だと 4.0.9 が最新のようでした。
.zip は解凍しておきましょう。
続いてターミナルでダウンロードしたファイルがあるフォルダにアクセスします。私がダウンロードした.zipファイルをダウンロードフォルダに保存し、そこに展開しましたので下記コマンドでアクセスしました。
cd /Users/[私のユーザ名]//Downloads/tiff-4.0.9
LibTIFF の設定
続いてそのフォルダで下記コマンドを実行します。これによりあなたの PC に合わせて LibTIFF の設定が行われます。
./configure
このコマンド実行後たくさんのメッセージが表示されながら処理が実行されますが1分ほどで処理が完了するはずです。
最後の方のメッセージは下記のような感じでした。良ければご参考に。
Libtiff is now configured for i386-apple-darwin17.5.0 Installation directory: /usr/local Documentation directory:${prefix}/share/doc/tiff-4.0.9 C compiler: gcc -g -O2 -Wall -W C++ compiler: g++ -g -O2 Enable runtime linker paths:no Enable linker symbol versioning:no Support Microsoft Document Imaging: yes Use win32 IO: no Support for internal codecs: CCITT Group 3 & 4 algorithms: yes Macintosh PackBits algorithm: yes LZW algorithm:yes ThunderScan 4-bit RLE algorithm:yes NeXT 2-bit RLE algorithm: yes LogLuv high dynamic range encoding: yes Support for external codecs: ZLIB support: yes Pixar log-format algorithm: yes JPEG support: no Old JPEG support: no JPEG 8/12 bit dual mode:no ISO JBIG support: no LZMA2 support:no C++ support:yes OpenGL support:no
LibTIFF ライブラリの生成
続いて同じフォルダ内で下記の make
コマンドを実行します。これにより LibTIFF ライブラリが生成されます。
make
こちらも1分ほどで処理完了します。最後の方のメッセージはこんな感じ。
ibtool: link: gcc -g -O2 -Wall -W -o .libs/iptcutil iptcutil.o ../../libtiff/.libs/libtiff.dylib -lz Making all in mfs make[2]: Nothing to be done for `all’. Making all in pds make[2]: Nothing to be done for `all’. Making all in ras make[2]: Nothing to be done for `all’. Making all in stream make[2]: Nothing to be done for `all’. Making all in tags make[2]: Nothing to be done for `all’. Making all in win_dib make[2]: Nothing to be done for `all’. make[2]: Nothing to be done for `all-am’. Making all in test make[1]: Nothing to be done for `all’. Making all in man make[1]: Nothing to be done for `all’. Making all in html Making all in images make[2]: Nothing to be done for `all’. Making all in man make[2]: Nothing to be done for `all’. make[2]: Nothing to be done for `all-am’. make[1]: Nothing to be done for `all-am’
スポンサーリンク
LibTIFF のインストール
次に LibTIFF をインストールします。次のコマンドによりインストールが行われるはずです。
sudo make install
インストールはすぐ処理が完了すると思います。最後の方のメッセージを念のため載せておきます。
make[2]: Nothing to be done for `install-exec-am'. config/install-sh -c -d '/usr/local/share/doc/tiff-4.0.9' /usr/bin/install -c -m 644 COPYRIGHT ChangeLog README README.vms RELEASE-DATE TODO VERSION '/usr/local/share/doc/tiff-4.0.9' config/install-sh -c -d '/usr/local/lib/pkgconfig' /usr/bin/install -c -m 644 libtiff-4.pc '/usr/local/lib/pkgconfig'
インストールの確認
最後にインストールされたことを確認しておきましょう。
今まで作成したC言語のプログラムファイルをコンパイルしてやるときに、最後に -ltiff
をつけてからコンパイルしてみてください。下記のような感じです。
-ltiff
を付けることにより LibTIFF をリンクすることができます。これにより自分のプログラムで TIFF 画像を扱うための様々な関数が使用可能になります。
gcc japanese.c -o japanese.exe -ltiff
エラーが表示されずコンパイルが完了すれば、LibTIFF のインストールに成功です。お疲れ様でした!
インストールがうまくできていなければ下記のようなメッセージが表示されますので再度手順を確認してみてください。
ld: library not found for -ltiff clang: error: linker command failed with exit code 1 (use -v to see invocation)
LibTIFF を使用したTIFFファイル読み込み・書き込み関数の作成
続いて、インストールした LibTIFF を用いて TIFF ファイルを読み込み・書き込みを行う関数の例を紹介していきたいと思います。
スポンサーリンク
ヘッダーファイル
まずは LibTIFF に関連するヘッダーをインクルードしたり、必要な構造体の定義、TIFF ファイルを読み込み・書き込みする関数の定義を行うヘッダーファイルを用意します。
下記がそのヘッダーファイルの例になります。
#include <stdio.h>
#include <stdlib.h>
#include "tiffio.h"
typedef enum{
NONE_COMPRESSION,
LZW_COMPRESSION
} COMPRESSION_TYPE_t;
typedef struct{
unsigned char *data;
unsigned int width;
unsigned int height;
unsigned int ch;
} BITMAPDATA_t;
int tiffFileReadDecode(BITMAPDATA_t *, const char*);
int tiffFileEncodeWrite(BITMAPDATA_t *, COMPRESSION_TYPE_t, const char*);
int freeBitmapData(BITMAPDATA_t *);
ポイントを説明しておきます。
tiffio.h
のインクルード
LibTIFF が提供する関数や定数などは tiffio.h
というファイルで宣言・定義されています。
ですので、LibTIFF を利用するためにはこの tiffio.h
をインクルードする必要があります。
#include "tiffio.h"
もし tiffio.h が見つからない場合は、ヘッダーインクルードパスが tiffio.h がインストールされたフォルダに通っているかを確認してみてください
インストール時にこのヘッダーインクルードパスも設定されるはずですが、環境によっては別途設定する必要があるかもしれません
圧縮方法の定義
さらに、下記で出力TIFFファイルの圧縮方法を enum
型で定義しています。
typedef enum{
NONE_COMPRESSION,
LZW_COMPRESSION
} COMPRESSION_TYPE_t;
それぞれが下記の圧縮形式に対応しています。
NONE_COMPRESSION
:非圧縮LZW_COMPRESSION
:LZW圧縮
ちなみにこのページで紹介しているプログラムでは JPEG 圧縮には対応していません。
JPEG 圧縮を行うためには libJpeg のインストールが必要です。インストールすれば JPEG 圧縮も可能に変更できます。
LibJPEG のインストールについては次の記事を参考にしていただければと思います。
【C言語】libjpegのインストールと使用方法・使用例BITMAP 形式データ構造体の定義
また、下記では BITMAP 形式データの情報格納用構造体 BITMAPDATA_t
を定義しています。
typedef struct{
unsigned char *data;
unsigned int width;
unsigned int height;
unsigned int ch;
} BITMAPDATA_t;
それぞれのメンバの説明は下記のようになります。
data
:TIFF をデコードした BITMAP 形式画像データの先頭アドレスwidth
:画像の横幅height
:画像の高さch
:画像の色数(カラーの時は3
、グレーの時は1
)
BITMAP 形式画像データって何?という方は下記ページで説明していますので是非参考にしてください。
画像データの構造・画素・ビットマップデータについて解説上のページでも解説しているように data
のポインタの先は下図のように各ピクセルの RGB 順にデータが並んでいます。
ソースファイル
次は実際に LibTIFF が提供している関数を利用して TIFF ファイルを読み込んだり、TIFF ファイルとして保存したりする関数を作成していきます。
#include "myTiff.h"
int tiffFileReadDecode(BITMAPDATA_t *bitmapData, const char* filename){
TIFF *tiff;
unsigned int length = 0;
unsigned int width = 0;
unsigned int bitpersample = 0;
unsigned int ch = 0;
unsigned int *rgbaData = NULL;
unsigned char *rgbData = NULL;
int i, j;
if(filename == NULL){
printf("ファイル名がNULL\n");
return -1;
}
tiff = TIFFOpen(filename, "r");
if(tiff == NULL){
printf("TIFFOpen error\n");
return -1;
}
if(!TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &length)){
printf("TIFFGetField length error\n");
TIFFClose(tiff);
return -1;
}
if(!TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &width)){
printf("TIFFGetField width error\n");
TIFFClose(tiff);
return -1;
}
if(!TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bitpersample)){
printf("TIFFGetField bitpersample error\n");
TIFFClose(tiff);
return -1;
}
if(bitpersample != 8){
printf("1プレーン8bit以外の画像データは扱っていません\n");
TIFFClose(tiff);
return -1;
}
if(!TIFFGetField(tiff, TIFFTAG_SAMPLESPERPIXEL, &ch)){
printf("TIFFGetField samplesperpixel error\n");
TIFFClose(tiff);
return -1;
}
printf("width = %d, length = %d, ch = %d\n", width, length, ch);
rgbaData = (unsigned int*)malloc(sizeof(unsigned int) * width * length);
if(rgbaData == NULL){
printf("malloc rgbaData error\n");
TIFFClose(tiff);
return -1;
}
if(!TIFFReadRGBAImage(tiff, width, length, rgbaData, 0)){
printf("TIFFReadRGBAImage error\n");
free(rgbData);
TIFFClose(tiff);
return -1;
}
TIFFClose(tiff);
rgbData = (unsigned char*)malloc(sizeof(unsigned char) * width * length * 3);
if(rgbData == NULL){
printf("malloc rgbData error\n");
free(rgbaData);
return -1;
}
/* なぜか読み込み画像が上限反転するので強制的にさらに上下回転させてる */
for(j = 0; j < length; j++){
for(i = 0; i < width; i++){
#if 1
rgbData[3 * (i + j * width) + 0] = TIFFGetR(rgbaData[i + (length - 1 - j) * width]);
rgbData[3 * (i + j * width) + 1] = TIFFGetG(rgbaData[i + (length - 1 - j) * width]);
rgbData[3 * (i + j * width) + 2] = TIFFGetB(rgbaData[i + (length - 1 - j) * width]);
#else
rgbData[3 * (i + j * width) + 0] = TIFFGetR(rgbaData[i + j * width]);
rgbData[3 * (i + j * width) + 1] = TIFFGetG(rgbaData[i + j * width]);
rgbData[3 * (i + j * width) + 2] = TIFFGetB(rgbaData[i + j * width]);
#endif
}
}
free(rgbaData);
bitmapData->data = rgbData;
bitmapData->width = width;
bitmapData->height = length;
bitmapData->ch = 3;
return 0;
}
int tiffFileEncodeWrite(BITMAPDATA_t *bitmapData, COMPRESSION_TYPE_t cmpType, const char* filename){
TIFF *tiff;
tsize_t size;
if(filename == NULL){
printf("ファイル名がNULL\n");
return -1;
}
tiff = TIFFOpen(filename, "w");
if(tiff == NULL){
printf("TIFFOpen error\n");
return -1;
}
if(cmpType == NONE_COMPRESSION){
if(!TIFFSetField(tiff, TIFFTAG_COMPRESSION, COMPRESSION_NONE)){
printf("TIFFSetField compression error\n");
TIFFClose(tiff);
return -1;
}
} else if(cmpType == LZW_COMPRESSION){
if(!TIFFSetField(tiff, TIFFTAG_COMPRESSION, COMPRESSION_LZW)){
printf("TIFFSetField compression error\n");
TIFFClose(tiff);
return -1;
}
} else {
printf("encode type error:%d\n", cmpType);
TIFFClose(tiff);
return -1;
}
if(!TIFFSetField(tiff, TIFFTAG_IMAGEWIDTH, bitmapData->width)){
printf("TIFFSetField width error\n");
TIFFClose(tiff);
return -1;
}
if(!TIFFSetField(tiff, TIFFTAG_IMAGELENGTH, bitmapData->height)){
printf("TIFFSetField length error\n");
TIFFClose(tiff);
return -1;
}
if(!TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8)){
printf("TIFFSetField bitspersample error\n");
TIFFClose(tiff);
return -1;
}
if(!TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, 3)){
printf("TIFFSetField samplesperpixel error\n");
TIFFClose(tiff);
return -1;
}
if(!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB)){
printf("TIFFSetField photometric error\n");
TIFFClose(tiff);
return -1;
}
if(!TIFFSetField(tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)){
printf("TIFFSetField planarconfig error\n");
TIFFClose(tiff);
return -1;
}
if(!TIFFSetField(tiff, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB)){
printf("TIFFSetField fillorder error\n");
TIFFClose(tiff);
return -1;
}
if(!TIFFSetField(tiff, TIFFTAG_XRESOLUTION, 72.0)){
printf("TIFFSetField xresolution error\n");
TIFFClose(tiff);
return -1;
}
if(!TIFFSetField(tiff, TIFFTAG_YRESOLUTION, 72.0)){
printf("TIFFSetField yresolution error\n");
TIFFClose(tiff);
return -1;
}
if(!TIFFSetField(tiff, TIFFTAG_ROWSPERSTRIP, bitmapData->height)){
printf("TIFFSetField rowsperstrip error\n");
TIFFClose(tiff);
return -1;
}
size = TIFFWriteEncodedStrip(tiff, 0, bitmapData->data, bitmapData->width * bitmapData->height * 3);
if(size == -1){
printf("TIFFWriteEncodedStrip error\n");
TIFFClose(tiff);
return -1;
}
printf("writeSize = %lu\n", size);
TIFFClose(tiff);
return 0;
}
int freeBitmapData(BITMAPDATA_t *bitmap){
free(bitmap->data);
return 0;
}
特に TIFF の読み込みを行う tiffFileReadDecode
関数と、TIFF の書き込みを行う tiffFileEncodeWrite
関数の詳細を解説していきます。
TIFF ファイルの読み込みを行う関数
tiffFileReadDecode
関数は TIFF ファイルの読み込みを行う関数になります。
より具体的には、この tiffFileReadDecode
関数は下記を行う関数になります。
- 引数で指定された
filename
のファイルを読み込む - 読み込んだファイルの TIFF データをデコードし BITMAP 形式画像データに変換
- BITMAP 形式画像データをさらに関数呼び元で扱いやすいように
unsigned int
型からunsigned char
型に変換(RGB それぞれを 1 バイトずつに分けて格納。Aチャネルは捨てています) - 画像データのアドレスや画像の幅や高さを引数の
bitmapData
にセット
tiffFileReadDecode
関数で使用している下記関数は、LibTIFF が提供している関数になります。
TIFFOpen
:TIFF ファイルを開くTIFFReadRGBAImage
:TIFF ファイルを RGBA 形式にデコードTIFFSetField
:TIFF ファイルのヘッダー内の指定したタグの値を取得TIFFClose
:TIFF ファイルを閉じる
一応 Mac のプレビューソフトで TIFF 形式で書き出したデータの読み込みの動作確認はしています。ただし JPEG 圧縮のみ試していません(前述の通り JPEG 圧縮は上でも触れているように libJpeg をインストールしないと対応できません)。
コメントでも書いているのですがなぜか画像が上下逆転する現象が起きたので無理やり直しています
もしかしたら何か勘違いして処理してしまっているのかも
スポンサーリンク
TIFF ファイルの書き込み(保存)を行う関数
tiffFileEncodeWrite
関数は TIFF ファイルの書き込み(保存)を行う関数になります。
より具体的には、この tiffFileEncodeWrite
関数下記を行う関数になります。
- 引数で指定された
filename
のファイルを作成 - 引数の
bitmapData
にセットされている情報等から TIFF のヘッダのタグの値の設定(圧縮方法は引数のcmpType
で指定されたものを使用) - 引数の
bitmapData
のdata
メンバで指定されるアドレスのデータをエンコードして開いているファイルに書き込み
tiffFileEncodeWrite
内でも LibTIFF が提供する下記関数を利用しています(tiffFileReadDecode
で使用している関数は省略しています)。
TIFFWriteEncodedStrip
:TIFFをエンコードして指定したTIFFファイルに書き込むTIFFSetField
:TIFFヘッダーのタグの値を指定してセットする
作成した TIFF 読み込み・書き込み関数の使用例
上記で作成した関数の使い方がイメージつくように使用例を書いてみました。
#include "myTiff.h"
int main(int argc, char *argv[]){
BITMAPDATA_t bitmap;
int i, j, c;
int ave, sum;
char outname[256];
FILE *fo;
if(argc != 2){
printf("ファイル名が指定されていません\n");
return -1;
}
if(tiffFileReadDecode(&bitmap, argv[1]) == -1){
printf("tiffFileReadDecode error\n");
return -1;
}
printf("bitmap->data = %p\n", bitmap.data);
printf("bitmap->width = %d\n", bitmap.width);
printf("bitmap->height = %d\n", bitmap.height);
printf("bitmap->ch = %d\n", bitmap.ch);
#if 0
/* ちゃんと読み込めているか確認する場合はここを有効に */
fo = fopen("testoutput.ppm", "wb");
fprintf(fo, "P6\n#\n%d %d\n255\n", bitmap.width, bitmap.height);
fwrite(bitmap.data, bitmap.height * bitmap.width * 3, 1,fo);
fclose(fo);
#endif
/* グレースケールに変換 */
for(j = 0; j < bitmap.height; j++){
for(i = 0; i < bitmap.width; i++){
sum = 0;
for(c = 0; c < bitmap.ch; c++){
sum += bitmap.data[bitmap.ch * (i + j * bitmap.width) + c];
}
ave = sum / bitmap.ch;
for(c = 0; c < bitmap.ch; c++){
bitmap.data[bitmap.ch * (i + j * bitmap.width) + c] = ave;
}
}
}
sprintf(outname, "%s", "output.tiff");
if(tiffFileEncodeWrite(&bitmap, LZW_COMPRESSION, outname) == -1){
printf("tiffFileEncodeWrite error\n");
freeBitmapData(&bitmap);
return -1;
}
freeBitmapData(&bitmap);
return 0;
}
処理の流れ
この main
関数の処理の流れは下記の通りです。
tiffFileReadDecode
関数を使用して TIFF ファイルの読み込みデコード- 1. でデコードした BITMAP データに対して画像処理
- 2. 画像処理後の BITMAP データを
tiffFileEncodeWrite
関数を使用してエンコード & TIFF ファイルへの書き込み freeBitmapData
関数でメモリ解放して終了
画像処理
2. の画像処理では、1. でデコードした画像をグレースケールに変換しています(単純に RGB の輝度値の平均値を求めているだけ)。
画像処理をいろいろ試す場合はここをいろいろ変更して試してみると良いと思います。
/* グレースケールに変換 */
for(j = 0; j < bitmap.height; j++){
for(i = 0; i < bitmap.width; i++){
sum = 0;
for(c = 0; c < bitmap.ch; c++){
sum += bitmap.data[bitmap.ch * (i + j * bitmap.width) + c];
}
ave = sum / bitmap.ch;
for(c = 0; c < bitmap.ch; c++){
bitmap.data[bitmap.ch * (i + j * bitmap.width) + c] = ave;
}
}
}
コンパイル
このページで紹介するソースコードでは、 TIFF 読み込み用・書き込み用の関数を myTiff.c
に作成し、それらの関数のプロトタイプ宣言をヘッダーファイルの myTiff.h
で行っています。
ですので、上記のソースコードで myTiff.h
のインクルードを行なっています。
違う名前にする場合は変更必要ですのでお気をつけください。
このページで紹介しているファイル名でソースコードファイルを作成している時、下記のコマンドでコンパイルとプログラムの実行が可能です。
gcc main.c -c gcc myTiff.c -c gcc main.o myTiff.o -o tiff.exe -ltiff ./tiff.exe test.tiff
前にも説明していますが、重要なのはコンパイル時に -ltiff
を付けることです。これは LibTIFF にリンクするためのコンパイルオプションになります。
また、ここで載せたソースコードはあくまで一例です。
TIFF ファイルを読み込んでデコードするあたりや TIFF ファイルをエンコードして書き込むあたりはご自身が使いやすいようにカスタマイズしてください。
LibTIFF が提供する関数
LibTIFF が提供する関数にどんなものがあるかや、使用方法は下記の「Man Pages – LibTIFF」に記載されています。
英語なので読むのが大変かもしれませんが、これを参考にすればC言語で TIFF ファイルをもっと巧みに扱えるようになると思います。
参考 Man Pages - LibTIFFlibtiff.orgリクエストが多いようであれば使用方法を別記事でまた作成したいと思います。
このページは LibTIFF のインストール方法や使用例の紹介を目的としたページであり、LibTIFF のライセンス体系については私も詳しくないのでこのページでは言及していません
LibTIFF を使用する方は自己責任で使用してください
例えば商用利用等を行う場合はライセンス体系についてご自分で調査してから使用の可否をご判断ください
スポンサーリンク
まとめ
このページでは LibTIFF のインストール方法やプログラム中での使い方について解説しました。
画像処理プログラミングを始めるにあたって大きな壁になるのは「画像ファイルの読み込みと書き込み」です。
LibTIFF が使えればこれらを簡単に行えるようになりますので、是非このページを参考にして TIFF ファイルの読み込み・書き込みできる環境を整えてみてください!
私のサイトでは他にも libjpeg や libpng、libwebp のインストール方法や使い方についても解説していますので、他の画像フォーマットを利用したい方は是非下記のページも読んでみてください。
【C言語】libjpegのインストールと使用方法・使用例 【C言語】libpngのインストールと使用方法・使用例 【C言語】libwebpのインストールと使用方法・使用例