您的位置:首页 > 编程语言 > C#

30种图像动画特效算法(C#多线程版)(中)

2011-01-06 16:54 281 查看
这是截屏动画效果:

这次是(中),共10种特效:

#region 随机竖条

// 原理:将图像分成宽度相等的列,然后随机选择每一列并从上到下显示
private void Animator11()
{
const float lineWidth = 40; // 竖条宽度
const int stepCount = 12; // 竖条每次前进量
try
{
OnDrawStarted(this, EventArgs.Empty);
ClearBackground();

Random rnd = new Random(); // 随机数类
// 生成每个列随机显示的次序
int[] colIndex = new int[(int)Math.Ceiling(bmp.Width / lineWidth)];
int index = 1; // 数组索引
// 数组被自动初始化为0,因此可以通过判断其中的元素是否为0而得知该位置是否产生了随机数
// 为了区别自动初始化的元素值,index从1开始
do
{
int s = rnd.Next(colIndex.Length);
if (colIndex[s] == 0)
{
colIndex[s] = index++;
}
} while (index <= colIndex.Length);
// 按照上面随机生成的次序逐一显示每个竖条
for (int i = 0; i < colIndex.Length; i++)
{
for (int y = 0; y < bmp.Height; y += stepCount)
{
RectangleF rect = new RectangleF((colIndex[i] - 1) * lineWidth, y, lineWidth, stepCount);
dc.DrawImage(bmp, rect, rect, GraphicsUnit.Pixel);

Thread.Sleep(1 * delay);
ShowBmp(rect);
}

Thread.Sleep(10 * delay);
}
}
catch (Exception ex)
{
ShowError(ex.Message);
}
finally
{
OnDrawCompleted(this, EventArgs.Empty);
}
}

#endregion

#region 随机拉丝

// 原理:每次随机显示图像的一个像素行
private void Animator12()
{
try
{
OnDrawStarted(this, EventArgs.Empty);
ClearBackground();

Random rnd = new Random(); // 随机数类
// 生成每个像素行的显示次序
int[] rowIndex = new int[bmp.Height];
int index = 1; // 数组索引
do
{
int s = rnd.Next(rowIndex.Length);
if (rowIndex[s] == 0)
{
rowIndex[s] = index++;
}
} while (index <= rowIndex.Length);
// 按照上面随机生成的次序逐一显示每个像素行
for (int i = 0; i < rowIndex.Length; i++)
{
RectangleF rect = new RectangleF(0, (rowIndex[i] - 1), bmp.Width, 1);
dc.DrawImage(bmp, rect, rect, GraphicsUnit.Pixel);

ShowBmp(rect);
Thread.Sleep(1 * delay);
}
}
catch (Exception ex)
{
ShowError(ex.Message);
}
finally
{
OnDrawCompleted(this, EventArgs.Empty);
}
}

#endregion

#region 垂直对切

// 原理:由图像中心向分左右两半分别向上下两个方向显示,到达边缘后按同样方向补齐另外的部分
private void Animator13()
{
const int stepCount = 4; // 上下前进的增量像素,应能被高度整除
try
{
OnDrawStarted(this, EventArgs.Empty);
ClearBackground();

// 第一次循环,左半部分从垂直中心向上显示,右半部分从垂直中心向下显示
for (int y = 0; y <= bmp.Height / 2; y += stepCount)
{
// 左半部分
Rectangle rectLeft = new Rectangle(0, bmp.Height / 2 - y - stepCount, bmp.Width / 2, stepCount);
dc.DrawImage(bmp, rectLeft, rectLeft, GraphicsUnit.Pixel);
// 右半部分
Rectangle rectRight = new Rectangle(bmp.Width / 2, bmp.Height / 2 + y, bmp.Width / 2, stepCount);
dc.DrawImage(bmp, rectRight, rectRight, GraphicsUnit.Pixel);

ShowBmp(Rectangle.Union(rectLeft, rectRight));
Thread.Sleep(10 * delay);
}
// 第二次循环,左半部分从底边向上显示,右半部分从顶边向下显示
for (int y = 0; y <= bmp.Height / 2; y += stepCount)
{
// 左半部分
Rectangle rectLeft = new Rectangle(0, bmp.Height - y - stepCount, bmp.Width / 2, stepCount);
dc.DrawImage(bmp, rectLeft, rectLeft, GraphicsUnit.Pixel);
// 右半部分
Rectangle rectRight = new Rectangle(bmp.Width / 2, y, bmp.Width / 2, stepCount);
dc.DrawImage(bmp, rectRight, rectRight, GraphicsUnit.Pixel);

ShowBmp(Rectangle.Union(rectLeft, rectRight));
Thread.Sleep(10 * delay);
}
}
catch (Exception ex)
{
ShowError(ex.Message);
}
finally
{
OnDrawCompleted(this, EventArgs.Empty);
}
}

#endregion

#region 随机分块

// 原理:框像分割为相等的正方块,然后逐个随机显示其中之一,直到全部显示完成
private void Animator14()
{
const float blockSize = 50; // 分块尺寸,如果该尺寸为4到6时,显示效果为随机图点
try
{
OnDrawStarted(this, EventArgs.Empty);
ClearBackground();

Random rnd = new Random(); // 随机数类
// 定义二维数组,对应每个分块,其中保存该块的位置索引(基于总块数)
int[,] blockIndex = new int[(int)Math.Ceiling(bmp.Width / blockSize), (int)Math.Ceiling(bmp.Height / blockSize)];

// 生成随机快坐标,并填充顺序号
int s = 1; // 分块次序(从左到右,从上到下)
do
{
int x = rnd.Next(blockIndex.GetLength(0));
int y = rnd.Next(blockIndex.GetLength(1));
if (blockIndex[x, y] == 0)
{
blockIndex[x, y] = s++;
}
} while (s <= blockIndex.GetLength(0) * blockIndex.GetLength(1));

// 按照上面随机生成的次序逐一显示所有分块
for (int x = 0; x < blockIndex.GetLength(0); x++)
{
for (int y = 0; y < blockIndex.GetLength(1); y++)
{
// blockIndex[x, y]中保存的是分块的显示次序,可以将其转换为对应的坐标
RectangleF rect = new RectangleF(((blockIndex[x, y] - 1) % blockIndex.GetLength(0)) * blockSize,
((blockIndex[x, y] - 1) / blockIndex.GetLength(0)) * blockSize, blockSize, blockSize);
dc.DrawImage(bmp, rect, rect, GraphicsUnit.Pixel);

ShowBmp(rect);
Thread.Sleep(10 * delay);
}
}
}
catch (Exception ex)
{
ShowError(ex.Message);
}
finally
{
OnDrawCompleted(this, EventArgs.Empty);
}
}

#endregion

#region 对角闭幕

// 原理:每次绘制所有图像内容,然后将不可见的区域生成闭合GraphicsPath并用背景色填充该区域
private void Animator15()
{
const int stepCount = 4; // y轴的增量像素,应能被高度整除
try
{
OnDrawStarted(this, EventArgs.Empty);
ClearBackground();

// 左上角坐标p0(x0, y0)从左到右,p1(x1, y1)从上到下
// 右下角坐标p2(x2, y2)从右到左,p3(x3, y3)从下到上
// 这四个点与左下角点和右上角点构成不可见区域
PointF p0 = new Point(0, 0);
PointF p1 = new Point(0, 0);
PointF p2 = new Point(bmp.Width - 1, bmp.Height - 1);
PointF p3 = new Point(bmp.Width - 1, bmp.Height - 1);
// 表示不可见区域的闭合路径
GraphicsPath path = new GraphicsPath();
// 以y轴stepCount个像素为增量,也可以使用x轴为增量,一般使用较短的那个轴
for (int y = 0; y < bmp.Height; y += stepCount)
{
p0.X = y * Convert.ToSingle(bmp.Width) / Convert.ToSingle(bmp.Height); // 以浮点数计算,保证精度
p1.Y = y;
p2.X = bmp.Width - 1 - p0.X;
p3.Y = bmp.Height - 1 - p1.Y;
path.Reset();
path.AddPolygon(new PointF[] { p0, new PointF(bmp.Width, 0), p3, p2, new PointF(0, bmp.Height), p1 });
dc.DrawImage(bmp, 0, 0); // 绘制全部图像
dc.FillPath(new SolidBrush(Color.FromKnownColor(KnownColor.ButtonFace)), path); // 填充不可见区域

ShowBmp(path.GetBounds());
Thread.Sleep(10 * delay);
}
// 由于最后一次绘制的不可见区域并不需要,在这里使全部区域可见
dc.DrawImage(bmp, 0, 0);

ShowBmp();
}
catch (Exception ex)
{
ShowError(ex.Message);
}
finally
{
OnDrawCompleted(this, EventArgs.Empty);
}
}

#endregion

#region 垂直百叶(改进版)

// 原理:在图像的垂直方向分为高度相等的若干条,然后从上到下计算每次需要显示的区域
private void Animator16()
{
const float lineHeight = 50; // 百叶高度
try
{
OnDrawStarted(this, EventArgs.Empty);
ClearBackground();

GraphicsPath path = new GraphicsPath();
TextureBrush textureBrush = new TextureBrush(bmp);
for (int i = 0; i < lineHeight; i++) // 每条百叶逐行像素显示
{
for (int j = 0; j < Math.Ceiling(bmp.Height / lineHeight); j++)
{
RectangleF rect = new RectangleF(0, lineHeight * j + i, bmp.Width, 1);
path.AddRectangle(rect);
}
dc.FillPath(textureBrush, path);

ShowBmp();
Thread.Sleep(10 * delay);
}
}
catch (Exception ex)
{
ShowError(ex.Message);
}
finally
{
OnDrawCompleted(this, EventArgs.Empty);
}
}

#endregion

#region 压缩竖条(改进版)

// 原理:在图像的水平方向分为宽度相等的若干条,然后逐一加宽每条竖条的宽度,并在其中显示该条图像的全部内容
private void Animator17()
{
const float lineWidth = 100; // 分条宽度
const int stepCount = 4; // 每次加宽的步进像素,应能被lineWidth整除
try
{
OnDrawStarted(this, EventArgs.Empty);
ClearBackground();

for (int i = 0; i < Math.Ceiling(bmp.Width / lineWidth); i++)
{
for (int j = stepCount; j <= lineWidth; j += stepCount) // 每条宽度逐渐增加,以产生缩放效果
{
RectangleF sourRect = new RectangleF(lineWidth * i, 0, lineWidth, bmp.Height);
RectangleF destRect = new RectangleF(lineWidth * i, 0, j, bmp.Height);
dc.DrawImage(bmp, destRect, sourRect, GraphicsUnit.Pixel);

ShowBmp(destRect);
Thread.Sleep(10 * delay);
}
}
}
catch (Exception ex)
{
ShowError(ex.Message);
}
finally
{
OnDrawCompleted(this, EventArgs.Empty);
}
}

#endregion

#region 水平拉入(改进版)

// 原理:由于内存位图与设备无关,故不能使用在水平方向逐渐改变图像分辨率(每英寸点数)的办法
// 而改为使用在水平方向拉伸显示,并逐步缩小
private void Animator18()
{
try
{
OnDrawStarted(this, EventArgs.Empty);
//ClearBackground();

for (float i = 1; i <= dc.DpiX; i++)
{
RectangleF destRect = new RectangleF(0, 0, bmp.Width * dc.DpiX / i, bmp.Height);
RectangleF sourRect = new RectangleF(0, 0, bmp.Width, bmp.Height);
dc.DrawImage(bmp, destRect, sourRect, GraphicsUnit.Pixel);

ShowBmp();
Thread.Sleep(10 * delay);
}
}
catch (Exception ex)
{
ShowError(ex.Message);
}
finally
{
OnDrawCompleted(this, EventArgs.Empty);
}
}

#endregion

#region 三色对接(改进版)

// 原理:使用ImageAttributes类和颜色转换矩阵处理图像,首先R和B分别从左右向中心移动,相遇后继续移动,且G从两侧向中间移动,直到相遇
private void Animator19()
{
const int stepCount = 4; // 各个区域每次增加的像素量
try
{
OnDrawStarted(this, EventArgs.Empty);
ClearBackground();

// 建立三个时间段所需的5个不同颜色转换后的位图
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); // 位图的全部矩形区域
// 红色分量位图
ColorMatrix matrix = new ColorMatrix();
matrix.Matrix00 = 1f; // R
matrix.Matrix11 = 0f; // G
matrix.Matrix22 = 0f; // B
ImageAttributes attributes = new ImageAttributes();
attributes.SetColorMatrix(matrix); // 使用R分量转换矩阵
Bitmap redBmp = new Bitmap(bmp.Width, bmp.Height);
Graphics.FromImage(redBmp).DrawImage(bmp, rect, 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, attributes);
// 蓝色分量位图
matrix.Matrix00 = 0f; // R
matrix.Matrix11 = 0f; // G
matrix.Matrix22 = 1f; // B
attributes.SetColorMatrix(matrix); // 使用B分量转换矩阵
Bitmap blueBmp = new Bitmap(bmp.Width, bmp.Height);
Graphics.FromImage(blueBmp).DrawImage(bmp, rect, 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, attributes);
// 红蓝分量位图
matrix.Matrix00 = 1f; // R
matrix.Matrix11 = 0f; // G
matrix.Matrix22 = 1f; // B
attributes.SetColorMatrix(matrix); // 使用B分量转换矩阵
Bitmap redBlueBmp = new Bitmap(bmp.Width, bmp.Height);
Graphics.FromImage(redBlueBmp).DrawImage(bmp, rect, 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, attributes);
// 红绿分量位图
matrix.Matrix00 = 1f; // R
matrix.Matrix11 = 1f; // G
matrix.Matrix22 = 0f; // B
attributes.SetColorMatrix(matrix); // 使用B分量转换矩阵
Bitmap redGreenBmp = new Bitmap(bmp.Width, bmp.Height);
Graphics.FromImage(redGreenBmp).DrawImage(bmp, rect, 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, attributes);
// 蓝绿分量位图
matrix.Matrix00 = 0f; // R
matrix.Matrix11 = 1f; // G
matrix.Matrix22 = 1f; // B
attributes.SetColorMatrix(matrix); // 使用B分量转换矩阵
Bitmap blueGreenBmp = new Bitmap(bmp.Width, bmp.Height);
Graphics.FromImage(blueGreenBmp).DrawImage(bmp, rect, 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, attributes);

// 第1段:1/2时间(设从左到右时间为1),R和B分别从左右向中间移动,在1/2处相遇
for (int x = 0; x < bmp.Width / 2; x += stepCount)
{
Rectangle rectR = new Rectangle(x, 0, stepCount, bmp.Height); // R的区域,从左到右
dc.DrawImage(redBmp, rectR, rectR, GraphicsUnit.Pixel);

Rectangle rectB = new Rectangle(bmp.Width - x - stepCount, 0, stepCount, bmp.Height); // B的区域,从右到左
dc.DrawImage(blueBmp, rectB, rectB, GraphicsUnit.Pixel);

ShowBmp(Rectangle.Union(rectR, rectB));
Thread.Sleep(10 * delay);
}

// 第2段:1/4时间,R和B从中间分别向右、左移动,G从左右向中间移动,在1/4和3/4处相遇
ColorMatrix matrixGLeft = new ColorMatrix(); // 处理从左到右的G
ColorMatrix matrixGRight = new ColorMatrix(); // 处理从右到左的G
for (int x = 0; x < bmp.Width / 4; x += stepCount)
{
Rectangle rectBR = new Rectangle(bmp.Width / 2 - x - stepCount, 0, 2 * (x + stepCount), bmp.Height); // B和R的区域(位于中心)
dc.DrawImage(redBlueBmp, rectBR, rectBR, GraphicsUnit.Pixel);

Rectangle rectGLeft = new Rectangle(x, 0, stepCount, bmp.Height); // 左侧G的区域,从左到右
dc.DrawImage(redGreenBmp, rectGLeft, rectGLeft, GraphicsUnit.Pixel);

Rectangle rectGRight = new Rectangle(bmp.Width - x - stepCount, 0, stepCount, bmp.Height); // 右侧G的区域,从右到左
dc.DrawImage(blueGreenBmp, rectGRight, rectGRight, GraphicsUnit.Pixel);

ShowBmp(Rectangle.Union(Rectangle.Union(rectBR, rectGLeft), rectGRight));
Thread.Sleep(10 * delay);
}

// 第3段:1/4时间,显示全色,在1/4处同时向左右两侧扩展(即每次左右各扩展stepCount像素),3/4处与1/4处相同
for (int x = 0; x < bmp.Width / 4; x += stepCount)
{
Rectangle rect1_4 = new Rectangle(bmp.Width / 4 - x - stepCount, 0, 2 * (x + stepCount), bmp.Height); // 1/4处的区域
dc.DrawImage(bmp, rect1_4, rect1_4, GraphicsUnit.Pixel);

Rectangle rect3_4 = new Rectangle(bmp.Width / 4 * 3 - x - stepCount, 0, 2 * (x + stepCount), bmp.Height); // 3/4处的区域
dc.DrawImage(bmp, rect3_4, rect3_4, GraphicsUnit.Pixel);

ShowBmp(Rectangle.Union(rect1_4, rect3_4));
Thread.Sleep(10 * delay);
}

}
catch (Exception ex)
{
ShowError(ex.Message);
}
finally
{
OnDrawCompleted(this, EventArgs.Empty);
}
}

#endregion

#region 对角滑动(改进版)

// 原理:在水平方向从右到左,在垂直方向从下到上移动图像
private void Animator20()
{
const int movePixel = 4; // 每次移动的像素,应能被图像高度整除
try
{
OnDrawStarted(this, EventArgs.Empty);
ClearBackground();

RectangleF sourRect = new RectangleF(0, 0, bmp.Width, bmp.Height);
for (int y = bmp.Height; y >= 0; y -= movePixel) // 从下到上移动图像
{
// 按比例计算水平方向移动的量
RectangleF destRect = new RectangleF(y * Convert.ToSingle(bmp.Width) / bmp.Height, y, bmp.Width, bmp.Height);
dc.DrawImage(bmp, destRect, sourRect, GraphicsUnit.Pixel);

ShowBmp(destRect);
Thread.Sleep(10 * delay);
}
}
catch (Exception ex)
{
ShowError(ex.Message);
}
finally
{
OnDrawCompleted(this, EventArgs.Empty);
}
}

#endregion

源程序没有必要解释了,当初编写的时候我就加了非常详细的注释,只要你又一定的.NET基础,应该完全可以读懂!

这里是本文的最后一部分:http://mengliao.blog.51cto.com/876134/473214
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息