// 画像描画クラス // (C)2002,2003 Yutaka Wada, AirparkLab /* 使い方 // オブジェクトとメンバ変数の確保 CDrawImage m_DrawImage; CRect Rect; // OnInitDialog() で描画エリアの情報を取得しておく this->GetClientRect( &Rect ); // 描画タイミングでの処理 BITMAPINFO *info = 画像ヘッダへのアドレス; BYTE *data = 画像データへのアドレス; CDC *pDC = this->GetDC(); if( pDC ){ m_DrawImage.Draw( pDC, &Rect, info, data ); this->ReleaseDC( pDC ); } // 再描画処理 int x = 0; // オフセットX座標 int y = 0; // オフセットY座標 CDC *pDC = this->GetDC(); if( pDC ){ m_DrawImage.Redraw( pDC ); this->ReleaseDC( pDC ); } ※デバイスコンテキストはシステムで最大5つなのでの毎回取得、解放すること。 パブリックメンバ関数は以下の通り。 // コンストラクタ CDrawImage() // イメージの描画 BOOL Draw( CDC *p_target_dc, CRect *p_target_rect, BITMAPINFO *info, BYTE *data, int Rate = 0, DrawMode mode = NORMAL, BOOL exec_flag = TRUE ) 引数 CDC *p_target_dc 描画対象DCへのポインタ CRect *p_target_rect 描画領域サイズへのポインタ BITMAPINFO *info 画像ヘッダへのアドレス BYTE *data 画像データへのアドレス int Rate = 0 伸縮率指定[%]、0で領域に収まる最大サイズで描画 DrawMode mode = NORMAL 回転・反転表示種別 NORMAL, ROT_090, ROT_180, ROT_270, TURN_H, ROT_090_AND_TURN_H, TURN_V, ROT_270_AND_TURN_H BOOL exec_flag = TRUE 描画実行フラグ 戻値 TRUE(成功)、FALSE(失敗) // イメージの再描画 BOOL Redraw( int offset_x = 0, int offset_y = 0, BOOL bg_flag = TRUE ) 引数 CDC *p_target_dc 描画対象DCへのポインタ int offset_x, offset_y 描画オフセットX,Y[ドット] BOOL bg_flag 背景も再描画するかどうかのフラグ 戻値 TRUE(成功)、FALSE(失敗) // 描画伸縮率の取得 int GetRate() 戻値 実際の描画伸縮率[%] // 描画伸縮サイズの取得 BOOL GetRect( CRect *pRect ) 引数 サイズ取得先 戻値 TRUE(成功)、FALSE(失敗) // 回転・反転表示種別の取得 DrawMode GetDrawMode( DrawMode mode, Action action ) 引数 DrawMode mode 現在の回転・反転表示種別 Action action アクション ROTATION_RIGHT, ROTATION_LEFT, TURN_VERTICAL, TURN_HORIZONTAL 戻値 アクション後の回転・反転表示種別 // 表示画像をクリップボードにコピー void CopyToClipBoard() // 描画有効無効の設定 void Enable( BOOL flag ) 引数 TRUE 描画有効 FALSE 描画無効 // 描画有効無効の取得 BOOL GetEnable() 戻値 TRUE 描画有効 FALSE 描画無効 // デストラクタ ~CDrawImage() */ #ifndef __DRAW_IMAGE_H__ #define __DRAW_IMAGE_H__ // CBitmap::GetBitmapBits()で得たバッファの座標アドレスを得るマクロ #define BITADDR(base,bits,width,flag,x,y) (base+(bits*width+flag)*y+bits*x) // 回転・反転表示種別定義 enum DrawMode { NORMAL = 0, ROT_090, ROT_180, ROT_270, TURN_H, ROT_090_AND_TURN_H, TURN_V, ROT_270_AND_TURN_H }; enum Action { ROTATION_RIGHT = 0, ROTATION_LEFT, TURN_VERTICAL, TURN_HORIZONTAL }; class CDrawImage { CRect TargetRect; // 描画エリアの領域情報 CRect ImageRect; // 表示画像の領域情報(伸縮後) int ImageRate; // 表示画像伸縮率 CPoint DrawPoint; // 描画エリアへの表示開始位置 BOOL DrawFlag; // 描画フラグ CBitmap *pImageBitmap; // 表示画像のビットマップデータを保存するオブジェクトへのポインタ // 回転画像の作成処理 BOOL RotationProc( DrawMode mode, CDC *p_dc, CBitmap *p_bitmap, int dst_w, int dst_h, int src_w, int src_h, BITMAPINFO *info, BYTE *data ) { BOOL ret; if( mode == ROT_090 || mode == ROT_090_AND_TURN_H ){ ret = Rotate090( p_dc, p_bitmap, dst_w, dst_h, src_w, src_h, info, data ); } else if( mode == ROT_180 ){ ret = Rotate180( p_dc, p_bitmap, dst_w, dst_h, src_w, src_h, info, data ); } else if( mode == ROT_270 || mode == ROT_270_AND_TURN_H ){ ret = Rotate270( p_dc, p_bitmap, dst_w, dst_h, src_w, src_h, info, data ); } return( ret ); } // 右90度回転画像の作成 BOOL Rotate090( CDC *p_dc, CBitmap *p_bitmap, int dst_w, int dst_h, int src_w, int src_h, BITMAPINFO *info, BYTE *data ) { // まず回転していない伸縮後の画像をメモリに展開する CBitmap SrcBitmap; SrcBitmap.CreateCompatibleBitmap( p_dc, dst_h, dst_w ); CDC SrcDC; SrcDC.CreateCompatibleDC( p_dc ); int OldBltMode = SrcDC.SetStretchBltMode( COLORONCOLOR ); CBitmap *OldBitmap = SrcDC.SelectObject( &SrcBitmap ); int ret = StretchDIBits( SrcDC.GetSafeHdc(), 0, 0, dst_h, dst_w, 0, 0, src_h, src_w, data, info, DIB_RGB_COLORS, SRCCOPY ); if( ret == GDI_ERROR ) return( FALSE ); // 展開したビットマップを取得し回転イメージを作成する BITMAP bm; SrcBitmap.GetObject( sizeof(BITMAP), &bm ); int bits = bm.bmBitsPixel / 8; // 水平方向のスキャンラインが16ビットの倍数になるように調整する DWORD dwCountSrc, dwCountDst; int bFixSrc, bFixDst; bFixSrc = bFixDst = 0; dwCountSrc = dst_h * bits; dwCountDst = dst_w * bits; if( dwCountSrc & 1 ){ bFixSrc = 1; dwCountSrc++; } if( dwCountDst & 1 ){ bFixDst = 1; dwCountDst++; } dwCountSrc *= dst_w; dwCountDst *= dst_h; // 作業バッファの確保 BYTE *src = new BYTE[ dwCountSrc ]; BYTE *dst = new BYTE[ dwCountDst ]; // ビットマップデータを取得 SrcBitmap.GetBitmapBits( dwCountSrc, src ); // ビットデータを右90度回転 BYTE *s, *d; int sx, sy, dx, dy; dx = dst_w - 1; dy = 0; for( sx=0; sxSetBitmapBits( dwCountDst, dst ); // 後処理 delete [] src; delete [] dst; SrcDC.SetStretchBltMode( OldBltMode ); SrcDC.SelectObject( OldBitmap ); SrcBitmap.DeleteObject(); return( TRUE ); } // 右180度回転画像の作成 BOOL Rotate180( CDC *p_dc, CBitmap *p_bitmap, int dst_w, int dst_h, int src_w, int src_h, BITMAPINFO *info, BYTE *data ) { // まず回転していない伸縮後の画像をメモリに展開する CBitmap SrcBitmap; SrcBitmap.CreateCompatibleBitmap( p_dc, dst_w, dst_h ); CDC SrcDC; SrcDC.CreateCompatibleDC( p_dc ); int OldBltMode = SrcDC.SetStretchBltMode( COLORONCOLOR ); CBitmap *OldBitmap = SrcDC.SelectObject( &SrcBitmap ); int ret = StretchDIBits( SrcDC.GetSafeHdc(), 0, 0, dst_w, dst_h, 0, 0, src_w, src_h, data, info, DIB_RGB_COLORS, SRCCOPY ); if( ret == GDI_ERROR ) return( FALSE ); // 展開したビットマップを取得し回転イメージを作成する BITMAP bm; SrcBitmap.GetObject( sizeof(BITMAP), &bm ); int bits = bm.bmBitsPixel / 8; // 水平方向のスキャンラインが16ビットの倍数になるように調整する DWORD dwCountSrc, dwCountDst; int bFixSrc, bFixDst; bFixSrc = bFixDst = 0; dwCountSrc = dst_w * bits; dwCountDst = dst_w * bits; if( dwCountSrc & 1 ){ bFixSrc = 1; dwCountSrc++; } if( dwCountDst & 1 ){ bFixDst = 1; dwCountDst++; } dwCountSrc *= dst_h; dwCountDst *= dst_h; // 作業バッファの確保 BYTE *src = new BYTE[ dwCountSrc ]; BYTE *dst = new BYTE[ dwCountDst ]; // ビットマップデータを取得 SrcBitmap.GetBitmapBits( dwCountSrc, src ); // ビットデータを右180度回転 BYTE *s, *d; int sx, sy, dx, dy; dx = dst_w - 1; dy = dst_h - 1; for( sx=0; sxSetBitmapBits( dwCountDst, dst ); // 後処理 delete [] src; delete [] dst; SrcDC.SetStretchBltMode( OldBltMode ); SrcDC.SelectObject( OldBitmap ); SrcBitmap.DeleteObject(); return( TRUE ); } // 右270度回転画像の作成 BOOL Rotate270( CDC *p_dc, CBitmap *p_bitmap, int dst_w, int dst_h, int src_w, int src_h, BITMAPINFO *info, BYTE *data ) { // まず回転していない伸縮後の画像をメモリに展開する CBitmap SrcBitmap; SrcBitmap.CreateCompatibleBitmap( p_dc, dst_h, dst_w ); CDC SrcDC; SrcDC.CreateCompatibleDC( p_dc ); int OldBltMode = SrcDC.SetStretchBltMode( COLORONCOLOR ); CBitmap *OldBitmap = SrcDC.SelectObject( &SrcBitmap ); int ret = StretchDIBits( SrcDC.GetSafeHdc(), 0, 0, dst_h, dst_w, 0, 0, src_h, src_w, data, info, DIB_RGB_COLORS, SRCCOPY ); if( ret == GDI_ERROR ) return( FALSE ); // 展開したビットマップを取得し回転イメージを作成する BITMAP bm; SrcBitmap.GetObject( sizeof(BITMAP), &bm ); int bits = bm.bmBitsPixel / 8; // 水平方向のスキャンラインが16ビットの倍数になるように調整する DWORD dwCountSrc, dwCountDst; int bFixSrc, bFixDst; bFixSrc = bFixDst = 0; dwCountSrc = dst_h * bits; dwCountDst = dst_w * bits; if( dwCountSrc & 1 ){ bFixSrc = 1; dwCountSrc++; } if( dwCountDst & 1 ){ bFixDst = 1; dwCountDst++; } dwCountSrc *= dst_w; dwCountDst *= dst_h; // 作業バッファの確保 BYTE *src = new BYTE[ dwCountSrc ]; BYTE *dst = new BYTE[ dwCountDst ]; // ビットマップデータを取得 SrcBitmap.GetBitmapBits( dwCountSrc, src ); // ビットデータを右90度回転 BYTE *s, *d; int sx, sy, dx, dy; dx = 0; dy = dst_h - 1; for( sx=0; sx= dst_w ){ dx = 0; dy--; } } } // 回転したイメージをイメージバッファに転送 p_bitmap->SetBitmapBits( dwCountDst, dst ); // 後処理 delete [] src; delete [] dst; SrcDC.SetStretchBltMode( OldBltMode ); SrcDC.SelectObject( OldBitmap ); SrcBitmap.DeleteObject(); return( TRUE ); } // 反転画像の作成処理 BOOL TurnProc( DrawMode mode, CDC *p_dc, CBitmap *p_bitmap ) { BOOL brh = TRUE; BOOL brv = TRUE; if( mode == TURN_H || mode == ROT_090_AND_TURN_H || mode == ROT_270_AND_TURN_H ){ brh = TurnHorizontal( p_dc, p_bitmap ); } else if( mode == TURN_V ){ brv = TurnVertical( p_dc, p_bitmap ); } if( brh == TRUE && brv == TRUE ) return( TRUE ); else return( FALSE ); } // イメージの水平反転表示 BOOL TurnHorizontal( CDC *p_dc, CBitmap *p_bitmap ) { // 表示画像が有効であれば水平反転表示 if( p_bitmap->GetSafeHandle() != NULL ){ BITMAP bm; p_bitmap->GetObject( sizeof(BITMAP), &bm ); int bits = bm.bmBitsPixel / 8; int bmWidth = bm.bmWidth; int bmHeight = bm.bmHeight; // 水平方向のスキャンラインが16ビットの倍数になるように調整する DWORD dwCountSrc, dwCountDst; int bFixSrc, bFixDst; bFixSrc = bFixDst = 0; dwCountSrc = bmWidth * bits; dwCountDst = bmWidth * bits; if( dwCountSrc & 1 ){ bFixSrc = 1; dwCountSrc++; } if( dwCountDst & 1 ){ bFixDst = 1; dwCountDst++; } dwCountSrc *= bmHeight; dwCountDst *= bmHeight; // 作業バッファの確保 BYTE *src = new BYTE[ dwCountSrc ]; BYTE *dst = new BYTE[ dwCountDst ]; // ビットマップデータを取得 p_bitmap->GetBitmapBits( dwCountSrc, src ); // ライン毎に左右を入れ替える BYTE *s, *d; int sx, sy, dx, dy; dx = bmWidth - 1; dy = 0; for( sx=0; sx= bmHeight ){ dy = 0; dx--; } } } // 回転したイメージをイメージバッファに転送 p_bitmap->SetBitmapBits( dwCountDst, dst ); // 後処理 delete [] src; delete [] dst; return( TRUE ); } else return( FALSE ); } // イメージの垂直反転表示 BOOL TurnVertical( CDC *p_dc, CBitmap *p_bitmap ) { // 表示画像が有効であれば垂直反転表示 if( p_bitmap->GetSafeHandle() != NULL ){ BITMAP bm; p_bitmap->GetObject( sizeof(BITMAP), &bm ); int bits = bm.bmBitsPixel / 8; int bmWidth = bm.bmWidth; int bmHeight = bm.bmHeight; // 水平方向のスキャンラインが16ビットの倍数になるように調整する DWORD dwCountSrc, dwCountDst; int bFixSrc, bFixDst; bFixSrc = bFixDst = 0; dwCountSrc = bmWidth * bits; dwCountDst = bmWidth * bits; if( dwCountSrc & 1 ){ bFixSrc = 1; dwCountSrc++; } if( dwCountDst & 1 ){ bFixDst = 1; dwCountDst++; } dwCountSrc *= bmHeight; dwCountDst *= bmHeight; // 作業バッファの確保 BYTE *src = new BYTE[ dwCountSrc ]; BYTE *dst = new BYTE[ dwCountDst ]; // ビットマップデータを取得 p_bitmap->GetBitmapBits( dwCountSrc, src ); // ライン毎に上下を入れ替える BYTE *s, *d; int sx, sy, dx, dy; dx = 0; dy = bmHeight - 1; for( sx=0; sxSetBitmapBits( dwCountDst, dst ); // 後処理 delete [] src; delete [] dst; return( TRUE ); } else return( FALSE ); } public: // コンストラクタ CDrawImage() { // メンバ変数のクリア TargetRect.SetRect( 0, 0, 0, 0 ); ImageRect.SetRect( 0, 0, 0, 0 ); ImageRate = 0; DrawPoint.x = DrawPoint.y = 0; DrawFlag = FALSE; pImageBitmap = NULL; } // デストラクタ ~CDrawImage() { if( pImageBitmap ){ pImageBitmap->DeleteObject(); delete pImageBitmap; pImageBitmap = NULL; } } // イメージの描画 BOOL Draw( CDC *p_target_dc, CRect *p_target_rect, BITMAPINFO *info, BYTE *data, int Rate = 0, DrawMode mode = NORMAL, BOOL exec_flag = TRUE ) { DrawFlag = FALSE; if( p_target_dc == NULL || p_target_rect == NULL || info == NULL || data == NULL ) return( FALSE ); // 表示するための伸縮後のサイズを計算する int src_w, src_h; // 回転により幅と高さが入れ替わる場合 if( mode == ROT_090 || mode == ROT_270 || mode == ROT_090_AND_TURN_H || mode == ROT_270_AND_TURN_H ){ src_h = info->bmiHeader.biWidth; // 元画像データの幅 src_w = info->bmiHeader.biHeight; // 元画像データの高さ } // 通常の場合 else { src_w = info->bmiHeader.biWidth; // 元画像データの幅 src_h = info->bmiHeader.biHeight; // 元画像データの高さ } // 伸縮率指定があればそれを元に算出する int rate, dst_w, dst_h; if( Rate ){ rate = Rate; dst_w = Rate * src_w / 100; dst_h = Rate * src_h / 100; } // なければ表示エリア内に収まるサイズを算出する else { // エリア内に収まる伸縮率を算出 int rate_w = 100 * p_target_rect->Width() / src_w; // 幅伸縮率[%] int rate_h = 100 * p_target_rect->Height() / src_h; // 高さ伸縮率[%] if( rate_w <= rate_h ) rate = rate_w; else rate = rate_h; dst_w = rate * src_w / 100; dst_h = rate * src_h / 100; } // 描画開始座標の決定 CPoint point; if( dst_w < p_target_rect->Width() ) point.x = ( p_target_rect->Width() - dst_w ) / 2; else point.x = 0; if( dst_h < p_target_rect->Height() ) point.y = ( p_target_rect->Height() - dst_h ) / 2; else point.y = 0; // 表示画像情報の(再)設定 CRect image_rect; image_rect.SetRect( 0, 0, dst_w, dst_h ); int OldTargetMode = p_target_dc->SetStretchBltMode( COLORONCOLOR ); // 表示画像用デバイスコンテキストの確保 CDC *pImageDC = new CDC; // 描画エリアのものと同じ物を作成する pImageDC->CreateCompatibleDC( p_target_dc ); int OldImageMode = pImageDC->SetStretchBltMode( COLORONCOLOR ); CBitmap *pOldImageBitmap = pImageDC->GetCurrentBitmap(); // 描画エリアのサイズのみ変更の場合 if( ImageRect == image_rect && ImageRate == rate ){ TargetRect = *p_target_rect; DrawPoint = point; pImageDC->SelectObject( pImageBitmap ); } else { // 描画エリア情報の保存 TargetRect = *p_target_rect; // 表示画像(伸縮後)の情報を保存 ImageRate = rate; ImageRect = image_rect; DrawPoint = point; // 表示画像用バッファのリセット if( pImageBitmap ){ pImageBitmap->DeleteObject(); delete pImageBitmap; pImageBitmap = NULL; } // 再描画用ビットマップデータを保存するオブジェクトの確保 pImageBitmap = new CBitmap; // 伸縮後の表示画像サイズでビットマップを作成する pImageBitmap->CreateCompatibleBitmap( p_target_dc, ImageRect.Width(), ImageRect.Height() ); // 表示画像用デバイスコンテキストと表示画像ビットマップの結合 pImageDC->SelectObject( pImageBitmap ); } // 表示画像を内部で描画 int ret; BOOL br; // 回転表示の場合 if( mode == ROT_090 || mode == ROT_180 || mode == ROT_270 || mode == ROT_090_AND_TURN_H || mode == ROT_270_AND_TURN_H ){ br = RotationProc( mode, p_target_dc, pImageBitmap, dst_w, dst_h, src_w, src_h, info, data ); } // 通常表示の場合 else { ret = StretchDIBits( pImageDC->GetSafeHdc(), 0, 0, dst_w, dst_h, 0, 0, src_w, src_h, data, info, DIB_RGB_COLORS, SRCCOPY ); if( ret == GDI_ERROR ) br = FALSE; else br = TRUE; } // 反転表示の場合 if( br == TRUE ){ if( mode == TURN_H || mode == ROT_090_AND_TURN_H || mode == TURN_V || mode == ROT_270_AND_TURN_H ){ br = TurnProc( mode, p_target_dc, pImageBitmap ); } } // 描画実行 if( br == TRUE ){ if( exec_flag == TRUE ){ // 表示領域の背景を描画 p_target_dc->FillSolidRect( p_target_rect, RGB(128,128,128) ); // 再描画用エリアから描画用エリアに転送する br = p_target_dc->BitBlt( point.x, point.y, p_target_rect->Width(), p_target_rect->Height(), pImageDC, 0, 0, SRCCOPY ); if( br == TRUE ) DrawFlag = TRUE; } else DrawFlag = TRUE; } // デバイスコンテキストの後始末 pImageDC->SetStretchBltMode( OldImageMode ); pImageDC->SelectObject( pOldImageBitmap ); delete pImageDC; p_target_dc->SetStretchBltMode( OldTargetMode ); return( DrawFlag ); } // イメージの再描画 BOOL Redraw( CDC *p_target_dc, int offset_x = 0, int offset_y = 0, BOOL bg_flag = TRUE ) { if( DrawFlag != TRUE || p_target_dc == NULL ) return( FALSE ); // 背景を再描画 if( bg_flag == TRUE ) p_target_dc->FillSolidRect( TargetRect, RGB(128,128,128) ); // 前回表示画像が有効であれば再描画 if( DrawFlag == TRUE ){ int OldTargetMode = p_target_dc->SetStretchBltMode( COLORONCOLOR ); CDC *pImageDC = new CDC; pImageDC->CreateCompatibleDC( p_target_dc ); int OldImageMode = pImageDC->SetStretchBltMode( COLORONCOLOR ); CBitmap *pOldImageBitmap = pImageDC->SelectObject( pImageBitmap ); p_target_dc->BitBlt( DrawPoint.x, DrawPoint.y, TargetRect.Width(), TargetRect.Height(), pImageDC, offset_x, offset_y, SRCCOPY ); pImageDC->SetStretchBltMode( OldImageMode ); pImageDC->SelectObject( pOldImageBitmap ); delete pImageDC; p_target_dc->SetStretchBltMode( OldTargetMode ); } return( DrawFlag ); } // 描画伸縮率の取得 int GetRate() { return( ImageRate ); } // 描画伸縮サイズの取得 BOOL GetRect( CRect *pRect ) { *pRect = ImageRect; return( DrawFlag ); } // 回転・反転表示種別の取得 DrawMode GetDrawMode( DrawMode mode, Action action ) { const DrawMode DrawModeArray[8][4] = { { ROT_090, ROT_270, TURN_V, TURN_H }, { ROT_180, NORMAL, ROT_270_AND_TURN_H, ROT_090_AND_TURN_H }, { ROT_270, ROT_090, TURN_H, TURN_V }, { NORMAL, ROT_180, ROT_090_AND_TURN_H, ROT_270_AND_TURN_H }, { ROT_270_AND_TURN_H, ROT_090_AND_TURN_H, ROT_180, NORMAL }, { TURN_H, TURN_V, ROT_270, ROT_090 }, { ROT_090_AND_TURN_H, ROT_270_AND_TURN_H, NORMAL, ROT_180 }, { TURN_V, TURN_H, ROT_090, ROT_270 } }; return( DrawModeArray[mode][action] ); } // クリップボードへコピー void CopyToClipBoard() { OpenClipboard( NULL ); EmptyClipboard(); SetClipboardData( CF_BITMAP, (HBITMAP)*pImageBitmap ); CloseClipboard(); } // 描画有効無効の設定 void Enable( BOOL flag ) { DrawFlag = flag; } // 描画有効無効の取得 BOOL GetEnable() { return( DrawFlag ); } }; #endif