参考書を元に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)なっているのでしょうか?
どこに画像データが有るのでしょうか?
No.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);
で解放しなければならない。
詳しい説明ありがとうございます。
lpPixelはデータそのものではなく、
lpPixelを始点として、そこから画像データが並んでいて
それを指しているのですね。
解放についても教えてくださりありがとうございます。
感謝。
No.2
- 回答日時:
こんばんは。
大分的ハズレな回答をしてしましました・・・。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ビット型のビットマップファイルとしてセーブした時、他のソフトがどの様に読み込もうとするかは不明です。
>32ビット型ではビットフィールドが無くてもBI_RGBのフラグを立てると描写が出来る様です。
なるほど・・。
ありがとうございました。
No.1
- 回答日時:
こんばんは。
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を取り扱ったサイトを見た方が良いと思います。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- その他(プログラミング・Web制作) pythonでクラスで複数のメソッドを利用する方法 2 2022/04/15 04:17
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# leetcode 155 minstack 1 2022/05/07 16:43
- JavaScript clear機能を失わずにファイルアップロード機能を作成したい 3 2023/06/10 16:12
- C言語・C++・C# c言語の問題です 2 2023/07/21 10:51
- Java javaでのプログラム(配列)について質問です. 2 2022/10/14 22:27
- PHP ここでの ②if($su_d<>"")の比較演算子 を使う理由は 1 2022/03/26 02:33
- Visual Basic(VBA) 3つのプロシージャをまとめたら実行時エラー発生で対応不能 6 2022/05/17 01:47
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
バッファとは何ですか
-
Microsoft VBAで2GBを超えるフ...
-
エラー:ストリームの終わりを...
-
EXCEL VBAでテキストファイルの...
-
エクセルVBA 2千万行のCSVファ...
-
バイナリファイルの比較につい...
-
画像の保存方法。
-
バイナリファイルの検索について
-
HDDのバイナリイメージの取得方...
-
入力ファイルをバイナリにする利点
-
削除したファイルの復旧、およ...
-
JavaScriptの実行速度が遅い
-
VBA バイナリ―から文字列にす...
-
ページ読み込み時に自動的にsub...
-
C言語とシリアル通信の送受信...
-
FMFファイルの構造を知りたいの...
-
バイナリ形式のXMLファイルを読...
-
MacからWinにファイルを添付す...
-
バイナリデータ処理
-
テキストデータをSQLServerに取...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
バッファとは何ですか
-
Microsoft VBAで2GBを超えるフ...
-
EXCEL VBAでテキストファイルの...
-
VBA バイナリ―から文字列にす...
-
バイナリエディタのつかいかた
-
エクセルVBA 2千万行のCSVファ...
-
EOF
-
ページ読み込み時に自動的にsub...
-
エラー:ストリームの終わりを...
-
画像の保存方法。
-
【python】Excelファイルを読み...
-
MacからWinにファイルを添付す...
-
入力ファイルをバイナリにする利点
-
EXCEL VBAで、バイナリデータの...
-
PHPのfgetcsvの処理容量について
-
VBAを使って、一部バイナリデー...
-
HDDのバイナリイメージの取得方...
-
FTPでエクセルをPUTするとファ...
-
リストビュー ⇔ 別ファイル構...
-
クリップボードからファイル名...
おすすめ情報