TIFFTAG_PHOTOMETRIC
の値が3
ならばインデックスカラーファイルです。
この場合、TIFFTAG_COLORMAP
が書き込まれていないファイルは無効になります。
インデックスカラーのTIFFファイルでも、画像部分は普通に読み込むことが出来ます。
問題はパレットの扱いです。
TIFFTAG_COLORMAP
にはパレットが書き込まれているわけですが、
パレットの数は2^BitsPerSample
と決まっているようです。8bitなら256個のパレットが書き込まれています。
なので、たとえば4色しか使用していなくても必ず256個のパレットが書き込まれています。
順番はRGBの順番で書き込まれていることとなっているようです。
また、パレットは0~65535のうちの任意の値が使用できることになっているようです。
つまり、RGBの値が全て65535のときに白と定義されています。
8bitに変換したいときは255/65535をかけなければいけないわけです。
とはいうものの、この仕様に従っていない場合も多いようで、libtiffに付属のpal2rgbのソースコードでは
パレットが8bitか16bitかを確認する関数が用意されていました。
以下の例ではカラーテーブルを読み込んだ後にインデックスカラーの画像を読み込み、RGBの値に変換する例です。
いくつかの関数でlibtiffに付属のpal2rgb.cを参考にしています。
TIFFGetField()
関数でTIFFTAG_COLORMAP
を読み込むときに渡す引数に注意してください。
#include <windows.h> #include <tiffio.h> // 16bit → 8bit深度への変換 #define CVT(x) (((x) * 255) / ((1L<<16)-1)) // パレットが16bit深度のものかどうか調べる static int checkcmap(int n, WORD *r, WORD *g, WORD *b) { while (n-- > 0) if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256) return (16); return (8); } bool ReadTIFF( LPCTSTR lpszFName ) { int nImageLength; int nImageWidth; int nBitsPerSample; int nSamplePerPixel; int nPhotometric; int nRowsPerStrip; int i; int nRow; TIFF *pTif; LPBYTE pBuf; WORD *pwPalR, *pwPalG, *pwPalB; // カラーテーブルを保持するポインタ pTif = TIFFOpen( lpszFName, "r" ); if (!pTif) return false; //横 if ( TIFFGetField( pTif, TIFFTAG_IMAGEWIDTH, &nImageWidth ) != 1 ) return false; //縦 if ( TIFFGetField( pTif, TIFFTAG_IMAGELENGTH, &nImageLength ) != 1 ) return false; //色深度のビット数 if ( TIFFGetField( pTif, TIFFTAG_BITSPERSAMPLE, &nBitsPerSample ) != 1 ) return false; //色数 if ( TIFFGetField( pTif, TIFFTAG_SAMPLESPERPIXEL, &nSamplePerPixel ) != 1 ) return false; //ストリップ1つあたりの行数 エラーの場合はデフォルト値 if ( TIFFGetField( pTif, TIFFTAG_ROWSPERSTRIP, &nRowsPerStrip ) != 1 ) nRowsPerStrip = 1; //画像の種別 if ( TIFFGetField( pTif, TIFFTAG_PHOTOMETRIC, &nPhotometric ) != 1 ) return false; if ( nPhotometric == 3 ) // インデックスカラーならば { // カラーマップは必須 if ( TIFFGetField( pTif, TIFFTAG_COLORMAP, &pwPalR, &pwPalG, &pwPalB ) != 1 ) return false; if ( checkcmap( 1<<nBitsPerSample, pwPalR, pwPalG, pwPalB ) == 16 ) { for ( int i = (1<<nBitsPerSample)-1; i >= 0; i--) { pwPalR[i] = CVT( pwPalR[i] ); pwPalG[i] = CVT( pwPalG[i] ); pwPalB[i] = CVT( pwPalB[i] ); } } } pBuf = new BYTE[nImageWidth*nSamplePerPixel*nRowsPerStrip]; for ( i = 0; i < nImageLength; i += nRowsPerStrip ) { /* ストリップの行数を計算 */ nRow = (i + nRowsPerStrip > nImageLength) ? nImageLength - i : nRowsPerStrip; /* バッファに1ストリップ分読み込み */ if ( TIFFReadEncodedStrip( pTif, TIFFComputeStrip( pTif, i, 0 ), pBuf, nRow*nImageWidth*nSamplePerPixel ) == -1 ) { fprintf( stderr, "errorn" ); delete[] pBuf; return false; } else { /* バッファに入っているピクセルに対する処理 */ /* パレットからRGBに変換するならこんなかんじ r = pwPalR[pBuf[x]]; g = pwPalG[pBuf[x]]; b = pwPalB[pBuf[x]]; */ } } delete[] pBuf; TIFFClose( pTif ); return true; }