gdiplusを用いて画像特効---画像特効(スキャン、モザイク、ブラインド..)を作成


転載は引用と明記してくださいhttp://blog.csdn.net/chenyujing1234
皆さんの意見を歓迎して、一緒に討論します!
 ソースコードが必要な場合は、単独で連絡してください.
 
 
画像表示の特効は、画像をいくつかの小さなブロックに細分化し、一定の順序で出力するプロセスです.
1、基本原理
(1)スキャン特効は、画像を複数行に分割し、1行の画像を表示するたびに、画像がすべて表示されるまで2回の表示間を遅延させることである.
スキャン特効は特効の中で最も簡単で、最も基本的な特効表示方式であり、表面は画像の琢行や琢列を表示し、カーテンを開けたり巻いたりするのに似ている.
(2)モザイク効果は,画像を大きさが等しいブロックに分割し,ランダムに表示することである.
(3)ブラインドの特効はストライプ状のブロックを分けることです.
(4)水平グリッドバー.水平イメージバーの場合、奇数偶数イメージバーの移動方向が逆になります.
......
2、プログラミング実現
 ステップ1:メモリに画像を事前に描画します.
PreDrawImageはgdiplusgraphic方法で画像をメモリにロードする.
//--------------------------------------------------------------
//	  :		          
//--------------------------------------------------------------
void CMagicHouseView::PreDrawImage(void)
{
	Image image(GetFilePath(m_nPos));

	::delete m_pBitmap;

	m_pBitmap = ::new Bitmap(image.GetWidth(), image.GetHeight(), PixelFormat32bppARGB);
	Graphics* graph = Graphics::FromImage(m_pBitmap);

	graph->DrawImage(&image, 0, 0, image.GetWidth(), image.GetHeight());
	SAFE_DELETE (graph);
}

2番目:  ビュー再描画関数OnDrawで特効を行います.
 デュアルバッファ図面を使用します.まずShowPictureで画像を表示する(このような画像の画素はmemDC上にある)、EffectDisplayImageで特効をとる.
//--------------------------------------------------------------
//	  :		      
//--------------------------------------------------------------
void CMagicHouseView::OnDraw(CDC* pDC)
{
	CMagicHouseDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	CRect rect;
	GetClientRect(rect);

	CDC memDC;
	CBitmap MemBitmap;

	//         
	memDC.CreateCompatibleDC(NULL);

	//                 
	MemBitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());

	//       
	memDC.SelectObject(MemBitmap);
	memDC.FillSolidRect(0, 0, rect.Width(), rect.Height(), RGB(255,255,255));

	//         
	//          memDC  ,       memDC  
	if (m_nPos >= 0)
		ShowPicture(&memDC, *m_pBitmap, m_nShowType);

	if (m_bEffectDraw && m_nEffectDisplayType != EDT_NONE)
	{
		int nHeight = rect.Height() - m_nShowPicHeight;
		int nWidth = rect.Width() - m_nShowPicWidth;

		if (nHeight < 0)	
			nHeight = 0;
		if (nWidth < 0)	
			nWidth = 0;

		pDC->FillSolidRect(0, 0, rect.Width(), rect.Height(), RGB(255,255,255));

		EffectDisplay::s_nOffsetX = nWidth / 2;
		EffectDisplay::s_nOffsetY = nHeight / 2;
		EffectDisplay::s_nPicWidth = m_nShowPicWidth;
		EffectDisplay::s_nPicHeight = m_nShowPicHeight;
		EffectDisplay::s_nCDCWidth = rect.Width();
		EffectDisplay::s_nCDCHeight = rect.Height();

		//         , memDC  ,   pDC 
		EffectDisplayImage(pDC, &memDC);

		m_bEffectDraw = false;
	}
	else
		pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &memDC, 0, 0, SRCCOPY);

	MemBitmap.DeleteObject();
	memDC.DeleteDC();
}

 
 
 
//----------------------------------
//	  :			         
//	  :		
//  	pDC			         
//		image		    
//		nShowType	    
//----------------------------------
void CMagicHouseView::ShowPicture(CDC* pDC, Image& image, int nShowType)
{
	Graphics graph(pDC->GetSafeHdc());

	CRect winRect;
	GetClientRect(winRect);

	REAL x = 0.0;
	REAL y = 0.0;
	CSize showPicSize = GetShowPicSize(image, m_nShowType);
	REAL width  = (REAL)showPicSize.cx;
	REAL height = (REAL)showPicSize.cy;

	//      
	if ((UINT)winRect.Width() > width)
		x = (winRect.Width() - width) / 2.0f;

	if ( (UINT)winRect.Height() > height )
		y = ((UINT)winRect.Height() - height) / 2.0f;

	if (m_bWidhtOut)
		x += m_nXX;

	if (m_bHeightOut)
		y += m_nYY;

	m_nShowPicHeight = (int)height;
	m_nShowPicWidth = (int)width;

	//   gdiplusgraphics   
	graph.DrawImage(&image, x, y, width, height);
}

第三歩:特効関数の実現に重点を置く
//       
enum EffectDislayType
{
	EDT_SCANDOWN = 0,		//     
	EDT_VSCAN,				//       
	EDT_MOVERIGHT,			//     
	EDT_HSMOVE,				//       
	EDT_VBLIND,				//      
	EDT_HBLIND,				//      
	EDT_VRASTER,			//     
	EDT_HRASTER,			//     
	EDT_MOSAIC,				//    
	EDT_RAINDROP,			//   
	
	EDT_NONE,				//    
	EDT_RAND				//     
};

 
//--------------------------------------------------------------
//	  :		        
//	  :
//		pDC		       
//		pMemDC	       
//	  :	                                
//--------------------------------------------------------------
void CMagicHouseView::EffectDisplayImage(CDC* pDC, CDC* pMemDC)
{
	int nType = m_nEffectDisplayType;

	if (nType == EDT_RAND)
	{
		LARGE_INTEGER seed;
		QueryPerformanceFrequency(&seed);
		QueryPerformanceCounter(&seed);

		//                
		srand((int)seed.QuadPart);

		nType = rand() % 10;
	}

	switch (nType)
	{
	case EDT_SCANDOWN:
		EffectDisplay::ScanDownDisplay(pDC, pMemDC);
		break;

	case EDT_VSCAN:
		EffectDisplay::VSScanDisplay(pDC, pMemDC);
		break;

	case EDT_MOVERIGHT:
		EffectDisplay::MoveRightDisplay(pDC, pMemDC);
		break;

	case EDT_HSMOVE:
		EffectDisplay::HSMoveDisplay(pDC, pMemDC);
		break;

	case EDT_VBLIND:
		EffectDisplay::VBlindDisplay(pDC, pMemDC);
		break;

	case EDT_HBLIND:
		EffectDisplay::HBlindDisplay(pDC, pMemDC);
		break;

	case EDT_VRASTER:
		EffectDisplay::VRasterDisplay(pDC, pMemDC);
		break;

	case EDT_HRASTER:
		EffectDisplay::HRasterDisplay(pDC, pMemDC);
		break;

	case EDT_MOSAIC:
		EffectDisplay::MosaicDisplay(pDC, pMemDC);
		break;

	default:
		EffectDisplay::RaindropDisplay(pDC, pMemDC);
	}
}

 
ここでは、下向きスキャン、垂直二重スキャン、 モザイク特効の実現
//--------------------------------------------
//	  :		      
//--------------------------------------------
void EffectDisplay::ScanDownDisplay(CDC* pDC, CDC* pMemDC)
{
	//     
	int nHeight = min(s_nPicHeight, s_nCDCHeight);

	//     
	int nWidth = min(s_nPicWidth, s_nCDCWidth);
	
	for (int i = 0; i <= nHeight; i += 1)
	{
		pDC->BitBlt(s_nOffsetX, i + s_nOffsetY, nWidth, 1, 
					pMemDC, s_nOffsetX, i + s_nOffsetY, SRCCOPY);
		DelayTime(1);
	}
}

 
//--------------------------------------------
//   :          
//--------------------------------------------
void EffectDisplay::VSScanDisplay(CDC* pDC, CDC* pMemDC)
{
 //     
 int nHeight = min(s_nPicHeight, s_nCDCHeight);

 //     
 int nWidth = min(s_nPicWidth, s_nCDCWidth);

 for (int i = 0; i <= nHeight / 2; i += 1)
 {
  //     
  pDC->BitBlt(s_nOffsetX, i + s_nOffsetY, nWidth, 1, 
     pMemDC, s_nOffsetX, i + s_nOffsetY, SRCCOPY);
  //     
  pDC->BitBlt(s_nOffsetX, nHeight - i + s_nOffsetY, nWidth, 1, 
     pMemDC, s_nOffsetX, nHeight - i + s_nOffsetY, SRCCOPY);
  DelayTime(2);
 }
}


 
//--------------------------------------------
//	  :		     
//--------------------------------------------
void EffectDisplay::MosaicDisplay(CDC* pDC, CDC* pMemDC)
{
	int nTileSize = 24;	//         
	int nRw = 0;
	int nRh = 0;
	
	if (s_nPicWidth % nTileSize != 0)
		nRw = 1;
	if (s_nPicHeight % nTileSize != 0)
		nRh = 1;

	//         
	int nTileCount = (s_nPicWidth / nTileSize + nRw) * (s_nPicHeight / nTileSize + nRh);

	CPtrArray	points;		//             
	long		lx = 0;
	long		ly = 0;

	for (int k = 0; k < nTileCount; k++)
	{
		CPoint* point = new CPoint;
		point->x = lx;
		point->y = ly;
		lx = lx + nTileSize;
		if (lx >= s_nPicWidth)
		{
			lx = 0;
			ly = ly + nTileSize;
		}

		points.Add(point);
	}

	int nDelayTime = 2;
	if (s_nPicHeight * s_nPicWidth > 600 * 500)
		nDelayTime = 1;

	LARGE_INTEGER seed;
	QueryPerformanceFrequency(&seed);
	QueryPerformanceCounter(&seed);

	//                
	srand((int)seed.QuadPart);

	for (int i = nTileCount - 1; i >= 0; i--)
	{
		int n = rand() % (i + 1);
		CPoint* point = (CPoint*)points[n];

		lx = point->x;
		ly = point->y;

		pDC->BitBlt(lx + s_nOffsetX, ly + s_nOffsetY, nTileSize, nTileSize, 
					pMemDC, lx + s_nOffsetX, ly + s_nOffsetY, SRCCOPY);

		SAFE_DELETE (point);
		points.RemoveAt(n);

		DelayTime(nDelayTime);
	}
}

 
//--------------------------------------------
//	  :		    
//--------------------------------------------
void EffectDisplay::RaindropDisplay(CDC* pDC, CDC* pMemDC)
{
	//     
	int nHeight = min(s_nPicHeight, s_nCDCHeight);

	//     
	int nWidth = min(s_nPicWidth, s_nCDCWidth);

	for (int i = 0; i <= nHeight + s_nOffsetY; i++)
	{
		for (int j = 0; j <= nHeight + s_nOffsetY - i; j++)
		{
			pDC->BitBlt(s_nOffsetX, j, nWidth, 1, 
						pMemDC, s_nOffsetX, nHeight + s_nOffsetY - i, SRCCOPY);
		}

		DelayTime(1);
	}
}