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ファイルを読み込んでいます。
★☆ ダウンロード ☆★