libtiff: モノクロ2階調の読み込み

TIFFTAG_PHOTOMETRICの値が0、TIFFTAG_BITSPERSAMPLEの値が1ならばモノクロ2階調ファイルです。
このフォーマットは1バイトの中に8ピクセル分のデータが入っていることになります。
したがって、各ピクセルの値を取り出すにはビット演算が必要になります。

このフォーマットを扱う場合の注意点は以下のとおりです。
(当たり前といえば当たり前のことですが、、)


  • TIFFScanlineSize()関数が返す値は”(int)(ピクセル数/8)+1”です。
    例として、幅50pxのファイルの場合は、(int)(50/8)+1=7(Bytes)となります。

    2011/07/20:間違いです。下記コメントラン参照。
  • 1pixel=1bitのまま処理するならこれでもいいのですが、1バイトに1ピクセルを割り当てたほうが何かと便利なことも多いかと思います。
    その場合はしょうがないので別のバッファを用意する必要があります。
  • 画像の幅が8で割り切れない数字の場合、スキャンライン1列を処理するとき、最後の1バイトは端数が出ることになります。
    しょうがないので、ここは場合分けで対応したほうがいいでしょう。
#include <windows.h>
#include <tiffio.h>

bool ReadTIFF( LPCTSTR lpszFName )
{
  int  nImageLength;
  int  nImageWidth;
  int  nBitsPerSample;
  int  nSamplePerPixel;
  int  nPhotometric;
  int  nRowsPerStrip;
  int i, j, k, l;
  int nRow, nPix;
  int nScanlineSize;
  TIFF *pTif;
  LPBYTE pBuf;  // 読み込んだままの状態のデータを保持するバッファ
  LPBYTE pPix;  // 読み込んだデータを1byte=1pixに取り込むバッファ

  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;  //色数
  if ( TIFFGetField( pTif, TIFFTAG_ROWSPERSTRIP,    &nRowsPerStrip    ) != 1 ) 
    nRowsPerStrip = 1;  //ストリップ1つあたりの行数 エラーの場合はデフォルト値
  if ( TIFFGetField( pTif, TIFFTAG_PHOTOMETRIC,     &nPhotometric     ) != 1 ) 
    return false;  //画像の種別
  
  nScanlineSize = TIFFScanlineSize( pTif );

  pBuf = (LPBYTE)_TIFFmalloc( nScanlineSize ); // 修正しました(Hayashi様ありがとうございます)
  pBuf = (LPBYTE)_TIFFmalloc( nRowsPerStrip*nScanlineSize );
  pPix = new BYTE[nImageWidth*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*nScanlineSize ) == -1 )
    {
      fprintf( stderr, "errorn" );
      delete[] pPix;
      _TIFFfree( pBuf );
      return false;
    }
    else
    {
      for ( j = 0; j < nRow; j++ )
      {
        for ( k = 0; k < nScanlineSize; k++ )
        {
          /* 最終列かどうかで場合分け */
          nPix = k == nScanlineSize-1 ? nScanlineSize % 8 : 8;
          for ( l = 0; l < nPix; l++ )
          {
            // 0 or 1で格納
            pPix[j*nImageWidth+k*8+l] = ((pBuf[j*nScanlineSize+k] << l) & 0x01) >> 7;
          }
        }
      }
    }
  }
  
  delete[] pBuf;
  delete[] pPix;  // 修正しました(Hayashi様ありがとうございます)
  TIFFClose( pTif );
  
  return true;
}
アーカイブ