画像の拡大・縮小とスクロール

画像を拡大・縮小して表示する方法と、拡大表示の時にスクロールバーを設定するプログラムです。

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

プログラムの説明

  1. Image Object Class を使っています。
    ImgFile が表示する画像ファイルです。適当な画像を調達してきて下さい。
    g_Size が表示する画像の倍率でメニューから設定します。
    si_v と si_h が縦と横のスクロールバー構造体です。
        #include    <windows.h>
        #include    "image.h"
        #include    "resource.h"
    
        HINSTANCE   g_hInst;
        HWND        g_hWnd;
        IMAGE       *Img= NULL;         // IMAGE Object Class
        char        ImgFile[128]= "ffx2.jpg";
        float       g_Size= 1.0f;
    
        //スクロール制御領域
        SCROLLINFO  si_v;
        SCROLLINFO  si_h;
        
  2. WM_COMMAND: を参考にして「拡大/縮小」のメニューを作成して下さい。
    メニューのIDは規定値の IDR_MENU1 でプログラムされています。
  3. WinMain() はいつもと同じです。
  4. CALLBACK 関数です。
    WM_CREATE: で Image Object Class を初期化して画像を入力します。
        switch (msg)
        {   case WM_CREATE:         // 初期化
                Img= new IMAGE(hWnd);
                Img->LoadFile(ImgFile);
                break;
        
  5. WM_PAINT: で画像を拡大・縮小して描画します。
    StretchBlt() が拡大・縮小して表示する Win32 の API です。
            case WM_PAINT:
                hdc = BeginPaint(hWnd, &ps);
                W= Img->Width-si_h.nPos;
                H= Img->Height-si_v.nPos;
                StretchBlt(hdc,0,0,(int)(W*g_Size),(int)(H*g_Size),
                    Img->hBmpDC,si_h.nPos,si_v.nPos,W,H,SRCCOPY);
                EndPaint(hWnd, &ps);
                break;
        
    StretchBlt() のパラメータです。
    パラメータ 説明
    hdc コピー先の DC
    0 コピー先の左上X座標
    0 コピー先の左上Y座標
    (int)(W*g_Size)コピー先の幅
    (int)(H*g_Size)コピー先の高さ
    Img->hBmpDC コピー元の DC
    si_h.nPos コピー元の左上X座標
    si_v.nPos コピー元の左上Y座標
    W コピー元の幅
    H コピー元の高さ
    SRCCOPY ラスタオペレーション
    si_h.nPos, si_v.nPos は画像を拡大したときのスクロールの量で、スクロールしなければゼロです。
    画像の幅と高さからスクロールの量を引いて、描画するサイズを計算します。
    この値に拡大・縮小倍率を乗じた値が、ウインドウに表示する画像の大きさです。
    提供したソースコードでは Img->hBmpDC が protected: で宣言されているかも知れません。
    今回のプログラムでは public: で宣言して下さい。
  6. WM_SIZE: でスクロールバーを設定していますが、拡大・縮小のときに設定した方が良いかも知れません。
    画像の表示サイズとウインドウサイズを比べてスクロールバーの設定を判断します。
    SIF_PAGE フラグを ON にして nPage にページの大きさを設定します。
    SIF_RANGE フラグを ON にして nMax と nMin にスクロールの範囲を設定します。
    SIF_POS フラグを ON にして nPos に位置を設定します。
    nPage > (nMax - nMin + 1) のとき、スクロールバーは表示されません。
    SetScrollInfo() で縦と横のスクロールバーを表示します。
            case WM_SIZE:
                // 縦スクロールの設定
                M= int(Img->Height*g_Size)-HIWORD(lParam);   //画像の高さ-ウインドウの高さ
                if (M<0)  M= 0;
                si_v.cbSize = sizeof(SCROLLINFO);
                si_v.fMask = SIF_POS | SIF_RANGE | SIF_PAGE;
                si_v.nMin = 0;
                si_v.nMax = M;
                si_v.nPage = 64;
                si_v.nPos = 0;
                // 横スクロールの設定
                si_h= si_v;
                M= int(Img->Width*g_Size)-LOWORD(lParam);	//画像の幅-ウインドウの幅
                if (M<0)  M= 0;
                si_h.nMax = M;
                SetScrollInfo(hWnd, SB_VERT, &si_v, TRUE);
                SetScrollInfo(hWnd, SB_HORZ, &si_h, TRUE);
                break;
        
  7. WM_VSCROLL: で縦スクロールバーの操作を検出します。
    スクロールバーの操作情報に基づき dy に縦方向の移動量を格納します。
    dy から nPos を計算して、縦のスクロールバーを設定します。
    スクロールバーが操作されたときは InvalidateRect() で画面を更新します。
    TRUE を指定すると画面がちらつきます。
    FALSE を指定するとちらつきは無くなるのですが、以前の画像が残ります。
            case WM_VSCROLL:
                switch (LOWORD(wParam))
                {   case SB_LINEUP:     dy = -1;    break;
                    case SB_LINEDOWN:   dy =  1;    break;
                    case SB_PAGEUP:     dy = -1*si_v.nPage;             break;
                    case SB_PAGEDOWN:   dy = si_v.nPage;                break;
                    case SB_THUMBTRACK: dy = HIWORD(wParam)-si_v.nPos;  break;
                    default:            dy =  0;    break;
                }
                dy = max(-1*si_v.nPos, min(dy,si_v.nMax-si_v.nPos));
                if (dy != 0)
                {   si_v.nPos += dy;
                    SetScrollInfo(hWnd, SB_VERT, &si_v, TRUE);
    //                InvalidateRect(hWnd,NULL,FALSE);
                    InvalidateRect(hWnd,NULL,TRUE);
                }
                break;
        
  8. WM_HSCROLL: で横スクロールバーの操作を検出します。
    横スクロールバーの説明は、縦の操作に準じます。
            case WM_HSCROLL:
                switch (LOWORD(wParam))
                {   case SB_LINEUP:     dx = -1;    break;
                    case SB_LINEDOWN:   dx =  1;    break;
                    case SB_PAGEUP:     dx = -1*si_h.nPage;             break;
                    case SB_PAGEDOWN:   dx = si_h.nPage;                break;
                    case SB_THUMBTRACK: dx = HIWORD(wParam)-si_h.nPos;  break;
                    default:            dx =  0;    break;
                }
                dx = max(-1*si_h.nPos, min(dx,si_h.nMax-si_h.nPos));
                if (dx != 0)
                {   si_h.nPos += dx;
                    SetScrollInfo(hWnd, SB_HORZ, &si_h, TRUE);
                    InvalidateRect(hWnd,NULL,FALSE);
                }
                break;
        
  9. 画像の倍率を設定する WM_COMMAND: です。
    メニューに合わせて g_Size を設定するだけです。
    WM_SIZE: よりも、ここでスクロールバーを設定した方が良いかも知れません。
                    case ID_VIEW_10:        //画像の表示サイズ
                        g_Size= 0.1f;
                        InvalidateRect(hWnd,NULL,TRUE);
                        break;
                    case ID_VIEW_25:
                        g_Size= 0.25f;
                        InvalidateRect(hWnd,NULL,TRUE);
                        break;
                    case   :
                           :
                    case ID_VIEW_400:
                        g_Size= 4.0f;
                        InvalidateRect(hWnd,NULL,TRUE);
                        break;
                }
                break;
        
  10. WM_CLOSE: では、Image Object Class を開放して下さい。
    マウスで選択した範囲を拡大して描画するプログラムを Image Big に掲載しています。

超初心者の方のために全ソースコードを掲載します。 (^_^;)
全ソースコード

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