電子書籍の厳選無料作品が豊富!

参考書を元にBMPを読み込み、
BYTE*型にデータを移して、画像処理や転送に利用できるようにしたいのですが、
どこに画像データの実体が有るのかがよくわかりません・・。
----------
static LPBYTE lpDIB = NULL;
static LPBITMAPINFO lpbiInfo;
static LPDWORD lpPixel;

LPBYTE lpBMP;
LPBITMAPINFOHEADER lpbiBMPInfo;
LPBYTE lpBMPPixel;
BYTE* ppp;

static int iWidth, iHeight, iLength;
int iFileSize;
DWORD dwOffset;
int i, j;

HANDLE fhBMP;
DWORD dwRead;

HDC hdc;
PAINTSTRUCT ps;

/*BMP取得*/
//ファイルオープン
fhBMP = CreateFile("test.bmp", GENERIC_READ, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

if (fhBMP == INVALID_HANDLE_VALUE) {
MessageBox(NULL, "test.bmpが見つかりません。", "エラー", MB_OK);
return 0;
}

//ファイルサイズ取得
iFileSize = GetFileSize(fhBMP, NULL);

//ファイル読み込みバッファ確保
lpBMP = (LPBYTE)HeapAlloc(GetProcessHeap(), 0, iFileSize);

//ファイル読み込み
ReadFile(fhBMP, lpBMP, iFileSize, &dwRead, NULL);

//ファイルを閉じる
CloseHandle(fhBMP);

//BMP内のBITMAPINFO取得
lpbiBMPInfo = (LPBITMAPINFOHEADER)
(lpBMP + sizeof(BITMAPFILEHEADER));

//先頭からピクセル列までのオフセット取得
dwOffset = *(LPDWORD)(lpBMP + 10);

//BMP内ピクセル列の先頭アドレス計算
lpBMPPixel = lpBMP + dwOffset;

//ビットマップの大きさ取得
iWidth = lpbiBMPInfo->biWidth;
iHeight = lpbiBMPInfo->biHeight;

//BMPピクセル列の1ラインの長さを計算
if (iWidth % 4 == 0) {
iLength = iWidth * 3;
} else {
iLength = iWidth * 3 + (4 - (iWidth * 3) % 4);
}

//DIB用バッファを確保
lpDIB = (LPBYTE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof(BITMAPINFO) + iWidth * iHeight * 4);

//DIB用ポインタ分配
lpbiInfo = (LPBITMAPINFO)lpDIB;
lpPixel = (LPDWORD)(lpDIB + sizeof(BITMAPINFO));

//BITMAPINFO設定
lpbiInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
lpbiInfo->bmiHeader.biWidth = iWidth;
lpbiInfo->bmiHeader.biHeight = iHeight;
lpbiInfo->bmiHeader.biPlanes = 1;
lpbiInfo->bmiHeader.biBitCount = 32;
lpbiInfo->bmiHeader.biCompression = BI_RGB;

//BMP内のピクセル列を32ビット化してコピー
for (i = 0;i < iHeight;i++)
for (j = 0;j < iWidth; j++)
CopyMemory(lpPixel + j + i * iWidth,
lpBMPPixel + j * 3 + i * iLength, 3);

//ファイル読み込みバッファ解放
HeapFree(GetProcessHeap(), 0, lpBMP);


/*描画*/
hdc = BeginPaint(hWnd, &ps);

//DIBをウインドウのDCに描画
StretchDIBits(hdc, 0, 0, iWidth, iHeight,
0, 0, iWidth, iHeight, lpPixel, lpbiInfo,
DIB_RGB_COLORS,SRCCOPY);

EndPaint(hWnd, &ps);

----------
描画部分のStretchDIBits()を調べて
lpPixelに格納されているように思えたのですが、これはただのDWORDですし。
lpBMPPixelだとしても、描画では全く使われていないのが不可解で。

なぜこう(描画にDWORD)なっているのでしょうか?
どこに画像データが有るのでしょうか?

A 回答 (3件)

>どこに画像データが有るのでしょうか?



>//ファイルサイズ取得
>iFileSize = GetFileSize(fhBMP, NULL);
>//ファイル読み込みバッファ確保
>lpBMP = (LPBYTE)HeapAlloc(GetProcessHeap(), 0, iFileSize);
>//ファイル読み込み
>ReadFile(fhBMP, lpBMP, iFileSize, &dwRead, NULL);

まず「ファイルの中身」が、ヘッダーや、生の画像データごと、まるまま「lpBMPが指しているメモリ」に入って来る。

このメモリはHeapAllocで確保している。

つまり「bmpファイルの中身そのまま」が「lpBMPが指すメモリ」に居る。

>//BMP内ピクセル列の先頭アドレス計算
>lpBMPPixel = lpBMP + dwOffset;

で、画像データは、lpBMPからdwOffsetだけ進んだ先にあるので、lpBMPPixelに「ファイルから読み込んだ、生の画像データの先頭のポインタ」を代入している。

>//DIB用バッファを確保
>lpDIB = (LPBYTE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFO) + iWidth * iHeight * 4);

一方、実際に描画に使うデータはDIBデータなので、ヘッダとDIBデータのサイズを求め、そのサイズ分だけのメモリを確保し、確保したメモリの先頭アドレスをlpDIBに代入している。

>//DIB用ポインタ分配
>lpbiInfo = (LPBITMAPINFO)lpDIB;
>lpPixel = (LPDWORD)(lpDIB + sizeof(BITMAPINFO));

で、確保したメモリの先頭部分がヘッダ、ヘッダの大きさ分だけ進んだアドレスがDIBピクセルデータなので、それぞれをlpbiInfo、lpPixelに代入している。

次に、lpbiInfoとlpPixelが指すアドレスに「ファイルから読み込んだデータを、DIBデータに合うように変形して、コピー」して、DIBデータを作る必要がある。

それが

>//BITMAPINFO設定
>lpbiInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
>lpbiInfo->bmiHeader.biWidth = iWidth;
>lpbiInfo->bmiHeader.biHeight = iHeight;
>lpbiInfo->bmiHeader.biPlanes = 1;
>lpbiInfo->bmiHeader.biBitCount = 32;
>lpbiInfo->bmiHeader.biCompression = BI_RGB;

>//BMP内のピクセル列を32ビット化してコピー
>for (i = 0;i < iHeight;i++)
>for (j = 0;j < iWidth; j++)
>CopyMemory(lpPixel + j + i * iWidth,
>lpBMPPixel + j * 3 + i * iLength, 3);
の部分。

「lpBMPが指す、ファイルの中身」を「lpbiInfoが指すヘッダ、lpBMPPixelが指すDIBピクセルデータ」にコピーし終わったなら、もう「lpBMPが指す、ファイルの中身」は不要なので
>HeapFree(GetProcessHeap(), 0, lpBMP);
で解放している。

このプログラム、lpDIBが指してるDIBヘッダ+DIBデータのメモリ、確保だけ行って使い終わってから解放してないので、何度も実行するとメモリがリークするので注意。

要は
lpbiInfo = (LPBITMAPINFO)lpDIB;
lpPixel = (LPDWORD)(lpDIB + sizeof(BITMAPINFO));
が肝心の部分で、
lpbiInfo⇒読み込んだデータのDIBヘッダー
lplpPixel⇒読み込んだデータのDIB画像データ
って事。

因みに、lpDIBは「DIBヘッダーとDIB画像データの両方を合わせた、確保したメモリのアドレス」を保持していて、不要になったら
HeapFree(GetProcessHeap(), 0, lpDIB);
で解放しなければならない。
    • good
    • 0
この回答へのお礼

詳しい説明ありがとうございます。
lpPixelはデータそのものではなく、
lpPixelを始点として、そこから画像データが並んでいて
それを指しているのですね。

解放についても教えてくださりありがとうございます。
感謝。

お礼日時:2009/03/17 01:09

 こんばんは。

大分的ハズレな回答をしてしましました・・・。

 lpBMPPixelについての事ですが、

 //BMP内のピクセル列を32ビット化してコピー
 for (i = 0;i < iHeight;i++)
  for (j = 0;j < iWidth; j++)
   CopyMemory(lpPixel/*こっちにコピーしている*/ + j + i * iWidth, lpBMPPixel/*ココで必要*/ + j * 3 + i * iLength, 3);

 の所で使用されています。描画に関連してこないのは、lpPixelにコピーしているからです。
 コメントに書いて有る様に、lpBMPPixelは、24ビットの扱いに成っていますから、32ビット型のバッファであるlpPixelに変換コピーして、lpPixelの方を描写に使用するという事です。

 なので、このプログラムは読み込んでくるtest.bmpが24ビット型でなければいけない事に成ります。
 後ビットフィールドの事ですが、32ビット型ではビットフィールドが無くてもBI_RGBのフラグを立てると描写が出来る様です。
 ただ、此の侭32ビット型のビットマップファイルとしてセーブした時、他のソフトがどの様に読み込もうとするかは不明です。
    • good
    • 0
この回答へのお礼

>32ビット型ではビットフィールドが無くてもBI_RGBのフラグを立てると描写が出来る様です。
なるほど・・。
ありがとうございました。

お礼日時:2009/03/17 01:01

 こんばんは。



 LPDWORDに成っているのは、32ビット型のDIBを処理するのに楽だからだと思います。LPBYTEで回した場合、次のピクセルを指すのに4つ分飛ばさないといけません(回し方にもよります)。
 lpBMPPixelに読み取り元、lpPixelに書き込み先ではないでしょうか。
 但し、其の前に、32ビット型DIBで有るにもかかわらず、ビットフィールドの指定が無い等、何だかパッと見て怪しい様な感じが・・・。
 本来BI_RGBではなく、BI_BITFIELDSを指定した上でBITMAPINFOHEADERの直下にRGBQUAD[3]相当の拡張割り当てが無ければいけない筈です。

 一応似た様な事例を挙げておきます。
 http://oshiete1.goo.ne.jp/qa4364441.html
 http://oshiete1.goo.ne.jp/qa4431353.html

 どちらにしろ、その参考書は置いて、DIBを取り扱ったサイトを見た方が良いと思います。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

お礼日時:2010/05/26 20:42

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!