• ベストアンサー

読み込んだBMPデータの行方

参考書を元に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)なっているのでしょうか? どこに画像データが有るのでしょうか?

質問者が選んだベストアンサー

  • ベストアンサー
  • chie65535
  • ベストアンサー率43% (8514/19356)
回答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); で解放しなければならない。

zaxs5968
質問者

お礼

詳しい説明ありがとうございます。 lpPixelはデータそのものではなく、 lpPixelを始点として、そこから画像データが並んでいて それを指しているのですね。 解放についても教えてくださりありがとうございます。 感謝。

その他の回答 (2)

回答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ビット型のビットマップファイルとしてセーブした時、他のソフトがどの様に読み込もうとするかは不明です。

zaxs5968
質問者

お礼

>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を取り扱ったサイトを見た方が良いと思います。

zaxs5968
質問者

お礼

ご回答ありがとうございます。

関連するQ&A

  • windowsのアプリケーションを作っているのですがどうにもうまくコン

    windowsのアプリケーションを作っているのですがどうにもうまくコンパイルできず困っています。 キャスト演算子かポインタ関係だと思うのですがいろいろ変えてみてもうまくいきませんでした。 私は朝までしかいられないため起きておられる方ですぐに答えられる方がいれば具体的にどうしたらできるようになるか答えていただけますでしょうか? 今日を逃したら大体、一ヶ月先に反応すると思うのでよろしくお願いします。 以下エラー部分です。 LRESULT CALLBACK WndProc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam) { HDC hdc,hdcWin; PAINTSTRUCT ps; int i,j; switch(iMsg){ case WM_CREATE: lpDIB=(LPBYTE)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(BITMAPINFO)+E*F); lI=(LPBITMAPINFO)lpDIB; for(i=0;i<F;i++){ alpPixel[i]=(LPDWORD)(lpDIB+sizeof(BITMAPINFO)+E*i); } lI->bmiHeader.biSize =sizeof(BITMAPINFOHEADER); lI->bmiHeader.biWidth =B; lI->bmiHeader.biHeight =-B; lI->bmiHeader.biPlanes =1; lI->bmiHeader.biBitCount =B; lI->bmiHeader.biCompression =BI_RGB; for(i=0;i<D;i++){ *(alpPixel[0]+i)=0x00ff0000; *(alpPixel[1]+i)=0x0000ff00; *(alpPixel[2]+i)=0x000000ff; *(alpPixel[3]+i)=0x0000ffff; *(alpPixel[4]+i)=0x00ffffff; } hdc=GetDC(hwnd); hBMP=CreateCompatibleBitmap(hdcWin,C,C); hdcBMP=CreateCompatibleDC(hdc); hOldBMP=(HBITMAP)SelectObject(hdcBMP,hBMP); for(i=0;i<A;i++){ for(j=0;j<A;j++){ StretchDIBits(hdcBMP,j*B,i*B,B,B, 0,0,B,B,alpPixel[map[j+i*A]], lI,DIB_RGB_COLORS,SRCCOPY); } } ZeroMemory(&biInfo,sizeof(BITMAPINFO)); lI->bmiHeader.biSize =sizeof(BITMAPINFOHEADER); lI->bmiHeader.biWidth =C; lI->bmiHeader.biHeight =-C; lI->bmiHeader.biPlanes =1; lI->bmiHeader.biBitCount =B; lI->bmiHeader.biCompression =BI_RGB; ○ hBMP2=CreateDIBSection(hdc,&biInfo,DIB_RGB_COLORS,(LPVOID)(&lpPixel),NULL,0); //エラーはここ hdcBMP2=CreateCompatibleDC(hdc); hOldBMP2=(HBITMAP)SelectObject(hdcBMP2,hBMP2); ReleaseDC(hwnd,hdc); X=0; Y=1; return 0; case WM_DESTROY: ~中略~ } return DefWindowProc(hwnd,iMsg,wParam,lParam); }

  • BMPの保存

    プリントスクリーンをして、それをBMP形式で保存しようとしているのですが、保存後のファイルを開いてウィンドウを動かすと、それにつれ逐次、画像が更新されていきます。 この問題の原因がわかる方、助言をお願いします。 プログラムはC++で作成しています。 下にソースを載せています。 宜しくお願いします。 #include<windows.h> LRESULT CALLBACK WindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; static BITMAPINFO bmpInfo; static LPDWORD lpPixel; static HBITMAP hBitmap; static HDC hMemDC; HWND desktop; RECT rc; static int width,height; switch(uMsg) { case WM_CREATE: //スクリーンの情報を得る desktop=GetDesktopWindow(); GetWindowRect(desktop,&rc); width=rc.right; height=rc.bottom; //DIBの情報を設定する bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); bmpInfo.bmiHeader.biWidth=width; bmpInfo.bmiHeader.biHeight=height; bmpInfo.bmiHeader.biPlanes=1; bmpInfo.bmiHeader.biBitCount=32; bmpInfo.bmiHeader.biCompression=BI_RGB; //DIBSection作成 hdc=GetDC(hWnd); hBitmap=CreateDIBSection(hdc,&bmpInfo,DIB_RGB_COLORS,(void**)&lpPixel,NULL,0); hMemDC=CreateCompatibleDC(hdc); SelectObject(hMemDC,hBitmap); ReleaseDC(hWnd,hdc); //スクリーンをDIBSectionにコピー hdc=GetDC(desktop); BitBlt(hMemDC,0,0,width,height,hdc,0,0,SRCCOPY); ReleaseDC(desktop,hdc); return 0; case WM_DESTROY: //自らlpPixelを解放するべからず DeleteDC(hMemDC); DeleteObject(hBitmap); //BMPを削除した時、lpPixelも自動的に解放される 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; } SaveBitmap((HWND)hWnd,"PrintScreen.BMP"); return DefWindowProc(hWnd,uMsg,wParam,lParam); } int WINAPI WinMain( HINSTANCE hInstance,HINSTANCE hPrevInstance,PSTR lpCmdLine,int nCmdShow) { WNDCLASS wc; MSG msg; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WindowProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL,IDI_APPLICATION); wc.hCursor = LoadCursor(NULL,IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = __FILE__; if(!RegisterClass(&wc)) return 0; HWND hWnd=CreateWindow( __FILE__,"スクリーンキャプチャ", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT, NULL,NULL,hInstance,NULL); if(hWnd==NULL) return 0; BOOL bRet; while((bRet=GetMessage(&msg,NULL,0,0))!=0){ if(bRet==-1) break; DispatchMessage(&msg); } return (int)msg.wParam; }

  • PrintScreenしたあとに画像を保存する方法

    LRESULT CALLBACK WndProcScreenCapture(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { // MMTIME mm; // CommonClass Common; static int id,x,y; HDC hdc; PAINTSTRUCT ps; static HBRUSH hBrush; HWND desktop; RECT rc; static int width,height; static BITMAPINFO bmpInfo; static LPDWORD lpPixel; static HBITMAP hBitmap; static HDC hMemDC; FILE *fpt; int i,j; //clock_t start,end; switch (message) { case WM_CREATE: desktop=GetDesktopWindow();//デスクトップのハンドルを取得 GetWindowRect(desktop,&rc);//デスクトップのRECT情報を取得 width=rc.right; height=rc.bottom; //DIBの情報を設定する bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); bmpInfo.bmiHeader.biWidth=width; bmpInfo.bmiHeader.biHeight=height; bmpInfo.bmiHeader.biPlanes=1; bmpInfo.bmiHeader.biBitCount=32; bmpInfo.bmiHeader.biCompression=BI_RGB; //DIBSection作成 hdc=GetDC(hWnd); hBitmap=CreateDIBSection(hdc,&bmpInfo,DIB_RGB_COLORS,(void**)&lpPixel,NULL,0); hMemDC=CreateCompatibleDC(hdc); SelectObject(hMemDC,hBitmap); ReleaseDC(hWnd,hdc); fopen_s(&fpt,"20090715.raw","wb"); fwrite((void**)&lpPixel[0],sizeof(unsigned char),width*height,fpt); /* DIBSectionにグラデーション描画 */ for (i = 0;i < height;i++) { for (j = 0;j <width;j++) { #if 0 /* DIBピクセル列に直接アクセス */ lpPixel[i + j * 256] = (i << 16); lpPixel[i + (j + 32) * 256] = (i << 8); lpPixel[i + (j + 64) * 256] = i; lpPixel[i + (j + 96) * 256] = (i << 16) | (i << 8) | i; /* GDI経由で描画 */ SetPixel(hMemDC, i, j + 128, RGB(i, 0, 0)); SetPixel(hMemDC, i, j + 128 + 32, RGB(0, i, 0)); SetPixel(hMemDC, i, j + 128 + 64, RGB(0, 0, i)); SetPixel(hMemDC, i, j + 128 + 96, RGB(i, i, i)); #endif } } //fwrite(&(bmpInfo.bmiHeader),sizeof(unsigned char),40,fpt); //fwrite((void**)&lpPixel,sizeof(unsigned char),width*height,fpt); //fwrite(&(bmpInfo.bmiColors),sizeof(unsigned char),width*height,fpt); fclose(fpt); //スクリーンをDIBSectionにコピー hdc=GetDC(desktop); BitBlt(hMemDC,0,0,width,height,hdc,0,0,SRCCOPY); ReleaseDC(desktop,hdc); break; case WM_DESTROY: //自らlpPixelを解放するべからず DeleteDC(hMemDC); DeleteObject(hBitmap); //BMPを削除した時、lpPixelも自動的に解放される PostQuitMessage(0); break; case WM_PAINT: hdc=BeginPaint(hWnd,&ps); BitBlt(hdc,0,0,width,height,hMemDC,0,0,SRCCOPY); EndPaint(hWnd,&ps); break; case WM_CHAR: の様に書いて、windowにキャプチャ画像を表示することは できたのですが、 この画像の画像情報のピクセルのポインタはどれなのでしょうか? 画像をraw形式でもいいので保存したいのですが、 どうしたら、キャプチャした画像を ファイルとして保存 できますか? //fwrite((void**)&lpPixel,sizeof(unsigned char),width*height,fpt); ではうまくいきませんでした。

  • windowsのアプリケーションを作っているのですがどうにもうまくコン

    windowsのアプリケーションを作っているのですがどうにもうまくコンパイルできず困っています。 一ヶ月前に同じ質問をしたのですが具体的にどうすればいいのかわからなかったのでもう一度質問させていただきます。 キャスト演算子かポインタ関係だと思うのですがいろいろ変えてみてもうまくいきませんでした。 具体的にどうしたらできるようになるか答えていただけますでしょうか? 私の都合により、一ヶ月先に反応すると思うのでよろしくお願いします。 以下エラー部分です。 LRESULT CALLBACK WndProc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam) { HDC hdc,hdcWin; PAINTSTRUCT ps; int i,j; switch(iMsg){ case WM_CREATE: lpDIB=(LPBYTE)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(BITMAPINFO)+E*F); lI=(LPBITMAPINFO)lpDIB; for(i=0;i<F;i++){ alpPixel[i]=(LPDWORD)(lpDIB+sizeof(BITMAPINFO)+E*i); } lI->bmiHeader.biSize =sizeof(BITMAPINFOHEADER); lI->bmiHeader.biWidth =B; lI->bmiHeader.biHeight =-B; lI->bmiHeader.biPlanes =1; lI->bmiHeader.biBitCount =B; lI->bmiHeader.biCompression =BI_RGB; for(i=0;i<D;i++){ *(alpPixel[0]+i)=0x00ff0000; *(alpPixel[1]+i)=0x0000ff00; *(alpPixel[2]+i)=0x000000ff; *(alpPixel[3]+i)=0x0000ffff; *(alpPixel[4]+i)=0x00ffffff; } hdc=GetDC(hwnd); hBMP=CreateCompatibleBitmap(hdcWin,C,C); hdcBMP=CreateCompatibleDC(hdc); hOldBMP=(HBITMAP)SelectObject(hdcBMP,hBMP); for(i=0;i<A;i++){ for(j=0;j<A;j++){ StretchDIBits(hdcBMP,j*B,i*B,B,B, 0,0,B,B,alpPixel[map[j+i*A]], lI,DIB_RGB_COLORS,SRCCOPY); } } ZeroMemory(&biInfo,sizeof(BITMAPINFO)); lI->bmiHeader.biSize =sizeof(BITMAPINFOHEADER); lI->bmiHeader.biWidth =C; lI->bmiHeader.biHeight =-C; lI->bmiHeader.biPlanes =1; lI->bmiHeader.biBitCount =B; lI->bmiHeader.biCompression =BI_RGB; ○ hBMP2=CreateDIBSection(hdc,&biInfo,DIB_RGB_COLORS,(LPVOID)(&lpPixel),NULL,0); //エラーはここ hdcBMP2=CreateCompatibleDC(hdc); hOldBMP2=(HBITMAP)SelectObject(hdcBMP2,hBMP2); ReleaseDC(hwnd,hdc); X=0; Y=1; return 0; case WM_DESTROY: ~中略~ } return DefWindowProc(hwnd,iMsg,wParam,lParam); } エラー E2034 169: 'void *' 型は 'void * *' 型に変換できない(関数 __stdcall WndProc(HWND__ *,unsigned int,unsigned int,long) ) エラー E2340 169: 4 番目のパラメータは void * * 型として定義されているので void * 型は渡せない(関数 __stdcall WndProc(HWND__ *,unsigned int,unsigned int,long) ) エラーの部分はこんな感じでした。

  • CopyMemory()をmemcpy()に書き換える方法

    読み込んだBMP画像をテスクチャに転送しようとしています。 CopyMemory(lpPixel + j + i * iWidth, lpBMPPixel + j*3 + i * iLength, 3); の第二引数から memcpy((BYTE*)LockedRect.pBits + LockedRect.Pitch*i +4*j, &Color, sizeof(DWORD)); の第一引数へ入れたいのですが、 CopyMemory()は LPDWORD型のlpPixelに数値を足して指したメモリブロックに対して、 LPBYTE型のlpBMPPixelに数値を足して(?)指したメモリブロックの情報を 3バイトずつ転送している事。 memcpy()は pBits=テスクチャのメモリブロックの始点 Pitch=テスクチャ1行分のメモリの長さ(改行保障値)で指定したアドレスに DWORD型のColorを直接のデータとして書き込んでいる。 という事まではわかったのですが CopyMemory()側の第二引数   lpBMPPixel + j*3 + i * iLength, から色情報を取り出そうと、型変換したりポインタで受け取ろうとしてみたのですが、 上手く行きませんでした。 ヒント程度で構いませんので、何か教えて頂けると幸いです。

  • ウインドウ内全体を一定時間で更新したいWinAPI

    ウインドウ内全体をWM_TIMERを使って一定時間毎に更新したいのですが、うまくいきません。資料・アドバイスを参考にここまで作ったのですが、おそらくWM_PAINTのところでリージョン領域しか更新していないのかと思います。そこでInvalidateRect( hwnd, NULL, NULL ); をウインドウ内全体をリージョンする関数、たとえはRedrawWindow などを使ってみたのですが、正しくできていないためか状況が変わりません。 毎度のことで申し訳ありませんがアドバイスお願いします。 #include <windows.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); void getScreenShot(HBITMAP hBmpShot, int iX, int iY, int iWidth, int iHeight) ; /*ビットマップハンドル*/ static HBITMAP _bmpShot = 0; int _iWidth=1024, _iHeight=400; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow){ MSG msg; WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; /* ウインドウクラス設定 */ wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = "vcshot"; RegisterClass(&wndclass); /* メインウインドウ作成 */ HWND hwMain = CreateWindow("vcshot", "", WS_POPUP | WS_VISIBLE , 0,0, _iWidth, _iHeight, NULL, NULL, hInstance, NULL); ShowWindow(hwMain, iCmdShow); /* メッセージループ */ while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { switch (iMsg) { case WM_CREATE: { /*先に外側で作成してしまう方が得策かもしれない*/ HDC hDC = ::GetDC(0); _bmpShot = ::CreateCompatibleBitmap(hDC, _iWidth, _iHeight); ::ReleaseDC(0, hDC); /* スクリーンショット取得 */ getScreenShot(_bmpShot, 0, 0, _iWidth, _iHeight); SetTimer(hwnd , 1 , 16 , NULL); return 0; } case WM_TIMER:{ getScreenShot(_bmpShot, 0, 0, _iWidth, _iHeight); InvalidateRect( hwnd, NULL, NULL ); return 0;} case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps); /* ビットマップが作成されていれば描画 */ if(_bmpShot != NULL) { BITMAP bmp; /*この関数でビットマップから、詳細を知る事が出来る*/ ::GetObject(_bmpShot, sizeof(BITMAP), &bmp); /*以下決まり文句*/ HDC _hdcShot = ::CreateCompatibleDC(0); ::SelectObject(_hdcShot, _bmpShot); BitBlt(hdc, 0, 0, _iWidth, _iHeight, _hdcShot, 0, 0, SRCCOPY); /*使い終えたら直に閉じる*/ ::DeleteDC(_hdcShot); } EndPaint(hwnd, &ps); return 0; } case WM_DESTROY : /* ビットマップが作成されていたら関連リソースを削除 */ if(_bmpShot != NULL) { /*SelectObject(_hdcShot, _bmpOld);*/ DeleteObject(_bmpShot); /*DeleteObject(_hdcShot);←よく見ると、デバイスコンテキストに対してDeleteObjectを使用しています。*/ } PostQuitMessage(0); return 0; } return DefWindowProc (hwnd, iMsg, wParam, lParam); } void getScreenShot(HBITMAP hBmpShot, int iX, int iY, int iWidth, int iHeight) { /* キャプチャサイズを保存 _iWidth = iWidth; _iHeight = iHeight; */ /* 画面のデバイスコンテキスト取得 */ HDC hdcScreen = GetDC(0); /* ビットマップ描画用デバイスコンテキスト作成 */ HDC _hdcShot = CreateCompatibleDC(hdcScreen); /* スクリーンショット保存用ビットマップ作成 */ /*_bmpShot = CreateCompatibleBitmap(hdcScreen, iWidth, iHeight);*/ /* デバイスコンテキストにビットマップを設定 */ /*_bmpOld = (HBITMAP)*/SelectObject(_hdcShot, hBmpShot); /* 画面上の領域をビットマップに描く */ BitBlt(_hdcShot, 0, 0, iWidth, iHeight, hdcScreen, 0, 0, SRCCOPY); /* 画面のデバイスコンテキスト解放 */ ReleaseDC(0, hdcScreen); /*使用したら直に閉じる*/ ::DeleteDC(_hdcShot); }

  • PrintScreenKey押下でメモリはどこで取得?

    PrintScreenKey押下で mspaint(画像処理ソフト)で「貼り付け」をすると 画像が張り付けられますが、この過程をプログラミングしたいのですが どうしたらいいですか? どのようにOSメモリに保存された画像ポインタの先頭を取得 できますか? PrintScreenKeyをプログラミングするのは以下の様になるのは 知っています。 desktop=GetDesktopWindow();//デスクトップのハンドルを取得 GetWindowRect(desktop,&rc);//デスクトップのRECT情報を取得 width=rc.right; height=rc.bottom; //DIBの情報を設定する bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); bmpInfo.bmiHeader.biWidth=width; bmpInfo.bmiHeader.biHeight=height; bmpInfo.bmiHeader.biPlanes=1; bmpInfo.bmiHeader.biBitCount=32; bmpInfo.bmiHeader.biCompression=BI_RGB; //DIBSection作成 hdc=GetDC(hWnd); hBitmap=CreateDIBSection(hdc,&bmpInfo,DIB_RGB_COLORS,(void**)&lpPixel,NULL,0); hMemDC=CreateCompatibleDC(hdc); SelectObject(hMemDC,hBitmap); ReleaseDC(hWnd,hdc); fopen_s(&fpt,"ScreenCapture.bmp","wb"); //スクリーンをDIBSectionにコピー hdc=GetDC(desktop); BitBlt(hMemDC,0,0,width,height,hdc,0,0,SRCCOPY); ReleaseDC(desktop,hdc); BITMAPINFOHEADER bmih; BITMAPFILEHEADER bmfh; //RGBQUAD rgbquad; DWORD filesize,bmfhsize,bmihsize,rgbquadsize; bmfhsize=sizeof(bmfh); bmihsize=sizeof(bmih); //rgbquadsize=sizeof(rgbquad); filesize=bmfhsize+bmihsize+width*height; ::ZeroMemory(&bmfh, bmfhsize); ::ZeroMemory(&bmih, bmihsize); bmfh.bfType=0x4d42; bmfh.bfSize=filesize; bmfh.bfReserved1=0; bmfh.bfReserved2=0; bmfh.bfOffBits=bmfhsize+bmihsize; bmih.biSize=bmihsize; bmih.biWidth=width; bmih.biHeight=height; bmih.biPlanes=1; bmih.biBitCount=32; bmih.biClrUsed=2; bmih.biCompression=BI_RGB;//無圧縮形式 bmih.biSizeImage=0;//BI_RGBをセットした場合、0が好ましいとMSDNに書いてあった。 bmih.biXPelsPerMeter=0; bmih.biYPelsPerMeter=0; bmih.biClrImportant=0; fwrite(&bmfh,sizeof(unsigned char),bmfhsize,fpt); fwrite(&bmih,sizeof(unsigned char),bmihsize,fpt); fwrite(lpPixel,sizeof(DWORD),width*height,fpt);

  • SetDIBitsToDeviceで88x31のpngを

    表示しようとして int SetDIBitsToDevice( HDC hdc, int XDest,←0 int YDest,←0 DWORD dwWidth,←88 DWORD dwHeight,←31 int XSrc,←0 int YSrc,←0と31でトライ UINT uStartScan,←0 UINT cScanLines,←31 CONST VOID *lpvBits,←読み込んだpngのfufferポイ CONST BITMAPINFO *lpbmi,←&bmpInfo UINT fuColorUse←DIB_RGB_COLORS ); としました。ただし BITMAPINFO bmpInfoは bmpInfo.bmiHeader.biSize=40; bmpInfo.bmiHeader.biWidth=88; bmpInfo.bmiHeader.biHeight=31; bmpInfo.bmiHeader.biPlanes=1; bmpInfo.bmiHeader.biBitCount=0; bmpInfo.bmiHeader.biCompression=BI_PNG; bmpInfo.bmiHeader.biSizeImage=pngのbufferのsize; bmpInfo.bmiHeader.biXPelsPerMeter=0; bmpInfo.bmiHeader.biYPelsPerMeter=0; bmpInfo.bmiHeader.biClrUsed=0; bmpInfo.bmiHeader.biClrImportant=0; と定義しました。 (実際にdivファイルを表示できていたプログラムの関連部分の書き換え) が、絵がでません。 どの設定に問題があるのでしょうか?

  • WinAPIでスクリーン画像を映し続けるプログラムその2

    タイマー1秒ごとに画面を更新させたいのですが、リージョンの範囲しか更新されないため、ウインドウを最上層に置いておくと、画面がかわりません。下記ソースはそれを確かめるため、タイマーで更新する画面を100×100pixlから1秒ごとに徐々に大きくしていったところ、やはりペイントが違う画面で覆った部分しかそのとおり更新されていませんでした。参考書だとこんな感じでできる気がするのですが、InvalidateRect( hwnd, NULL, TRUE );のところでウインドウ全体を更新しなければいけない範囲にするべきだと思うのですが、具体的な解決策がわかりません。 お力を貸していただけると助かります。 #include <windows.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); void getScreenShot(HBITMAP hBmpShot, int iX, int iY, int iWidth, int iHeight) ; /*ビットマップハンドル*/ static HBITMAP _bmpShot = 0; int popo=100; int _iWidth=1024, _iHeight=400; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow){ MSG msg; WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; /* ウインドウクラス設定 */ wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = "vcshot"; RegisterClass(&wndclass); /* メインウインドウ作成 */ HWND hwMain = CreateWindow("vcshot", "", WS_POPUP | WS_VISIBLE , 0,0, _iWidth, _iHeight, NULL, NULL, hInstance, NULL); ShowWindow(hwMain, iCmdShow); /* メッセージループ */ while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { switch (iMsg) { case WM_CREATE: { /*先に外側で作成してしまう方が得策かもしれない*/ HDC hDC = ::GetDC(0); _bmpShot = ::CreateCompatibleBitmap(hDC, _iWidth, _iHeight); ::ReleaseDC(0, hDC); /* スクリーンショット取得 */ getScreenShot(_bmpShot, 0, 0, _iWidth, _iHeight); SetTimer(hwnd , 1 , 1000 , NULL); return 0; } case WM_TIMER:{ popo=popo+20; getScreenShot(_bmpShot, 0, 0, popo, popo); InvalidateRect( hwnd, NULL, TRUE ); return 0;} case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps); /* ビットマップが作成されていれば描画 */ if(_bmpShot != NULL) { BITMAP bmp; /*この関数でビットマップから、詳細を知る事が出来る*/ ::GetObject(_bmpShot, sizeof(BITMAP), &bmp); /*以下決まり文句*/ HDC _hdcShot = ::CreateCompatibleDC(0); ::SelectObject(_hdcShot, _bmpShot); BitBlt(hdc, 0, 0, _iWidth, _iHeight, _hdcShot, 0, 0, SRCCOPY); /*使い終えたら直に閉じる*/ ::DeleteDC(_hdcShot); } EndPaint(hwnd, &ps); return 0; } case WM_DESTROY : /* ビットマップが作成されていたら関連リソースを削除 */ if(_bmpShot != NULL) { /*SelectObject(_hdcShot, _bmpOld);*/ DeleteObject(_bmpShot); /*DeleteObject(_hdcShot);←よく見ると、デバイスコンテキストに対してDeleteObjectを使用しています。*/ } PostQuitMessage(0); return 0; } return DefWindowProc (hwnd, iMsg, wParam, lParam); } void getScreenShot(HBITMAP hBmpShot, int iX, int iY, int iWidth, int iHeight) { /* キャプチャサイズを保存 _iWidth = iWidth; _iHeight = iHeight; */ /* 画面のデバイスコンテキスト取得 */ HDC hdcScreen = GetDC(0); /* ビットマップ描画用デバイスコンテキスト作成 */ HDC _hdcShot = CreateCompatibleDC(hdcScreen); /* スクリーンショット保存用ビットマップ作成 */ /*_bmpShot = CreateCompatibleBitmap(hdcScreen, iWidth, iHeight);*/ /* デバイスコンテキストにビットマップを設定 */ /*_bmpOld = (HBITMAP)*/SelectObject(_hdcShot, hBmpShot); /* 画面上の領域をビットマップに描く */ BitBlt(_hdcShot, 0, 0, iWidth, iHeight, hdcScreen, 0, 0, SRCCOPY); /* 画面のデバイスコンテキスト解放 */ ReleaseDC(0, hdcScreen); /*使用したら直に閉じる*/ ::DeleteDC(_hdcShot); }

  • OnDraw以外でクライアント領域をBMPに保存できない

    いつもお世話になっています。 MFCでシミュレーション計算プログラムを作っていて クライアント領域の画像をBMPファイルに落とすため 下記サブルーチンを作成しましたが、 ファイルができません。 OnDraw関数に記述すると、 最初の1ステップ目のみファイルが出力されます??? どなたかアドバイス・参考URL等ご教示お願い致します。 また、他に有用なライブラリ等ありましたら、 URL等ご紹介いただければありがたいです。 void CMPSView::SaveBMP(HWND hwnd, char* filename) { DWORD dwSize,dwFSize,dwWidth,dwHeight,dwLength; HANDLE fh; LPBITMAPFILEHEADER lpHead; LPBITMAPINFOHEADER lpInfo; LPBYTE lpBuf,lpPixel; RECT rec; HDC hdc,hdcMem; HBITMAP hBMP,hOld; (中略:バッファ確保、ヘッダ作成) hdc = this->GetDC()->m_hDC; hBMP=CreateCompatibleBitmap(hdc,dwWidth,dwHeight); hdcMem=CreateCompatibleDC(hdc); hOld=(HBITMAP)SelectObject(hdcMem,hBMP); BitBlt(hdcMem,0,0,dwWidth,dwHeight,hdc,0,0,SRCCOPY); SelectObject(hdcMem,hOld); GetDIBits(hdc,hBMP,0,dwHeight,lpPixel,(LPBITMAPINFO)lpInfo,DIB_RGB_COLORS); ReleaseDC(this->GetDC()); DeleteObject(hBMP); DeleteObject(hdcMem); fh=CreateFile(filename, GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); WriteFile(fh,lpBuf,dwFSize,&dwSize,NULL); CloseHandle(fh); GlobalFree(lpBuf); }

専門家に質問してみよう