当前位置: 首页 > news >正文

【学习笔记】Windows GDI绘图(十三)动画播放ImageAnimator(可调速)

文章目录

  • 前言
  • 定义
  • 方法
    • CanAnimate 是否可动画显示
    • Animate 动画显示多帧图像
    • UpdateFrames
    • StopAnimate终止动画
    • Image.GetFrameCount 获取动画总帧数
    • Image.GetPropertyItem(0x5100) 获取帧延迟
  • 自定义GIF播放(可调速)

前言

在前一篇文章中用到ImageAnimator获取了GIF动画的一些属性,但没有真正使用ImageAnimator来进行GIF动画播放(还可能误导),所有这篇就深入了解ImageAnimator的使用。
本文使用的动画为另一篇文章 心动(GDI+) 使用 GDI+纯手工绘制生成,有兴趣的可以查看原文,并配原码。

定义

public sealed class ImageAnimator

作用:对具有基于时间帧的图像进行动画显示。

方法

CanAnimate 是否可动画显示

原型:

public static bool CanAnimate (System.Drawing.Image image);

作用:判断指定图像是否包含基于时间帧。

Animate 动画显示多帧图像

原型:

public static void Animate (System.Drawing.Image image, EventHandler onFrameChangedHandler);

作用:将多帧图像显示为动画。

UpdateFrames

原型:

public static void UpdateFrames ();
public static void UpdateFrames (System.Drawing.Image image);

作用:使多帧动画前推进,下次渲染时,使用新的图像。

1、加载一个动画Image.FromFile
2、判断该图像是基于时间帧的图像 CanAnimate
3、指定帧切换事件 Animate
4、推进多帧动画
5、绘制最新图像

private Image gifImg = null;
/// <summary>
/// 加载多帧图像
/// </summary>
private void LoadGif()
{gifImg = Image.FromFile("Heartbeat.gif");if (ImageAnimator.CanAnimate(gifImg)){ImageAnimator.Animate(gifImg, OnFrameChanged);}
}
//切换帧事件
private void OnFrameChanged(object o, EventArgs e)
{//强制显示this.paintCtrl_Main.Panel_Main.Invalidate();
}[System.ComponentModel.Description("ImageAnimator的Animate方法")]
public void Demo13_01(PaintEventArgs e)
{if (gifImg == null){LoadGif();}ImageAnimator.UpdateFrames(gifImg);e.Graphics.DrawImage(gifImg, 0, 0, this.paintCtrl_Main.Panel_Main.Width, this.paintCtrl_Main.Panel_Main.Height);
}

由以上代码,使用ImageAnimator加GDI+绘制,可以很容易实现GIF动画的播放。
Gif动画播放

StopAnimate终止动画

原型:

public static void StopAnimate (System.Drawing.Image image, EventHandler onFrameChangedHandler);

作用:停止动画显示。(实际上没有真正停止,还需要其他条件配合)

private Image gifImg = null;
EventHandler OnFrameChangedEventHandler;
/// <summary>
/// 加载多帧图像
/// </summary>
private void LoadGif()
{gifImg = Image.FromFile("Heartbeat.gif");if (ImageAnimator.CanAnimate(gifImg)){OnFrameChangedEventHandler = new EventHandler(OnFrameChanged);isStop = false;ImageAnimator.Animate(gifImg, OnFrameChangedEventHandler);this.paintCtrl_Main.Panel_Main.Click += PaintCtrl_Main_Click; ;}
}private void PaintCtrl_Main_Click(object sender, EventArgs e)
{if (isStop){ImageAnimator.Animate(gifImg, OnFrameChangedEventHandler);}else{ImageAnimator.StopAnimate(gifImage, OnFrameChangedEventHandler);}isStop = !isStop;
}private bool isStop = false;
private void OnFrameChangedStop(object o, EventArgs e)
{isStop = true;
}//切换帧事件
private void OnFrameChanged(object o, EventArgs e)
{//强制显示this.paintCtrl_Main.Panel_Main.Invalidate();
}[System.ComponentModel.Description("ImageAnimator的Animate方法")]
public void Demo13_01(PaintEventArgs e)
{if (gifImg == null){LoadGif();}if (!isStop){ImageAnimator.UpdateFrames(gifImg);}e.Graphics.DrawImage(gifImg, 0, 0, this.paintCtrl_Main.Panel_Main.Width,this.paintCtrl_Main.Panel_Main.Height);
}

通过鼠标点击,控制Gif动画开始,还是停止。

Image.GetFrameCount 获取动画总帧数

原型:

public int GetFrameCount (System.Drawing.Imaging.FrameDimension dimension);

作用:返回指定维度的帧数。

Image.GetPropertyItem(0x5100) 获取帧延迟

作用:返回每帧的延迟数

/// <summary>
/// 获取帧总数、帧延迟
/// </summary>
private void GetFrameDelays()
{//总帧数var frameCount = gifImg.GetFrameCount(FrameDimension.Time);var frameDelay = gifImg.GetPropertyItem(0x5100);//FrameDelay 帧延迟//var loopCount= gifImg.GetPropertyItem(0x5110);//LoopCount GIF循环计数byte[] values = frameDelay.Value;// 每个延迟时间占 4 个字节var frameDelays = new int[frameCount];for (int i = 0; i < frameCount; i++){frameDelays[i] = BitConverter.ToInt32(values, i * 4) * 10; // 单位是 1/100 秒,转换为毫秒}
}

自定义GIF播放(可调速)

使用ImageAnimator的Animate的速度由Gif内置的每帧时间延迟控制,具体可见GetFrameDelays函数示例。如果需要实现自定义速度播放,可使用Timer来控制播放速度。
1、使用Image.FromFile加载Gif动画
2、用ImageAnimator.CanAnimate判断是否为多帧动画
3、获取Gif动画的FrameDimension和总帧数
4、定义并启用一个Timer,设置Interval控制播放速度
5、设置Timer.Tick函数,切换当前帧数和强制控件刷新
6、设置控件MouseClick事件,左键timer.Interval减小,右键Interval加大
7、在Paint事件中SelectActiveFrame激活指定帧,然后绘制

[System.ComponentModel.Description("ImageAnimator的GIF动画播放可调速")]
public void Demo13_02(PaintEventArgs e)
{if (gifImg == null){LoadGif2();}if (FrameCount > 0){gifImg.SelectActiveFrame(dimension, currentFrame);e.Graphics.DrawImage(gifImg, 0, 0, gifImg.Width, gifImg.Height);e.Graphics.DrawString($"左键加速/右键减速 {1000 / GifTimer.Interval}帧/秒,当前帧:{currentFrame}", Font, Brushes.Red, new PointF(20, 20));}
}FrameDimension dimension;
/// <summary>
/// 加载多帧图像
/// </summary>
private void LoadGif2()
{gifImg = Image.FromFile("Heartbeat.gif");if (ImageAnimator.CanAnimate(gifImg)){dimension = new FrameDimension(gifImg.FrameDimensionsList[0]);FrameCount = gifImg.GetFrameCount(dimension);GifTimer = new Timer();GifTimer.Interval = 40;GifTimer.Tick += OnTick;GifTimer.Start();this.paintCtrl_Main.Panel_Main.MouseClick += Panel_Main_MouseClick;}
}
private int currentFrame = 0;
/// <summary>
/// 切换当前帧数
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnTick(object sender, EventArgs e)
{currentFrame = (currentFrame + 1) % FrameCount;this.paintCtrl_Main.Panel_Main.Invalidate();
}private Timer GifTimer;
//加/减速
private void Panel_Main_MouseClick(object sender, MouseEventArgs e)
{if (e.Button == MouseButtons.Right){GifTimer.Interval *= 2;}else{var interval = GifTimer.Interval / 2;if (interval < 1){interval = 1;}GifTimer.Interval = interval;}
}
int FrameCount = 0;

使用Timer控制Gif播放

http://www.lryc.cn/news/366132.html

相关文章:

  • fps游戏如何快速定位矩阵
  • 【机器学习基础】Python编程06:五个实用练习题的解析与总结
  • R可视化:生存分析森林图
  • 一个 python+tensorFlow训练1万张图片分类的简单直观例子( 回答由百度 AI 给出 )
  • DBeaver无法连接Clickhouse,连接失败
  • python基础实例
  • ADASIS V2 协议-1
  • 人工智能安全风险分析及应对策略
  • Python驱动下的AI革命:技术赋能与案例解析
  • JavaScrip轮播图
  • 达梦8 网络中断对系统的影响
  • OpenAI发布GPT-4思维破解新策略,Ilya亦有贡献!
  • [消息队列 Kafka] Kafka 架构组件及其特性(二)Producer原理
  • faiss ivfpq索引构建
  • ffmpeg视频编码原理和实战-(2)视频帧的创建和编码packet压缩
  • 数据结构:线索二叉树
  • 宝塔Linux面板-Docker管理(2024详解)
  • 【Linux】进程(8):Linux真正是如何调度的
  • R语言探索与分析14-美国房价及其影响因素分析
  • golang websocket 数据处理和返回JSON数据示例
  • 【Mac】Downie 4 for Mac(视频download工具)兼容14系统软件介绍及安装教程
  • 【操作系统】进程与线程的区别及总结(非常非常重要,面试必考题,其它文章可以不看,但这篇文章最后的总结你必须要看,满满的全是干货......)
  • 自动驾驶仿真(高速道路)LaneKeeping
  • 数据挖掘实战-基于Catboost算法的艾滋病数据可视化与建模分析
  • 分水岭算法分割和霍夫变换识别图像中的硬币
  • 什么是AVIEXP提前发货通知?
  • Python 之SQLAlchemy使用详细说明
  • 就业班 第四阶段(docker) 2401--5.29 day3 Dockerfile+前后段项目若依ruoyi
  • 【运维项目经历|026】Redis智能集群构建与性能优化工程
  • Linux编程for、while循环if判断以及case语句用法