キャプチャされた画像を BMP File に保存

表示中の画像をキャプチャして、BMP File として保存します。

前田稔(Maeda Minoru)の超初心者のプログラム入門

画像をキャプチャして、ファイルに保存

表示中の画面から矩形で選択して、ファイルに保存する手順は次のようになります。
最初の手順は 矩形領域を Clipbord に書き出す と同じです。
  1. Window を生成した後で矩形領域を選択する透明のもう一つの Window を作成します。
  2. トップレベルに表示中の自分自身の Window を隠します。
  3. 矩形領域を選択するために画面いっぱいに透明の Window を貼り付けます。
  4. 透明 Window で矩形領域を設定して取り込む範囲を定めます。
  5. 透明 Window の hdc を取得します。
  6. hdc と互換性のあるメモリデバイスコンテキストを作ります。
  7. hdc と互換性のあるビットマップを作成します。
  8. メモリデバイスコンテキストにこのビットマップを選択します。
  9. StretchBlt で hdc をメモリデバイスコンテキストに転送します。
  10. ビットマップをクリップボードに転送します。
  11. 不要になったデバイスコンテキストを破棄します。
  12. 透明 Window を隠して、本来の Window を表示します。
  13. メニュー選択で画像をファイルに保存します。

プログラムの説明

それでは具体的に説明して行きましょう。
最初の手順は 矩形領域を Clipbord に書き出す と同じです。
  1. Global Area に本来の Window(hMain)と透明 Window(hWhole)のハンドルを定義します。
    bCap と bBlock は矩形領域を設定するためのフラグです。
    本来の Window を作成した後で、透明 Window を生成する関数 CreateMyChild() を呼び出します。
        HWND        hWhole, hMain;
        BOOL        bCap, bBlock;
                    :
        //★ Windows Main 関数
        int WINAPI WinMain(...)
                    :
            if (!hWnd)  return FALSE;
    
            hMain = hWnd;
            CreateMyChild(hWnd);
                    :
        
  2. 透明 Window(NULL_BRUSH) を生成してその HWND を hWhole に格納するコードです。
        int CreateMyChild(HWND hWnd)
        {   WNDCLASSEX  wc;
            HINSTANCE   hInst;
            HWND        hwnd;
                    :
            hwnd = CreateWindow("WHOLE", "", WS_POPUP, 0, 0,
                GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN),
                NULL, NULL, hInst, NULL);
                    :
            hWhole = hwnd;
            return 0;
        }
        
  3. Main Window の CALLBACK 関数の処理です。
    IDM_CAP: で矩形領域を選択して画像を取得します。
    ShowWindow(hWnd, SW_HIDE); で Window を隠します。
    実行が終わるまで Sleep(300); で待機します。
    ShowWindow(hWhole, SW_SHOWNORMAL); で透明 Window を表示します。
            case WM_COMMAND:
                {
                          :
                    case IDM_CAP:
                        bCap = TRUE;
                        bBlock = FALSE;
                        ShowWindow(hWnd, SW_HIDE);
                        Sleep(300);
                        ShowWindow(hWhole, SW_SHOWNORMAL);
                        break;
                }
                break;
        
  4. 透明 Window の CALLBACK 関数です。
    マウスボタンを検出して透明 Window に矩形領域を DrawRect() で描画します。
    WM_LBUTTONUP: で矩形領域が確定します。
    矩形領域の画像を Clipboard に転送します。
    透明 Window を隠して、通常の Window を表示します。
        LRESULT CALLBACK WholeProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
        {   HDC     hdc, hdc_mem;
            HBITMAP hBitmap;
    
            switch(msg)
            {   case WM_LBUTTONDOWN:
                    if (bCap)
                    {     :
                          :
                    }
                    break;
                case WM_MOUSEMOVE:
                    if(bBlock)
                    {     :
                          :
                    }
                    break;
                case WM_LBUTTONUP:
                    if  (bBlock)
                    {     :
                          :
                    }
                    ShowWindow(hWhole, SW_HIDE);
                    ShowWindow(hMain, SW_RESTORE);
                    break;
        
  5. 矩形を表示するコードです。
    矩形はマウスの移動に従って、描画したものを消して描き直さなければなりません。
    SetROP2() で描画モードを R2_NOT に設定すると、もう一度同じ矩形を描くとこれを消してくれます。
        void    DrawRect(HWND hWnd, POINTS beg, POINTS end)
        {   HDC     hdc;
            HPEN    hPen;
    
            hdc = GetDC(hWhole);
            SetROP2(hdc, R2_NOT);
                :
            ReleaseDC(hWhole, hdc);
            return;
        }
        
  6. メニューから「保存」が選択されると SW を ON にします。
        switch(LOWORD(wp))
        {  case IDM_END:
                    :
                break;
            case IDM_SAVE:
                SW = 1;
            case IDM_REDRAW:
                InvalidateRect(hWnd, NULL, TRUE);
                break;
        
  7. WM_PAINT: ではクリップボードから画像を取得して描画します。
    このとき SW が設定されていると画像をファイルに保存します。
    このプログラムでは、カレントディレクトリに CAPTURE.BMP の名前で画像を保存しています。
        case WM_PAINT:
            hdc = BeginPaint(hWnd, &ps);
            if (IsClipboardFormatAvailable(CF_BITMAP))
            {   クリップボードから画像を取得して描画する
                    :
                if (SW)
                {   SW= 0;
                    PutBmp("CAPTURE.BMP",hdc_mem,hBitmap);
                }
                    :
            }
            EndPaint(hWnd, &ps);
            break;
        
  8. 画像をファイルに保存する PutBmp() 関数です。
    BITMAPFILEHEADER は BMP File のヘッダで、"BM" に続いてファイルサイズやビット配列までのオフセットが記録されています。
    BITMAPINFOHEADER は BMP 情報のヘッダです。
    このプログラムでは 24 ビットモードで保存しています。
    bmWidthBytes は一行分のピクセルサイズ(Byte)で、32ビットの境界に調整します。
    len はピクセルイメージのサイズで、bfSize はファイル全体のサイズです。
    g_img の領域はウインドウのサイズに合わせて「幅=800, 高さ=600, 色=24bit」で定義しています。
    現在ならもっと大きなサイズが必要です。
    ヘッダ情報の説明は BitMap(BMP)画像ファイル形式の説明書 を参照して下さい。
        BYTE        g_img[800*600*3];
    
        void    PutBmp(LPSTR fname, HDC hdc, HBITMAP hbm)
        {   HANDLE  hFile;
            DWORD   dwBytes,len;
            BITMAP  bm;
            int     ret;
            static  BITMAPFILEHEADER    g_Bf = {  0x4d42, 0, 0, 0, 0x36  };
            static  BITMAPINFOHEADER    g_Bi = {  0x28, 0, 0, 1, 24, 0, 0, 0, 0, 0, 0  };
    
            if (GetObject(hbm,sizeof(BITMAP),&bm)==0)
            {   MessageBox(NULL,"GetObject() に失敗しました", "PutBmp", MB_OK);
                return;
            }
    
            hFile= CreateFile(fname,GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
            if (hFile==NULL)    return;
    
            len= (bm.bmWidthBytes+3) & 0xfffffffc;
            len*= bm.bmHeight;
            g_Bi.biWidth   = bm.bmWidth;
            g_Bi.biHeight  = bm.bmHeight;
            g_Bf.bfSize    = g_Bf.bfOffBits+len;
    
            WriteFile(hFile,&g_Bf,sizeof(BITMAPFILEHEADER),&dwBytes,NULL);
            WriteFile(hFile,&g_Bi,sizeof(BITMAPINFOHEADER),&dwBytes,NULL);
            ret= GetDIBits(hdc,hbm,0,bm.bmHeight,g_img,(LPBITMAPINFO)&g_Bi,DIB_RGB_COLORS);
            if (ret==0)
            {   MessageBox(NULL,"ピクセルデータの取得に失敗しました", "PutBmp", MB_OK);
                CloseHandle(hFile);  return;
            }
            WriteFile(hFile,(BYTE*)g_img,len,&dwBytes,NULL);
            CloseHandle(hFile);
        }
        

超初心者のプログラム入門(Win32API C++)