第170章 とりあえずビットマップを表示してみる


さて、前章ではビットマップを読みこんでいろいろな 情報を取得しました。では、ビットマップを画面に表示するには どうしたらよいのでしょうか。これを実現するにはもう少し いくつかの知識が必要です。しかし、「表示できなきゃ面白くない」 と思うのも人情(?)です。そこで、今回は手っ取り早く表示する 方法を紹介します。しかし、いろいろ条件がつきます。 まず、ウィンドウズの表示色をHighColor以上にして下さい。また、読みこむ ビットマップファイルはフルカラーのものです。この条件を 満たさないとひどいことになります。

さて、ビットマップがフルカラーの時はBITMAPINFOHEADER構造体の biBitCountは24となり、RGBQUAD構造体はありません。 一般的に、ビットマップファイルを読みこんで表示するにはBITMAPFILEHEADER構造体を 除いた残りをメモリに読みこみます。これを「パック済みDIBメモリフォーマット」 などと呼ぶことがあります。そして、SetDIBitsToDevice関数を実行します。

int SetDIBitsToDevice( HDC hdc, // デバイスコンテキストハンドル int XDest, // 転送先左上のX座標 int YDest, // Y座標 DWORD dwWidth, // 転送元の横幅 DWORD dwHeight, // 転送元の高さ int XSrc, // 転送元左上のX座標 int YSrc, // 転送元左上のY座標 UINT uStartScan, // ビットマップデータの最初の走査線番号 UINT cScanLines, // 走査線の数 CONST VOID *lpvBits, // ビットマップデータを記憶したバッファへのポインタ CONST BITMAPINFO *lpbmi, // BITMAPINFO構造体へのポインタ UINT fuColorUse // ビットマップカラーテープルの種類 );

ビットマップ関係の関数の引数は多いです。

uStartScanは最初からスキャンしたいなら0にします。

cScanLinesはビットマップの高さになります。

さて、lpbmiはどうしたらよいのでしょうか。 bmiHeaderメンバはBITMAPINFOHEADER構造体をそのままコピーします。 bmiColors[1]メンバはRGBQUAD構造体はないので放置しておきます。

最後のfuColorUseは、DIB_PAL_COLORSかDIB_RGB_COLORSの いずれかです。前者はカラーテーブル(RGBQUAD構造体の集合)に16ビットのインデックスから なる配列が入っており、論理パレットに対するインデックスになっています。 パレットについては後の章で解説します。後者はカラーテーブルに RGBの値が直接入っています。

さて、今回のプログラムはなるべく簡略化するために前章で作った ReadDIB関数にビットマップ表示用のコードを少し加えただけです。 あとは、前章と全く同じです。

int ReadDIB(HWND hWnd) { HANDLE hF; HANDLE hMem1, hMem2; LPBITMAPFILEHEADER lpBf; LPBITMAPINFOHEADER lpBi; DWORD dwResult; LONG wx, wy; DWORD dwFileSize, dwOffBits; WORD wBitCount; DWORD dwClrUsed, dwClrImportant; DWORD dwSizeImage; char str[256]; char szFType[3]; hF = CreateFile(szFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hF == INVALID_HANDLE_VALUE) { MessageBox(hWnd, "ファイルのオープンに失敗しました", "Error", MB_OK); return -1; } hMem1 = GlobalAlloc(GHND, sizeof(BITMAPFILEHEADER)); lpBf = (LPBITMAPFILEHEADER)GlobalLock(hMem1); ReadFile(hF, (LPBITMAPFILEHEADER)lpBf, sizeof(BITMAPFILEHEADER), &dwResult, NULL); dwFileSize = lpBf->bfSize; szFType[0] = LOBYTE(lpBf->bfType); szFType[1] = HIBYTE(lpBf->bfType); szFType[2] = '\0'; dwOffBits = lpBf->bfOffBits; wsprintf(str, "dwFileSize = %d, szFType = %s dwOffBits = %d", dwFileSize, szFType, dwOffBits); MessageBox(hWnd, str, "BMP情報その1", MB_OK); hMem2 = GlobalAlloc(GHND, sizeof(BITMAPINFOHEADER)); lpBi = (LPBITMAPINFOHEADER)GlobalLock(hMem2); ReadFile(hF, (LPBITMAPINFOHEADER)lpBi, sizeof(BITMAPINFOHEADER), &dwResult, NULL); wx = lpBi->biWidth; wy = lpBi->biHeight; wBitCount = lpBi->biBitCount; dwClrUsed = lpBi->biClrUsed; dwClrImportant = lpBi->biClrImportant; dwSizeImage = lpBf->bfSize - lpBf->bfOffBits; wsprintf(str, "wx = %d, wy = %d\nwBitCount = %d, dwClrUsed = %d, dwClrImportant = %d", wx, wy, wBitCount, dwClrUsed, dwClrImportant); MessageBox(hWnd, str, "BMP情報その2", MB_OK); { HDC hdc; HANDLE hMem; char *szBuffer; BITMAPINFO bmp_info; bmp_info.bmiHeader = *lpBi; hMem = GlobalAlloc(GHND, dwFileSize - sizeof(BITMAPFILEHEADER)); szBuffer = (char *)GlobalLock(hMem); SetFilePointer(hF, sizeof(BITMAPFILEHEADER), 0, FILE_BEGIN); ReadFile(hF, szBuffer, sizeof(BITMAPINFOHEADER) + dwSizeImage, &dwResult, NULL); hdc = GetDC(hWnd); SetDIBitsToDevice(hdc, 0, 0, //転送先座標 wx, wy, //幅、高さ 0, 0, //転送元座標 0, wy, //走査開始番号、走査線の本数 //ビットマップデータ開始のアドレス (char *)szBuffer + dwOffBits - sizeof(BITMAPFILEHEADER), &bmp_info, //BITMAPINFO構造体へのポインタ DIB_RGB_COLORS); GlobalUnlock(hMem); GlobalFree(hMem); ReleaseDC(hWnd, hdc); } GlobalUnlock(hMem1); GlobalFree(hMem1); GlobalUnlock(hMem2); GlobalFree(hMem2); CloseHandle(hF); return 0; }

ブロックで囲んだ部分が今回追加したところです。とりあえずchar型へのポインタを 定義しておいてGlobalAllocで必要な分だけメモリを確保します。メモリに読みこむのは ビットマップファイルのサイズからからBITMAPFILEHEADERの部分を除いた分です。

次にSetFilePointer関数でファイルポインタをファイルの先頭からBITMAPFILEHEADERの分だけ 進めた位置にしておきます。そして、ReadFile関数でバッファに読みこみます。 読みこむ大きさは、BITMAPINFOHEADERとビット配列となります(今回はカラーテーブルは ない)。これが「パック済みDIBメモリフォーマット」となります。

あとは、SetDIBitsToDevice関数を実行します。ビットマップデータの開始アドレス に注意して下さい。筆者は最初間違ってszBufferの位置からdwOffBitsを加えたものにしていました。 しかし、dwOffBitsはファイルの先頭からビットマップデータまでのオフセットです。 メモリ中にはBITMAPFILEHEADER構造体は含まれていないのでポインタをその分戻さなくてはいけません。

これで、何とかビットマップを表示できるようになりました。 しかし、これはあくまでも仮のプログラムです。いろいろ問題点があります。

今回作ったプログラムで、フルカラーのビットマップファイルを表示したところです。 今回のプログラムでは表示をWM_PAINTのところで行っていないので、ウィンドウサイズを 変えると表示したグラフィックスが消えてしまいます。あらかじめウィンドウサイズを 変えてから読みこみます。ちょっと手直しをしてこの問題を解決してみて下さい。

あ、ReadDIB関数だけでなくてウィンドウのタイトルも変更していました。


[SDK第2部 Index] [総合Index] [Previous Chapter] [Next Chapter]

Update 13/Jan/1999 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。