Bài viết mới

[C#] Hiệu ứng Water Effect Image cho Banner

[C#] Hiệu ứng Water Effect Image cho Banner
Đăng bởi: Thảo meo - Lượt xem: 478 13:19:22, 02/06/2020C#   In bài viết

Xin chào các bạn, bài viết hôm nay mình tiếp tục chia sẽ đến các bạn source code Water Effect Image trên lập trình C# Winform.

[C#] Water Effect Image in Winform

Dưới đây là giao diện demo ứng dụng:

water_effect_demo

Hiệu ứng, khi mình di chuyển Move Mouse thì sẽ hiện thị hiệu ứng gợn sóng.

Đầu tiên, các bạn cần tạo một class WaterEffectControl.cs C#:

using System;
using System.Collections;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace WaterEffectImage
{
	/// <summary>
	/// 
	/// </summary>
	public class WaterEffectControl : System.Windows.Forms.Panel
	{
		private System.Windows.Forms.Timer effectTimer;
		private System.ComponentModel.IContainer components;

		private Bitmap		_bmp;
		private short[,,]	_waves;
		private int			_waveWidth;
		private int			_waveHeight;
		private int			_activeBuffer = 0;
		private bool		_weHaveWaves;
		private int			_bmpHeight,_bmpWidth;
		private byte[]		_bmpBytes;		
		private BitmapData	_bmpBitmapData;		
		private int			_scale;
	

		private void InitializeComponent()
		{
			this.components = new System.ComponentModel.Container();
			this.effectTimer = new System.Windows.Forms.Timer(this.components);
			// 
			// effectTimer
			// 
			this.effectTimer.Tick += new System.EventHandler(this.effectTimer_Tick);
			// 
			// WaterEffectControl
			// 
			this.Paint += new System.Windows.Forms.PaintEventHandler(this.WaterEffectControl_Paint);
			this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.WaterEffectControl_MouseMove);

		}
	
		public WaterEffectControl()
		{
			InitializeComponent();
			effectTimer.Enabled = true;
			effectTimer.Interval = 50;
			SetStyle(ControlStyles.UserPaint, true);
			SetStyle(ControlStyles.AllPaintingInWmPaint, true);
			SetStyle(ControlStyles.DoubleBuffer, true);
			this.BackColor = Color.White;
			_weHaveWaves = false;			
			_scale = 1;
			
		}

		public WaterEffectControl(Bitmap bmp) : this()
		{
			this.ImageBitmap = bmp;			
		}

		protected override void Dispose( bool disposing )
		{
			_bmp.UnlockBits(_bmpBitmapData);
			if( disposing )
			{
				if (components != null) 
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		/// <summary>
		/// Timer handler
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void effectTimer_Tick(object sender, System.EventArgs e)
		{	

			if(_weHaveWaves)
			{
				Invalidate();

				ProcessWaves();

			}
		}

		/// <summary>
		/// Paint handler
		/// 
		/// Calculates the final effect-image out of
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		public void WaterEffectControl_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
		{
	
			using(Bitmap tmp = (Bitmap)_bmp.Clone())
			{
				
				int xOffset, yOffset;
				byte alpha;
			
				if(_weHaveWaves)
				{
					BitmapData tmpData =  tmp.LockBits(new Rectangle(0,0,_bmpWidth,_bmpHeight), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
					
					byte[] tmpBytes = new Byte[_bmpWidth*_bmpHeight*4];

					Marshal.Copy(tmpData.Scan0,tmpBytes,0,_bmpWidth*_bmpHeight*4);
					
					for(int x=1; x<_bmpWidth -1; x++)
					{
						for(int y=1; y<_bmpHeight -1; y++)
						{
							int waveX = (int)x >> _scale;
							int waveY = (int)y >> _scale;

							//check bounds
							if(waveX <= 0) waveX = 1;
							if(waveY <= 0) waveY = 1;
							if(waveX >= _waveWidth-1) waveX = _waveWidth-2;
							if(waveY >= _waveHeight-1) waveY = _waveHeight-2;

							//this gives us the effect of water breaking the light
							xOffset = (_waves[waveX-1,waveY,_activeBuffer] -_waves[waveX+1,waveY,_activeBuffer]) >> 3;
							yOffset = (_waves[waveX,waveY-1,_activeBuffer] -_waves[waveX,waveY+1,_activeBuffer]) >> 3;

							if((xOffset != 0) || (yOffset != 0))
							{
								//check bounds
								if(x+xOffset >= _bmpWidth-1)	xOffset = _bmpWidth - x - 1;
								if(y+yOffset >= _bmpHeight-1)	yOffset = _bmpHeight - y - 1;
								if(x+xOffset < 0)	xOffset = -x;
								if(y+yOffset < 0)	yOffset = -y;
								
								//generate alpha
								alpha = (byte)(200-xOffset);
								if(alpha < 0) alpha = 0;
								if(alpha > 255) alpha = 254;

								//set colors
								tmpBytes[4*(x + y*_bmpWidth)]		= _bmpBytes[4*(x+xOffset + (y+yOffset)*_bmpWidth)];
								tmpBytes[4*(x + y*_bmpWidth) + 1]	= _bmpBytes[4*(x+xOffset + (y+yOffset)*_bmpWidth) + 1];
								tmpBytes[4*(x + y*_bmpWidth) + 2]	= _bmpBytes[4*(x+xOffset + (y+yOffset)*_bmpWidth) + 2];
								tmpBytes[4*(x + y*_bmpWidth) + 3]	= alpha;
								
							}

						}
					}

					//copy data back
					Marshal.Copy(tmpBytes, 0, tmpData.Scan0, _bmpWidth*_bmpHeight*4);
					tmp.UnlockBits(tmpData);
					
				}

				e.Graphics.DrawImage(tmp,0,0,this.ClientRectangle.Width, this.ClientRectangle.Height);
				
			}
			
		}

		/// <summary>
		/// This is the method that actually does move the waves around and simulates the
		/// behaviour of water.
		/// </summary>
		private void ProcessWaves()
		{
			int newBuffer = (_activeBuffer == 0) ? 1 : 0;
			bool wavesFound = false;

			for(int x=1; x<_waveWidth -1; x++)
			{
				for(int y=1; y<_waveHeight -1; y++)
				{
					_waves[x,y,newBuffer] = (short)(
											((_waves[x-1,y-1,_activeBuffer] +
											_waves[x,y-1,_activeBuffer] +
											_waves[x+1,y-1,_activeBuffer] +
											_waves[x-1,y,_activeBuffer] +
											_waves[x+1,y,_activeBuffer] +
											_waves[x-1,y+1,_activeBuffer] +
											_waves[x,y+1,_activeBuffer] +
											_waves[x+1,y+1,_activeBuffer]) >> 2) - _waves[x,y,newBuffer]);
					
					//damping
					if(_waves[x,y,newBuffer] != 0)
					{
						_waves[x,y,newBuffer] -= (short)(_waves[x,y,newBuffer] >> 4);					
						wavesFound = true;
					}
					
					
				}
			}

			_weHaveWaves = wavesFound;
			_activeBuffer = newBuffer;

		}


		/// <summary>
		/// This function is used to start a wave by simulating a round drop
		/// </summary>
		/// <param name="x">x position of the drop</param>
		/// <param name="y">y position of the drop</param>
		/// <param name="height">Height position of the drop</param>
		private void PutDrop(int x, int y, short height)
		{
			_weHaveWaves = true;
			int radius = 20;
			double dist;

			for(int i = -radius; i<=radius; i++)
			{
				for(int j = -radius; j<=radius; j++)
				{
					if(((x+i>=0) && (x+i<_waveWidth-1)) && ((y+j>=0) && (y+j<_waveHeight-1)))
					{
						dist = Math.Sqrt(i*i +j*j);
						if(dist<radius)
							_waves[x+i,y+j,_activeBuffer] = (short)(Math.Cos(dist*Math.PI  / radius) * height);
					}
				}
			}
		}

		/// <summary>
		/// The MouseMove handler.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void WaterEffectControl_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
		{
			if(e.Button == MouseButtons.Left)
			{
				int realX = (int)((e.X / (double)this.ClientRectangle.Width)*_waveWidth);
				int realY = (int)((e.Y / (double)this.ClientRectangle.Height)*_waveHeight);
				PutDrop(realX,realY,200);
			}
		}


		#region Properties
		/// <summary>
		/// Our background image
		/// </summary>
		public Bitmap ImageBitmap
		{
			get { return _bmp; }
			set 
			{				
				_bmp = value;
				_bmpHeight = _bmp.Height;
				_bmpWidth = _bmp.Width;

				_waveWidth = _bmpWidth >> _scale;
				_waveHeight = _bmpHeight  >> _scale;
				_waves = new Int16[_waveWidth,_waveHeight, 2];								

				_bmpBytes = new Byte[_bmpWidth*_bmpHeight*4];
				_bmpBitmapData =  _bmp.LockBits(new Rectangle(0,0,_bmpWidth,_bmpHeight), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
				Marshal.Copy(_bmpBitmapData.Scan0,_bmpBytes,0,_bmpWidth*_bmpHeight*4);
			}
		}

		/// <summary>
		/// The scale of the wave matrix compared to the size of the image.
		/// Use it for large images to reduce processor load.
		/// 
		/// 0 : wave resolution is the same than image resolution
		/// 1 : wave resolution is half the image resolution
		/// ...and so on
		/// </summary>
		public int Scale
		{
			get { return _scale; }
			set { _scale = value;	}
		}
		#endregion
	}
}

Và khi sử dụng, các bạn chỉ cần truyền đường dẫn hình ảnh vào thuộc tính Property ImageBitmap.

Thanks for watching!

Theo CodeProject

DOWNLOAD SOURCE

Tags: water effect c#water image effect c#

THÔNG TIN TÁC GIẢ

THẢO LUẬN BÀI VIẾT

BÀI VIẾT LIÊN QUAN

[C#] Hiệu ứng Water Effect Image cho Banner
Đăng bởi: Thảo meo - Lượt xem: 478 13:19:22, 02/06/2020C#   In bài viết

PHẦN MỀM LẤY TIN BẤT ĐỘNG SẢN

phần mềm lấy tin tự động bất động sản

CÁC BÀI CÙNG CHỦ ĐỀ

Đọc tiếp
.