DIB と DIBSection との違いはメモリ領域を確保するのが
HeapAlloc 関数であるか、CreateDIBSection 関数であるか、くらいのものです。
今回の解説を読む前に、「BMPファイルを32ビットDIBとして読み込む」の内容をきちんと理解しておいて下さい。
■関数の設計
関数名 → CreateDIBSection32FromFile248
引数 → ファイル名 , ビットマップハンドルのポインタ , ピクセル列のポインタのポインタ
, BITMAPINFO構造体のポインタ
戻り値 → 0 (成功) or 負値(失敗)
int CreateDIBSection32FromFile248(
char *lpFileName,HBITMAP *lphBmp,LPDWORD *lppPixel,BITMAPINFO *lpBmpInfo)
{
……
}
読み込みに対応するBMPファイルのビット数は24/8ビットです。
作成する DIBSection は32ビットです。
*lphBmp , *lppPixel , *lpBmpInfo には作成した DIBSection の情報が格納されます。
関数はピクセル列のメモリ領域を確保しますが、BITMAPINFO構造体のメモリ領域は確保しません。
■一行分のバイト数を計算するまで
ここまでは32ビットDIBの時と同じです。
HANDLE fh;
DWORD dwFileSize,dwReadSize;
LPBYTE lpbuf;
LPBITMAPFILEHEADER lpbmpfh;
LPBITMAPINFO lpbmpInfo;
LPBYTE lpbmpPixel;
int bitCount,iWidth,iHeight,iLength;
fh=CreateFile(lpFileName,GENERIC_READ,0,NULL,
OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(fh==INVALID_HANDLE_VALUE){
MessageBox(NULL,"ファイルが開けません",lpFileName,MB_OK);
return -1;
}
dwFileSize=GetFileSize(fh,NULL);
lpbuf=(LPBYTE)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,dwFileSize);
ReadFile(fh,lpbuf,dwFileSize,&dwReadSize,NULL);
CloseHandle(fh);
lpbmpfh=(LPBITMAPFILEHEADER)lpbuf;
lpbmpInfo=(LPBITMAPINFO)(lpbuf+sizeof(BITMAPFILEHEADER));
bitCount=lpbmpInfo->bmiHeader.biBitCount;
if(lpbmpfh->bfType!=('M'<<8)+'B' || (bitCount!=24 && bitCount!=8)){
HeapFree(GetProcessHeap(),0,lpbuf);
MessageBox(NULL,"24 or 8 ビットBMPファイルしか読み込めません",lpFileName,MB_OK);
return -2;
}
lpbmpPixel=lpbuf + lpbmpfh->bfOffBits;
iWidth=lpbmpInfo->bmiHeader.biWidth;
iHeight=lpbmpInfo->bmiHeader.biHeight;
if(iWidth*(bitCount/8)%4) iLength=iWidth*(bitCount/8)+(4-iWidth*(bitCount/8)%4);
else iLength=iWidth*(bitCount/8);
■CreateDIBSection関数を実行するまで
CreateDIBSection関数は、BITMAPINFO構造体の情報を基に、
ピクセル列のメモリ領域確保、ビットマップ作成を行います。
従って、CreateDIBSection関数を実行する前にBITMAPINFO構造体を設定しておかなければなりません。
32ビットDIBSectionの場合は biWidth , biHeight , biBitCount だけを参照していると思われます。
カラーテーブルは無いかもしれないので、
コピーするのはBITMAPINFO構造体ではなく、BITMAPINFOHEADER構造体の領域までです。
CopyMemory(lpBmpInfo,&lpbmpInfo->bmiHeader,sizeof(BITMAPINFOHEADER)); lpBmpInfo->bmiHeader.biBitCount=32; *lphBmp=CreateDIBSection(NULL,lpBmpInfo,DIB_RGB_COLORS,(void**)lppPixel,NULL,0);
■ピクセル列の詰め替え&関数の終了処理
ここも32ビットDIBの時と同じです。
LPRGBQUAD lpColorTable;
int x,y;
switch(bitCount){
case 24:
for(y=0;y<iHeight;y++)
for(x=0;x<iWidth;x++)
CopyMemory(*lppPixel+x+y*iWidth,lpbmpPixel+x*3+y*iLength,3);
break;
case 8:
lpColorTable=lpbmpInfo->bmiColors;
for(y=0;y<iHeight;y++)
for(x=0;x<iWidth;x++)
CopyMemory(*lppPixel+x+y*iWidth,lpColorTable+lpbmpPixel[x+y*iLength],3);
break;
}
HeapFree(GetProcessHeap(),0,lpbuf);
return 0;
■DIBSectionを削除する関数
DIBSectionはビットマップを削除する事で、ピクセル列のメモリ領域も自動的に解放されます。
自らピクセル列のメモリ領域を解放してはいけません。
従って、削除関数に渡すのはピクセル列のポインタではなく、ビットマップハンドルのポインタです。
void DeleteDIBSection32(HBITMAP *lphBmp)
{
if(*lphBmp!=NULL){
DeleteObject(*lphBmp);
*lphBmp=NULL;
}
}
■関数を呼び出す
それでは、関数を呼び出してみましょう。
描画する時はDIBで、表示する時はDDBで処理してみました。
LRESULT CALLBACK WindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
static BITMAPINFO bmpInfo;
static LPDWORD lpPixel;
static HBITMAP hBmp;
static HDC hMemDC;
static int width,height;
int x,y;
switch(uMsg) {
case WM_CREATE:
CreateDIBSection32FromFile248("BARBARA.bmp",&hBmp,&lpPixel,&bmpInfo);
width=bmpInfo.bmiHeader.biWidth;
height=bmpInfo.bmiHeader.biHeight;
hMemDC=CreateCompatibleDC(NULL);
SelectObject(hMemDC,hBmp);
//描画
for(y=height/10;y<height/5;y++){
for(x=width/10;x<width/2;x++){
lpPixel[x+y*width]=0x0000ff00;
}
}
return 0;
case WM_DESTROY:
DeleteDC(hMemDC);
DeleteDIBSection32(&hBmp);
PostQuitMessage(0);
return 0;
case WM_PAINT:
hdc=BeginPaint(hWnd,&ps);
//表画面へ転送
BitBlt(hdc,0,0,width,height,hMemDC,0,0,SRCCOPY);
EndPaint(hWnd,&ps);
return 0;
}
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}

サンプルは8ビットBMPファイルを読み込んでいます。
★☆ ダウンロード ☆★