c#动画设计初探 循环切换图片达到动画效果

WPF 专栏收录该内容
25 篇文章 1 订阅

最近需要做个图像采集的工作,其中一个步骤是需要将从摄像机采集的图像播放出来,由于摄像机采集的是一帧帧的图片,而播放的时候需要对播放速度进行控制,因此我考虑将图片放在一个缓冲区中,然后从缓存区中读取后进行播放。因此首先要做的就是如何将一帧帧的图片播放出来,

      通过几天WPF学习,发现可以通过改变image控件的Imagesource或者改变 imageBrush.ImageSource,然后改变Rectangle等的Fill属性,来实现图片的切换。但是做了一个例子发现不是那回事,我在一个循环中不断改变ImageSource值却发现只有最后一帧放出来了,其它帧根本没有显示。并且加入Thread.sleep()让线程等待一段时间也不行。

      再研究发现一些例子中都用了CompositionTarget这个类,但是MSDN中帮助让我看一头雾水,“使用 CompositionTarget 对象,可以基于每个帧回调来创建自定义动画。 CompositionTarget是一个静态类,表示您的应用程序要在其上进行绘制的显示图面。 每次绘制应用程序的场景时,都会引发 Rendering 事件。 呈现帧速率是指每秒绘制场景的次数。”弄了好半天才搞明白,其实说白了,就是程序窗口会按照一定的频率进行刷新,在这个刷新时会触发 Rendering 这个事件,在这个事件中编写你的动画过程(例如改变ImageSource)就可以了。真怀念VB6的帮助,详尽易懂,当时市面的书籍基本上照抄,无出其右。现在的帮助搞的我都怀疑自己是不是中国人,怎么中文搞得比英文还难看懂。
from:
http://greatverve.cnblogs.com/archive/2011/06/27/csharp-flash.html

      如果用CompositionTarget,可以用二种方法改变刷新频率(抄来的,没试过,不保证可用。以后有机会再试)。

      方法一:

< param  name ="maxFramerate"  value ="15"   />  //设置最大帧频。
< param  name ="enableGPUAcceleration"  value ="true"   />  //开启硬件加速
< param  name ="enableCacheVisualization"  value ="true"   />  //测试时,帮忙诊断是否性能有所提示
< param  name ="enableFrameRateCounter"  value ="true"   />  //发布时,和上述参数可一并删除
方法二:
App.Current.Host.Settings.MaxFrameRate  =   30 ; // 播放速度
CompositionTarget.Rendering  +=   new  EventHandler(CompositionTarget_Rendering);
最后我没有用CompositionTarget,而是用的定时器DispatcherTimer,来实现图片连续播放。
 DispatcherTimer timer  =   new  DispatcherTimer();
 timer.Tick 
+=   this .timer_Tick;

  
// 定义刷新频率(帧率),即DispatcherTimer启动的间隔时间
    int  x  =  Convert.ToInt32(((cmbFrames.SelectedItem  as  ComboBoxItem).Content));
   
int  p  =   1000   /  x;
   timer.Interval 
=  TimeSpan.FromMilliseconds(p);
   timer.Start();
   IEnumerator it 
=  al.GetEnumerator();

   
   
private   void  timer_Tick( object  sender, EventArgs e)
   {
      
// 图片切换
       if  (it.MoveNext())
      {
         ImageBrush imageBrush 
=   new  ImageBrush();
         imageBrush.ImageSource 
=  (ImageSource)it.Current;
         img.Fill 
=  imageBrush;
       }
    }










  最近刚接触WPF,  一边学着一边用着,知识点还没有系统化的进行学习整理.

  现在手上有一些美术做好的图片,需要连起来观看形成动画的效果,由于需求比较急,一时半会也静不下心来看WPF关于动画的知识.

  潜意识里一个Image控件,循环设定Source属性,一看效果总是显示集合的最后一项.难道是循环速度太快?基于此思路下折腾了好久也无结果。开始不得不借着可以找到的资源进行尝试。试想我们一张张的图片进行播放形成的动画,是不是类似帧的这种概念.顺这个便找到了CompositionTarget.Rendering事件创建基于帧的动画.

  第一种尝试:

 

?
namespace  ImgAniDemo
{
     /// <summary>
     /// Interaction logic for MainWindow.xaml
     /// </summary>
     public  partial  class  MainWindow : Window
     {
         ObservableCollection<BitmapImage> bmList;
 
         public  MainWindow()
         {
             InitializeComponent();
 
             InitList();
 
             CompositionTarget.Rendering += new  EventHandler(CompositionTarget_Rendering);
         }
 
         public  void  InitList()
         {
             bmList = new  ObservableCollection<BitmapImage>();
             for  ( int  i = 1; i < 4; i++)
             {
                 BitmapImage bmImg = new  BitmapImage( new  Uri(System.Environment.CurrentDirectory + "\\"  + i.ToString() + ".jpg" ));
                 bmList.Add(bmImg);
             }
         }
 
         void  CompositionTarget_Rendering( object  sender, EventArgs e)
         {
             for  ( int  i = 0; i < bmList.Count; i++)
             {
                 this .imgViewer.Source = bmList[i];
                 this .imgViewer.Width = this .imgViewer.Source.Width;
                 this .imgViewer.Height = this .imgViewer.Source.Height;
             }
         }
     }
}

 运行程序ImgAniDemo.exe结果还是只显示了最后一幅图片.

  回头认真思考一下,可以做一个这样的猜测,WPF是不是做了优化,如果循环去设置Image的Source属性,用户看到的效果只会是最后一张图片呢?

  Render是什么意思?不错,Rendering事件被处理的时候,我们是用了一个循环,按着上面的猜测,只会显示最后一张图片便在情理之中了.

  聪明的你一定是想到了方法,我们在Rendering事件的时候不去循环了,只指定某一个图片给Source属性不就ok了吗?

  修改后的代码:

复制代码
namespace ImgAniDemo
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
ObservableCollection<BitmapImage> bmList;

int index = 0; //记录索引

public MainWindow()
{
InitializeComponent();

InitList();

CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
}

public void InitList()
{
bmList = new ObservableCollection<BitmapImage>();
for (int i = 1; i < 4; i++)
{
BitmapImage bmImg = new BitmapImage(new Uri(System.Environment.CurrentDirectory + "\\" + i.ToString() + ".jpg"));
bmList.Add(bmImg);
}
}

void CompositionTarget_Rendering(object sender, EventArgs e)
{
if (index < bmList.Count)
{
this.imgViewer.Source = bmList[index];
this.imgViewer.Width = this.imgViewer.Source.Width;
this.imgViewer.Height = this.imgViewer.Source.Height;

index++;
}
else
{
index = 0;
}
}
}
}
复制代码

这时候我们已经可以看到图片在自动切换了.会不会感觉速度太快了,我想按着一定的速度来控件切换怎么办?

直接上代码了

复制代码
namespace ImgAniDemo
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
ObservableCollection<BitmapImage> bmList;

int index = 0; //记录索引
bool isRendering = false;

public MainWindow()
{
InitializeComponent();

InitList();

CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerAsync();
}

void bw_DoWork(object sender, DoWorkEventArgs e)
{
while (true)
{
isRendering = true;
System.Threading.Thread.Sleep(1000); //停1秒
}
}

public void InitList()
{
bmList = new ObservableCollection<BitmapImage>();
for (int i = 1; i < 4; i++)
{
BitmapImage bmImg = new BitmapImage(new Uri(System.Environment.CurrentDirectory + "\\" + i.ToString() + ".jpg"));
bmList.Add(bmImg);
}
}

void CompositionTarget_Rendering(object sender, EventArgs e)
{
if (isRendering)
{
if (index < bmList.Count)
{
this.imgViewer.Source = bmList[index];
this.imgViewer.Width = this.imgViewer.Source.Width;
this.imgViewer.Height = this.imgViewer.Source.Height;

index++;
}
else
{
index = 0;
}
isRendering = false;
}
}
}
}
复制代码

在运行看下效果呢?

呵呵,图片是不是在自动播放呢?

 

注:以上代码中用到的图片名称分别为1.jpg,2.jpg,3.jpg,且图片放在exe程序一起即可

 

以上仅是个人想到的一种方法,若有不正确的地方,还请多多指点...


  • 0
    点赞
  • 0
    评论
  • 4
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值