DWORD境界の脅威
相変わらずBitmap読んでるんですが(ぉ^^;*1 )、従来のコードにバグみたいなものがあることに気づいたわけです。
仮に24bitBitmapのデータ本体を読み込むとした時…
BITMAPHEADERINFO sInfo; // + どうにかする void* pBuff; // | DWORD dwReadSize; const UINT nBMPSize = sInfo.biWidth * abs(sInfo.biHeight) * sInfo.biBitCount / 8;
- ReadFile(hBMPFile, pBuff, nBMPSize, &dwReadSize);
と描いては正常に読めない事は有名どころ。横幅は 4byte の倍数として記録されているため、ごみバイトを考慮してないわけですねー。
というわけで、こんな感じのコードを描いてたわけです。
BITMAPHEADERINFO sInfo; // + どうにかする void* pBuff; // | DWORD dwReadSize; const UINT nWidthDWORD = (sInfo.biWidth + 3) & ~0x03; const UINT nBMPSize = nWidthDWORD * abs(sInfo.biHeight) * sInfo.biBitCount / 8;
- ReadFile(hBMPFile, pBuff, nBMPSize, &dwReadSize);
これであれば、width が 4の倍数になるので良い感じ。 うむ。
…と思ったのですが、読み取ったデータを利用する時に大問題があることに気づいたわけです。
// 24bit bmp だとした場合 const int nPixelSize = sInfo.biWidth * abs(sInfo.biHeight); RGBTRIPLE* psData = static_cast<RGBTRIPLE*>(pBuff); RGBTRIPLE* psDataEnd = psData + nPixelSize; for(; psData != psDataEnd; ++psData) { psData->rgbRead; // とかごにょごにょ… }
……
// 24bit bmp, w:h = 2:3 だった場合 bgrbgrxx bgrbgrxx bgrbgrxx ↓バイト列だと bgrbgrxxbgrbgrxxbgrbgrxx
psData[2].rgbRed = x; psData[2].rgbGreen = x;
じゃん! orz
つか、それ以前にゴミを考慮してないから、普通に ++ していくだけじゃ扱うことできないやん……。
というわけで 「1行分のデータを読む -> ゴミを読みすてる -> 1行分のデータを読む -> ゴミを読みすてる」 という形で、ゴミデータを読み捨てる方法で、データ本体だけの純粋な配列にすることにしました。
…が、8bit 以上であればコレでよいのですが、問題は4bit以下のビットマップでして…。 0.5byte の世界は激しくめんどくさいヨ orz
*1:コード打つ時間が中々ないのよ…