メモリに転送したBMPを表示したいのですが。

[戻る]
CGA 2004/04/24(土) 01:45:06
はじめまして。
メモリに転送したBMP(フルカラー)を表示したいのですが、目的のBMPではなく
ゴミのようなものが表示されてしまいます。(表示されている高さ、幅は目的サイズです)
どうぞよろしくお願いします。
開発環境はWINDOWS ME。VC++6.0です。

WM_PAINTから呼ばれてくるのが下記コードです。

void SampleLoad(HWND hWnd)
{
    HANDLE fp;
    BITMAPFILEHEADER Bf;
    LPBITMAPINFOHEADER lpBi;
    DWORD dwResult;
    HDC hdc;
    HBITMAP hBitmap;
    LPBYTE pDibBits;
    HDC hdcRef;
    HBITMAP hbmOld;
    HDC hdcBitmap;

    //ファイルオープン
    fp = CreateFile(".\\pai\\1man.bmp", GENERIC_READ, 0, NULL,
                                  OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,NULL);
    if (fp == INVALID_HANDLE_VALUE)
        MessageBox(hWnd, "ファイルのオープンに失敗しました", "Error", MB_OK);

    //ファイルポインタを先頭位置にする
    SetFilePointer(fp,0,NULL,FILE_BEGIN);
    //ヘッダ部読み込み
    ReadFile(fp,&Bf,sizeof(BITMAPFILEHEADER),&dwResult,NULL);
  //ヘッダのbfSizeメンバからヘッダのサイズを引いた領域をメモリ上に確保し
  //その領域に,現在のファイルポインタ位置からデータを読み込む
    lpBi=(LPBITMAPINFOHEADER)GlobalAlloc(GPTR,
                                   (Bf.bfSize -sizeof(BITMAPFILEHEADER)));
    ReadFile(fp,lpBi,(Bf.bfSize - sizeof(BITMAPFILEHEADER)),&dwResult,NULL);
    //メモリ上に読み込んだのでファイルクローズする
    CloseHandle(fp);

    //問題は下記からだと思います。
    hdcRef = GetDC(0);
    hBitmap = CreateDIBSection(hdcRef,(BITMAPINFO *)lpBi,DIB_RGB_COLORS,
                                                   (VOID **)&pDibBits,NULL,0);
    hdcBitmap = CreateCompatibleDC(hdcRef);
    ReleaseDC(0,hdcRef);
    hbmOld = (HBITMAP)SelectObject(hdcBitmap,hBitmap);

    //表示したいウインドウのDCを取得
    hdc = GetDC(hWnd);
    //BMP表示
    BitBlt(hdc,0,0,lpBi->biWidth,lpBi->biHeight,hdcBitmap,0,0,SRCCOPY);
    //DCの解放
    ReleaseDC(hWnd,hdc);
    SelectObject(hdcBitmap,hbmOld);
    DeleteObject(hBitmap);
    GlobalFree(lpBi);
}

kuma 2004/04/24(土) 03:02:22
ファイルから読み出されたカラーデータが
hBitmapの方へコピーされていません。
pDibBitsの指すメモリ領域の値を調べてみてください。
(WinXPではゼロクリアされていました)

CGA 2004/04/25(日) 00:55:01
kuma様、回答ありがとうございます。

hdcBitmap = CreateCompatibleDC(hdcRef);
ここでブレークして、lpBiのメンバ値と&pDibBitsの指すメモリ領域を見ました。
&pDibBitsの指すメモリ領域は0x0065fa1cで、その位置をデバッグウインドウのメモリで
見たところ下記の様な感じでした。
0065FA1C  6C E9 13 82 8A 20 00 00 CC CC CC CC
0065FA28  FA 0F 00 00 78 00 43 00 42 4D 08 10

lpBiのそれぞれのメンバ値はこうなっていました。
biSize=40
biWidth=29
biHeight=46
biPlanes=1
biBitCount=24
biCompression=0
biSizeImage=0
biXPelsPerMeter=11808
biYPelsPerMeter=11808
biClrUsed=0
biClrImportant=0
でした。

>ファイルから読み出されたカラーデータが
カラーデータ?カラーテーブルの事でしょうか?フルカラーBMPってカラーテーブルは
無いような事がどこかのHPにあったのですが、どうなんでしょうか?
すいません、グラフィックの事は初心者なので。。。

>hBitmapの方へコピーされていません
カラーテーブルをコピーするには、どの位置にコードを追加すればいいのでしょうか?

どうぞ、よろしくお願いします

MASATO [E-Mail] [HomePage] 2004/04/25(日) 05:55:39
kumaさんの発言中のカラーデータはカラーテーブルではなく
ビットマップデータのことだと思います。

CreateDIBSectionは、ビットマップデータからビットマップを作成する関数ではなく、
からっぽのビットマップデータを持ったビットマップを生成する関数です。

CreateDIBSectionではなくCreateDIBitmapを使ってはどうでしょうか。

(例)
hBitmap = CreateDIBitmap(hdcRef, lpBi, CBM_INIT, (BYTE*)lpBi + sizeof
(BITMAPFILEHEADER), (LPBITMAPINFO)lpBi, DIB_RGB_COLORS);

MASATO [E-Mail] [HomePage] 2004/04/25(日) 05:56:57
バグがありました。訂正します。

hBitmap = CreateDIBitmap(hdcRef, lpBi, CBM_INIT, (BYTE*)lpBi + sizeof
(BITMAPINFOHEADER), (LPBITMAPINFO)lpBi, DIB_RGB_COLORS);

kuma 2004/04/25(日) 19:22:31
&pDibBits に、hBitmapのRGB値・パレット番号のいずれかの格納されている
先頭アドレスが格納されています。
またビットマップファイルのビットマップデータは
先頭から (sizeof(BITMAPFILEHEADER)+Bf.bfOffBits) バイト後ろに
格納されています。

あくまで CreateDIBSection() でされるのでしたら
CreateDIBSection() でビットマップを作成してから
pDibBitsの指すメモリ領域に必要バイト数だけ
ファイルから読み込むようにしてみてはいかがでしょうか。

CGA 2004/04/26(月) 01:11:41
MASATO様、KUMA様、回答ありがとうございます。

MASATO様の回答で
>hBitmap = CreateDIBitmap(hdcRef, lpBi, CBM_INIT, (BYTE*)lpBi + sizeof
>(BITMAPINFOHEADER), (LPBITMAPINFO)lpBi, DIB_RGB_COLORS);
に変えてみたところ、うまく表示することが出来ました。

KUMA様の回答で
>CreateDIBSection() でビットマップを作成してから
>pDibBitsの指すメモリ領域に必要バイト数だけ
>ファイルから読み込むようにしてみてはいかがでしょうか。
はまだ試していないのですが、やってみたいと思います。

で質問です。CreateDIBitmapとCreateDIBSectionの違いのことなのですが
ゲーム(内容にもよると思いますが)を作成する上で、どこかのHPには
CreateDIBSectionを使用したほうがゲームには適しているとありました。
今、僕が作成しようとしているのは麻雀ゲームで、キャラクタが動いたり、ちょっとした
アニメーション?の様なものを想像しています。
こういった場合のものを作るにはやはりCreateDIBSectionの方がいいのでしょうか?

MASATO [E-Mail] [HomePage] 2004/04/26(月) 06:59:53
> ゲーム(内容にもよると思いますが)を作成する上で、どこかのHPには
> CreateDIBSectionを使用したほうがゲームには適しているとありました。

これは推測ですが、そのHPでは
「ゲームでは○○○という処理を良く行うので」といったような
理由があるからCreateDIBSectionの方が良い、と書いてあったのではないでしょうか?

重要なのは、CreateDIBSectionの方が良い、という結論ではなく、
その結論に至った過程の方です。そこらへんをそのHPに行って確認してみて下さい。

どちらが良いのか良く分からない段階では、
とりあえずCreateDIBitmapを使ってみてはいかがでしょうか?
もしCreateDIBitmapでは機能が足らないと思ったら、
そのときCreateDIBSectionを使うことを検討してみましょう。

PATIO 2004/04/26(月) 13:33:00
使い方しだいかなという気もしますね。
CreateDIBSectionを使う場合、作成されたDIBのビットマップデータの先頭アドレスが
得られるのでその先頭アドレスと、ビットマップの幅などから操作したい画素子の
アドレスを計算して直接弄る事が出来るのでそういう事がしたいのであれば、
向いていると言えなくもないです。
GDIを使った描画が遅いのでGDIを使わずに描画したい場合などに使うと思います。
この辺はそれこそやり方しだいだと思います。
こういう泥臭い事をしなくてもDirectXなんかは似たような事を内部でやっていると
思うので自前でぐりぐりやるか、ライブラリ任せにするかはあなたしだいだと思います。

CGA 2004/04/26(月) 22:32:29
[[解決]]
MASATO様、PATIO様、回答ありがとうございます。

>とりあえずCreateDIBitmapを使ってみてはいかがでしょうか?
>もしCreateDIBitmapでは機能が足らないと思ったら、
>そのときCreateDIBSectionを使うことを検討してみましょう。
MASATO様の発言どおり、自分の出来ることからやってみたいと思います。
で、どうしてもCreateDIBitmapでは駄目だと思った場合は
再度CreateDIBSectionに挑戦したいと思います。
そのときはまた、質問させていただくと思いますので、どうかよろしくお願いいたします。

とりあえずは、解決チェックを付けておきます。
どうもありがとうございました。

古いスレッドには追加発言できません。